commit
532cba1422
3
.gitignore
vendored
3
.gitignore
vendored
@ -23,3 +23,6 @@ Doxyfile
|
||||
Doxyfile.zh-cn
|
||||
DartConfiguration.tcl
|
||||
*.nupkg
|
||||
|
||||
# Files created by OS
|
||||
*.DS_Store
|
||||
|
@ -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:
|
||||
|
14
CHANGELOG.md
14
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
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
BIN
bin/jsonschema/remotes/.DS_Store
vendored
BIN
bin/jsonschema/remotes/.DS_Store
vendored
Binary file not shown.
BIN
bin/jsonschema/tests/.DS_Store
vendored
BIN
bin/jsonschema/tests/.DS_Store
vendored
Binary file not shown.
BIN
bin/jsonschema/tests/draft4/.DS_Store
vendored
BIN
bin/jsonschema/tests/draft4/.DS_Store
vendored
Binary file not shown.
45
contrib/natvis/LICENSE
Normal file
45
contrib/natvis/LICENSE
Normal file
@ -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.
|
7
contrib/natvis/README.md
Normal file
7
contrib/natvis/README.md
Normal file
@ -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).
|
38
contrib/natvis/rapidjson.natvis
Normal file
38
contrib/natvis/rapidjson.natvis
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<!-- rapidjson::GenericValue - basic support -->
|
||||
<Type Name="rapidjson::GenericValue<*,*>">
|
||||
<DisplayString Condition="(data_.f.flags & kTypeMask) == kNullType">null</DisplayString>
|
||||
<DisplayString Condition="data_.f.flags == kTrueFlag">true</DisplayString>
|
||||
<DisplayString Condition="data_.f.flags == kFalseFlag">false</DisplayString>
|
||||
<DisplayString Condition="data_.f.flags == kShortStringFlag">{data_.ss.str}</DisplayString>
|
||||
<DisplayString Condition="(data_.f.flags & kTypeMask) == kStringType">{(const char*)((size_t)data_.s.str & 0x0000FFFFFFFFFFFF)}</DisplayString>
|
||||
<DisplayString Condition="(data_.f.flags & kNumberIntFlag) == kNumberIntFlag">{data_.n.i.i}</DisplayString>
|
||||
<DisplayString Condition="(data_.f.flags & kNumberUintFlag) == kNumberUintFlag">{data_.n.u.u}</DisplayString>
|
||||
<DisplayString Condition="(data_.f.flags & kNumberInt64Flag) == kNumberInt64Flag">{data_.n.i64}</DisplayString>
|
||||
<DisplayString Condition="(data_.f.flags & kNumberUint64Flag) == kNumberUint64Flag">{data_.n.u64}</DisplayString>
|
||||
<DisplayString Condition="(data_.f.flags & kNumberDoubleFlag) == kNumberDoubleFlag">{data_.n.d}</DisplayString>
|
||||
<DisplayString Condition="data_.f.flags == kObjectType">Object members={data_.o.size}</DisplayString>
|
||||
<DisplayString Condition="data_.f.flags == kArrayType">Array members={data_.a.size}</DisplayString>
|
||||
<Expand>
|
||||
<Item Condition="data_.f.flags == kObjectType" Name="[size]">data_.o.size</Item>
|
||||
<Item Condition="data_.f.flags == kObjectType" Name="[capacity]">data_.o.capacity</Item>
|
||||
<ArrayItems Condition="data_.f.flags == kObjectType">
|
||||
<Size>data_.o.size</Size>
|
||||
<!-- NOTE: Rapidjson stores some extra data in the high bits of pointers, which is why the mask -->
|
||||
<ValuePointer>(rapidjson::GenericMember<$T1,$T2>*)(((size_t)data_.o.members) & 0x0000FFFFFFFFFFFF)</ValuePointer>
|
||||
</ArrayItems>
|
||||
|
||||
<Item Condition="data_.f.flags == kArrayType" Name="[size]">data_.a.size</Item>
|
||||
<Item Condition="data_.f.flags == kArrayType" Name="[capacity]">data_.a.capacity</Item>
|
||||
<ArrayItems Condition="data_.f.flags == kArrayType">
|
||||
<Size>data_.a.size</Size>
|
||||
<!-- NOTE: Rapidjson stores some extra data in the high bits of pointers, which is why the mask -->
|
||||
<ValuePointer>(rapidjson::GenericValue<$T1,$T2>*)(((size_t)data_.a.elements) & 0x0000FFFFFFFFFFFF)</ValuePointer>
|
||||
</ArrayItems>
|
||||
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
</AutoVisualizer>
|
||||
|
@ -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}/../
|
||||
)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
// ...
|
||||
|
@ -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()` 获取解析的错误状态。
|
||||
|
||||
解析错误代号 | 描述
|
||||
--------------------------------------------|---------------------------------------------------
|
||||
|
@ -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]
|
||||
|
||||
|
26
doc/faq.md
26
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
|
||||
|
||||
|
@ -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. 它会消耗许多内存么?
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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}
|
||||
|
||||
|
@ -18,7 +18,7 @@ $extrastylesheet
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="topbanner"><a href="https://github.com/miloyip/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
|
||||
<div id="topbanner"><a href="https://github.com/Tencent/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
|
||||
$searchbox
|
||||
<!--END TITLEAREA-->
|
||||
<!-- end header part -->
|
||||
|
@ -7,7 +7,7 @@
|
||||
...
|
||||
"dependencies": {
|
||||
...
|
||||
"rapidjson": "git@github.com:miloyip/rapidjson.git"
|
||||
"rapidjson": "git@github.com:Tencent/rapidjson.git"
|
||||
},
|
||||
...
|
||||
"gypfile": true
|
||||
|
@ -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/)
|
||||
|
@ -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/)
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
292
doc/schema.md
292
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`.
|
||||
|
@ -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 库。
|
||||
|
||||
|
@ -42,6 +42,7 @@ Note that, `StringStream` is a typedef of `GenericStringStream<UTF8<> >`, user m
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <rapidjson/writer.h>
|
||||
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
@ -98,6 +99,7 @@ Apart from reading file, user can also use `FileReadStream` to read `stdin`.
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include <rapidjson/writer.h>
|
||||
#include <cstdio>
|
||||
|
||||
using namespace rapidjson;
|
||||
@ -215,6 +217,7 @@ fclose(fp);
|
||||
~~~~~~~~~~cpp
|
||||
#include "rapidjson/filewritestream.h" // FileWriteStream
|
||||
#include "rapidjson/encodedstream.h" // EncodedOutputStream
|
||||
#include <rapidjson/writer.h>
|
||||
#include <cstdio>
|
||||
|
||||
Document d; // Document is GenericDocument<UTF8<> >
|
||||
|
@ -42,6 +42,7 @@ d.Parse(json);
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <rapidjson/writer.h>
|
||||
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
@ -98,6 +99,7 @@ fclose(fp);
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include <rapidjson/writer.h>
|
||||
#include <cstdio>
|
||||
|
||||
using namespace rapidjson;
|
||||
@ -215,6 +217,7 @@ fclose(fp);
|
||||
~~~~~~~~~~cpp
|
||||
#include "rapidjson/filewritestream.h" // FileWriteStream
|
||||
#include "rapidjson/encodedstream.h" // EncodedOutputStream
|
||||
#include <rapidjson/writer.h>
|
||||
#include <cstdio>
|
||||
|
||||
Document d; // Document 为 GenericDocument<UTF8<> >
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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()
|
||||
|
292
example/archiver/archiver.cpp
Normal file
292
example/archiver/archiver.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
#include "archiver.h"
|
||||
#include <cassert>
|
||||
#include <stack>
|
||||
#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<JsonReaderStackItem> JsonReaderStack;
|
||||
|
||||
#define DOCUMENT reinterpret_cast<Document*>(mDocument)
|
||||
#define STACK (reinterpret_cast<JsonReaderStack*>(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<PrettyWriter<StringBuffer>*>(mWriter)
|
||||
#define STREAM reinterpret_cast<StringBuffer*>(mStream)
|
||||
|
||||
JsonWriter::JsonWriter() : mWriter(), mStream() {
|
||||
mStream = new StringBuffer;
|
||||
mWriter = new PrettyWriter<StringBuffer>(*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<SizeType>(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<SizeType>(s.size()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonWriter& JsonWriter::SetNull() {
|
||||
WRITER->Null();
|
||||
return *this;
|
||||
}
|
||||
|
||||
#undef STREAM
|
||||
#undef WRITER
|
145
example/archiver/archiver.h
Normal file
145
example/archiver/archiver.h
Normal file
@ -0,0 +1,145 @@
|
||||
#ifndef ARCHIVER_H_
|
||||
#define ARCHIVER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
\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__
|
287
example/archiver/archivertest.cpp
Normal file
287
example/archiver/archivertest.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
#include "archiver.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <typename Archiver>
|
||||
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<Student> students;
|
||||
};
|
||||
|
||||
template <typename Archiver>
|
||||
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<Student>::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 <typename Archiver>
|
||||
friend Archiver& operator&(Archiver& ar, Shape& s);
|
||||
|
||||
double x_, y_;
|
||||
};
|
||||
|
||||
template <typename Archiver>
|
||||
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 <typename Archiver>
|
||||
friend Archiver& operator&(Archiver& ar, Circle& c);
|
||||
|
||||
double radius_;
|
||||
};
|
||||
|
||||
template <typename Archiver>
|
||||
Archiver& operator&(Archiver& ar, Circle& c) {
|
||||
ar & static_cast<Shape&>(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 <typename Archiver>
|
||||
friend Archiver& operator&(Archiver& ar, Box& b);
|
||||
|
||||
double width_, height_;
|
||||
};
|
||||
|
||||
template <typename Archiver>
|
||||
Archiver& operator&(Archiver& ar, Box& b) {
|
||||
ar & static_cast<Shape&>(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<Shape*>::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<Shape*>::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) {
|
||||
(*itr)->Print(os);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Archiver>
|
||||
friend Archiver& operator&(Archiver& ar, Canvas& c);
|
||||
|
||||
std::vector<Shape*> shapes_;
|
||||
};
|
||||
|
||||
template <typename Archiver>
|
||||
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<Circle&>(*shape);
|
||||
}
|
||||
else if (type == "Box") {
|
||||
if (ar.IsReader) shape = new Box;
|
||||
ar & static_cast<Box&>(*shape);
|
||||
}
|
||||
return ar.EndObject();
|
||||
}
|
||||
|
||||
template <typename Archiver>
|
||||
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();
|
||||
}
|
@ -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,
|
||||
|
@ -2,6 +2,11 @@
|
||||
#include "rapidjson/document.h"
|
||||
#include <iostream>
|
||||
|
||||
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
|
||||
|
@ -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] } ";
|
||||
|
||||
|
@ -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<StringBuffer> w(sb);
|
||||
validator.GetError().Accept(w);
|
||||
fprintf(stderr, "Error report:\n%s\n", sb.GetString());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
78
include/rapidjson/cursorstreamwrapper.h
Normal file
78
include/rapidjson/cursorstreamwrapper.h
Normal file
@ -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 <typename InputStream, typename Encoding = UTF8<> >
|
||||
class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
CursorStreamWrapper(InputStream& is):
|
||||
GenericStreamWrapper<InputStream, Encoding>(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_
|
@ -26,23 +26,13 @@
|
||||
#include <limits>
|
||||
|
||||
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 <iterator> // std::iterator, std::random_access_iterator_tag
|
||||
#include <iterator> // 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 <bool Const, typename Encoding, typename Allocator>
|
||||
class GenericMemberIterator
|
||||
: public std::iterator<std::random_access_iterator_tag
|
||||
, typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
|
||||
class GenericMemberIterator {
|
||||
|
||||
friend class GenericValue<Encoding,Allocator>;
|
||||
template <bool, typename, typename> friend class GenericMemberIterator;
|
||||
|
||||
typedef GenericMember<Encoding,Allocator> PlainType;
|
||||
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
|
||||
typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
|
||||
|
||||
public:
|
||||
//! Iterator type itself
|
||||
@ -125,12 +112,21 @@ public:
|
||||
//! Non-constant iterator type
|
||||
typedef GenericMemberIterator<false,Encoding,Allocator> 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<SizeType N>
|
||||
GenericStringRef(CharType (&str)[N]) /* = delete */;
|
||||
@ -338,6 +342,9 @@ private:
|
||||
GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
|
||||
};
|
||||
|
||||
template<typename CharType>
|
||||
const CharType GenericStringRef<CharType>::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<typename CharType>
|
||||
inline GenericStringRef<CharType> StringRef(const CharType* str) {
|
||||
return GenericStringRef<CharType>(str, internal::StrLen(str));
|
||||
return GenericStringRef<CharType>(str);
|
||||
}
|
||||
|
||||
//! Mark a character pointer as constant string
|
||||
@ -442,6 +449,26 @@ struct TypeHelper<ValueType, unsigned> {
|
||||
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<typename ValueType>
|
||||
struct TypeHelper<ValueType, long> {
|
||||
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<typename ValueType>
|
||||
struct TypeHelper<ValueType, unsigned long> {
|
||||
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<typename ValueType>
|
||||
struct TypeHelper<ValueType, int64_t> {
|
||||
static bool Is(const ValueType& v) { return v.IsInt64(); }
|
||||
@ -515,7 +542,7 @@ struct TypeHelper<ValueType, typename ValueType::Object> {
|
||||
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<typename ValueType>
|
||||
@ -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 <typename SourceAllocator>
|
||||
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator) {
|
||||
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
|
||||
switch (rhs.GetType()) {
|
||||
case kObjectType: {
|
||||
SizeType count = rhs.data_.o.size;
|
||||
Member* lm = reinterpret_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
|
||||
const typename GenericValue<Encoding,SourceAllocator>::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<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
|
||||
const GenericValue<Encoding,SourceAllocator>* 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<const Data*>(&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 <typename SourceAllocator>
|
||||
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
|
||||
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
|
||||
RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&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<double>(u);
|
||||
return (d >= 0.0)
|
||||
&& (d < static_cast<double>(std::numeric_limits<uint64_t>::max()))
|
||||
&& (d < static_cast<double>((std::numeric_limits<uint64_t>::max)()))
|
||||
&& (u == static_cast<uint64_t>(d));
|
||||
}
|
||||
if (IsInt64()) {
|
||||
int64_t i = GetInt64();
|
||||
volatile double d = static_cast<double>(i);
|
||||
return (d >= static_cast<double>(std::numeric_limits<int64_t>::min()))
|
||||
&& (d < static_cast<double>(std::numeric_limits<int64_t>::max()))
|
||||
return (d >= static_cast<double>((std::numeric_limits<int64_t>::min)()))
|
||||
&& (d < static_cast<double>((std::numeric_limits<int64_t>::max)()))
|
||||
&& (i == static_cast<int64_t>(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<double>(-std::numeric_limits<float>::max())
|
||||
|| a > static_cast<double>(std::numeric_limits<float>::max()))
|
||||
if (a < static_cast<double>(-(std::numeric_limits<float>::max)())
|
||||
|| a > static_cast<double>((std::numeric_limits<float>::max)()))
|
||||
return false;
|
||||
double b = static_cast<double>(static_cast<float>(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<Member*>(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<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
|
||||
}
|
||||
else {
|
||||
SizeType oldCapacity = o.capacity;
|
||||
o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
|
||||
SetMembersPointer(reinterpret_cast<Member*>(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<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
|
||||
GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
|
||||
#endif
|
||||
|
||||
//@}
|
||||
@ -1986,7 +2032,12 @@ private:
|
||||
if (count) {
|
||||
GenericValue* e = static_cast<GenericValue*>(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<Member*>(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 <unsigned parseFlags, typename SourceEncoding>
|
||||
GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
|
||||
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
|
||||
MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
|
||||
MemoryStream ms(reinterpret_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
|
||||
EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
|
||||
ParseStream<parseFlags, SourceEncoding>(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 <typename T> ValueType& operator[](T* name) const { return value_[name]; }
|
||||
template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& 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<Ch>& 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_
|
||||
|
@ -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<CharType> {
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
@ -620,28 +620,28 @@ struct AutoUTF {
|
||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
template<typename OutputStream>
|
||||
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<typename OutputStream>
|
||||
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 <typename InputStream>
|
||||
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 <typename InputStream, typename OutputStream>
|
||||
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<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder {
|
||||
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
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<typename InputStream, typename OutputStream>
|
||||
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<typename InputStream, typename OutputStream>
|
||||
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<typename Encoding>
|
||||
struct Transcoder<Encoding, Encoding> {
|
||||
template<typename InputStream, typename OutputStream>
|
||||
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<typename InputStream, typename OutputStream>
|
||||
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<typename InputStream, typename OutputStream>
|
||||
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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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<size_t>(current_ - buffer_), fp_);
|
||||
size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||
// failure deliberately ignored at this time
|
||||
// added to avoid warn_unused_result build errors
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64)
|
||||
#include <intrin.h> // for _umul128
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
@ -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 <intrin.h>
|
||||
#pragma intrinsic(_BitScanReverse64)
|
||||
#pragma intrinsic(_umul128)
|
||||
|
@ -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<uint32_t>(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<uint32_t>(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<uint32_t>(value / kTen8);
|
||||
const uint32_t v1 = static_cast<uint32_t>(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<uint32_t>(value / kTen16); // 1 to 1844
|
||||
value %= kTen16;
|
||||
|
||||
|
||||
if (a < 10)
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||
else if (a < 100) {
|
||||
@ -232,7 +236,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
|
||||
}
|
||||
else if (a < 1000) {
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(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<uint32_t>(value / kTen8);
|
||||
const uint32_t v1 = static_cast<uint32_t>(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<uint64_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
|
@ -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 <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { 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
|
||||
|
||||
|
@ -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<Regex> 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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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<Token*>(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<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);
|
||||
}
|
||||
#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
|
||||
|
||||
|
@ -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 OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
|
||||
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
|
||||
public:
|
||||
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
|
||||
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
|
||||
typedef typename Base::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
|
@ -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 <bool x> struct STATIC_ASSERTION_FAILURE;
|
||||
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||
template<int x> struct StaticAssertTest {};
|
||||
template <size_t x> 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<bool(x) >)> \
|
||||
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
|
||||
|
@ -33,12 +33,8 @@
|
||||
#include <nmmintrin.h>
|
||||
#elif defined(RAPIDJSON_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#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 <arm_neon.h>
|
||||
#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<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
while (p != nextAligned)
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
|
||||
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<const uint8_t *>(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<uint64x2_t>(x), 0); // extract
|
||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(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<const uint8_t *>(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<uint64x2_t>(x), 0); // extract
|
||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(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<typename InputStream>
|
||||
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<unsigned char>(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<const __m128i *>(&dquote[0]));
|
||||
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||
@ -999,7 +1085,7 @@ private:
|
||||
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||
const __m128i 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<unsigned short>(_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<const __m128i *>(&dquote[0]));
|
||||
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||
@ -1062,7 +1148,7 @@ private:
|
||||
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||
const __m128i 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<unsigned short>(_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<const __m128i *>(&dquote[0]));
|
||||
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||
@ -1110,7 +1196,7 @@ private:
|
||||
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||
const __m128i 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<unsigned short>(_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<char>
|
||||
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
|
||||
const char* p = is.src_;
|
||||
|
||||
// Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
while (p != nextAligned)
|
||||
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
|
||||
is.src_ = p;
|
||||
return;
|
||||
}
|
||||
else
|
||||
os.Put(*p++);
|
||||
|
||||
// The rest of string using SIMD
|
||||
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<const uint8_t *>(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<uint64x2_t>(x), 0); // extract
|
||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(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<char*>(os.Push(length));
|
||||
for (size_t i = 0; i < length; i++)
|
||||
q[i] = p[i];
|
||||
|
||||
p += length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
vst1q_u8(reinterpret_cast<uint8_t *>(os.Push(16)), s);
|
||||
}
|
||||
|
||||
is.src_ = p;
|
||||
}
|
||||
|
||||
// InsituStringStream -> InsituStringStream
|
||||
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
|
||||
RAPIDJSON_ASSERT(&is == &os);
|
||||
(void)os;
|
||||
|
||||
if (is.src_ == is.dst_) {
|
||||
SkipUnescapedString(is);
|
||||
return;
|
||||
}
|
||||
|
||||
char* p = is.src_;
|
||||
char *q = is.dst_;
|
||||
|
||||
// Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
while (p != nextAligned)
|
||||
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
|
||||
is.src_ = p;
|
||||
is.dst_ = q;
|
||||
return;
|
||||
}
|
||||
else
|
||||
*q++ = *p++;
|
||||
|
||||
// The rest of string using SIMD
|
||||
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<uint8_t *>(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<uint64x2_t>(x), 0); // extract
|
||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(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<uint8_t *>(q), s);
|
||||
}
|
||||
|
||||
is.src_ = p;
|
||||
is.dst_ = q;
|
||||
}
|
||||
|
||||
// When read/write pointers are the same for insitu stream, just skip unescaped characters
|
||||
static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
|
||||
RAPIDJSON_ASSERT(is.src_ == is.dst_);
|
||||
char* p = is.src_;
|
||||
|
||||
// Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
for (; p != nextAligned; p++)
|
||||
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
|
||||
is.src_ = is.dst_ = p;
|
||||
return;
|
||||
}
|
||||
|
||||
// The rest of string using SIMD
|
||||
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<uint8_t *>(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<uint64x2_t>(x), 0); // extract
|
||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(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<typename InputStream, bool backup, bool pushOnTake>
|
||||
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<>, 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_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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.
|
||||
|
||||
#include "rapidjson.h"
|
||||
@ -100,6 +100,50 @@ inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||
PutUnsafe(stream, c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericStreamWrapper
|
||||
|
||||
//! A Stream Wrapper
|
||||
/*! \tThis string stream is a wrapper for any stream by just forwarding any
|
||||
\treceived message to the origin stream.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
template <typename InputStream, typename Encoding = UTF8<> >
|
||||
class GenericStreamWrapper {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
GenericStreamWrapper(InputStream& is): is_(is) {}
|
||||
|
||||
Ch Peek() const { return is_.Peek(); }
|
||||
Ch Take() { return is_.Take(); }
|
||||
size_t Tell() { return is_.Tell(); }
|
||||
Ch* PutBegin() { return is_.PutBegin(); }
|
||||
void Put(Ch ch) { is_.Put(ch); }
|
||||
void Flush() { is_.Flush(); }
|
||||
size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); }
|
||||
|
||||
// wrapper for MemoryStream
|
||||
const Ch* Peek4() const { return is_.Peek4(); }
|
||||
|
||||
// wrapper for AutoUTFInputStream
|
||||
UTFType GetType() const { return is_.GetType(); }
|
||||
bool HasBOM() const { return is_.HasBOM(); }
|
||||
|
||||
protected:
|
||||
InputStream& is_;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// StringStream
|
||||
|
||||
|
@ -32,11 +32,8 @@
|
||||
#include <nmmintrin.h>
|
||||
#elif defined(RAPIDJSON_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
#elif defined(RAPIDJSON_NEON)
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
@ -44,6 +41,9 @@ RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#elif defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
@ -220,6 +220,13 @@ public:
|
||||
|
||||
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool Key(const std::basic_string<Ch>& str)
|
||||
{
|
||||
return Key(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
|
||||
@ -451,9 +458,14 @@ protected:
|
||||
|
||||
bool WriteRawValue(const Ch* json, size_t length) {
|
||||
PutReserve(*os_, length);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
RAPIDJSON_ASSERT(json[i] != '\0');
|
||||
PutUnsafe(*os_, json[i]);
|
||||
GenericStringStream<SourceEncoding> is(json);
|
||||
while (RAPIDJSON_LIKELY(is.Tell() < length)) {
|
||||
const Ch c = is.Peek();
|
||||
RAPIDJSON_ASSERT(c != '\0');
|
||||
if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
|
||||
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
|
||||
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -585,7 +597,7 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
|
||||
// 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<const __m128i *>(&dquote[0]));
|
||||
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||
@ -594,7 +606,7 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
|
||||
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||
const __m128i 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<unsigned short>(_mm_movemask_epi8(x));
|
||||
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
|
||||
@ -619,15 +631,79 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||
#elif defined(RAPIDJSON_NEON)
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
|
||||
if (length < 16)
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
|
||||
if (!RAPIDJSON_LIKELY(is.Tell() < length))
|
||||
return false;
|
||||
|
||||
const char* p = is.src_;
|
||||
const char* end = is.head_ + length;
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
|
||||
if (nextAligned > end)
|
||||
return true;
|
||||
|
||||
while (p != nextAligned)
|
||||
if (*p < 0x20 || *p == '\"' || *p == '\\') {
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
else
|
||||
os_->PutUnsafe(*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 != endAligned; p += 16) {
|
||||
const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(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<uint64x2_t>(x), 0); // extract
|
||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
||||
|
||||
SizeType len = 0;
|
||||
bool escaped = false;
|
||||
if (low == 0) {
|
||||
if (high != 0) {
|
||||
unsigned lz = (unsigned)__builtin_clzll(high);
|
||||
len = 8 + (lz >> 3);
|
||||
escaped = true;
|
||||
}
|
||||
} else {
|
||||
unsigned lz = (unsigned)__builtin_clzll(low);
|
||||
len = lz >> 3;
|
||||
escaped = true;
|
||||
}
|
||||
if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
|
||||
char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
|
||||
for (size_t i = 0; i < len; i++)
|
||||
q[i] = p[i];
|
||||
|
||||
p += len;
|
||||
break;
|
||||
}
|
||||
vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
|
||||
}
|
||||
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
#endif // RAPIDJSON_NEON
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if defined(_MSC_VER) || defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
|
BIN
library.json
BIN
library.json
Binary file not shown.
BIN
package.json
BIN
package.json
Binary file not shown.
@ -5,10 +5,10 @@ nuget {
|
||||
id = rapidjson;
|
||||
version : ${MYVERSION};
|
||||
title: "rapidjson";
|
||||
authors: {"https://github.com/miloyip/rapidjson/releases/tag/v1.1.0"};
|
||||
authors: {"https://github.com/Tencent/rapidjson/releases/tag/v1.1.0"};
|
||||
owners: {"@lsantos (github)"};
|
||||
licenseUrl: "https://github.com/miloyip/rapidjson/blob/master/license.txt";
|
||||
projectUrl: "https://github.com/miloyip/rapidjson/";
|
||||
licenseUrl: "https://github.com/Tencent/rapidjson/blob/master/license.txt";
|
||||
projectUrl: "https://github.com/Tencent/rapidjson/";
|
||||
iconUrl: "https://cdn1.iconfinder.com/data/icons/fatcow/32x32/json.png";
|
||||
requireLicenseAcceptance:false;
|
||||
summary: @"A fast JSON parser/generator for C++ with both SAX/DOM style API";
|
||||
@ -48,7 +48,7 @@ Changed
|
||||
|
||||
dependencies {
|
||||
packages : {
|
||||
//TODO: Add dependecies here in [pkg.name]/[version] form per newline
|
||||
//TODO: Add dependencies here in [pkg.name]/[version] form per newline
|
||||
//zlib/[1.2.8],
|
||||
};
|
||||
}
|
||||
|
62
readme.md
62
readme.md
@ -1,14 +1,14 @@
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
## A fast JSON parser/generator for C++ with both SAX/DOM style API
|
||||
## A fast JSON parser/generator for C++ with both SAX/DOM style API
|
||||
|
||||
Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
|
||||
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
|
||||
* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
|
||||
* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/)
|
||||
* RapidJSON Documentation
|
||||
* [English](http://rapidjson.org/)
|
||||
* [简体中文](http://rapidjson.org/zh-cn/)
|
||||
@ -20,12 +20,12 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
|
||||
| :---------------: | :-----------------: | :-------------------: |
|
||||
| ![lin-badge] | ![win-badge] | ![cov-badge] |
|
||||
|
||||
[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status"
|
||||
[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status"
|
||||
[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status"
|
||||
[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status"
|
||||
[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master
|
||||
[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master
|
||||
[lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status"
|
||||
[lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status"
|
||||
[win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status"
|
||||
[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status"
|
||||
[cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage"
|
||||
[cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage"
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -43,10 +43,10 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](
|
||||
|
||||
More features can be read [here](doc/features.md).
|
||||
|
||||
JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at
|
||||
JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in full compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at
|
||||
* [Introducing JSON](http://json.org/)
|
||||
* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt)
|
||||
* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm)
|
||||
* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159)
|
||||
* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm)
|
||||
|
||||
## Highlights in v1.1 (2016-8-25)
|
||||
|
||||
@ -74,8 +74,8 @@ RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder
|
||||
|
||||
RapidJSON uses following software as its dependencies:
|
||||
* [CMake](https://cmake.org/) as a general build tool
|
||||
* (optional)[Doxygen](http://www.doxygen.org) to build documentation
|
||||
* (optional)[googletest](https://github.com/google/googletest) for unit and performance testing
|
||||
* (optional) [Doxygen](http://www.doxygen.org) to build documentation
|
||||
* (optional) [googletest](https://github.com/google/googletest) for unit and performance testing
|
||||
|
||||
To generate user documentation and run tests please proceed with the steps below:
|
||||
|
||||
@ -84,7 +84,7 @@ To generate user documentation and run tests please proceed with the steps below
|
||||
3. Change to `build` directory and run `cmake ..` command to configure your build. Windows users can do the same with cmake-gui application.
|
||||
4. On Windows, build the solution found in the build directory. On Linux, run `make` from the build directory.
|
||||
|
||||
On successfull build you will find compiled test and example binaries in `bin`
|
||||
On successful build you will find compiled test and example binaries in `bin`
|
||||
directory. The generated documentation will be available in `doc/html`
|
||||
directory of the build tree. To run tests after finished build please run `make
|
||||
test` or `ctest` from your build tree. You can get detailed output using `ctest
|
||||
@ -136,25 +136,25 @@ The following diagram shows the process.
|
||||
|
||||

|
||||
|
||||
More [examples](https://github.com/miloyip/rapidjson/tree/master/example) are available:
|
||||
More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are available:
|
||||
|
||||
* DOM API
|
||||
* [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API.
|
||||
* [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API.
|
||||
|
||||
* SAX API
|
||||
* [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`.
|
||||
* [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed.
|
||||
* [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`.
|
||||
* [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON.
|
||||
* [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API.
|
||||
* [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API.
|
||||
* [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format.
|
||||
* [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`.
|
||||
* [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed.
|
||||
* [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`.
|
||||
* [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON.
|
||||
* [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API.
|
||||
* [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API.
|
||||
* [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format.
|
||||
|
||||
* Schema
|
||||
* [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema.
|
||||
|
||||
* [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema.
|
||||
|
||||
* Advanced
|
||||
* [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings.
|
||||
* [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread.
|
||||
* [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key.
|
||||
* [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`.
|
||||
* [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings.
|
||||
* [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread.
|
||||
* [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key.
|
||||
* [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`.
|
||||
|
@ -1,6 +1,6 @@
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
## 高效的 C++ JSON 解析/生成器,提供 SAX 及 DOM 风格 API
|
||||
|
||||
@ -8,11 +8,11 @@ Tencent is pleased to support the open source community by making RapidJSON avai
|
||||
|
||||
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
|
||||
* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
|
||||
* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/)
|
||||
* RapidJSON 文档
|
||||
* [English](http://rapidjson.org/)
|
||||
* [简体中文](http://rapidjson.org/zh-cn/)
|
||||
* [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。
|
||||
* [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/details/zh-cn) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。
|
||||
|
||||
## Build 状态
|
||||
|
||||
@ -20,12 +20,12 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
|
||||
| :---------------: | :-----------------: | :-------------------: |
|
||||
| ![lin-badge] | ![win-badge] | ![cov-badge] |
|
||||
|
||||
[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status"
|
||||
[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status"
|
||||
[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status"
|
||||
[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status"
|
||||
[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master
|
||||
[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master
|
||||
[lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status"
|
||||
[lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status"
|
||||
[win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status"
|
||||
[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status"
|
||||
[cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage"
|
||||
[cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage"
|
||||
|
||||
## 简介
|
||||
|
||||
@ -45,8 +45,8 @@ RapidJSON 是一个 C++ 的 JSON 解析器及生成器。它的灵感来自 [Rap
|
||||
|
||||
JSON(JavaScript Object Notation)是一个轻量的数据交换格式。RapidJSON 应该完全遵从 RFC7159/ECMA-404,并支持可选的放宽语法。 关于 JSON 的更多信息可参考:
|
||||
* [Introducing JSON](http://json.org/)
|
||||
* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt)
|
||||
* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm)
|
||||
* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159)
|
||||
* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm)
|
||||
|
||||
## v1.1 中的亮点 (2016-8-25)
|
||||
|
||||
@ -73,9 +73,9 @@ RapidJSON 是跨平台的。以下是一些曾测试的平台/编译器组合
|
||||
RapidJSON 是只有头文件的 C++ 库。只需把 `include/rapidjson` 目录复制至系统或项目的 include 目录中。
|
||||
|
||||
RapidJSON 依赖于以下软件:
|
||||
* [CMake](http://www.cmake.org) 作为通用生成工具
|
||||
* (optional)[Doxygen](http://www.doxygen.org) 用于生成文档
|
||||
* (optional)[googletest](https://code.google.com/p/googletest/) 用于单元及性能测试
|
||||
* [CMake](https://cmake.org/) 作为通用生成工具
|
||||
* (optional) [Doxygen](http://www.doxygen.org) 用于生成文档
|
||||
* (optional) [googletest](https://github.com/google/googletest) 用于单元及性能测试
|
||||
|
||||
生成测试及例子的步骤:
|
||||
|
||||
@ -128,25 +128,25 @@ int main() {
|
||||
|
||||

|
||||
|
||||
还有许多 [例子](https://github.com/miloyip/rapidjson/tree/master/example) 可供参考:
|
||||
还有许多 [例子](https://github.com/Tencent/rapidjson/tree/master/example) 可供参考:
|
||||
|
||||
* DOM API
|
||||
* [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): DOM API 的基本使用方法。
|
||||
* [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): DOM API 的基本使用方法。
|
||||
|
||||
* SAX API
|
||||
* [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): 使用 `Reader` 解析 JSON 时,打印所有 SAX 事件。
|
||||
* [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): 移除 JSON 中所有空白符的命令行工具。
|
||||
* [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): 为 JSON 加入缩进与换行的命令行工具,当中使用了 `PrettyWriter`。
|
||||
* [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): 把 JSON 中所有字符串改为大写的命令行工具。
|
||||
* [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): 使用 SAX API 去解析一个 JSON 报文。
|
||||
* [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): 使用 SAX API 去序列化 C++ 对象,生成 JSON。
|
||||
* [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): 实现了一个 `JsonxWriter`,它能把 SAX 事件写成 [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)(一种 XML)格式。这个例子是把 JSON 输入转换成 JSONx 格式的命令行工具。
|
||||
* [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): 使用 `Reader` 解析 JSON 时,打印所有 SAX 事件。
|
||||
* [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): 移除 JSON 中所有空白符的命令行工具。
|
||||
* [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): 为 JSON 加入缩进与换行的命令行工具,当中使用了 `PrettyWriter`。
|
||||
* [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): 把 JSON 中所有字符串改为大写的命令行工具。
|
||||
* [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): 使用 SAX API 去解析一个 JSON 报文。
|
||||
* [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): 使用 SAX API 去序列化 C++ 对象,生成 JSON。
|
||||
* [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): 实现了一个 `JsonxWriter`,它能把 SAX 事件写成 [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)(一种 XML)格式。这个例子是把 JSON 输入转换成 JSONx 格式的命令行工具。
|
||||
|
||||
* Schema API
|
||||
* [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp): 使用 JSON Schema 去校验 JSON 的命令行工具。
|
||||
|
||||
* [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp): 使用 JSON Schema 去校验 JSON 的命令行工具。
|
||||
|
||||
* 进阶
|
||||
* [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,可自动处理任何 UTF 编码的 JSON。
|
||||
* [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例子中的 `AsyncDocumentParser` 类使用 C++ 线程来逐段解析 JSON。
|
||||
* [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 移取使用者指定的键值的命令行工具。
|
||||
* [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。
|
||||
* [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,可自动处理任何 UTF 编码的 JSON。
|
||||
* [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例子中的 `AsyncDocumentParser` 类使用 C++ 线程来逐段解析 JSON。
|
||||
* [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): 移取使用者指定的键值的命令行工具。
|
||||
* [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。
|
@ -432,7 +432,7 @@ bool Writer1<rapidjson::StringBuffer>::WriteUint(unsigned u) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Using digits LUT to reduce divsion/modulo
|
||||
// Using digits LUT to reduce division/modulo
|
||||
template<typename OutputStream>
|
||||
class Writer2 {
|
||||
public:
|
||||
@ -616,7 +616,7 @@ inline bool Writer3<rapidjson::InsituStringStream>::WriteUint64(uint64_t u) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Using digits LUT to reduce divsion/modulo, two passes
|
||||
// Using digits LUT to reduce division/modulo, two passes
|
||||
template<typename OutputStream>
|
||||
class Writer4 {
|
||||
public:
|
||||
|
@ -24,10 +24,13 @@
|
||||
|
||||
// __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
|
||||
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
@ -28,6 +28,8 @@
|
||||
#define SIMD_SUFFIX(name) name##_SSE2
|
||||
#elif defined(RAPIDJSON_SSE42)
|
||||
#define SIMD_SUFFIX(name) name##_SSE42
|
||||
#elif defined(RAPIDJSON_NEON)
|
||||
#define SIMD_SUFFIX(name) name##_NEON
|
||||
#else
|
||||
#define SIMD_SUFFIX(name) name
|
||||
#endif
|
||||
|
@ -3,6 +3,7 @@ include(CheckCXXCompilerFlag)
|
||||
set(UNITTEST_SOURCES
|
||||
allocatorstest.cpp
|
||||
bigintegertest.cpp
|
||||
cursorstreamwrappertest.cpp
|
||||
documenttest.cpp
|
||||
dtoatest.cpp
|
||||
encodedstreamtest.cpp
|
||||
|
115
test/unittest/cursorstreamwrappertest.cpp
Normal file
115
test/unittest/cursorstreamwrappertest.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/cursorstreamwrapper.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
// static const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
|
||||
|
||||
bool testJson(const char *json, size_t &line, size_t &col) {
|
||||
StringStream ss(json);
|
||||
CursorStreamWrapper<StringStream> csw(ss);
|
||||
Document document;
|
||||
document.ParseStream(csw);
|
||||
bool ret = document.HasParseError();
|
||||
if (ret) {
|
||||
col = csw.GetColumn();
|
||||
line = csw.GetLine();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingFirstBracket) {
|
||||
const char json[] = "\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 3);
|
||||
EXPECT_EQ(col, 0);
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingQuotes) {
|
||||
const char json[] = "{\"string\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 1);
|
||||
EXPECT_EQ(col, 8);
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingColon) {
|
||||
const char json[] = "{\"string\"\n\n\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 3);
|
||||
EXPECT_EQ(col, 0);
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingSecondQuotes) {
|
||||
const char json[] = "{\"string\"\n\n:my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 3);
|
||||
EXPECT_EQ(col, 1);
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingComma) {
|
||||
const char json[] = "{\"string\"\n\n:\"my string\"\"array\"\n:[\"1\", \"2\", \"3\"]}";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 3);
|
||||
EXPECT_EQ(col, 12);
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingArrayBracket) {
|
||||
const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:\"1\", \"2\", \"3\"]}";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 4);
|
||||
EXPECT_EQ(col, 9);
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingArrayComma) {
|
||||
const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\" \"2\", \"3\"]}";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 4);
|
||||
EXPECT_EQ(col, 6);
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingLastArrayBracket) {
|
||||
const char json8[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"}";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json8, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 4);
|
||||
EXPECT_EQ(col, 15);
|
||||
}
|
||||
|
||||
TEST(CursorStreamWrapper, MissingLastBracket) {
|
||||
const char json9[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]";
|
||||
size_t col, line;
|
||||
bool ret = testJson(json9, line, col);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(line, 4);
|
||||
EXPECT_EQ(col, 16);
|
||||
}
|
@ -128,8 +128,14 @@ TEST(Document, UnchangedOnParseError) {
|
||||
Document doc;
|
||||
doc.SetArray().PushBack(0, doc.GetAllocator());
|
||||
|
||||
ParseResult noError;
|
||||
EXPECT_TRUE(noError);
|
||||
|
||||
ParseResult err = doc.Parse("{]");
|
||||
EXPECT_TRUE(doc.HasParseError());
|
||||
EXPECT_NE(err, noError);
|
||||
EXPECT_NE(err.Code(), noError);
|
||||
EXPECT_NE(noError, doc.GetParseError());
|
||||
EXPECT_EQ(err.Code(), doc.GetParseError());
|
||||
EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
|
||||
EXPECT_TRUE(doc.IsArray());
|
||||
@ -138,6 +144,9 @@ TEST(Document, UnchangedOnParseError) {
|
||||
err = doc.Parse("{}");
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
EXPECT_FALSE(err.IsError());
|
||||
EXPECT_TRUE(err);
|
||||
EXPECT_EQ(err, noError);
|
||||
EXPECT_EQ(err.Code(), noError);
|
||||
EXPECT_EQ(err.Code(), doc.GetParseError());
|
||||
EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
|
||||
EXPECT_TRUE(doc.IsObject());
|
||||
@ -291,7 +300,14 @@ TEST(Document, Swap) {
|
||||
o.SetObject().AddMember("a", 1, a);
|
||||
|
||||
// Swap between Document and Value
|
||||
// d1.Swap(o); // doesn't compile
|
||||
d1.Swap(o);
|
||||
EXPECT_TRUE(d1.IsObject());
|
||||
EXPECT_TRUE(o.IsArray());
|
||||
|
||||
d1.Swap(o);
|
||||
EXPECT_TRUE(d1.IsArray());
|
||||
EXPECT_TRUE(o.IsObject());
|
||||
|
||||
o.Swap(d1);
|
||||
EXPECT_TRUE(d1.IsObject());
|
||||
EXPECT_TRUE(o.IsArray());
|
||||
@ -488,15 +504,19 @@ TYPED_TEST(DocumentMove, MoveConstructorParseError) {
|
||||
a.Parse("{ 4 = 4]");
|
||||
ParseResult error(a.GetParseError(), a.GetErrorOffset());
|
||||
EXPECT_TRUE(a.HasParseError());
|
||||
EXPECT_NE(error, noError);
|
||||
EXPECT_NE(error.Code(), noError);
|
||||
EXPECT_NE(error.Code(), noError.Code());
|
||||
EXPECT_NE(error.Offset(), noError.Offset());
|
||||
|
||||
D b(std::move(a));
|
||||
EXPECT_FALSE(a.HasParseError());
|
||||
EXPECT_TRUE(b.HasParseError());
|
||||
EXPECT_EQ(a.GetParseError(), noError);
|
||||
EXPECT_EQ(a.GetParseError(), noError.Code());
|
||||
EXPECT_EQ(b.GetParseError(), error.Code());
|
||||
EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
|
||||
EXPECT_EQ(b.GetParseError(), error);
|
||||
EXPECT_EQ(b.GetParseError(), error.Code());
|
||||
EXPECT_EQ(b.GetErrorOffset(), error.Offset());
|
||||
|
||||
D c(std::move(b));
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#endif
|
||||
@ -176,6 +176,6 @@ TEST(IStreamWrapper, wfstream) {
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
@ -70,8 +70,8 @@ template <typename T>
|
||||
static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) {
|
||||
// Boundary cases
|
||||
VerifyValue<T>(0, f, g);
|
||||
VerifyValue<T>(std::numeric_limits<T>::min(), f, g);
|
||||
VerifyValue<T>(std::numeric_limits<T>::max(), f, g);
|
||||
VerifyValue<T>((std::numeric_limits<T>::min)(), f, g);
|
||||
VerifyValue<T>((std::numeric_limits<T>::max)(), f, g);
|
||||
|
||||
// 2^n - 1, 2^n, 10^n - 1, 10^n until overflow
|
||||
for (int power = 2; power <= 10; power += 8) {
|
||||
|
@ -69,14 +69,15 @@ static void TestFileStream() {
|
||||
|
||||
const char* s = "Hello World!\n";
|
||||
{
|
||||
ofstream ofs(filename, ios::out | ios::binary);
|
||||
BasicOStreamWrapper<ofstream> osw(ofs);
|
||||
FileStreamType ofs(filename, ios::out | ios::binary);
|
||||
BasicOStreamWrapper<FileStreamType> osw(ofs);
|
||||
for (const char* p = s; *p; p++)
|
||||
osw.Put(*p);
|
||||
osw.Flush();
|
||||
}
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
ASSERT_TRUE( fp != NULL );
|
||||
for (const char* p = s; *p; p++)
|
||||
EXPECT_EQ(*p, static_cast<char>(fgetc(fp)));
|
||||
fclose(fp);
|
||||
|
@ -441,8 +441,8 @@ TEST(Pointer, Stringify) {
|
||||
}
|
||||
|
||||
// Construct a Pointer with static tokens, no dynamic allocation involved.
|
||||
#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
|
||||
#define INDEX(i) { #i, sizeof(#i) - 1, i }
|
||||
#define NAME(s) { s, static_cast<SizeType>(sizeof(s) / sizeof(s[0]) - 1), kPointerInvalidIndex }
|
||||
#define INDEX(i) { #i, static_cast<SizeType>(sizeof(#i) - 1), i }
|
||||
|
||||
static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(0) }; // equivalent to "/foo/0"
|
||||
|
||||
@ -462,7 +462,8 @@ TEST(Pointer, ConstructorWithToken) {
|
||||
|
||||
TEST(Pointer, CopyConstructor) {
|
||||
{
|
||||
Pointer p("/foo/0");
|
||||
CrtAllocator allocator;
|
||||
Pointer p("/foo/0", &allocator);
|
||||
Pointer q(p);
|
||||
EXPECT_TRUE(q.IsValid());
|
||||
EXPECT_EQ(2u, q.GetTokenCount());
|
||||
@ -471,6 +472,7 @@ TEST(Pointer, CopyConstructor) {
|
||||
EXPECT_EQ(1u, q.GetTokens()[1].length);
|
||||
EXPECT_STREQ("0", q.GetTokens()[1].name);
|
||||
EXPECT_EQ(0u, q.GetTokens()[1].index);
|
||||
EXPECT_EQ(&p.GetAllocator(), &q.GetAllocator());
|
||||
}
|
||||
|
||||
// Static tokens
|
||||
@ -489,7 +491,8 @@ TEST(Pointer, CopyConstructor) {
|
||||
|
||||
TEST(Pointer, Assignment) {
|
||||
{
|
||||
Pointer p("/foo/0");
|
||||
CrtAllocator allocator;
|
||||
Pointer p("/foo/0", &allocator);
|
||||
Pointer q;
|
||||
q = p;
|
||||
EXPECT_TRUE(q.IsValid());
|
||||
@ -499,6 +502,7 @@ TEST(Pointer, Assignment) {
|
||||
EXPECT_EQ(1u, q.GetTokens()[1].length);
|
||||
EXPECT_STREQ("0", q.GetTokens()[1].name);
|
||||
EXPECT_EQ(0u, q.GetTokens()[1].index);
|
||||
EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
|
||||
q = q;
|
||||
EXPECT_TRUE(q.IsValid());
|
||||
EXPECT_EQ(2u, q.GetTokenCount());
|
||||
@ -507,6 +511,7 @@ TEST(Pointer, Assignment) {
|
||||
EXPECT_EQ(1u, q.GetTokens()[1].length);
|
||||
EXPECT_STREQ("0", q.GetTokens()[1].name);
|
||||
EXPECT_EQ(0u, q.GetTokens()[1].index);
|
||||
EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
|
||||
}
|
||||
|
||||
// Static tokens
|
||||
@ -1488,7 +1493,7 @@ TEST(Pointer, Ambiguity) {
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/miloyip/rapidjson/issues/483
|
||||
// https://github.com/Tencent/rapidjson/issues/483
|
||||
namespace myjson {
|
||||
|
||||
class MyAllocator
|
||||
|
@ -167,6 +167,7 @@ TEST(PrettyWriter, OStreamWrapper) {
|
||||
TEST(PrettyWriter, FileWriteStream) {
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
ASSERT_TRUE(fp!=NULL);
|
||||
char buffer[16];
|
||||
FileWriteStream os(fp, buffer, sizeof(buffer));
|
||||
PrettyWriter<FileWriteStream> writer(os);
|
||||
@ -258,6 +259,49 @@ TEST(PrettyWriter, InvalidEventSequence) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PrettyWriter, NaN) {
|
||||
double nan = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
EXPECT_TRUE(internal::Double(nan).IsNan());
|
||||
StringBuffer buffer;
|
||||
{
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(nan));
|
||||
}
|
||||
{
|
||||
PrettyWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
|
||||
EXPECT_TRUE(writer.Double(nan));
|
||||
EXPECT_STREQ("NaN", buffer.GetString());
|
||||
}
|
||||
GenericStringBuffer<UTF16<> > buffer2;
|
||||
PrettyWriter<GenericStringBuffer<UTF16<> > > writer2(buffer2);
|
||||
EXPECT_FALSE(writer2.Double(nan));
|
||||
}
|
||||
|
||||
TEST(PrettyWriter, Inf) {
|
||||
double inf = std::numeric_limits<double>::infinity();
|
||||
|
||||
EXPECT_TRUE(internal::Double(inf).IsInf());
|
||||
StringBuffer buffer;
|
||||
{
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(inf));
|
||||
}
|
||||
{
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(-inf));
|
||||
}
|
||||
{
|
||||
PrettyWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
|
||||
EXPECT_TRUE(writer.Double(inf));
|
||||
}
|
||||
{
|
||||
PrettyWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
|
||||
EXPECT_TRUE(writer.Double(-inf));
|
||||
}
|
||||
EXPECT_STREQ("Infinity-Infinity", buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(PrettyWriter, Issue_889) {
|
||||
char buf[100] = "Hello";
|
||||
|
||||
|
@ -233,7 +233,7 @@ static void TestParseDouble() {
|
||||
TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow
|
||||
TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
|
||||
TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
|
||||
TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
|
||||
TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/Tencent/rapidjson/issues/120
|
||||
TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise
|
||||
TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0);
|
||||
TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
|
||||
@ -415,7 +415,7 @@ TEST(Reader, ParseNumber_NormalPrecisionError) {
|
||||
uint64_t bias1 = e.ToBias();
|
||||
uint64_t bias2 = a.ToBias();
|
||||
double ulp = static_cast<double>(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1);
|
||||
ulpMax = std::max(ulpMax, ulp);
|
||||
ulpMax = (std::max)(ulpMax, ulp);
|
||||
ulpSum += ulp;
|
||||
}
|
||||
printf("ULP Average = %g, Max = %g \n", ulpSum / count, ulpMax);
|
||||
@ -725,6 +725,8 @@ TEST(Reader, ParseString_Error) {
|
||||
|
||||
// Malform ASCII sequence
|
||||
TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80u), '\"', ']', '\0'));
|
||||
TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x01u), '\"', ']', '\0'));
|
||||
TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x1Cu), '\"', ']', '\0'));
|
||||
|
||||
#undef ARRAY
|
||||
#undef TEST_STRINGARRAY_ERROR
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,8 @@
|
||||
# define RAPIDJSON_SSE42
|
||||
#elif defined(__SSE2__)
|
||||
# define RAPIDJSON_SSE2
|
||||
#elif defined(__ARM_NEON)
|
||||
# define RAPIDJSON_NEON
|
||||
#endif
|
||||
|
||||
#define RAPIDJSON_NAMESPACE rapidjson_simd
|
||||
@ -41,6 +43,8 @@ using namespace rapidjson_simd;
|
||||
#define SIMD_SUFFIX(name) name##_SSE2
|
||||
#elif defined(RAPIDJSON_SSE42)
|
||||
#define SIMD_SUFFIX(name) name##_SSE42
|
||||
#elif defined(RAPIDJSON_NEON)
|
||||
#define SIMD_SUFFIX(name) name##_NEON
|
||||
#else
|
||||
#define SIMD_SUFFIX(name) name
|
||||
#endif
|
||||
|
@ -91,7 +91,7 @@ TEST(Strtod, CheckApproximationCase) {
|
||||
}
|
||||
|
||||
// Remove common power of two factor from all three scaled values
|
||||
int common_Exp2 = std::min(dS_Exp2, std::min(bS_Exp2, hS_Exp2));
|
||||
int common_Exp2 = (std::min)(dS_Exp2, (std::min)(bS_Exp2, hS_Exp2));
|
||||
dS_Exp2 -= common_Exp2;
|
||||
bS_Exp2 -= common_Exp2;
|
||||
hS_Exp2 -= common_Exp2;
|
||||
|
@ -78,7 +78,7 @@ inline Ch* StrDup(const Ch* str) {
|
||||
}
|
||||
|
||||
inline FILE* TempFile(char *filename) {
|
||||
#ifdef _MSC_VER
|
||||
#if defined(__WIN32__) || defined(_MSC_VER)
|
||||
filename = tmpnam(filename);
|
||||
|
||||
// For Visual Studio, tmpnam() adds a backslash in front. Remove it.
|
||||
@ -117,7 +117,12 @@ public:
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
||||
// Not using noexcept for testing RAPIDJSON_ASSERT()
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
||||
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u)
|
||||
#endif
|
||||
|
||||
class Random {
|
||||
public:
|
||||
|
@ -439,6 +439,17 @@ TEST(Value, Int) {
|
||||
EXPECT_EQ(5678, z.Get<int>());
|
||||
EXPECT_EQ(5679, z.Set(5679).Get<int>());
|
||||
EXPECT_EQ(5680, z.Set<int>(5680).Get<int>());
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// long as int on MSC platforms
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));
|
||||
z.SetInt(2222);
|
||||
EXPECT_TRUE(z.Is<long>());
|
||||
EXPECT_EQ(2222l, z.Get<long>());
|
||||
EXPECT_EQ(3333l, z.Set(3333l).Get<long>());
|
||||
EXPECT_EQ(4444l, z.Set<long>(4444l).Get<long>());
|
||||
EXPECT_TRUE(z.IsInt());
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Value, Uint) {
|
||||
@ -485,6 +496,17 @@ TEST(Value, Uint) {
|
||||
EXPECT_EQ(2147483648u, z.Get<unsigned>());
|
||||
EXPECT_EQ(2147483649u, z.Set(2147483649u).Get<unsigned>());
|
||||
EXPECT_EQ(2147483650u, z.Set<unsigned>(2147483650u).Get<unsigned>());
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// unsigned long as unsigned on MSC platforms
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));
|
||||
z.SetUint(2222);
|
||||
EXPECT_TRUE(z.Is<unsigned long>());
|
||||
EXPECT_EQ(2222ul, z.Get<unsigned long>());
|
||||
EXPECT_EQ(3333ul, z.Set(3333ul).Get<unsigned long>());
|
||||
EXPECT_EQ(4444ul, z.Set<unsigned long>(4444ul).Get<unsigned long>());
|
||||
EXPECT_TRUE(x.IsUint());
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Value, Int64) {
|
||||
@ -857,9 +879,46 @@ TEST(Value, String) {
|
||||
}
|
||||
|
||||
// Issue 226: Value of string type should not point to NULL
|
||||
TEST(Value, SetStringNullException) {
|
||||
Value v;
|
||||
EXPECT_THROW(v.SetString(0, 0), AssertException);
|
||||
TEST(Value, SetStringNull) {
|
||||
|
||||
MemoryPoolAllocator<> allocator;
|
||||
const char* nullPtr = 0;
|
||||
{
|
||||
// Construction with string type creates empty string
|
||||
Value v(kStringType);
|
||||
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||
|
||||
// Construction from/setting to null without length not allowed
|
||||
EXPECT_THROW(Value(StringRef(nullPtr)), AssertException);
|
||||
EXPECT_THROW(Value(StringRef(nullPtr), allocator), AssertException);
|
||||
EXPECT_THROW(v.SetString(nullPtr, allocator), AssertException);
|
||||
|
||||
// Non-empty length with null string is not allowed
|
||||
EXPECT_THROW(v.SetString(nullPtr, 17u), AssertException);
|
||||
EXPECT_THROW(v.SetString(nullPtr, 42u, allocator), AssertException);
|
||||
|
||||
// Setting to null string with empty length is allowed
|
||||
v.SetString(nullPtr, 0u);
|
||||
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||
|
||||
v.SetNull();
|
||||
v.SetString(nullPtr, 0u, allocator);
|
||||
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||
}
|
||||
// Construction with null string and empty length is allowed
|
||||
{
|
||||
Value v(nullPtr,0u);
|
||||
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||
}
|
||||
{
|
||||
Value v(nullPtr, 0u, allocator);
|
||||
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
|
@ -412,8 +412,10 @@ TEST(Writer, ValidateEncoding) {
|
||||
EXPECT_TRUE(writer.String("\xC2\xA2")); // Cents sign U+00A2
|
||||
EXPECT_TRUE(writer.String("\xE2\x82\xAC")); // Euro sign U+20AC
|
||||
EXPECT_TRUE(writer.String("\xF0\x9D\x84\x9E")); // G clef sign U+1D11E
|
||||
EXPECT_TRUE(writer.String("\x01")); // SOH control U+0001
|
||||
EXPECT_TRUE(writer.String("\x1B")); // Escape control U+001B
|
||||
writer.EndArray();
|
||||
EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\"]", buffer.GetString());
|
||||
EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\",\"\\u0001\",\"\\u001B\"]", buffer.GetString());
|
||||
}
|
||||
|
||||
// Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
@ -536,6 +538,43 @@ TEST(Writer, RawValue) {
|
||||
EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(Write, RawValue_Issue1152) {
|
||||
{
|
||||
GenericStringBuffer<UTF32<> > sb;
|
||||
Writer<GenericStringBuffer<UTF32<> >, UTF8<>, UTF32<> > writer(sb);
|
||||
writer.RawValue("null", 4, kNullType);
|
||||
EXPECT_TRUE(writer.IsComplete());
|
||||
const unsigned *out = sb.GetString();
|
||||
EXPECT_EQ(static_cast<unsigned>('n'), out[0]);
|
||||
EXPECT_EQ(static_cast<unsigned>('u'), out[1]);
|
||||
EXPECT_EQ(static_cast<unsigned>('l'), out[2]);
|
||||
EXPECT_EQ(static_cast<unsigned>('l'), out[3]);
|
||||
EXPECT_EQ(static_cast<unsigned>(0 ), out[4]);
|
||||
}
|
||||
|
||||
{
|
||||
GenericStringBuffer<UTF8<> > sb;
|
||||
Writer<GenericStringBuffer<UTF8<> >, UTF16<>, UTF8<> > writer(sb);
|
||||
writer.RawValue(L"null", 4, kNullType);
|
||||
EXPECT_TRUE(writer.IsComplete());
|
||||
EXPECT_STREQ("null", sb.GetString());
|
||||
}
|
||||
|
||||
{
|
||||
// Fail in transcoding
|
||||
GenericStringBuffer<UTF16<> > buffer;
|
||||
Writer<GenericStringBuffer<UTF16<> >, UTF8<>, UTF16<> > writer(buffer);
|
||||
EXPECT_FALSE(writer.RawValue("\"\xfe\"", 3, kStringType));
|
||||
}
|
||||
|
||||
{
|
||||
// Fail in encoding validation
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer);
|
||||
EXPECT_FALSE(writer.RawValue("\"\xfe\"", 3, kStringType));
|
||||
}
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
static Writer<StringBuffer> WriterGen(StringBuffer &target) {
|
||||
Writer<StringBuffer> writer(target);
|
||||
|
@ -4,12 +4,11 @@
|
||||
|
||||
set -e
|
||||
|
||||
DOXYGEN_VER=doxygen-1.8.7
|
||||
DOXYGEN_VER=doxygen-1.8.13
|
||||
DOXYGEN_TAR=${DOXYGEN_VER}.linux.bin.tar.gz
|
||||
DOXYGEN_URL="http://ftp.stack.nl/pub/users/dimitri/${DOXYGEN_TAR}"
|
||||
DOXYGEN_BIN="/usr/local/bin/doxygen"
|
||||
|
||||
: ${GITHUB_REPO:="miloyip/rapidjson"}
|
||||
: ${GITHUB_REPO:="Tencent/rapidjson"}
|
||||
GITHUB_HOST="github.com"
|
||||
GITHUB_CLONE="git://${GITHUB_HOST}/${GITHUB_REPO}"
|
||||
GITHUB_URL="https://${GITHUB_HOST}/${GITHUB_PUSH-${GITHUB_REPO}}"
|
||||
@ -66,7 +65,7 @@ gh_pages_prepare()
|
||||
[ ! -d "html" ] || \
|
||||
abort "Doxygen target directory already exists."
|
||||
git --version
|
||||
git clone -b gh-pages "${GITHUB_CLONE}" html
|
||||
git clone --single-branch -b gh-pages "${GITHUB_CLONE}" html
|
||||
cd html
|
||||
# setup git config (with defaults)
|
||||
git config user.name "${GIT_NAME-travis}"
|
||||
|
Loading…
x
Reference in New Issue
Block a user