diff --git a/.gitignore b/.gitignore
index e7e8fba..1d3073f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,6 @@ Doxyfile
Doxyfile.zh-cn
DartConfiguration.tcl
*.nupkg
+
+# Files created by OS
+*.DS_Store
diff --git a/.travis.yml b/.travis.yml
index f9319f2..df821a7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
sudo: required
-dist: precise
+dist: trusty
+group: edge
language: cpp
cache:
@@ -13,7 +14,7 @@ env:
- CCACHE_MAXSIZE=100M
- ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit
- ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit
- - GITHUB_REPO='miloyip/rapidjson'
+ - GITHUB_REPO='Tencent/rapidjson'
- secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk="
before_install:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0205e7b..1c580bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -109,7 +109,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [1.0.0] - 2015-04-22
### Added
-* 100% [Coverall](https://coveralls.io/r/miloyip/rapidjson?branch=master) coverage.
+* 100% [Coverall](https://coveralls.io/r/Tencent/rapidjson?branch=master) coverage.
* Version macros (#311)
### Fixed
@@ -140,7 +140,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Redo all documentation (English, Simplified Chinese)
### Changed
-* Copyright ownership transfered to THL A29 Limited (a Tencent company).
+* Copyright ownership transferred to THL A29 Limited (a Tencent company).
* Migrating from Premake to CMAKE (#192)
* Resolve all warning reports
@@ -151,8 +151,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## 0.1 - 2011-11-18
-[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.1.0...HEAD
-[1.1.0]: https://github.com/miloyip/rapidjson/compare/v1.0.2...v1.1.0
-[1.0.2]: https://github.com/miloyip/rapidjson/compare/v1.0.1...v1.0.2
-[1.0.1]: https://github.com/miloyip/rapidjson/compare/v1.0.0...v1.0.1
-[1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0
+[Unreleased]: https://github.com/Tencent/rapidjson/compare/v1.1.0...HEAD
+[1.1.0]: https://github.com/Tencent/rapidjson/compare/v1.0.2...v1.1.0
+[1.0.2]: https://github.com/Tencent/rapidjson/compare/v1.0.1...v1.0.2
+[1.0.1]: https://github.com/Tencent/rapidjson/compare/v1.0.0...v1.0.1
+[1.0.0]: https://github.com/Tencent/rapidjson/compare/v1.0-beta...v1.0.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d6823a8..7c60407 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,10 +31,16 @@ option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
"Use gtest installation in `thirdparty/gtest` by default if available" OFF)
option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON)
+if(RAPIDJSON_BUILD_CXX11)
+ set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
+endif()
option(RAPIDJSON_BUILD_ASAN "Build rapidjson with address sanitizer (gcc/clang)" OFF)
option(RAPIDJSON_BUILD_UBSAN "Build rapidjson with undefined behavior sanitizer (gcc/clang)" OFF)
+option(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT "Build rapidjson with -march or -mcpu options" ON)
+
option(RAPIDJSON_HAS_STDSTRING "" OFF)
if(RAPIDJSON_HAS_STDSTRING)
add_definitions(-DRAPIDJSON_HAS_STDSTRING)
@@ -49,16 +55,18 @@ if(CCACHE_FOUND)
endif()
endif(CCACHE_FOUND)
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "powerpc" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
- else()
- #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER.
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT AND NOT CMAKE_CROSSCOMPILING)
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
+ else()
+ #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
+ endif()
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")
set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wsign-conversion)
- if (RAPIDJSON_BUILD_CXX11)
+ if (RAPIDJSON_BUILD_CXX11 AND CMAKE_VERSION VERSION_LESS 3.1)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
@@ -80,15 +88,17 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
endif()
endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "powerpc" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
- else()
- #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER.
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
+ if(NOT CMAKE_CROSSCOMPILING)
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
+ else()
+ #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
+ endif()
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-missing-field-initializers")
- set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough -Weverything)
- if (RAPIDJSON_BUILD_CXX11)
+ set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough)
+ if (RAPIDJSON_BUILD_CXX11 AND CMAKE_VERSION VERSION_LESS 3.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
if (RAPIDJSON_BUILD_ASAN)
@@ -101,7 +111,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
endif()
endif()
-elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL")
@@ -118,7 +128,7 @@ IF(UNIX OR CYGWIN)
ELSEIF(WIN32)
SET(_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/cmake")
ENDIF()
-SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake fiels are installed in")
+SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake files are installed in")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
@@ -181,6 +191,8 @@ EXPORT( PACKAGE ${PROJECT_NAME} )
# ... for the build tree
SET( CONFIG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
SET( CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR})
+SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_SOURCE_DIR}/include" )
+
CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY )
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in
diff --git a/RapidJSON.pc.in b/RapidJSON.pc.in
index 7467f97..6afb079 100644
--- a/RapidJSON.pc.in
+++ b/RapidJSON.pc.in
@@ -3,5 +3,5 @@ includedir=@INCLUDE_INSTALL_DIR@
Name: @PROJECT_NAME@
Description: A fast JSON parser/generator for C++ with both SAX/DOM style API
Version: @LIB_VERSION_STRING@
-URL: https://github.com/miloyip/rapidjson
+URL: https://github.com/Tencent/rapidjson
Cflags: -I${includedir}
diff --git a/bin/jsonschema/remotes/.DS_Store b/bin/jsonschema/remotes/.DS_Store
deleted file mode 100644
index 1d098a4..0000000
Binary files a/bin/jsonschema/remotes/.DS_Store and /dev/null differ
diff --git a/bin/jsonschema/tests/.DS_Store b/bin/jsonschema/tests/.DS_Store
deleted file mode 100644
index dae9b18..0000000
Binary files a/bin/jsonschema/tests/.DS_Store and /dev/null differ
diff --git a/bin/jsonschema/tests/draft4/.DS_Store b/bin/jsonschema/tests/draft4/.DS_Store
deleted file mode 100644
index ef14229..0000000
Binary files a/bin/jsonschema/tests/draft4/.DS_Store and /dev/null differ
diff --git a/contrib/natvis/LICENSE b/contrib/natvis/LICENSE
new file mode 100644
index 0000000..f57da96
--- /dev/null
+++ b/contrib/natvis/LICENSE
@@ -0,0 +1,45 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Bart Muzzin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Derived from:
+
+The MIT License (MIT)
+
+Copyright (c) 2015 mojmir svoboda
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/contrib/natvis/README.md b/contrib/natvis/README.md
new file mode 100644
index 0000000..9685c7f
--- /dev/null
+++ b/contrib/natvis/README.md
@@ -0,0 +1,7 @@
+# rapidjson.natvis
+
+This file can be used as a [Visual Studio Visualizer](https://docs.microsoft.com/en-gb/visualstudio/debugger/create-custom-views-of-native-objects) to aid in visualizing rapidjson structures within the Visual Studio debugger. Natvis visualizers are supported in Visual Studio 2012 and later. To install, copy the file into this directory:
+
+`%USERPROFILE%\Documents\Visual Studio 2012\Visualizers`
+
+Each version of Visual Studio has a similar directory, it must be copied into each directory to be used with that particular version. In Visual Studio 2015 and later, this can be done without restarting Visual Studio (a new debugging session must be started).
diff --git a/contrib/natvis/rapidjson.natvis b/contrib/natvis/rapidjson.natvis
new file mode 100644
index 0000000..a804b7b
--- /dev/null
+++ b/contrib/natvis/rapidjson.natvis
@@ -0,0 +1,38 @@
+
+
+
+
+ null
+ true
+ false
+ {data_.ss.str}
+ {(const char*)((size_t)data_.s.str & 0x0000FFFFFFFFFFFF)}
+ {data_.n.i.i}
+ {data_.n.u.u}
+ {data_.n.i64}
+ {data_.n.u64}
+ {data_.n.d}
+ Object members={data_.o.size}
+ Array members={data_.a.size}
+
+ - data_.o.size
+ - data_.o.capacity
+
+ data_.o.size
+
+ (rapidjson::GenericMember<$T1,$T2>*)(((size_t)data_.o.members) & 0x0000FFFFFFFFFFFF)
+
+
+ - data_.a.size
+ - data_.a.capacity
+
+ data_.a.size
+
+ (rapidjson::GenericValue<$T1,$T2>*)(((size_t)data_.a.elements) & 0x0000FFFFFFFFFFFF)
+
+
+
+
+
+
+
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index c1f165a..c5345ba 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -10,11 +10,13 @@ ELSE()
CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY)
CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY)
+ file(GLOB DOXYFILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile*)
+
add_custom_command(OUTPUT html
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html
- DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile*
+ DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${DOXYFILES}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../
)
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index ca14233..6e79f93 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -1126,7 +1126,7 @@ HTML_STYLESHEET =
# defined cascading style sheet that is included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
+# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet file to the output directory. For an example
# see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
diff --git a/doc/Doxyfile.zh-cn.in b/doc/Doxyfile.zh-cn.in
index e7fffa6..6a08f72 100644
--- a/doc/Doxyfile.zh-cn.in
+++ b/doc/Doxyfile.zh-cn.in
@@ -1126,7 +1126,7 @@ HTML_STYLESHEET =
# defined cascading style sheet that is included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
+# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet file to the output directory. For an example
# see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
diff --git a/doc/diagram/move2.dot b/doc/diagram/move2.dot
index 7037ea6..2319871 100644
--- a/doc/diagram/move2.dot
+++ b/doc/diagram/move2.dot
@@ -18,7 +18,7 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7]
- c1 [label="{contact:array|}", fillcolor=4]
+ c1 [label="{contacts:array|}", fillcolor=4]
c11 [label="{|}"]
c12 [label="{|}"]
c13 [shape="none", label="...", style="solid"]
@@ -41,13 +41,13 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7]
- c2 [label="{contact:array|}", fillcolor=4]
+ c2 [label="{contacts:array|}", fillcolor=4]
c3 [label="{array|}", fillcolor=4]
c21 [label="{|}"]
c22 [label="{|}"]
c23 [shape=none, label="...", style="solid"]
o2 [label="{o:object|}", fillcolor=3]
- cs [label="{string|\"contact\"}", fillcolor=5]
+ cs [label="{string|\"contacts\"}", fillcolor=5]
c31 [label="{|}"]
c32 [label="{|}"]
c33 [shape="none", label="...", style="solid"]
@@ -59,4 +59,4 @@ digraph {
c3 -> { c31; c32; c33 }
}
ghost -> o2 [style=invis]
-}
\ No newline at end of file
+}
diff --git a/doc/diagram/move3.dot b/doc/diagram/move3.dot
index c197b99..57adb4f 100644
--- a/doc/diagram/move3.dot
+++ b/doc/diagram/move3.dot
@@ -19,7 +19,7 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7]
- c1 [label="{contact:array|}", fillcolor=4]
+ c1 [label="{contacts:array|}", fillcolor=4]
c11 [label="{|}"]
c12 [label="{|}"]
c13 [shape=none, label="...", style="solid"]
@@ -42,13 +42,13 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7]
- c2 [label="{contact:null|}", fillcolor=1]
+ c2 [label="{contacts:null|}", fillcolor=1]
c3 [label="{array|}", fillcolor=4]
c21 [label="{|}"]
c22 [label="{|}"]
c23 [shape="none", label="...", style="solid"]
o2 [label="{o:object|}", fillcolor=3]
- cs [label="{string|\"contact\"}", fillcolor=5]
+ cs [label="{string|\"contacts\"}", fillcolor=5]
c2 -> o2 [style="dashed", constraint=false, label="AddMember", style=invis]
edge [arrowhead=vee]
@@ -57,4 +57,4 @@ digraph {
cs -> c3 [arrowhead=none]
}
ghost -> o2 [style=invis]
-}
\ No newline at end of file
+}
diff --git a/doc/dom.md b/doc/dom.md
index 6c541fe..0079b64 100644
--- a/doc/dom.md
+++ b/doc/dom.md
@@ -128,7 +128,7 @@ And the `InputStream` is type of input stream.
## Parse Error {#ParseError}
-When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetParseOffset()`.
+When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetErrorOffset()`.
Parse Error Code | Description
--------------------------------------------|---------------------------------------------------
@@ -241,7 +241,7 @@ Some techniques about using DOM API is discussed here.
## DOM as SAX Event Publisher
-In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weired.
+In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weird.
~~~~~~~~~~cpp
// ...
diff --git a/doc/dom.zh-cn.md b/doc/dom.zh-cn.md
index b709485..9743b7a 100644
--- a/doc/dom.zh-cn.md
+++ b/doc/dom.zh-cn.md
@@ -128,7 +128,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
## 解析错误 {#ParseError}
-当解析过程顺利完成,`Document` 便会含有解析结果。当过程出现错误,原来的 DOM 会*维持不变*。可使用 `bool HasParseError()`、`ParseErrorCode GetParseError()` 及 `size_t GetParseOffset()` 获取解析的错误状态。
+当解析过程顺利完成,`Document` 便会含有解析结果。当过程出现错误,原来的 DOM 会*维持不变*。可使用 `bool HasParseError()`、`ParseErrorCode GetParseError()` 及 `size_t GetErrorOffset()` 获取解析的错误状态。
解析错误代号 | 描述
--------------------------------------------|---------------------------------------------------
diff --git a/doc/encoding.md b/doc/encoding.md
index 8f8ff7f..e663aea 100644
--- a/doc/encoding.md
+++ b/doc/encoding.md
@@ -10,7 +10,7 @@ The earlier [RFC4627](http://www.ietf.org/rfc/rfc4627.txt) stated that,
> (in §6) JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON is written in UTF-8, JSON is 8bit compatible. When JSON is written in UTF-16 or UTF-32, the binary content-transfer-encoding must be used.
-RapidJSON supports various encodings. It can also validate the encodings of JSON, and transconding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)).
+RapidJSON supports various encodings. It can also validate the encodings of JSON, and transcoding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)).
[TOC]
diff --git a/doc/faq.md b/doc/faq.md
index 1b0541c..1d738c0 100644
--- a/doc/faq.md
+++ b/doc/faq.md
@@ -18,7 +18,7 @@
4. Is RapidJSON free?
- Yes, it is free under MIT license. It can be used in commercial applications. Please check the details in [license.txt](https://github.com/miloyip/rapidjson/blob/master/license.txt).
+ Yes, it is free under MIT license. It can be used in commercial applications. Please check the details in [license.txt](https://github.com/Tencent/rapidjson/blob/master/license.txt).
5. Is RapidJSON small? What are its dependencies?
@@ -44,7 +44,7 @@
10. How RapidJSON is tested?
- RapidJSON contains a unit test suite for automatic testing. [Travis](https://travis-ci.org/miloyip/rapidjson/)(for Linux) and [AppVeyor](https://ci.appveyor.com/project/miloyip/rapidjson/)(for Windows) will compile and run the unit test suite for all modifications. The test process also uses Valgrind (in Linux) to detect memory leaks.
+ RapidJSON contains a unit test suite for automatic testing. [Travis](https://travis-ci.org/Tencent/rapidjson/)(for Linux) and [AppVeyor](https://ci.appveyor.com/project/Tencent/rapidjson/)(for Windows) will compile and run the unit test suite for all modifications. The test process also uses Valgrind (in Linux) to detect memory leaks.
11. Is RapidJSON well documented?
@@ -70,7 +70,7 @@
3. Does RapidJSON support relaxed syntax?
- Currently no. RapidJSON only support the strict standardized format. Support on related syntax is under discussion in this [issue](https://github.com/miloyip/rapidjson/issues/36).
+ Currently no. RapidJSON only support the strict standardized format. Support on related syntax is under discussion in this [issue](https://github.com/Tencent/rapidjson/issues/36).
## DOM and SAX
@@ -116,7 +116,7 @@
~~~~~~~~~~cpp
Value(kObjectType).Swap(d);
~~~~~~~~~~
- or equivalent, but sightly longer to type:
+ or equivalent, but slightly longer to type:
~~~~~~~~~~cpp
d.Swap(Value(kObjectType).Move());
~~~~~~~~~~
@@ -140,11 +140,11 @@
}
~~~~~~~~~~
- 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 management using the right allocator during the value transfer.
Simple yet most efficient way to achieve that is to modify the `address` definition above to initialize it with allocator of the `person` document, then we just add the root member of the value:
~~~~~~~~~~cpp
- Documnet address(person.GetAllocator());
+ Document address(person.GetAllocator());
...
person["person"].AddMember("address", address["address"], person.GetAllocator());
~~~~~~~~~~
@@ -174,7 +174,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
3. Why do I need to provide the length of string?
- Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unncessary overhead of many operations, if the user already knows the length of string.
+ Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unnecessary overhead of many operations, if the user already knows the length of string.
Also, RapidJSON can handle `\u0000` (null character) within a string. If a string contains null characters, `strlen()` cannot return the true length of it. In such case user must provide the length of string explicitly.
@@ -204,7 +204,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
2. Can it validate the encoding?
- Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it wil generate `kParseErrorStringInvalidEncoding` error.
+ Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it will generate `kParseErrorStringInvalidEncoding` error.
3. What is surrogate pair? Does RapidJSON support it?
@@ -236,7 +236,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
4. What is BOM? How RapidJSON handle it?
- [Byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark) sometimes reside at the beginning of file/stream to indiciate the UTF encoding type of it.
+ [Byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark) sometimes reside at the beginning of file/stream to indicate the UTF encoding type of it.
RapidJSON's `EncodedInputStream` can detect/consume BOM. `EncodedOutputStream` can optionally write a BOM. See [Encoded Streams](doc/stream.md) for example.
@@ -248,7 +248,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
1. Is RapidJSON really fast?
- Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libaries.
+ Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libraries.
2. Why is it fast?
@@ -256,19 +256,19 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
3. What is SIMD? How it is applied in RapidJSON?
- [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 to accelerate whitespace skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash.
+ [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 and ARM's Neon to accelerate whitespace/tabspace/carriage-return/line-feed skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2`, `RAPIDJSON_SSE42` or `RAPIDJSON_NEON` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash.
4. Does it consume a lot of memory?
The design of RapidJSON aims at reducing memory footprint.
- In the SAX API, `Reader` consumes memory portional to maximum depth of JSON tree, plus maximum length of JSON string.
+ In the SAX API, `Reader` consumes memory proportional to maximum depth of JSON tree, plus maximum length of JSON string.
In the DOM API, each `Value` consumes exactly 16/24 bytes for 32/64-bit architecture respectively. RapidJSON also uses a special memory allocator to minimize overhead of allocations.
5. What is the purpose of being high performance?
- Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throuput. In a broad sense, it will also save energy.
+ Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throughput. In a broad sense, it will also save energy.
## Gossip
diff --git a/doc/faq.zh-cn.md b/doc/faq.zh-cn.md
index f12d830..f279acf 100644
--- a/doc/faq.zh-cn.md
+++ b/doc/faq.zh-cn.md
@@ -18,7 +18,7 @@
4. RapidJSON 是免费的么?
- 是的,它在 MIT 特許條款下免费。它可用于商业软件。详情请参看 [license.txt](https://github.com/miloyip/rapidjson/blob/master/license.txt)。
+ 是的,它在 MIT 特許條款下免费。它可用于商业软件。详情请参看 [license.txt](https://github.com/Tencent/rapidjson/blob/master/license.txt)。
5. RapidJSON 很小么?它有何依赖?
@@ -44,7 +44,7 @@
10. RapidJSON 是如何被测试的?
- RapidJSON 包含一组单元测试去执行自动测试。[Travis](https://travis-ci.org/miloyip/rapidjson/)(供 Linux 平台)及 [AppVeyor](https://ci.appveyor.com/project/miloyip/rapidjson/)(供 Windows 平台)会对所有修改进行编译及执行单元测试。在 Linux 下还会使用 Valgrind 去检测内存泄漏。
+ RapidJSON 包含一组单元测试去执行自动测试。[Travis](https://travis-ci.org/Tencent/rapidjson/)(供 Linux 平台)及 [AppVeyor](https://ci.appveyor.com/project/Tencent/rapidjson/)(供 Windows 平台)会对所有修改进行编译及执行单元测试。在 Linux 下还会使用 Valgrind 去检测内存泄漏。
11. RapidJSON 是否有完整的文档?
@@ -70,7 +70,7 @@
3. RapidJSON 是否支持宽松的语法?
- 现时不支持。RapidJSON 只支持严格的标准格式。宽松语法现时在这 [issue](https://github.com/miloyip/rapidjson/issues/36) 中进行讨论。
+ 现时不支持。RapidJSON 只支持严格的标准格式。宽松语法现时在这 [issue](https://github.com/Tencent/rapidjson/issues/36) 中进行讨论。
## DOM 与 SAX
@@ -257,7 +257,7 @@
3. 什是是 SIMD?它如何用于 RapidJSON?
- [SIMD](http://en.wikipedia.org/wiki/SIMD) 指令可以在现代 CPU 中执行并行运算。RapidJSON 支持了 Intel 的 SSE2/SSE4.2 去加速跳过空白字符。在解析含缩进的 JSON 时,这能提升性能。只要定义名为 `RAPIDJSON_SSE2` 或 `RAPIDJSON_SSE42` 的宏,就能启动这个功能。然而,若在不支持这些指令集的机器上执行这些可执行文件,会导致崩溃。
+ [SIMD](http://en.wikipedia.org/wiki/SIMD) 指令可以在现代 CPU 中执行并行运算。RapidJSON 支持使用 Intel 的 SSE2/SSE4.2 和 ARM 的 Neon 来加速对空白符、制表符、回车符和换行符的过滤处理。在解析含缩进的 JSON 时,这能提升性能。只要定义名为 `RAPIDJSON_SSE2` ,`RAPIDJSON_SSE42` 或 `RAPIDJSON_NEON` 的宏,就能启动这个功能。然而,若在不支持这些指令集的机器上执行这些可执行文件,会导致崩溃。
4. 它会消耗许多内存么?
diff --git a/doc/features.md b/doc/features.md
index 732fb21..0d79e7f 100644
--- a/doc/features.md
+++ b/doc/features.md
@@ -29,7 +29,7 @@
* Single line (`// ...`) and multiple line (`/* ... */`) comments (`kParseCommentsFlag`).
* Trailing commas at the end of objects and arrays (`kParseTrailingCommasFlag`).
* `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (`kParseNanAndInfFlag`)
-* [NPM compliant](http://github.com/miloyip/rapidjson/blob/master/doc/npm.md).
+* [NPM compliant](http://github.com/Tencent/rapidjson/blob/master/doc/npm.md).
## Unicode
diff --git a/doc/features.zh-cn.md b/doc/features.zh-cn.md
index 19908a8..7662cc1 100644
--- a/doc/features.zh-cn.md
+++ b/doc/features.zh-cn.md
@@ -29,7 +29,7 @@
* 单行(`// ...`)及多行(`/* ... */`) 注释 (`kParseCommentsFlag`)。
* 在对象和数组结束前含逗号 (`kParseTrailingCommasFlag`)。
* `NaN`、`Inf`、`Infinity`、`-Inf` 及 `-Infinity` 作为 `double` 值 (`kParseNanAndInfFlag`)
-* [NPM 兼容](https://github.com/miloyip/rapidjson/blob/master/doc/npm.md).
+* [NPM 兼容](https://github.com/Tencent/rapidjson/blob/master/doc/npm.md).
## Unicode
diff --git a/doc/internals.md b/doc/internals.md
index 49802a0..706f98c 100644
--- a/doc/internals.md
+++ b/doc/internals.md
@@ -28,7 +28,7 @@ Both SAX and DOM APIs depends on 3 additional concepts: `Allocator`, `Encoding`
## Data Layout {#DataLayout}
-`Value` is a [variant type](http://en.wikipedia.org/wiki/Variant_type). In RapidJSON's context, an instance of `Value` can contain 1 of 6 JSON value types. This is possible by using `union`. Each `Value` contains two members: `union Data data_` and a`unsigned flags_`. The `flags_` indiciates the JSON type, and also additional information.
+`Value` is a [variant type](http://en.wikipedia.org/wiki/Variant_type). In RapidJSON's context, an instance of `Value` can contain 1 of 6 JSON value types. This is possible by using `union`. Each `Value` contains two members: `union Data data_` and a`unsigned flags_`. The `flags_` indicates the JSON type, and also additional information.
The following tables show the data layout of each type. The 32-bit/64-bit columns indicates the size of the field in bytes.
@@ -101,7 +101,7 @@ The following tables show the data layout of each type. The 32-bit/64-bit column
Here are some notes:
* To reduce memory consumption for 64-bit architecture, `SizeType` is typedef as `unsigned` instead of `size_t`.
-* Zero padding for 32-bit number may be placed after or before the actual type, according to the endianess. This makes possible for interpreting a 32-bit integer as a 64-bit integer, without any conversion.
+* Zero padding for 32-bit number may be placed after or before the actual type, according to the endianness. This makes possible for interpreting a 32-bit integer as a 64-bit integer, without any conversion.
* An `Int` is always an `Int64`, but the converse is not always true.
## Flags {#Flags}
@@ -183,17 +183,20 @@ void SkipWhitespace(InputStream& s) {
However, this requires 4 comparisons and a few branching for each character. This was found to be a hot spot.
-To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON only supports SSE2 and SSE4.2 instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing.
+To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON supports SSE2, SSE4.2 and ARM Neon instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing.
-To enable this optimization, need to define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`:
+To enable this optimization, need to define `RAPIDJSON_SSE2`, `RAPIDJSON_SSE42` or `RAPIDJSON_NEON` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`:
~~~cpp
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
+// Likewise, __ARM_NEON is used to detect Neon.
#if defined(__SSE4_2__)
# define RAPIDJSON_SSE42
#elif defined(__SSE2__)
# define RAPIDJSON_SSE2
+#elif defined(__ARM_NEON)
+# define RAPIDJSON_NEON
#endif
~~~
@@ -211,7 +214,7 @@ In [Intel® 64 and IA-32 Architectures Optimization Reference Manual
This is not feasible as RapidJSON should not enforce such requirement.
-To fix this issue, currently the routine process bytes up to the next aligned address. After tha, use aligned read to perform SIMD processing. Also see [#85](https://github.com/miloyip/rapidjson/issues/85).
+To fix this issue, currently the routine process bytes up to the next aligned address. After tha, use aligned read to perform SIMD processing. Also see [#85](https://github.com/Tencent/rapidjson/issues/85).
## Local Stream Copy {#LocalStreamCopy}
diff --git a/doc/internals.zh-cn.md b/doc/internals.zh-cn.md
index ec57959..ca3d297 100644
--- a/doc/internals.zh-cn.md
+++ b/doc/internals.zh-cn.md
@@ -183,17 +183,20 @@ void SkipWhitespace(InputStream& s) {
但是,这需要对每个字符进行4次比较以及一些分支。这被发现是一个热点。
-为了加速这一处理,RapidJSON 使用 SIMD 来在一次迭代中比较16个字符和4个空格。目前 RapidJSON 只支持 SSE2 和 SSE4.2 指令。同时它也只会对 UTF-8 内存流启用,包括字符串流或 *原位* 解析。
+为了加速这一处理,RapidJSON 使用 SIMD 来在一次迭代中比较16个字符和4个空格。目前 RapidJSON 支持 SSE2 , SSE4.2 和 ARM Neon 指令。同时它也只会对 UTF-8 内存流启用,包括字符串流或 *原位* 解析。
-你可以通过在包含 `rapidjson.h` 之前定义 `RAPIDJSON_SSE2` 或 `RAPIDJSON_SSE42` 来启用这个优化。一些编译器可以检测这个设置,如 `perftest.h`:
+你可以通过在包含 `rapidjson.h` 之前定义 `RAPIDJSON_SSE2` , `RAPIDJSON_SSE42` 或 `RAPIDJSON_NEON` 来启用这个优化。一些编译器可以检测这个设置,如 `perftest.h`:
~~~cpp
// __SSE2__ 和 __SSE4_2__ 可被 gcc、clang 和 Intel 编译器识别:
// 如果支持的话,我们在 gmake 中使用了 -march=native 来启用 -msse2 和 -msse4.2
+// 同样的, __ARM_NEON 被用于识别Neon
#if defined(__SSE4_2__)
# define RAPIDJSON_SSE42
#elif defined(__SSE2__)
# define RAPIDJSON_SSE2
+#elif defined(__ARM_NEON)
+# define RAPIDJSON_NEON
#endif
~~~
@@ -211,7 +214,7 @@ void SkipWhitespace(InputStream& s) {
对于 RapidJSON 来说,这显然是不可行的,因为 RapidJSON 不应当强迫用户进行内存对齐。
-为了修复这个问题,当前的代码会先按字节处理直到下一个对齐的地址。在这之后,使用对齐读取来进行 SIMD 处理。见 [#85](https://github.com/miloyip/rapidjson/issues/85)。
+为了修复这个问题,当前的代码会先按字节处理直到下一个对齐的地址。在这之后,使用对齐读取来进行 SIMD 处理。见 [#85](https://github.com/Tencent/rapidjson/issues/85)。
## 局部流拷贝 {#LocalStreamCopy}
diff --git a/doc/misc/header.html b/doc/misc/header.html
index 2dbe721..a89ba46 100644
--- a/doc/misc/header.html
+++ b/doc/misc/header.html
@@ -18,7 +18,7 @@ $extrastylesheet
-
+
$searchbox
diff --git a/doc/npm.md b/doc/npm.md
index 5efa768..6f4e85a 100644
--- a/doc/npm.md
+++ b/doc/npm.md
@@ -7,7 +7,7 @@
...
"dependencies": {
...
- "rapidjson": "git@github.com:miloyip/rapidjson.git"
+ "rapidjson": "git@github.com:Tencent/rapidjson.git"
},
...
"gypfile": true
diff --git a/doc/performance.md b/doc/performance.md
index 988e799..6f9e1bf 100644
--- a/doc/performance.md
+++ b/doc/performance.md
@@ -1,6 +1,6 @@
# Performance
-There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 37 JSON libaries.
+There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 37 JSON libraries.
[1]: https://github.com/miloyip/nativejson-benchmark
@@ -15,12 +15,12 @@ Additionally, you may refer to the following third-party benchmarks.
* [json_spirit](https://github.com/cierelabs/json_spirit)
* [jsoncpp](http://jsoncpp.sourceforge.net/)
* [libjson](http://sourceforge.net/projects/libjson/)
- * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [rapidjson](https://github.com/Tencent/rapidjson/)
* [QJsonDocument](http://qt-project.org/doc/qt-5.0/qtcore/qjsondocument.html)
* [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013)
* [sajson](https://github.com/chadaustin/sajson)
- * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [rapidjson](https://github.com/Tencent/rapidjson/)
* [vjson](https://code.google.com/p/vjson/)
* [YAJL](http://lloyd.github.com/yajl/)
* [Jansson](http://www.digip.org/jansson/)
diff --git a/doc/performance.zh-cn.md b/doc/performance.zh-cn.md
index c20c505..2322c9c 100644
--- a/doc/performance.zh-cn.md
+++ b/doc/performance.zh-cn.md
@@ -15,12 +15,12 @@ RapidJSON 0.1 版本的性能测试文章位于 [这里](https://code.google.com
* [json_spirit](https://github.com/cierelabs/json_spirit)
* [jsoncpp](http://jsoncpp.sourceforge.net/)
* [libjson](http://sourceforge.net/projects/libjson/)
- * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [rapidjson](https://github.com/Tencent/rapidjson/)
* [QJsonDocument](http://qt-project.org/doc/qt-5.0/qtcore/qjsondocument.html)
* [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013)
* [sajson](https://github.com/chadaustin/sajson)
- * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [rapidjson](https://github.com/Tencent/rapidjson/)
* [vjson](https://code.google.com/p/vjson/)
* [YAJL](http://lloyd.github.com/yajl/)
* [Jansson](http://www.digip.org/jansson/)
diff --git a/doc/pointer.md b/doc/pointer.md
index b343d78..9a0e5ca 100644
--- a/doc/pointer.md
+++ b/doc/pointer.md
@@ -211,7 +211,7 @@ p.Stringify(sb);
std::cout << sb.GetString() << std::endl;
~~~
-It can also stringify to URI fragment reprsentation by `StringifyUriFragment()`.
+It can also stringify to URI fragment representation by `StringifyUriFragment()`.
# User-Supplied Tokens {#UserSuppliedTokens}
diff --git a/doc/sax.md b/doc/sax.md
index 4867880..874361f 100644
--- a/doc/sax.md
+++ b/doc/sax.md
@@ -126,7 +126,7 @@ When the `Reader` encounters a JSON number, it chooses a suitable C++ type mappi
When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeat until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler; users who do not need this parameter may ignore it.
-Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler.
+Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArray()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler.
Every handler function returns a `bool`. Normally it should return `true`. If the handler encounters an error, it can return `false` to notify the event publisher to stop further processing.
diff --git a/doc/schema.md b/doc/schema.md
index 8b4195b..238d7a5 100644
--- a/doc/schema.md
+++ b/doc/schema.md
@@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://
[TOC]
-## Basic Usage
+# Basic Usage {#Basic}
First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`.
@@ -20,7 +20,7 @@ Secondly, construct a `SchemaValidator` with the `SchemaDocument`. It is similar
// ...
Document sd;
-if (!sd.Parse(schemaJson).HasParseError()) {
+if (sd.Parse(schemaJson).HasParseError()) {
// the schema is not a valid JSON.
// ...
}
@@ -28,7 +28,7 @@ SchemaDocument schema(sd); // Compile a Document to SchemaDocument
// sd is no longer needed here.
Document d;
-if (!d.Parse(inputJson).HasParseError()) {
+if (d.Parse(inputJson).HasParseError()) {
// the input is not a valid JSON.
// ...
}
@@ -49,14 +49,14 @@ if (!d.Accept(validator)) {
Some notes:
-* One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s.
+* One `SchemaDocument` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s.
* A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first.
-## Validation during parsing/serialization
+# Validation during parsing/serialization {#Fused}
Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files.
-### DOM parsing
+## DOM parsing {#DOM}
For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work.
@@ -97,7 +97,7 @@ if (!reader.GetParseResult()) {
}
~~~
-### SAX parsing
+## SAX parsing {#SAX}
For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply:
@@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) {
}
~~~
-### Serialization
+## Serialization {#Serialization}
It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema.
@@ -144,7 +144,7 @@ if (!d.Accept(validator)) {
Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`.
-## Remote Schema
+# Remote Schema {#Remote}
JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](doc/pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example:
@@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider;
SchemaDocument schema(sd, &provider);
~~~
-## Conformance
+# Conformance {#Conformance}
RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4).
@@ -176,7 +176,7 @@ The failed test is "changed scope ref invalid" of "change resolution scope" in `
Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification.
-### Regular Expression
+## Regular Expression {#Regex}
The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern.
@@ -211,7 +211,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d
For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size.
-## Performance
+# Performance {#Performance}
Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js.
@@ -235,3 +235,271 @@ On a Mac Book Pro (2.8 GHz Intel Core i7), the following results are collected.
|[`jayschema`](https://github.com/natesilva/jayschema)|0.1%|21 (± 1.14%)|
That is, RapidJSON is about 1.5x faster than the fastest JavaScript library (ajv). And 1400x faster than the slowest one.
+
+# Schema violation reporting {#Reporting}
+
+(Unreleased as of 2017-09-20)
+
+When validating an instance against a JSON Schema,
+it is often desirable to report not only whether the instance is valid,
+but also the ways in which it violates the schema.
+
+The `SchemaValidator` class
+collects errors encountered during validation
+into a JSON `Value`.
+This error object can then be accessed as `validator.GetError()`.
+
+The structure of the error object is subject to change
+in future versions of RapidJSON,
+as there is no standard schema for violations.
+The details below this point are provisional only.
+
+## General provisions {#ReportingGeneral}
+
+Validation of an instance value against a schema
+produces an error value.
+The error value is always an object.
+An empty object `{}` indicates the instance is valid.
+
+* The name of each member
+ corresponds to the JSON Schema keyword that is violated.
+* The value is either an object describing a single violation,
+ or an array of such objects.
+
+Each violation object contains two string-valued members
+named `instanceRef` and `schemaRef`.
+`instanceRef` contains the URI fragment serialization
+of a JSON Pointer to the instance subobject
+in which the violation was detected.
+`schemaRef` contains the URI of the schema
+and the fragment serialization of a JSON Pointer
+to the subschema that was violated.
+
+Individual violation objects can contain other keyword-specific members.
+These are detailed further.
+
+For example, validating this instance:
+
+~~~json
+{"numbers": [1, 2, "3", 4, 5]}
+~~~
+
+against this schema:
+
+~~~json
+{
+ "type": "object",
+ "properties": {
+ "numbers": {"$ref": "numbers.schema.json"}
+ }
+}
+~~~
+
+where `numbers.schema.json` refers
+(via a suitable `IRemoteSchemaDocumentProvider`)
+to this schema:
+
+~~~json
+{
+ "type": "array",
+ "items": {"type": "number"}
+}
+~~~
+
+produces the following error object:
+
+~~~json
+{
+ "type": {
+ "instanceRef": "#/numbers/2",
+ "schemaRef": "numbers.schema.json#/items",
+ "expected": ["number"],
+ "actual": "string"
+ }
+}
+~~~
+
+## Validation keywords for numbers {#Numbers}
+
+### multipleOf {#multipleof}
+
+* `expected`: required number strictly greater than 0.
+ The value of the `multipleOf` keyword specified in the schema.
+* `actual`: required number.
+ The instance value.
+
+### maximum {#maximum}
+
+* `expected`: required number.
+ The value of the `maximum` keyword specified in the schema.
+* `exclusiveMaximum`: optional boolean.
+ This will be true if the schema specified `"exclusiveMaximum": true`,
+ and will be omitted otherwise.
+* `actual`: required number.
+ The instance value.
+
+### minimum {#minimum}
+
+* `expected`: required number.
+ The value of the `minimum` keyword specified in the schema.
+* `exclusiveMinimum`: optional boolean.
+ This will be true if the schema specified `"exclusiveMinimum": true`,
+ and will be omitted otherwise.
+* `actual`: required number.
+ The instance value.
+
+## Validation keywords for strings {#Strings}
+
+### maxLength {#maxLength}
+
+* `expected`: required number greater than or equal to 0.
+ The value of the `maxLength` keyword specified in the schema.
+* `actual`: required string.
+ The instance value.
+
+### minLength {#minLength}
+
+* `expected`: required number greater than or equal to 0.
+ The value of the `minLength` keyword specified in the schema.
+* `actual`: required string.
+ The instance value.
+
+### pattern {#pattern}
+
+* `actual`: required string.
+ The instance value.
+
+(The expected pattern is not reported
+because the internal representation in `SchemaDocument`
+does not store the pattern in original string form.)
+
+## Validation keywords for arrays {#Arrays}
+
+### additionalItems {#additionalItems}
+
+This keyword is reported
+when the value of `items` schema keyword is an array,
+the value of `additionalItems` is `false`,
+and the instance is an array
+with more items than specified in the `items` array.
+
+* `disallowed`: required integer greater than or equal to 0.
+ The index of the first item that has no corresponding schema.
+
+### maxItems and minItems {#maxItems-minItems}
+
+* `expected`: required integer greater than or equal to 0.
+ The value of `maxItems` (respectively, `minItems`)
+ specified in the schema.
+* `actual`: required integer greater than or equal to 0.
+ Number of items in the instance array.
+
+### uniqueItems {#uniqueItems}
+
+* `duplicates`: required array
+ whose items are integers greater than or equal to 0.
+ Indices of items of the instance that are equal.
+
+(RapidJSON only reports the first two equal items,
+for performance reasons.)
+
+## Validation keywords for objects
+
+### maxProperties and minProperties {#maxProperties-minProperties}
+
+* `expected`: required integer greater than or equal to 0.
+ The value of `maxProperties` (respectively, `minProperties`)
+ specified in the schema.
+* `actual`: required integer greater than or equal to 0.
+ Number of properties in the instance object.
+
+### required {#required}
+
+* `missing`: required array of one or more unique strings.
+ The names of properties
+ that are listed in the value of the `required` schema keyword
+ but not present in the instance object.
+
+### additionalProperties {#additionalProperties}
+
+This keyword is reported
+when the schema specifies `additionalProperties: false`
+and the name of a property of the instance is
+neither listed in the `properties` keyword
+nor matches any regular expression in the `patternProperties` keyword.
+
+* `disallowed`: required string.
+ Name of the offending property of the instance.
+
+(For performance reasons,
+RapidJSON only reports the first such property encountered.)
+
+### dependencies {#dependencies}
+
+* `errors`: required object with one or more properties.
+ Names and values of its properties are described below.
+
+Recall that JSON Schema Draft 04 supports
+*schema dependencies*,
+where presence of a named *controlling* property
+requires the instance object to be valid against a subschema,
+and *property dependencies*,
+where presence of a controlling property
+requires other *dependent* properties to be also present.
+
+For a violated schema dependency,
+`errors` will contain a property
+with the name of the controlling property
+and its value will be the error object
+produced by validating the instance object
+against the dependent schema.
+
+For a violated property dependency,
+`errors` will contain a property
+with the name of the controlling property
+and its value will be an array of one or more unique strings
+listing the missing dependent properties.
+
+## Validation keywords for any instance type {#AnyTypes}
+
+### enum {#enum}
+
+This keyword has no additional properties
+beyond `instanceRef` and `schemaRef`.
+
+* The allowed values are not listed
+ because `SchemaDocument` does not store them in original form.
+* The violating value is not reported
+ because it might be unwieldy.
+
+If you need to report these details to your users,
+you can access the necessary information
+by following `instanceRef` and `schemaRef`.
+
+### type {#type}
+
+* `expected`: required array of one or more unique strings,
+ each of which is one of the seven primitive types
+ defined by the JSON Schema Draft 04 Core specification.
+ Lists the types allowed by the `type` schema keyword.
+* `actual`: required string, also one of seven primitive types.
+ The primitive type of the instance.
+
+### allOf, anyOf, and oneOf {#allOf-anyOf-oneOf}
+
+* `errors`: required array of at least one object.
+ There will be as many items as there are subschemas
+ in the `allOf`, `anyOf` or `oneOf` schema keyword, respectively.
+ Each item will be the error value
+ produced by validating the instance
+ against the corresponding subschema.
+
+For `allOf`, at least one error value will be non-empty.
+For `anyOf`, all error values will be non-empty.
+For `oneOf`, either all error values will be non-empty,
+or more than one will be empty.
+
+### not {#not}
+
+This keyword has no additional properties
+apart from `instanceRef` and `schemaRef`.
diff --git a/doc/schema.zh-cn.md b/doc/schema.zh-cn.md
index fa076de..c85177f 100644
--- a/doc/schema.zh-cn.md
+++ b/doc/schema.zh-cn.md
@@ -8,7 +8,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document
[TOC]
-## 基本用法
+# 基本用法 {#BasicUsage}
首先,你要把 JSON Schema 解析成 `Document`,再把它编译成一个 `SchemaDocument`。
@@ -20,7 +20,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document
// ...
Document sd;
-if (!sd.Parse(schemaJson).HasParseError()) {
+if (sd.Parse(schemaJson).HasParseError()) {
// 此 schema 不是合法的 JSON
// ...
}
@@ -28,7 +28,7 @@ SchemaDocument schema(sd); // 把一个 Document 编译至 SchemaDocument
// 之后不再需要 sd
Document d;
-if (!d.Parse(inputJson).HasParseError()) {
+if (d.Parse(inputJson).HasParseError()) {
// 输入不是一个合法的 JSON
// ...
}
@@ -52,11 +52,11 @@ if (!d.Accept(validator)) {
* 一个 `SchemaDocment` 能被多个 `SchemaValidator` 引用。它不会被 `SchemaValidator` 修改。
* 可以重复使用一个 `SchemaValidator` 来校验多个文件。在校验其他文件前,须先调用 `validator.Reset()`。
-## 在解析/生成时进行校验
+# 在解析/生成时进行校验 {#ParsingSerialization}
与大部分 JSON Schema 校验器有所不同,RapidJSON 提供了一个基于 SAX 的 schema 校验器实现。因此,你可以在输入流解析 JSON 的同时进行校验。若校验器遇到一个与 schema 不符的值,就会立即终止解析。这设计对于解析大型 JSON 文件时特别有用。
-### DOM 解析
+## DOM 解析 {#DomParsing}
在使用 DOM 进行解析时,`Document` 除了接收 SAX 事件外,还需做一些准备及结束工作,因此,为了连接 `Reader`、`SchemaValidator` 和 `Document` 要做多一点事情。`SchemaValidatingReader` 是一个辅助类去做那些工作。
@@ -97,7 +97,7 @@ if (!reader.GetParseResult()) {
}
~~~
-### SAX 解析
+## SAX 解析 {#SaxParsing}
使用 SAX 解析时,情况就简单得多。若只需要校验 JSON 而无需进一步处理,那么仅需要:
@@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) {
}
~~~
-### 生成
+## 生成 {#Serialization}
我们也可以在生成(serialization)的时候进行校验。这能确保输出的 JSON 符合一个 JSON Schema。
@@ -144,7 +144,7 @@ if (!d.Accept(validator)) {
当然,如果你的应用仅需要 SAX 风格的生成,那么只需要把 SAX 事件由原来发送到 `Writer`,改为发送到 `SchemaValidator`。
-## 远程 Schema
+# 远程 Schema {#RemoteSchema}
JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个 [JSON pointer](doc/pointer.zh-cn.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或绝对 URI。例如:
@@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider;
SchemaDocument schema(sd, &provider);
~~~
-## 标准的符合程度
+# 标准的符合程度 {#Conformance}
RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4) 中 263 个测试的 262 个。
@@ -176,7 +176,7 @@ RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON
除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。
-### 正则表达式
+## 正则表达式 {#RegEx}
`pattern` 及 `patternProperties` 这两个 schema 关键字使用了正则表达式去匹配所需的模式。
@@ -211,7 +211,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用
对于使用 C++11 编译器的使用者,也可使用 `std::regex`,只需定义 `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` 及 `RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern` 或 `patternProperties`,可以把两个宏都设为零,以禁用此功能,这样做可节省一些代码体积。
-## 性能
+# 性能 {#Performance}
大部分 C++ JSON 库都未支持 JSON Schema。因此我们尝试按照 [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 去评估 RapidJSON 的 JSON Schema 校验器。该评测测试了 11 个运行在 node.js 上的 JavaScript 库。
diff --git a/doc/stream.md b/doc/stream.md
index b79ce53..d95de14 100644
--- a/doc/stream.md
+++ b/doc/stream.md
@@ -42,6 +42,7 @@ Note that, `StringStream` is a typedef of `GenericStringStream
>`, user m
~~~~~~~~~~cpp
#include "rapidjson/stringbuffer.h"
+#include
StringBuffer buffer;
Writer writer(buffer);
@@ -98,6 +99,7 @@ Apart from reading file, user can also use `FileReadStream` to read `stdin`.
~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h"
+#include
#include
using namespace rapidjson;
@@ -215,6 +217,7 @@ fclose(fp);
~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h" // FileWriteStream
#include "rapidjson/encodedstream.h" // EncodedOutputStream
+#include
#include
Document d; // Document is GenericDocument >
diff --git a/doc/stream.zh-cn.md b/doc/stream.zh-cn.md
index f2c54f7..7f2f356 100644
--- a/doc/stream.zh-cn.md
+++ b/doc/stream.zh-cn.md
@@ -42,6 +42,7 @@ d.Parse(json);
~~~~~~~~~~cpp
#include "rapidjson/stringbuffer.h"
+#include
StringBuffer buffer;
Writer writer(buffer);
@@ -98,6 +99,7 @@ fclose(fp);
~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h"
+#include
#include
using namespace rapidjson;
@@ -215,6 +217,7 @@ fclose(fp);
~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h" // FileWriteStream
#include "rapidjson/encodedstream.h" // EncodedOutputStream
+#include
#include
Document d; // Document 为 GenericDocument >
diff --git a/doc/tutorial.md b/doc/tutorial.md
index cb76b4b..3fa63c9 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -2,7 +2,7 @@
This tutorial introduces the basics of the Document Object Model(DOM) API.
-As shown in [Usage at a glance](@ref index), a JSON can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON.
+As shown in [Usage at a glance](@ref index), JSON can be parsed into a DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON.
[TOC]
@@ -14,7 +14,7 @@ Each JSON value is stored in a type called `Value`. A `Document`, representing t
In this section, we will use excerpt of `example/tutorial/tutorial.cpp`.
-Assumes we have a JSON stored in a C string (`const char* json`):
+Assume we have the following JSON stored in a C string (`const char* json`):
~~~~~~~~~~js
{
"hello": "world",
@@ -55,7 +55,7 @@ printf("hello = %s\n", document["hello"].GetString());
~~~~~~~~~~
~~~~~~~~~~
-world
+hello = world
~~~~~~~~~~
JSON true/false values are represented as `bool`.
@@ -65,16 +65,16 @@ printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
~~~~~~~~~~
~~~~~~~~~~
-true
+t = true
~~~~~~~~~~
-JSON null can be queryed by `IsNull()`.
+JSON null can be queried with `IsNull()`.
~~~~~~~~~~cpp
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
~~~~~~~~~~
~~~~~~~~~~
-null
+n = null
~~~~~~~~~~
JSON number type represents all numeric values. However, C++ needs more specific type for manipulation.
@@ -115,15 +115,15 @@ a[3] = 4
Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined.
-In the following, details about querying individual types are discussed.
+In the following sections we discuss details about querying individual types.
## Query Array {#QueryArray}
-By default, `SizeType` is typedef of `unsigned`. In most systems, array is limited to store up to 2^32-1 elements.
+By default, `SizeType` is typedef of `unsigned`. In most systems, an array is limited to store up to 2^32-1 elements.
-You may access the elements in array by integer literal, for example, `a[0]`, `a[1]`, `a[2]`.
+You may access the elements in an array by integer literal, for example, `a[0]`, `a[1]`, `a[2]`.
-Array is similar to `std::vector`, instead of using indices, you may also use iterator to access all the elements.
+Array is similar to `std::vector`: instead of using indices, you may also use iterator to access all the elements.
~~~~~~~~~~cpp
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
printf("%d ", itr->GetInt());
@@ -144,7 +144,7 @@ for (auto& v : a.GetArray())
## Query Object {#QueryObject}
-Similar to array, we can access all object members by iterator:
+Similar to Array, we can access all object members by iterator:
~~~~~~~~~~cpp
static const char* kTypeNames[] =
@@ -190,11 +190,11 @@ for (auto& m : document.GetObject())
## Querying Number {#QueryNumber}
-JSON provide a single numerical type called Number. Number can be integer or real numbers. RFC 4627 says the range of Number is specified by parser.
+JSON provides a single numerical type called Number. Number can be an integer or a real number. RFC 4627 says the range of Number is specified by the parser implementation.
-As C++ provides several integer and floating point number types, the DOM tries to handle these with widest possible range and good performance.
+As C++ provides several integer and floating point number types, the DOM tries to handle these with the widest possible range and good performance.
-When a Number is parsed, it is stored in the DOM as either one of the following type:
+When a Number is parsed, it is stored in the DOM as one of the following types:
Type | Description
-----------|---------------------------------------
@@ -204,7 +204,7 @@ Type | Description
`int64_t` | 64-bit signed integer
`double` | 64-bit double precision floating point
-When querying a number, you can check whether the number can be obtained as target type:
+When querying a number, you can check whether the number can be obtained as the target type:
Checking | Obtaining
------------------|---------------------
@@ -215,9 +215,9 @@ Checking | Obtaining
`bool IsInt64()` | `int64_t GetInt64()`
`bool IsDouble()` | `double GetDouble()`
-Note that, an integer value may be obtained in various ways without conversion. For example, A value `x` containing 123 will make `x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true`. But a value `y` containing -3000000000 will only makes `x.IsInt64() == true`.
+Note that, an integer value may be obtained in various ways without conversion. For example, A value `x` containing 123 will make `x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true`. But a value `y` containing -3000000000 will only make `x.IsInt64() == true`.
-When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `unsigned` can be safely convert to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits).
+When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `unsigned` can be safely converted to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits).
## Query String {#QueryString}
@@ -225,7 +225,7 @@ In addition to `GetString()`, the `Value` class also contains `GetStringLength()
According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats ``\0'` as the terminator symbol.
-To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` API to obtain the correct length of string.
+To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` to obtain the correct string length.
For example, after parsing a the following JSON to `Document d`:
@@ -360,14 +360,14 @@ a.PushBack(Value(42).Move(), allocator); // same as above
~~~~~~~~~~
## Create String {#CreateString}
-RapidJSON provide two strategies for storing string.
+RapidJSON provides two strategies for storing string.
1. copy-string: allocates a buffer, and then copy the source data into it.
2. const-string: simply store a pointer of string.
-Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing string literal, and in-situ parsing which we will mentioned in Document section.
+Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing a string literal, and for in-situ parsing which will be mentioned in the DOM section.
-To make memory allocation customizable, RapidJSON requires user to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value.
+To make memory allocation customizable, RapidJSON requires users to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value.
Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator:
@@ -385,7 +385,7 @@ In this example, we get the allocator from a `Document` instance. This is a comm
Besides, the above `SetString()` requires length. This can handle null characters within a string. There is another `SetString()` overloaded function without the length parameter. And it assumes the input is null-terminated and calls a `strlen()`-like function to obtain the length.
-Finally, for string literal or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter. For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient:
+Finally, for a string literal or string with a safe life-cycle one can use the const-string version of `SetString()`, which lacks an allocator parameter. For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient:
~~~~~~~~~~cpp
Value s;
@@ -393,7 +393,7 @@ s.SetString("rapidjson"); // can contain null character, length derived at co
s = "rapidjson"; // shortcut, same as above
~~~~~~~~~~
-For character pointer, the RapidJSON requires to mark it as safe before using it without copying. This can be achieved by using the `StringRef` function:
+For a character pointer, RapidJSON requires it to be marked as safe before using it without copying. This can be achieved by using the `StringRef` function:
~~~~~~~~~cpp
const char * cstr = getenv("USER");
@@ -408,7 +408,7 @@ s = StringRef(cstr,cstr_len); // shortcut, same as above
~~~~~~~~~
## Modify Array {#ModifyArray}
-Value with array type provides similar APIs as `std::vector`.
+Value with array type provides an API similar to `std::vector`.
* `Clear()`
* `Reserve(SizeType, Allocator&)`
@@ -418,7 +418,7 @@ Value with array type provides similar APIs as `std::vector`.
* `ValueIterator Erase(ConstValueIterator pos)`
* `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)`
-Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore require an allocator.
+Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore requiring an allocator.
Here is an example of `PushBack()`:
@@ -433,7 +433,7 @@ for (int i = 5; i <= 10; i++)
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
~~~~~~~~~~
-Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called _fluent interface_.
+This API differs from STL in that `PushBack()`/`PopBack()` return the array reference itself. This is called _fluent interface_.
If you want to add a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)) to the array, you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:
@@ -448,7 +448,7 @@ contact.PushBack(val, document.GetAllocator());
~~~~~~~~~~
## Modify Object {#ModifyObject}
-Object is a collection of key-value pairs (members). Each key must be a string value. To modify an object, either add or remove members. THe following APIs are for adding members:
+The Object class is a collection of key-value pairs (members). Each key must be a string value. To modify an object, either add or remove members. The following API is for adding members:
* `Value& AddMember(Value&, Value&, Allocator& allocator)`
* `Value& AddMember(StringRefType, Value&, Allocator&)`
@@ -462,7 +462,7 @@ contact.AddMember("name", "Milo", document.GetAllocator());
contact.AddMember("married", true, document.GetAllocator());
~~~~~~~~~~
-The name parameter with `StringRefType` is similar to the interface of `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, as constant key names are very common in JSON objects.
+The name parameter with `StringRefType` is similar to the interface of the `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, since constant key names are very common in JSON objects.
If you need to create a name from a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)), you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:
diff --git a/doc/tutorial.zh-cn.md b/doc/tutorial.zh-cn.md
index ec1315c..6b2588f 100644
--- a/doc/tutorial.zh-cn.md
+++ b/doc/tutorial.zh-cn.md
@@ -343,7 +343,7 @@ Value o(kObjectType);

-在 C++11 中这称为转移赋值操作(move assignment operator)。由于 RapidJSON 支持 C++03,它在赋值操作采用转移语义,其它修改形函数如 `AddMember()`, `PushBack()` 也采用转移语义。
+在 C++11 中这称为转移赋值操作(move assignment operator)。由于 RapidJSON 支持 C++03,它在赋值操作采用转移语义,其它修改型函数如 `AddMember()`, `PushBack()` 也采用转移语义。
### 转移语义及临时值 {#TemporaryValues}
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
index e00f77a..ff54199 100644
--- a/example/CMakeLists.txt
+++ b/example/CMakeLists.txt
@@ -32,6 +32,8 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
+add_executable(archivertest archiver/archiver.cpp archiver/archivertest.cpp)
+
foreach (example ${EXAMPLES})
add_executable(${example} ${example}/${example}.cpp)
endforeach()
diff --git a/example/archiver/archiver.cpp b/example/archiver/archiver.cpp
new file mode 100644
index 0000000..59ae4c4
--- /dev/null
+++ b/example/archiver/archiver.cpp
@@ -0,0 +1,292 @@
+#include "archiver.h"
+#include
+#include
+#include "rapidjson/document.h"
+#include "rapidjson/prettywriter.h"
+#include "rapidjson/stringbuffer.h"
+
+using namespace rapidjson;
+
+struct JsonReaderStackItem {
+ enum State {
+ BeforeStart, //!< An object/array is in the stack but it is not yet called by StartObject()/StartArray().
+ Started, //!< An object/array is called by StartObject()/StartArray().
+ Closed //!< An array is closed after read all element, but before EndArray().
+ };
+
+ JsonReaderStackItem(const Value* value, State state) : value(value), state(state), index() {}
+
+ const Value* value;
+ State state;
+ SizeType index; // For array iteration
+};
+
+typedef std::stack JsonReaderStack;
+
+#define DOCUMENT reinterpret_cast(mDocument)
+#define STACK (reinterpret_cast(mStack))
+#define TOP (STACK->top())
+#define CURRENT (*TOP.value)
+
+JsonReader::JsonReader(const char* json) : mDocument(), mStack(), mError(false) {
+ mDocument = new Document;
+ DOCUMENT->Parse(json);
+ if (DOCUMENT->HasParseError())
+ mError = true;
+ else {
+ mStack = new JsonReaderStack;
+ STACK->push(JsonReaderStackItem(DOCUMENT, JsonReaderStackItem::BeforeStart));
+ }
+}
+
+JsonReader::~JsonReader() {
+ delete DOCUMENT;
+ delete STACK;
+}
+
+// Archive concept
+JsonReader& JsonReader::StartObject() {
+ if (!mError) {
+ if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::BeforeStart)
+ TOP.state = JsonReaderStackItem::Started;
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::EndObject() {
+ if (!mError) {
+ if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started)
+ Next();
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::Member(const char* name) {
+ if (!mError) {
+ if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) {
+ Value::ConstMemberIterator memberItr = CURRENT.FindMember(name);
+ if (memberItr != CURRENT.MemberEnd())
+ STACK->push(JsonReaderStackItem(&memberItr->value, JsonReaderStackItem::BeforeStart));
+ else
+ mError = true;
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+bool JsonReader::HasMember(const char* name) const {
+ if (!mError && CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started)
+ return CURRENT.HasMember(name);
+ return false;
+}
+
+JsonReader& JsonReader::StartArray(size_t* size) {
+ if (!mError) {
+ if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::BeforeStart) {
+ TOP.state = JsonReaderStackItem::Started;
+ if (size)
+ *size = CURRENT.Size();
+
+ if (!CURRENT.Empty()) {
+ const Value* value = &CURRENT[TOP.index];
+ STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart));
+ }
+ else
+ TOP.state = JsonReaderStackItem::Closed;
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::EndArray() {
+ if (!mError) {
+ if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::Closed)
+ Next();
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(bool& b) {
+ if (!mError) {
+ if (CURRENT.IsBool()) {
+ b = CURRENT.GetBool();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(unsigned& u) {
+ if (!mError) {
+ if (CURRENT.IsUint()) {
+ u = CURRENT.GetUint();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(int& i) {
+ if (!mError) {
+ if (CURRENT.IsInt()) {
+ i = CURRENT.GetInt();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(double& d) {
+ if (!mError) {
+ if (CURRENT.IsNumber()) {
+ d = CURRENT.GetDouble();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(std::string& s) {
+ if (!mError) {
+ if (CURRENT.IsString()) {
+ s = CURRENT.GetString();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::SetNull() {
+ // This function is for JsonWriter only.
+ mError = true;
+ return *this;
+}
+
+void JsonReader::Next() {
+ if (!mError) {
+ assert(!STACK->empty());
+ STACK->pop();
+
+ if (!STACK->empty() && CURRENT.IsArray()) {
+ if (TOP.state == JsonReaderStackItem::Started) { // Otherwise means reading array item pass end
+ if (TOP.index < CURRENT.Size() - 1) {
+ const Value* value = &CURRENT[++TOP.index];
+ STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart));
+ }
+ else
+ TOP.state = JsonReaderStackItem::Closed;
+ }
+ else
+ mError = true;
+ }
+ }
+}
+
+#undef DOCUMENT
+#undef STACK
+#undef TOP
+#undef CURRENT
+
+////////////////////////////////////////////////////////////////////////////////
+// JsonWriter
+
+#define WRITER reinterpret_cast*>(mWriter)
+#define STREAM reinterpret_cast(mStream)
+
+JsonWriter::JsonWriter() : mWriter(), mStream() {
+ mStream = new StringBuffer;
+ mWriter = new PrettyWriter(*STREAM);
+}
+
+JsonWriter::~JsonWriter() {
+ delete WRITER;
+ delete STREAM;
+}
+
+const char* JsonWriter::GetString() const {
+ return STREAM->GetString();
+}
+
+JsonWriter& JsonWriter::StartObject() {
+ WRITER->StartObject();
+ return *this;
+}
+
+JsonWriter& JsonWriter::EndObject() {
+ WRITER->EndObject();
+ return *this;
+}
+
+JsonWriter& JsonWriter::Member(const char* name) {
+ WRITER->String(name, static_cast(strlen(name)));
+ return *this;
+}
+
+bool JsonWriter::HasMember(const char*) const {
+ // This function is for JsonReader only.
+ assert(false);
+ return false;
+}
+
+JsonWriter& JsonWriter::StartArray(size_t*) {
+ WRITER->StartArray();
+ return *this;
+}
+
+JsonWriter& JsonWriter::EndArray() {
+ WRITER->EndArray();
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(bool& b) {
+ WRITER->Bool(b);
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(unsigned& u) {
+ WRITER->Uint(u);
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(int& i) {
+ WRITER->Int(i);
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(double& d) {
+ WRITER->Double(d);
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(std::string& s) {
+ WRITER->String(s.c_str(), static_cast(s.size()));
+ return *this;
+}
+
+JsonWriter& JsonWriter::SetNull() {
+ WRITER->Null();
+ return *this;
+}
+
+#undef STREAM
+#undef WRITER
diff --git a/example/archiver/archiver.h b/example/archiver/archiver.h
new file mode 100644
index 0000000..285ca73
--- /dev/null
+++ b/example/archiver/archiver.h
@@ -0,0 +1,145 @@
+#ifndef ARCHIVER_H_
+#define ARCHIVER_H_
+
+#include
+#include
+
+/**
+\class Archiver
+\brief Archiver concept
+
+Archiver can be a reader or writer for serialization or deserialization respectively.
+
+class Archiver {
+public:
+ /// \returns true if the archiver is in normal state. false if it has errors.
+ operator bool() const;
+
+ /// Starts an object
+ Archiver& StartObject();
+
+ /// After calling StartObject(), assign a member with a name
+ Archiver& Member(const char* name);
+
+ /// After calling StartObject(), check if a member presents
+ bool HasMember(const char* name) const;
+
+ /// Ends an object
+ Archiver& EndObject();
+
+ /// Starts an array
+ /// \param size If Archiver::IsReader is true, the size of array is written.
+ Archiver& StartArray(size_t* size = 0);
+
+ /// Ends an array
+ Archiver& EndArray();
+
+ /// Read/Write primitive types.
+ Archiver& operator&(bool& b);
+ Archiver& operator&(unsigned& u);
+ Archiver& operator&(int& i);
+ Archiver& operator&(double& d);
+ Archiver& operator&(std::string& s);
+
+ /// Write primitive types.
+ Archiver& SetNull();
+
+ //! Whether it is a reader.
+ static const bool IsReader;
+
+ //! Whether it is a writer.
+ static const bool IsWriter;
+};
+*/
+
+/// Represents a JSON reader which implements Archiver concept.
+class JsonReader {
+public:
+ /// Constructor.
+ /**
+ \param json A non-const source json string for in-situ parsing.
+ \note in-situ means the source JSON string will be modified after parsing.
+ */
+ JsonReader(const char* json);
+
+ /// Destructor.
+ ~JsonReader();
+
+ // Archive concept
+
+ operator bool() const { return !mError; }
+
+ JsonReader& StartObject();
+ JsonReader& Member(const char* name);
+ bool HasMember(const char* name) const;
+ JsonReader& EndObject();
+
+ JsonReader& StartArray(size_t* size = 0);
+ JsonReader& EndArray();
+
+ JsonReader& operator&(bool& b);
+ JsonReader& operator&(unsigned& u);
+ JsonReader& operator&(int& i);
+ JsonReader& operator&(double& d);
+ JsonReader& operator&(std::string& s);
+
+ JsonReader& SetNull();
+
+ static const bool IsReader = true;
+ static const bool IsWriter = !IsReader;
+
+private:
+ JsonReader(const JsonReader&);
+ JsonReader& operator=(const JsonReader&);
+
+ void Next();
+
+ // PIMPL
+ void* mDocument; ///< DOM result of parsing.
+ void* mStack; ///< Stack for iterating the DOM
+ bool mError; ///< Whether an error has occurred.
+};
+
+class JsonWriter {
+public:
+ /// Constructor.
+ JsonWriter();
+
+ /// Destructor.
+ ~JsonWriter();
+
+ /// Obtains the serialized JSON string.
+ const char* GetString() const;
+
+ // Archive concept
+
+ operator bool() const { return true; }
+
+ JsonWriter& StartObject();
+ JsonWriter& Member(const char* name);
+ bool HasMember(const char* name) const;
+ JsonWriter& EndObject();
+
+ JsonWriter& StartArray(size_t* size = 0);
+ JsonWriter& EndArray();
+
+ JsonWriter& operator&(bool& b);
+ JsonWriter& operator&(unsigned& u);
+ JsonWriter& operator&(int& i);
+ JsonWriter& operator&(double& d);
+ JsonWriter& operator&(std::string& s);
+ JsonWriter& SetNull();
+
+ static const bool IsReader = false;
+ static const bool IsWriter = !IsReader;
+
+private:
+ JsonWriter(const JsonWriter&);
+ JsonWriter& operator=(const JsonWriter&);
+
+ // PIMPL idiom
+ void* mWriter; ///< JSON writer.
+ void* mStream; ///< Stream buffer.
+};
+
+#endif // ARCHIVER_H__
diff --git a/example/archiver/archivertest.cpp b/example/archiver/archivertest.cpp
new file mode 100644
index 0000000..417a421
--- /dev/null
+++ b/example/archiver/archivertest.cpp
@@ -0,0 +1,287 @@
+#include "archiver.h"
+#include
+#include
+
+//////////////////////////////////////////////////////////////////////////////
+// Test1: simple object
+
+struct Student {
+ Student() : name(), age(), height(), canSwim() {}
+ Student(const std::string name, unsigned age, double height, bool canSwim) :
+ name(name), age(age), height(height), canSwim(canSwim)
+ {}
+
+ std::string name;
+ unsigned age;
+ double height;
+ bool canSwim;
+};
+
+template
+Archiver& operator&(Archiver& ar, Student& s) {
+ ar.StartObject();
+ ar.Member("name") & s.name;
+ ar.Member("age") & s.age;
+ ar.Member("height") & s.height;
+ ar.Member("canSwim") & s.canSwim;
+ return ar.EndObject();
+}
+
+std::ostream& operator<<(std::ostream& os, const Student& s) {
+ return os << s.name << " " << s.age << " " << s.height << " " << s.canSwim;
+}
+
+void test1() {
+ std::string json;
+
+ // Serialize
+ {
+ Student s("Lua", 9, 150.5, true);
+
+ JsonWriter writer;
+ writer & s;
+ json = writer.GetString();
+ std::cout << json << std::endl;
+ }
+
+ // Deserialize
+ {
+ Student s;
+ JsonReader reader(json.c_str());
+ reader & s;
+ std::cout << s << std::endl;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Test2: std::vector <=> JSON array
+//
+// You can map a JSON array to other data structures as well
+
+struct Group {
+ Group() : groupName(), students() {}
+ std::string groupName;
+ std::vector students;
+};
+
+template
+Archiver& operator&(Archiver& ar, Group& g) {
+ ar.StartObject();
+
+ ar.Member("groupName");
+ ar & g.groupName;
+
+ ar.Member("students");
+ size_t studentCount = g.students.size();
+ ar.StartArray(&studentCount);
+ if (ar.IsReader)
+ g.students.resize(studentCount);
+ for (size_t i = 0; i < studentCount; i++)
+ ar & g.students[i];
+ ar.EndArray();
+
+ return ar.EndObject();
+}
+
+std::ostream& operator<<(std::ostream& os, const Group& g) {
+ os << g.groupName << std::endl;
+ for (std::vector::const_iterator itr = g.students.begin(); itr != g.students.end(); ++itr)
+ os << *itr << std::endl;
+ return os;
+}
+
+void test2() {
+ std::string json;
+
+ // Serialize
+ {
+ Group g;
+ g.groupName = "Rainbow";
+
+ Student s1("Lua", 9, 150.5, true);
+ Student s2("Mio", 7, 120.0, false);
+ g.students.push_back(s1);
+ g.students.push_back(s2);
+
+ JsonWriter writer;
+ writer & g;
+ json = writer.GetString();
+ std::cout << json << std::endl;
+ }
+
+ // Deserialize
+ {
+ Group g;
+ JsonReader reader(json.c_str());
+ reader & g;
+ std::cout << g << std::endl;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Test3: polymorphism & friend
+//
+// Note that friendship is not necessary but make things simpler.
+
+class Shape {
+public:
+ virtual ~Shape() {}
+ virtual const char* GetType() const = 0;
+ virtual void Print(std::ostream& os) const = 0;
+
+protected:
+ Shape() : x_(), y_() {}
+ Shape(double x, double y) : x_(x), y_(y) {}
+
+ template
+ friend Archiver& operator&(Archiver& ar, Shape& s);
+
+ double x_, y_;
+};
+
+template
+Archiver& operator&(Archiver& ar, Shape& s) {
+ ar.Member("x") & s.x_;
+ ar.Member("y") & s.y_;
+ return ar;
+}
+
+class Circle : public Shape {
+public:
+ Circle() : radius_() {}
+ Circle(double x, double y, double radius) : Shape(x, y), radius_(radius) {}
+ ~Circle() {}
+
+ const char* GetType() const { return "Circle"; }
+
+ void Print(std::ostream& os) const {
+ os << "Circle (" << x_ << ", " << y_ << ")" << " radius = " << radius_;
+ }
+
+private:
+ template
+ friend Archiver& operator&(Archiver& ar, Circle& c);
+
+ double radius_;
+};
+
+template
+Archiver& operator&(Archiver& ar, Circle& c) {
+ ar & static_cast(c);
+ ar.Member("radius") & c.radius_;
+ return ar;
+}
+
+class Box : public Shape {
+public:
+ Box() : width_(), height_() {}
+ Box(double x, double y, double width, double height) : Shape(x, y), width_(width), height_(height) {}
+ ~Box() {}
+
+ const char* GetType() const { return "Box"; }
+
+ void Print(std::ostream& os) const {
+ os << "Box (" << x_ << ", " << y_ << ")" << " width = " << width_ << " height = " << height_;
+ }
+
+private:
+ template
+ friend Archiver& operator&(Archiver& ar, Box& b);
+
+ double width_, height_;
+};
+
+template
+Archiver& operator&(Archiver& ar, Box& b) {
+ ar & static_cast(b);
+ ar.Member("width") & b.width_;
+ ar.Member("height") & b.height_;
+ return ar;
+}
+
+class Canvas {
+public:
+ Canvas() : shapes_() {}
+ ~Canvas() { Clear(); }
+
+ void Clear() {
+ for (std::vector::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr)
+ delete *itr;
+ }
+
+ void AddShape(Shape* shape) { shapes_.push_back(shape); }
+
+ void Print(std::ostream& os) {
+ for (std::vector::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) {
+ (*itr)->Print(os);
+ std::cout << std::endl;
+ }
+ }
+
+private:
+ template
+ friend Archiver& operator&(Archiver& ar, Canvas& c);
+
+ std::vector shapes_;
+};
+
+template
+Archiver& operator&(Archiver& ar, Shape*& shape) {
+ std::string type = ar.IsReader ? "" : shape->GetType();
+ ar.StartObject();
+ ar.Member("type") & type;
+ if (type == "Circle") {
+ if (ar.IsReader) shape = new Circle;
+ ar & static_cast(*shape);
+ }
+ else if (type == "Box") {
+ if (ar.IsReader) shape = new Box;
+ ar & static_cast(*shape);
+ }
+ return ar.EndObject();
+}
+
+template
+Archiver& operator&(Archiver& ar, Canvas& c) {
+ size_t shapeCount = c.shapes_.size();
+ ar.StartArray(&shapeCount);
+ if (ar.IsReader) {
+ c.Clear();
+ c.shapes_.resize(shapeCount);
+ }
+ for (size_t i = 0; i < shapeCount; i++)
+ ar & c.shapes_[i];
+ return ar.EndArray();
+}
+
+void test3() {
+ std::string json;
+
+ // Serialize
+ {
+ Canvas c;
+ c.AddShape(new Circle(1.0, 2.0, 3.0));
+ c.AddShape(new Box(4.0, 5.0, 6.0, 7.0));
+
+ JsonWriter writer;
+ writer & c;
+ json = writer.GetString();
+ std::cout << json << std::endl;
+ }
+
+ // Deserialize
+ {
+ Canvas c;
+ JsonReader reader(json.c_str());
+ reader & c;
+ c.Print(std::cout);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+int main() {
+ test1();
+ test2();
+ test3();
+}
diff --git a/example/jsonx/jsonx.cpp b/example/jsonx/jsonx.cpp
index 1346b57..954aa2b 100644
--- a/example/jsonx/jsonx.cpp
+++ b/example/jsonx/jsonx.cpp
@@ -1,4 +1,4 @@
-// JSON to JSONx conversion exmaple, using SAX API.
+// JSON to JSONx conversion example, using SAX API.
// JSONx is an IBM standard format to represent JSON as XML.
// https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html
// This example parses JSON text from stdin with validation,
diff --git a/example/lookaheadparser/lookaheadparser.cpp b/example/lookaheadparser/lookaheadparser.cpp
index 29469ed..f627f4d 100644
--- a/example/lookaheadparser/lookaheadparser.cpp
+++ b/example/lookaheadparser/lookaheadparser.cpp
@@ -2,6 +2,11 @@
#include "rapidjson/document.h"
#include
+RAPIDJSON_DIAG_PUSH
+#ifdef __GNUC__
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
// This example demonstrates JSON token-by-token parsing with an API that is
// more direct; you don't need to design your logic around a handler object and
// callbacks. Instead, you retrieve values from the JSON stream by calling
@@ -341,3 +346,5 @@ int main() {
return 0;
}
+
+RAPIDJSON_DIAG_POP
diff --git a/example/parsebyparts/parsebyparts.cpp b/example/parsebyparts/parsebyparts.cpp
index a377efd..ff73539 100644
--- a/example/parsebyparts/parsebyparts.cpp
+++ b/example/parsebyparts/parsebyparts.cpp
@@ -143,7 +143,7 @@ int main() {
AsyncDocumentParser<> parser(d);
const char json1[] = " { \"hello\" : \"world\", \"t\" : tr";
- //const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // Fot test parsing error
+ //const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // For test parsing error
const char json2[] = "ue, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.14";
const char json3[] = "16, \"a\":[1, 2, 3, 4] } ";
diff --git a/example/schemavalidator/schemavalidator.cpp b/example/schemavalidator/schemavalidator.cpp
index ce36ea9..06bbe4d 100644
--- a/example/schemavalidator/schemavalidator.cpp
+++ b/example/schemavalidator/schemavalidator.cpp
@@ -6,6 +6,7 @@
#include "rapidjson/filereadstream.h"
#include "rapidjson/schema.h"
#include "rapidjson/stringbuffer.h"
+#include "rapidjson/prettywriter.h"
using namespace rapidjson;
@@ -67,6 +68,11 @@ int main(int argc, char *argv[]) {
sb.Clear();
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
fprintf(stderr, "Invalid document: %s\n", sb.GetString());
+ // Detailed violation report is available as a JSON value
+ sb.Clear();
+ PrettyWriter w(sb);
+ validator.GetError().Accept(w);
+ fprintf(stderr, "Error report:\n%s\n", sb.GetString());
return EXIT_FAILURE;
}
}
diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h
index 655f4a3..06b3420 100644
--- a/include/rapidjson/allocators.h
+++ b/include/rapidjson/allocators.h
@@ -52,6 +52,19 @@ concept Allocator {
\endcode
*/
+
+/*! \def RAPIDJSON_ALLOCATOR_DEFUALT_CHUNK_CAPACITY
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kDefaultChunkCapacity definition.
+
+ User can define this as any \c size that is a power of 2.
+*/
+
+#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
+#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
+#endif
+
+
///////////////////////////////////////////////////////////////////////////////
// CrtAllocator
@@ -248,7 +261,7 @@ private:
return false;
}
- static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+ static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
//! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list.
diff --git a/include/rapidjson/cursorstreamwrapper.h b/include/rapidjson/cursorstreamwrapper.h
new file mode 100644
index 0000000..52c11a7
--- /dev/null
+++ b/include/rapidjson/cursorstreamwrapper.h
@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_
+#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
+
+#include "stream.h"
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+
+//! Cursor stream wrapper for counting line and column number if error exists.
+/*!
+ \tparam InputStream Any stream that implements Stream Concept
+*/
+template >
+class CursorStreamWrapper : public GenericStreamWrapper {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ CursorStreamWrapper(InputStream& is):
+ GenericStreamWrapper(is), line_(1), col_(0) {}
+
+ // counting line and column number
+ Ch Take() {
+ Ch ch = this->is_.Take();
+ if(ch == '\n') {
+ line_ ++;
+ col_ = 0;
+ } else {
+ col_ ++;
+ }
+ return ch;
+ }
+
+ //! Get the error line number, if error exists.
+ size_t GetLine() const { return line_; }
+ //! Get the error column number, if error exists.
+ size_t GetColumn() const { return col_; }
+
+private:
+ size_t line_; //!< Current Line
+ size_t col_; //!< Current Column
+};
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_POP
+#endif
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_
diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h
index 6de441f..d25c5c0 100644
--- a/include/rapidjson/document.h
+++ b/include/rapidjson/document.h
@@ -26,23 +26,13 @@
#include
RAPIDJSON_DIAG_PUSH
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
-RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
-#ifdef _MINWINDEF_ // see: http://stackoverflow.com/questions/22744262/cant-call-stdmax-because-minwindef-h-defines-max
-#ifndef NOMINMAX
-#pragma push_macro("min")
-#pragma push_macro("max")
-#undef min
-#undef max
-#endif
-#endif
-#endif
-
#ifdef __clang__
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(c++98-compat)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
#endif
#ifdef __GNUC__
@@ -53,7 +43,7 @@ RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_N
#endif // __GNUC__
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
-#include // std::iterator, std::random_access_iterator_tag
+#include // std::random_access_iterator_tag
#endif
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
@@ -106,16 +96,13 @@ struct GenericMember {
\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
*/
template
-class GenericMemberIterator
- : public std::iterator >::Type> {
+class GenericMemberIterator {
friend class GenericValue;
template friend class GenericMemberIterator;
typedef GenericMember PlainType;
typedef typename internal::MaybeAddConst::Type ValueType;
- typedef std::iterator BaseType;
public:
//! Iterator type itself
@@ -125,12 +112,21 @@ public:
//! Non-constant iterator type
typedef GenericMemberIterator NonConstIterator;
+ /** \name std::iterator_traits support */
+ //@{
+ typedef ValueType value_type;
+ typedef ValueType * pointer;
+ typedef ValueType & reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ //@}
+
//! Pointer to (const) GenericMember
- typedef typename BaseType::pointer Pointer;
+ typedef pointer Pointer;
//! Reference to (const) GenericMember
- typedef typename BaseType::reference Reference;
+ typedef reference Reference;
//! Signed integer type (e.g. \c ptrdiff_t)
- typedef typename BaseType::difference_type DifferenceType;
+ typedef difference_type DifferenceType;
//! Default constructor (singular value)
/*! Creates an iterator pointing to no element.
@@ -308,7 +304,7 @@ struct GenericStringRef {
*/
#endif
explicit GenericStringRef(const CharType* str)
- : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
+ : s(str), length(NotNullStrLen(str)) {}
//! Create constant string reference from pointer and length
#ifndef __clang__ // -Wdocumentation
@@ -320,7 +316,7 @@ struct GenericStringRef {
*/
#endif
GenericStringRef(const CharType* str, SizeType len)
- : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
+ : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); }
GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
@@ -331,6 +327,14 @@ struct GenericStringRef {
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
private:
+ SizeType NotNullStrLen(const CharType* str) {
+ RAPIDJSON_ASSERT(str != 0);
+ return internal::StrLen(str);
+ }
+
+ /// Empty string - used when passing in a NULL pointer
+ static const Ch emptyString[];
+
//! Disallow construction from non-const array
template
GenericStringRef(CharType (&str)[N]) /* = delete */;
@@ -338,6 +342,9 @@ private:
GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
};
+template
+const CharType GenericStringRef::emptyString[] = { CharType() };
+
//! Mark a character pointer as constant string
/*! Mark a plain character pointer as a "string literal". This function
can be used to avoid copying a character string to be referenced as a
@@ -352,7 +359,7 @@ private:
*/
template
inline GenericStringRef StringRef(const CharType* str) {
- return GenericStringRef(str, internal::StrLen(str));
+ return GenericStringRef(str);
}
//! Mark a character pointer as constant string
@@ -442,6 +449,26 @@ struct TypeHelper {
static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
};
+#ifdef _MSC_VER
+RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsInt(); }
+ static long Get(const ValueType& v) { return v.GetInt(); }
+ static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); }
+ static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
+};
+
+RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));
+template
+struct TypeHelper {
+ static bool Is(const ValueType& v) { return v.IsUint(); }
+ static unsigned long Get(const ValueType& v) { return v.GetUint(); }
+ static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); }
+ static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
+};
+#endif
+
template
struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsInt64(); }
@@ -515,7 +542,7 @@ struct TypeHelper {
static bool Is(const ValueType& v) { return v.IsObject(); }
static ObjectType Get(ValueType& v) { return v.GetObject(); }
static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
- static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }
+ static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; }
};
template
@@ -602,7 +629,7 @@ public:
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
kNumberAnyFlag
};
- RAPIDJSON_ASSERT(type <= kNumberType);
+ RAPIDJSON_ASSERT(type >= kNullType && type <= kNumberType);
data_.f.flags = defaultFlags[type];
// Use ShortString to store empty string.
@@ -615,18 +642,19 @@ public:
\tparam SourceAllocator allocator of \c rhs
\param rhs Value to copy from (read-only)
\param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
+ \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
\see CopyFrom()
*/
template
- GenericValue(const GenericValue& rhs, Allocator& allocator) {
+ GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) {
switch (rhs.GetType()) {
case kObjectType: {
SizeType count = rhs.data_.o.size;
Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member)));
const typename GenericValue::Member* rm = rhs.GetMembersPointer();
for (SizeType i = 0; i < count; i++) {
- new (&lm[i].name) GenericValue(rm[i].name, allocator);
- new (&lm[i].value) GenericValue(rm[i].value, allocator);
+ new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
+ new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
}
data_.f.flags = kObjectFlag;
data_.o.size = data_.o.capacity = count;
@@ -638,14 +666,14 @@ public:
GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue)));
const GenericValue* re = rhs.GetElementsPointer();
for (SizeType i = 0; i < count; i++)
- new (&le[i]) GenericValue(re[i], allocator);
+ new (&le[i]) GenericValue(re[i], allocator, copyConstStrings);
data_.f.flags = kArrayFlag;
data_.a.size = data_.a.capacity = count;
SetElementsPointer(le);
}
break;
case kStringType:
- if (rhs.data_.f.flags == kConstStringFlag) {
+ if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) {
data_.f.flags = rhs.data_.f.flags;
data_ = *reinterpret_cast(&rhs.data_);
}
@@ -850,12 +878,13 @@ public:
\tparam SourceAllocator Allocator type of \c rhs
\param rhs Value to copy from (read-only)
\param allocator Allocator to use for copying
+ \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
*/
template
- GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) {
+ GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) {
RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs));
this->~GenericValue();
- new (this) GenericValue(rhs, allocator);
+ new (this) GenericValue(rhs, allocator, copyConstStrings);
return *this;
}
@@ -1005,14 +1034,14 @@ public:
uint64_t u = GetUint64();
volatile double d = static_cast(u);
return (d >= 0.0)
- && (d < static_cast(std::numeric_limits::max()))
+ && (d < static_cast((std::numeric_limits::max)()))
&& (u == static_cast(d));
}
if (IsInt64()) {
int64_t i = GetInt64();
volatile double d = static_cast(i);
- return (d >= static_cast(std::numeric_limits::min()))
- && (d < static_cast(std::numeric_limits::max()))
+ return (d >= static_cast((std::numeric_limits::min)()))
+ && (d < static_cast((std::numeric_limits::max)()))
&& (i == static_cast(d));
}
return true; // double, int, uint are always lossless
@@ -1029,8 +1058,8 @@ public:
bool IsLosslessFloat() const {
if (!IsNumber()) return false;
double a = GetDouble();
- if (a < static_cast(-std::numeric_limits::max())
- || a > static_cast(std::numeric_limits::max()))
+ if (a < static_cast(-(std::numeric_limits::max)())
+ || a > static_cast((std::numeric_limits::max)()))
return false;
double b = static_cast(static_cast(a));
return a >= b && a <= b; // Prevent -Wfloat-equal
@@ -1065,6 +1094,9 @@ public:
//! Get the number of members in the object.
SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
+ //! Get the capacity of object.
+ SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; }
+
//! Check whether the object is empty.
bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
@@ -1133,6 +1165,21 @@ public:
/*! \pre IsObject() == true */
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
+ //! Request the object to have enough capacity to store members.
+ /*! \param newCapacity The capacity that the object at least need to have.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note Linear time complexity.
+ */
+ GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ if (newCapacity > data_.o.capacity) {
+ SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
+ data_.o.capacity = newCapacity;
+ }
+ return *this;
+ }
+
//! Check whether a member exists in the object.
/*!
\param name Member name to be searched.
@@ -1238,17 +1285,8 @@ public:
RAPIDJSON_ASSERT(name.IsString());
ObjectData& o = data_.o;
- if (o.size >= o.capacity) {
- if (o.capacity == 0) {
- o.capacity = kDefaultObjectCapacity;
- SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member))));
- }
- else {
- SizeType oldCapacity = o.capacity;
- o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
- SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
- }
- }
+ if (o.size >= o.capacity)
+ MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
Member* members = GetMembersPointer();
members[o.size].name.RawAssign(name);
members[o.size].value.RawAssign(value);
@@ -1760,7 +1798,7 @@ public:
\return The value itself for fluent API.
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
*/
- GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); }
//! Set this value as a string by copying from source string.
/*! \param s source string.
@@ -1768,7 +1806,15 @@ public:
\return The value itself for fluent API.
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
*/
- GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
+ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string reference
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; }
#if RAPIDJSON_HAS_STDSTRING
//! Set this value as a string by copying from source string.
@@ -1778,7 +1824,7 @@ public:
\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
\note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
- GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
+ GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
#endif
//@}
@@ -1986,7 +2032,12 @@ private:
if (count) {
GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue)));
SetElementsPointer(e);
+RAPIDJSON_DIAG_PUSH
+#if defined(__GNUC__) && __GNUC__ >= 8
+RAPIDJSON_DIAG_OFF(class-memaccess) // ignore complains from gcc that no trivial copy constructor exists.
+#endif
std::memcpy(e, values, count * sizeof(GenericValue));
+RAPIDJSON_DIAG_POP
}
else
SetElementsPointer(0);
@@ -1999,7 +2050,12 @@ private:
if (count) {
Member* m = static_cast(allocator.Malloc(count * sizeof(Member)));
SetMembersPointer(m);
+RAPIDJSON_DIAG_PUSH
+#if defined(__GNUC__) && __GNUC__ >= 8
+RAPIDJSON_DIAG_OFF(class-memaccess) // ignore complains from gcc that no trivial copy constructor exists.
+#endif
std::memcpy(m, members, count * sizeof(Member));
+RAPIDJSON_DIAG_POP
}
else
SetMembersPointer(0);
@@ -2162,6 +2218,10 @@ public:
return *this;
}
+ // Allow Swap with ValueType.
+ // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names.
+ using ValueType::Swap;
+
//! free-standing swap function helper
/*!
Helper function to enable support for common swap implementation pattern based on \c std::swap:
@@ -2293,7 +2353,7 @@ public:
template
GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
- MemoryStream ms(static_cast(str), length * sizeof(typename SourceEncoding::Ch));
+ MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch));
EncodedInputStream is(ms);
ParseStream(is);
return *this;
@@ -2330,7 +2390,7 @@ public:
//!@name Handling parse errors
//!@{
- //! Whether a parse error has occured in the last parsing.
+ //! Whether a parse error has occurred in the last parsing.
bool HasParseError() const { return parseResult_.IsError(); }
//! Get the \ref ParseErrorCode of last parsing.
@@ -2531,6 +2591,7 @@ public:
~GenericObject() {}
SizeType MemberCount() const { return value_.MemberCount(); }
+ SizeType MemberCapacity() const { return value_.MemberCapacity(); }
bool ObjectEmpty() const { return value_.ObjectEmpty(); }
template ValueType& operator[](T* name) const { return value_[name]; }
template ValueType& operator[](const GenericValue& name) const { return value_[name]; }
@@ -2539,6 +2600,7 @@ public:
#endif
MemberIterator MemberBegin() const { return value_.MemberBegin(); }
MemberIterator MemberEnd() const { return value_.MemberEnd(); }
+ GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; }
bool HasMember(const Ch* name) const { return value_.HasMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); }
@@ -2591,12 +2653,6 @@ private:
};
RAPIDJSON_NAMESPACE_END
-#ifdef _MINWINDEF_ // see: http://stackoverflow.com/questions/22744262/cant-call-stdmax-because-minwindef-h-defines-max
-#ifndef NOMINMAX
-#pragma pop_macro("min")
-#pragma pop_macro("max")
-#endif
-#endif
RAPIDJSON_DIAG_POP
#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h
index ed7d44d..12b562a 100644
--- a/include/rapidjson/encodings.h
+++ b/include/rapidjson/encodings.h
@@ -17,7 +17,7 @@
#include "rapidjson.h"
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
RAPIDJSON_DIAG_OFF(4702) // unreachable code
@@ -384,7 +384,7 @@ struct UTF16BE : UTF16 {
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast(static_cast(is.Take())) << 8;
- c |= static_cast(is.Take());
+ c |= static_cast(static_cast(is.Take()));
return static_cast(c);
}
@@ -620,28 +620,28 @@ struct AutoUTF {
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x
template
- RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
+ static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint);
}
template
- RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ static RAPIDJSON_FORCEINLINE 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
- RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
+ static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
return (*f[is.GetType()])(is, codepoint);
}
template
- RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
return (*f[is.GetType()])(is, os);
@@ -658,7 +658,7 @@ template
struct Transcoder {
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template
- RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
@@ -667,7 +667,7 @@ struct Transcoder {
}
template
- RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
@@ -677,7 +677,7 @@ struct Transcoder {
//! Validate one Unicode codepoint from an encoded stream.
template
- RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
return Transcode(is, os); // Since source/target encoding is different, must transcode.
}
};
@@ -690,26 +690,26 @@ inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
template
struct Transcoder {
template
- RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true;
}
template
- RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE 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
- RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
return Encoding::Validate(is, os); // source/target encoding are the same
}
};
RAPIDJSON_NAMESPACE_END
-#if defined(__GNUC__) || defined(_MSC_VER)
+#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
RAPIDJSON_DIAG_POP
#endif
diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h
index 95cb31a..9311d2f 100644
--- a/include/rapidjson/error/error.h
+++ b/include/rapidjson/error/error.h
@@ -104,6 +104,8 @@ enum ParseErrorCode {
\see GenericReader::Parse, GenericDocument::Parse
*/
struct ParseResult {
+ //!! Unspecified boolean type
+ typedef bool (ParseResult::*BooleanType)() const;
public:
//! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {}
@@ -115,8 +117,8 @@ public:
//! Get the error offset, if \ref IsError(), 0 otherwise.
size_t Offset() const { return offset_; }
- //! Conversion to \c bool, returns \c true, iff !\ref IsError().
- operator bool() const { return !IsError(); }
+ //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
+ operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
//! Whether the result is an error.
bool IsError() const { return code_ != kParseErrorNone; }
@@ -124,6 +126,10 @@ public:
bool operator==(ParseErrorCode code) const { return code_ == code; }
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+ bool operator!=(const ParseResult& that) const { return !(*this == that); }
+ bool operator!=(ParseErrorCode code) const { return !(*this == code); }
+ friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
+
//! Reset error code.
void Clear() { Set(kParseErrorNone); }
//! Update error code and offset.
diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h
index b56ea13..f1bfb7d 100644
--- a/include/rapidjson/filereadstream.h
+++ b/include/rapidjson/filereadstream.h
@@ -68,7 +68,7 @@ private:
++current_;
else if (!eof_) {
count_ += readCount_;
- readCount_ = fread(buffer_, 1, bufferSize_, fp_);
+ readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h
index 6378dd6..8b48fee 100644
--- a/include/rapidjson/filewritestream.h
+++ b/include/rapidjson/filewritestream.h
@@ -25,7 +25,7 @@ RAPIDJSON_DIAG_OFF(unreachable-code)
RAPIDJSON_NAMESPACE_BEGIN
-//! Wrapper of C file stream for input using fread().
+//! Wrapper of C file stream for output using fwrite().
/*!
\note implements Stream concept
*/
@@ -62,7 +62,7 @@ public:
void Flush() {
if (current_ != buffer_) {
- size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_);
+ size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_);
if (result < static_cast(current_ - buffer_)) {
// failure deliberately ignored at this time
// added to avoid warn_unused_result build errors
diff --git a/include/rapidjson/internal/biginteger.h b/include/rapidjson/internal/biginteger.h
index 9d3e88c..f936a10 100644
--- a/include/rapidjson/internal/biginteger.h
+++ b/include/rapidjson/internal/biginteger.h
@@ -17,7 +17,7 @@
#include "../rapidjson.h"
-#if defined(_MSC_VER) && defined(_M_AMD64)
+#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64)
#include // for _umul128
#pragma intrinsic(_umul128)
#endif
diff --git a/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h
index c9fefdc..29abf80 100644
--- a/include/rapidjson/internal/diyfp.h
+++ b/include/rapidjson/internal/diyfp.h
@@ -21,7 +21,7 @@
#include "../rapidjson.h"
-#if defined(_MSC_VER) && defined(_M_AMD64)
+#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
#include
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_umul128)
diff --git a/include/rapidjson/internal/itoa.h b/include/rapidjson/internal/itoa.h
index 01a4e7e..a39accb 100644
--- a/include/rapidjson/internal/itoa.h
+++ b/include/rapidjson/internal/itoa.h
@@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
-//
+//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
@@ -7,9 +7,9 @@
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ITOA_
@@ -37,12 +37,14 @@ inline const char* GetDigitsLut() {
}
inline char* u32toa(uint32_t value, char* buffer) {
+ RAPIDJSON_ASSERT(buffer != 0);
+
const char* cDigitsLut = GetDigitsLut();
if (value < 10000) {
const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1;
-
+
if (value >= 1000)
*buffer++ = cDigitsLut[d1];
if (value >= 100)
@@ -55,13 +57,13 @@ inline char* u32toa(uint32_t value, char* buffer) {
// value = bbbbcccc
const uint32_t b = value / 10000;
const uint32_t c = value % 10000;
-
+
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
-
+
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
-
+
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
@@ -69,7 +71,7 @@ inline char* u32toa(uint32_t value, char* buffer) {
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
-
+
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
@@ -77,10 +79,10 @@ inline char* u32toa(uint32_t value, char* buffer) {
}
else {
// value = aabbbbcccc in decimal
-
+
const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000;
-
+
if (a >= 10) {
const unsigned i = a << 1;
*buffer++ = cDigitsLut[i];
@@ -91,13 +93,13 @@ inline char* u32toa(uint32_t value, char* buffer) {
const uint32_t b = value / 10000; // 0 to 9999
const uint32_t c = value % 10000; // 0 to 9999
-
+
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
-
+
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
-
+
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
@@ -111,6 +113,7 @@ inline char* u32toa(uint32_t value, char* buffer) {
}
inline char* i32toa(int32_t value, char* buffer) {
+ RAPIDJSON_ASSERT(buffer != 0);
uint32_t u = static_cast(value);
if (value < 0) {
*buffer++ = '-';
@@ -121,6 +124,7 @@ inline char* i32toa(int32_t value, char* buffer) {
}
inline char* u64toa(uint64_t value, char* buffer) {
+ RAPIDJSON_ASSERT(buffer != 0);
const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10;
@@ -131,13 +135,13 @@ inline char* u64toa(uint64_t value, char* buffer) {
const uint64_t kTen14 = kTen8 * 1000000;
const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8;
-
+
if (value < kTen8) {
uint32_t v = static_cast(value);
if (v < 10000) {
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
-
+
if (v >= 1000)
*buffer++ = cDigitsLut[d1];
if (v >= 100)
@@ -150,13 +154,13 @@ inline char* u64toa(uint64_t value, char* buffer) {
// value = bbbbcccc
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;
-
+
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
-
+
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
-
+
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
@@ -164,7 +168,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
-
+
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
@@ -174,22 +178,22 @@ inline char* u64toa(uint64_t value, char* buffer) {
else if (value < kTen16) {
const uint32_t v0 = static_cast(value / kTen8);
const uint32_t v1 = static_cast(value % kTen8);
-
+
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
-
+
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
-
+
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
-
+
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
-
+
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
@@ -209,7 +213,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d4];
if (value >= kTen8)
*buffer++ = cDigitsLut[d4 + 1];
-
+
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
@@ -222,7 +226,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
else {
const uint32_t a = static_cast(value / kTen16); // 1 to 1844
value %= kTen16;
-
+
if (a < 10)
*buffer++ = static_cast('0' + static_cast(a));
else if (a < 100) {
@@ -232,7 +236,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
}
else if (a < 1000) {
*buffer++ = static_cast('0' + static_cast(a / 100));
-
+
const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
@@ -245,28 +249,28 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1];
}
-
+
const uint32_t v0 = static_cast(value / kTen8);
const uint32_t v1 = static_cast(value % kTen8);
-
+
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
-
+
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
-
+
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
-
+
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
-
+
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
-
+
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
-
+
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
@@ -284,11 +288,12 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
-
+
return buffer;
}
inline char* i64toa(int64_t value, char* buffer) {
+ RAPIDJSON_ASSERT(buffer != 0);
uint64_t u = static_cast(value);
if (value < 0) {
*buffer++ = '-';
diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h
index 5a9aaa4..d401edf 100644
--- a/include/rapidjson/internal/meta.h
+++ b/include/rapidjson/internal/meta.h
@@ -21,7 +21,8 @@
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
-#if defined(_MSC_VER)
+
+#if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(6334)
#endif
@@ -174,7 +175,11 @@ template struct RemoveSfinaeTag { typedef T Type;
RAPIDJSON_NAMESPACE_END
//@endcond
-#if defined(__GNUC__) || defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
diff --git a/include/rapidjson/internal/regex.h b/include/rapidjson/internal/regex.h
index 1369ea2..de06718 100644
--- a/include/rapidjson/internal/regex.h
+++ b/include/rapidjson/internal/regex.h
@@ -24,16 +24,17 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
+#if __GNUC__ >= 7
+RAPIDJSON_DIAG_OFF(implicit-fallthrough)
#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
#ifndef RAPIDJSON_REGEX_VERBOSE
@@ -720,11 +721,11 @@ typedef GenericRegexSearch RegexSearch;
} // namespace internal
RAPIDJSON_NAMESPACE_END
-#ifdef __clang__
+#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
-#ifdef _MSC_VER
+#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h
index 5c5398c..89558d0 100644
--- a/include/rapidjson/internal/stack.h
+++ b/include/rapidjson/internal/stack.h
@@ -100,7 +100,7 @@ public:
void ShrinkToFit() {
if (Empty()) {
// If the stack is empty, completely deallocate the memory.
- Allocator::Free(stack_);
+ Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
stack_ = 0;
stackTop_ = 0;
stackEnd_ = 0;
diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h
index 8639c8c..5f81698 100644
--- a/include/rapidjson/istreamwrapper.h
+++ b/include/rapidjson/istreamwrapper.h
@@ -21,9 +21,7 @@
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
-#endif
-
-#ifdef _MSC_VER
+#elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
#endif
diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h
index 0f377ef..3d339f2 100644
--- a/include/rapidjson/pointer.h
+++ b/include/rapidjson/pointer.h
@@ -21,9 +21,7 @@
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum)
-#endif
-
-#ifdef _MSC_VER
+#elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
@@ -165,7 +163,12 @@ public:
GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
//! Copy constructor.
- GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ *this = rhs;
+ }
+
+ //! Copy constructor.
+ GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
*this = rhs;
}
@@ -532,14 +535,14 @@ public:
*/
ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
+ ValueType& v = Create(root, allocator, &alreadyExist);
return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
}
//! Query a value in a subtree with default null-terminated string.
ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
+ ValueType& v = Create(root, allocator, &alreadyExist);
return alreadyExist ? v : v.SetString(defaultValue, allocator);
}
@@ -547,7 +550,7 @@ public:
//! Query a value in a subtree with default std::basic_string.
ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const {
bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
+ ValueType& v = Create(root, allocator, &alreadyExist);
return alreadyExist ? v : v.SetString(defaultValue, allocator);
}
#endif
@@ -1347,11 +1350,7 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
RAPIDJSON_NAMESPACE_END
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-#endif
-
-#ifdef _MSC_VER
+#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h
index ef36a8c..95bb6ff 100644
--- a/include/rapidjson/prettywriter.h
+++ b/include/rapidjson/prettywriter.h
@@ -39,7 +39,7 @@ enum PrettyFormatOptions {
//! Writer with indentation and spacing.
/*!
- \tparam OutputStream Type of ouptut os.
+ \tparam OutputStream Type of output os.
\tparam SourceEncoding Encoding of source string.
\tparam TargetEncoding Encoding of output stream.
\tparam StackAllocator Type of allocator for allocating memory of stack.
@@ -47,7 +47,7 @@ enum PrettyFormatOptions {
template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class PrettyWriter : public Writer {
public:
- typedef Writer Base;
+ typedef Writer Base;
typedef typename Base::Ch Ch;
//! Constructor
diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h
index e667d8b..9a476f6 100644
--- a/include/rapidjson/rapidjson.h
+++ b/include/rapidjson/rapidjson.h
@@ -26,7 +26,7 @@
Some RapidJSON features are configurable to adapt the library to a wide
variety of platforms, environments and usage scenarios. Most of the
- features can be configured in terms of overriden or predefined
+ features can be configured in terms of overridden or predefined
preprocessor macros at compile-time.
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
@@ -49,6 +49,11 @@
// token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x
+
+// token concatenation
+#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
+#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
+#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
//!@endcond
/*! \def RAPIDJSON_MAJOR_VERSION
@@ -214,7 +219,7 @@
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else
-# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __BYTE_ORDER__
// Detect with GLIBC's endian.h
# elif defined(__GLIBC__)
@@ -224,7 +229,7 @@
# elif (__BYTE_ORDER == __BIG_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else
-# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __GLIBC__
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
@@ -236,12 +241,12 @@
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
-# elif defined(_MSC_VER) && defined(_M_ARM)
+# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN
# else
-# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif
#endif // RAPIDJSON_ENDIAN
@@ -320,17 +325,17 @@
#endif
///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD
/*! \def RAPIDJSON_SIMD
\ingroup RAPIDJSON_CONFIG
- \brief Enable SSE2/SSE4.2 optimization.
+ \brief Enable SSE2/SSE4.2/Neon optimization.
RapidJSON supports optimized implementations for some parsing operations
- based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
- processors.
+ based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel
+ or ARM compatible processors.
- To enable these optimizations, two different symbols can be defined;
+ To enable these optimizations, three different symbols can be defined;
\code
// Enable SSE2 optimization.
#define RAPIDJSON_SSE2
@@ -339,13 +344,17 @@
#define RAPIDJSON_SSE42
\endcode
- \c RAPIDJSON_SSE42 takes precedence, if both are defined.
+ // Enable ARM Neon optimization.
+ #define RAPIDJSON_NEON
+ \endcode
+
+ \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined.
If any of these symbols is defined, RapidJSON defines the macro
\c RAPIDJSON_SIMD to indicate the availability of the optimized code.
*/
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
- || defined(RAPIDJSON_DOXYGEN_RUNNING)
+ || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING)
#define RAPIDJSON_SIMD
#endif
@@ -405,7 +414,15 @@ RAPIDJSON_NAMESPACE_END
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_STATIC_ASSERT
-// Adopt from boost
+// Prefer C++11 static_assert, if available
+#ifndef RAPIDJSON_STATIC_ASSERT
+#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
+#define RAPIDJSON_STATIC_ASSERT(x) \
+ static_assert(x, RAPIDJSON_STRINGIFY(x))
+#endif // C++11
+#endif // RAPIDJSON_STATIC_ASSERT
+
+// Adopt C++03 implementation from boost
#ifndef RAPIDJSON_STATIC_ASSERT
#ifndef __clang__
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
@@ -413,14 +430,10 @@ RAPIDJSON_NAMESPACE_END
RAPIDJSON_NAMESPACE_BEGIN
template struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; };
-template struct StaticAssertTest {};
+template struct StaticAssertTest {};
RAPIDJSON_NAMESPACE_END
-#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
-#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
-#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
-
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
#else
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
@@ -438,7 +451,7 @@ RAPIDJSON_NAMESPACE_END
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
-#endif
+#endif // RAPIDJSON_STATIC_ASSERT
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
@@ -530,7 +543,7 @@ RAPIDJSON_NAMESPACE_END
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if defined(__clang__)
#if __has_feature(cxx_rvalue_references) && \
- (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
+ (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#else
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h
index 00ab6a5..7441eda 100644
--- a/include/rapidjson/reader.h
+++ b/include/rapidjson/reader.h
@@ -33,12 +33,8 @@
#include
#elif defined(RAPIDJSON_SSE2)
#include
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
-RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#elif defined(RAPIDJSON_NEON)
+#include
#endif
#ifdef __clang__
@@ -46,6 +42,10 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(old-style-cast)
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
#endif
#ifdef __GNUC__
@@ -411,7 +411,92 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
return SkipWhitespace(p, end);
}
-#endif // RAPIDJSON_SSE2
+#elif defined(RAPIDJSON_NEON)
+
+//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15));
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ const uint8x16_t w0 = vmovq_n_u8(' ');
+ const uint8x16_t w1 = vmovq_n_u8('\n');
+ const uint8x16_t w2 = vmovq_n_u8('\r');
+ const uint8x16_t w3 = vmovq_n_u8('\t');
+
+ for (;; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast(p));
+ uint8x16_t x = vceqq_u8(s, w0);
+ x = vorrq_u8(x, vceqq_u8(s, w1));
+ x = vorrq_u8(x, vceqq_u8(s, w2));
+ x = vorrq_u8(x, vceqq_u8(s, w3));
+
+ x = vmvnq_u8(x); // Negate
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract
+
+ if (low == 0) {
+ if (high != 0) {
+ int lz =__builtin_clzll(high);;
+ return p + 8 + (lz >> 3);
+ }
+ } else {
+ int lz = __builtin_clzll(low);;
+ return p + (lz >> 3);
+ }
+ }
+}
+
+inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
+ // Fast return for single non-whitespace
+ if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+ ++p;
+ else
+ return p;
+
+ const uint8x16_t w0 = vmovq_n_u8(' ');
+ const uint8x16_t w1 = vmovq_n_u8('\n');
+ const uint8x16_t w2 = vmovq_n_u8('\r');
+ const uint8x16_t w3 = vmovq_n_u8('\t');
+
+ for (; p <= end - 16; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast(p));
+ uint8x16_t x = vceqq_u8(s, w0);
+ x = vorrq_u8(x, vceqq_u8(s, w1));
+ x = vorrq_u8(x, vceqq_u8(s, w2));
+ x = vorrq_u8(x, vceqq_u8(s, w3));
+
+ x = vmvnq_u8(x); // Negate
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract
+
+ if (low == 0) {
+ if (high != 0) {
+ int lz = __builtin_clzll(high);
+ return p + 8 + (lz >> 3);
+ }
+ } else {
+ int lz = __builtin_clzll(low);
+ return p + (lz >> 3);
+ }
+ }
+
+ return SkipWhitespace(p, end);
+}
+
+#endif // RAPIDJSON_NEON
#ifdef RAPIDJSON_SIMD
//! Template function specialization for InsituStringStream
@@ -457,7 +542,8 @@ public:
/*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
*/
- GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
+ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) :
+ stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {}
//! Parse JSON text.
/*! \tparam parseFlags Combination of \ref ParseFlag.
@@ -586,11 +672,11 @@ public:
//! Check if token-by-token parsing JSON text is complete
/*! \return Whether the JSON has been fully decoded.
*/
- RAPIDJSON_FORCEINLINE bool IterativeParseComplete() {
+ RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const {
return IsIterativeParsingCompleteState(state_);
}
- //! Whether a parse error has occured in the last parsing.
+ //! Whether a parse error has occurred in the last parsing.
bool HasParseError() const { return parseResult_.IsError(); }
//! Get the \ref ParseErrorCode of last parsing.
@@ -813,7 +899,7 @@ private:
return false;
}
- // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+ // Helper function to parse four hexadecimal digits in \uXXXX in ParseString().
template
unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
unsigned codepoint = 0;
@@ -920,7 +1006,7 @@ private:
Ch c = is.Peek();
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
- size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
+ size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset
is.Take();
Ch e = is.Peek();
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) {
@@ -955,7 +1041,7 @@ private:
if (c == '\0')
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
else
- RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
}
else {
size_t offset = is.Tell();
@@ -990,7 +1076,7 @@ private:
// 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 };
+ static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0]));
@@ -999,7 +1085,7 @@ private:
const __m128i s = _mm_load_si128(reinterpret_cast(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 t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
@@ -1053,7 +1139,7 @@ private:
// 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 };
+ static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0]));
@@ -1062,7 +1148,7 @@ private:
const __m128i s = _mm_load_si128(reinterpret_cast(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 t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
@@ -1101,7 +1187,7 @@ private:
// 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 };
+ static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0]));
@@ -1110,7 +1196,7 @@ private:
const __m128i s = _mm_load_si128(reinterpret_cast(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 t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
@@ -1129,7 +1215,180 @@ private:
is.src_ = is.dst_ = p;
}
-#endif
+#elif defined(RAPIDJSON_NEON)
+ // StringStream -> StackStream
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& 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((reinterpret_cast(p) + 15) & static_cast(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) {
+ is.src_ = p;
+ return;
+ }
+ else
+ os.Put(*p++);
+
+ // The rest of string using SIMD
+ const uint8x16_t s0 = vmovq_n_u8('"');
+ const uint8x16_t s1 = vmovq_n_u8('\\');
+ const uint8x16_t s2 = vmovq_n_u8('\b');
+ const uint8x16_t s3 = vmovq_n_u8(32);
+
+ for (;; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast(p));
+ uint8x16_t x = vceqq_u8(s, s0);
+ x = vorrq_u8(x, vceqq_u8(s, s1));
+ x = vorrq_u8(x, vceqq_u8(s, s2));
+ x = vorrq_u8(x, vcltq_u8(s, s3));
+
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract
+
+ SizeType length = 0;
+ bool escaped = false;
+ if (low == 0) {
+ if (high != 0) {
+ unsigned lz = (unsigned)__builtin_clzll(high);;
+ length = 8 + (lz >> 3);
+ escaped = true;
+ }
+ } else {
+ unsigned lz = (unsigned)__builtin_clzll(low);;
+ length = lz >> 3;
+ escaped = true;
+ }
+ if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
+ if (length != 0) {
+ char* q = reinterpret_cast(os.Push(length));
+ for (size_t i = 0; i < length; i++)
+ q[i] = p[i];
+
+ p += length;
+ }
+ break;
+ }
+ vst1q_u8(reinterpret_cast(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((reinterpret_cast(p) + 15) & static_cast(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) {
+ is.src_ = p;
+ is.dst_ = q;
+ return;
+ }
+ else
+ *q++ = *p++;
+
+ // The rest of string using SIMD
+ const uint8x16_t s0 = vmovq_n_u8('"');
+ const uint8x16_t s1 = vmovq_n_u8('\\');
+ const uint8x16_t s2 = vmovq_n_u8('\b');
+ const uint8x16_t s3 = vmovq_n_u8(32);
+
+ for (;; p += 16, q += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast(p));
+ uint8x16_t x = vceqq_u8(s, s0);
+ x = vorrq_u8(x, vceqq_u8(s, s1));
+ x = vorrq_u8(x, vceqq_u8(s, s2));
+ x = vorrq_u8(x, vcltq_u8(s, s3));
+
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract
+
+ SizeType length = 0;
+ bool escaped = false;
+ if (low == 0) {
+ if (high != 0) {
+ unsigned lz = (unsigned)__builtin_clzll(high);
+ length = 8 + (lz >> 3);
+ escaped = true;
+ }
+ } else {
+ unsigned lz = (unsigned)__builtin_clzll(low);
+ length = lz >> 3;
+ escaped = true;
+ }
+ if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
+ for (const char* pend = p + length; p != pend; ) {
+ *q++ = *p++;
+ }
+ break;
+ }
+ vst1q_u8(reinterpret_cast(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((reinterpret_cast(p) + 15) & static_cast(~15));
+ for (; p != nextAligned; p++)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) {
+ is.src_ = is.dst_ = p;
+ return;
+ }
+
+ // The rest of string using SIMD
+ const uint8x16_t s0 = vmovq_n_u8('"');
+ const uint8x16_t s1 = vmovq_n_u8('\\');
+ const uint8x16_t s2 = vmovq_n_u8('\b');
+ const uint8x16_t s3 = vmovq_n_u8(32);
+
+ for (;; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast(p));
+ uint8x16_t x = vceqq_u8(s, s0);
+ x = vorrq_u8(x, vceqq_u8(s, s1));
+ x = vorrq_u8(x, vceqq_u8(s, s2));
+ x = vorrq_u8(x, vcltq_u8(s, s3));
+
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract
+
+ if (low == 0) {
+ if (high != 0) {
+ int lz = __builtin_clzll(high);
+ p += 8 + (lz >> 3);
+ break;
+ }
+ } else {
+ int lz = __builtin_clzll(low);
+ p += lz >> 3;
+ break;
+ }
+ }
+
+ is.src_ = is.dst_ = p;
+ }
+#endif // RAPIDJSON_NEON
template
class NumberStream;
@@ -1525,7 +1784,7 @@ private:
kTokenCount
};
- RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
+ RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const {
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define N NumberToken
@@ -1552,7 +1811,7 @@ private:
return NumberToken;
}
- RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
+ RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const {
// current state x one lookahead token -> new state
static const char G[cIterativeParsingStateCount][kTokenCount] = {
// Finish(sink state)
@@ -1891,11 +2150,11 @@ private:
}
}
- RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) {
+ RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const {
return s >= IterativeParsingElementDelimiterState;
}
- RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) {
+ RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const {
return s <= IterativeParsingErrorState;
}
@@ -1945,7 +2204,7 @@ typedef GenericReader, UTF8<> > Reader;
RAPIDJSON_NAMESPACE_END
-#ifdef __clang__
+#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
@@ -1954,8 +2213,4 @@ RAPIDJSON_DIAG_POP
RAPIDJSON_DIAG_POP
#endif
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_POP
-#endif
-
#endif // RAPIDJSON_READER_H_
diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h
index 3dddd3a..d8caf9b 100644
--- a/include/rapidjson/schema.h
+++ b/include/rapidjson/schema.h
@@ -17,6 +17,7 @@
#include "document.h"
#include "pointer.h"
+#include "stringbuffer.h"
#include // abs, floor
#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
@@ -25,7 +26,7 @@
#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
#endif
-#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
+#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
#else
#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
@@ -62,9 +63,7 @@ RAPIDJSON_DIAG_OFF(weak-vtables)
RAPIDJSON_DIAG_OFF(exit-time-destructors)
RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
RAPIDJSON_DIAG_OFF(variadic-macros)
-#endif
-
-#ifdef _MSC_VER
+#elif defined(_MSC_VER)
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
@@ -157,6 +156,62 @@ public:
virtual void FreeState(void* p) = 0;
};
+///////////////////////////////////////////////////////////////////////////////
+// IValidationErrorHandler
+
+template
+class IValidationErrorHandler {
+public:
+ typedef typename SchemaType::Ch Ch;
+ typedef typename SchemaType::SValue SValue;
+
+ virtual ~IValidationErrorHandler() {}
+
+ virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
+ virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
+ virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
+ virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
+ virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
+ virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
+ virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
+ virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
+ virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
+
+ virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
+ virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
+ virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
+
+ virtual void DisallowedItem(SizeType index) = 0;
+ virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
+ virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
+ virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
+
+ virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
+ virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
+ virtual void StartMissingProperties() = 0;
+ virtual void AddMissingProperty(const SValue& name) = 0;
+ virtual bool EndMissingProperties() = 0;
+ virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
+ virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
+
+ virtual void StartDependencyErrors() = 0;
+ virtual void StartMissingDependentProperties() = 0;
+ virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
+ virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
+ virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
+ virtual bool EndDependencyErrors() = 0;
+
+ virtual void DisallowedValue() = 0;
+ virtual void StartDisallowedType() = 0;
+ virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
+ virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
+ virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
+ virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
+ virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
+ virtual void Disallowed() = 0;
+};
+
+
///////////////////////////////////////////////////////////////////////////////
// Hasher
@@ -261,6 +316,7 @@ template
struct SchemaValidationContext {
typedef Schema