Commit 62e785ba authored by Milo Yip's avatar Milo Yip

Merge branch 'master' into travis

parents facb432f 0d95d58f
...@@ -20,5 +20,9 @@ Testing ...@@ -20,5 +20,9 @@ Testing
/googletest /googletest
install_manifest.txt install_manifest.txt
Doxyfile Doxyfile
Doxyfile.zh-cn
DartConfiguration.tcl DartConfiguration.tcl
*.nupkg *.nupkg
# Files created by OS
*.DS_Store
[submodule "thirdparty/gtest"] [submodule "thirdparty/gtest"]
path = thirdparty/gtest path = thirdparty/gtest
url = https://chromium.googlesource.com/external/googletest.git url = https://github.com/google/googletest.git
sudo: required
dist: trusty
group: edge
language: cpp language: cpp
sudo: false
cache: cache:
- ccache - ccache
addons:
apt:
packages: &default_packages
- cmake
- valgrind
env: env:
global: global:
- USE_CCACHE=1 - USE_CCACHE=1
- CCACHE_SLOPPINESS=pch_defines,time_macros - CCACHE_SLOPPINESS=pch_defines,time_macros
- CCACHE_COMPRESS=1 - CCACHE_COMPRESS=1
- CCACHE_MAXSIZE=100M - CCACHE_MAXSIZE=100M
- ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit - ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit
- ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit - ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit
- GITHUB_REPO='miloyip/rapidjson' - GITHUB_REPO='Tencent/rapidjson'
- secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk=" - secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk="
before_install:
- sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
- sudo apt-get install -y cmake valgrind g++-multilib libc6-dbg:i386
matrix: matrix:
include: include:
# gcc # gcc
- env: CONF=release ARCH=x86 CXX11=ON - env: CONF=release ARCH=x86 CXX11=ON
compiler: gcc compiler: gcc
addons:
apt:
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- env: CONF=release ARCH=x86_64 CXX11=ON - env: CONF=release ARCH=x86_64 CXX11=ON
compiler: gcc compiler: gcc
- env: CONF=debug ARCH=x86 CXX11=OFF - env: CONF=debug ARCH=x86 CXX11=OFF
compiler: gcc compiler: gcc
addons:
apt:
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- env: CONF=debug ARCH=x86_64 CXX11=OFF - env: CONF=debug ARCH=x86_64 CXX11=OFF
compiler: gcc compiler: gcc
# clang # clang
- env: CONF=debug ARCH=x86 CXX11=ON CCACHE_CPP2=yes - env: CONF=debug ARCH=x86 CXX11=ON CCACHE_CPP2=yes
compiler: clang compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- clang-3.7
- env: CONF=debug ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes - env: CONF=debug ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
compiler: clang compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- clang-3.7
- env: CONF=debug ARCH=x86 CXX11=OFF CCACHE_CPP2=yes - env: CONF=debug ARCH=x86 CXX11=OFF CCACHE_CPP2=yes
compiler: clang compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- clang-3.7
- env: CONF=debug ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes - env: CONF=debug ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes
compiler: clang compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- clang-3.7
- env: CONF=release ARCH=x86 CXX11=ON CCACHE_CPP2=yes - env: CONF=release ARCH=x86 CXX11=ON CCACHE_CPP2=yes
compiler: clang compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- clang-3.7
- env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes - env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
compiler: clang compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- clang-3.7
# coverage report # coverage report
- env: CONF=debug ARCH=x86 CXX11=ON GCOV_FLAGS='--coverage' - env: CONF=debug ARCH=x86 CXX11=ON GCOV_FLAGS='--coverage'
compiler: gcc compiler: gcc
cache: cache:
- ccache - ccache
- pip - pip
addons:
apt:
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
after_success: after_success:
- pip install --user cpp-coveralls - pip install --user cpp-coveralls
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
...@@ -130,12 +60,6 @@ matrix: ...@@ -130,12 +60,6 @@ matrix:
cache: cache:
- ccache - ccache
- pip - pip
addons:
apt:
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
after_success: after_success:
- pip install --user cpp-coveralls - pip install --user cpp-coveralls
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
...@@ -158,7 +82,7 @@ before_script: ...@@ -158,7 +82,7 @@ before_script:
- mkdir build - mkdir build
script: script:
- if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi - if [ "$CXX" = "clang++" ]; then export CXXFLAGS="-stdlib=libc++ ${CXXFLAGS}"; fi
- > - >
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ; eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
(cd build && cmake (cd build && cmake
......
...@@ -4,6 +4,83 @@ This project adheres to [Semantic Versioning](http://semver.org/). ...@@ -4,6 +4,83 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
## 1.1.0 - 2016-08-25
### Added
* Add GenericDocument ctor overload to specify JSON type (#369)
* Add FAQ (#372, #373, #374, #376)
* Add forward declaration header `fwd.h`
* Add @PlatformIO Library Registry manifest file (#400)
* Implement assignment operator for BigInteger (#404)
* Add comments support (#443)
* Adding coapp definition (#460)
* documenttest.cpp: EXPECT_THROW when checking empty allocator (470)
* GenericDocument: add implicit conversion to ParseResult (#480)
* Use <wchar.h> with C++ linkage on Windows ARM (#485)
* Detect little endian for Microsoft ARM targets
* Check Nan/Inf when writing a double (#510)
* Add JSON Schema Implementation (#522)
* Add iostream wrapper (#530)
* Add Jsonx example for converting JSON into JSONx (a XML format) (#531)
* Add optional unresolvedTokenIndex parameter to Pointer::Get() (#532)
* Add encoding validation option for Writer/PrettyWriter (#534)
* Add Writer::SetMaxDecimalPlaces() (#536)
* Support {0, } and {0, m} in Regex (#539)
* Add Value::Get/SetFloat(), Value::IsLossLessFloat/Double() (#540)
* Add stream position check to reader unit tests (#541)
* Add Templated accessors and range-based for (#542)
* Add (Pretty)Writer::RawValue() (#543)
* Add Document::Parse(std::string), Document::Parse(const char*, size_t length) and related APIs. (#553)
* Add move constructor for GenericSchemaDocument (#554)
* Add VS2010 and VS2015 to AppVeyor CI (#555)
* Add parse-by-parts example (#556, #562)
* Support parse number as string (#564, #589)
* Add kFormatSingleLineArray for PrettyWriter (#577)
* Added optional support for trailing commas (#584)
* Added filterkey and filterkeydom examples (#615)
* Added npm docs (#639)
* Allow options for writing and parsing NaN/Infinity (#641)
* Add std::string overload to PrettyWriter::Key() when RAPIDJSON_HAS_STDSTRING is defined (#698)
### Fixed
* Fix gcc/clang/vc warnings (#350, #394, #397, #444, #447, #473, #515, #582, #589, #595, #667)
* Fix documentation (#482, #511, #550, #557, #614, #635, #660)
* Fix emscripten alignment issue (#535)
* Fix missing allocator to uses of AddMember in document (#365)
* CMake will no longer complain that the minimum CMake version is not specified (#501)
* Make it usable with old VC8 (VS2005) (#383)
* Prohibit C++11 move from Document to Value (#391)
* Try to fix incorrect 64-bit alignment (#419)
* Check return of fwrite to avoid warn_unused_result build failures (#421)
* Fix UB in GenericDocument::ParseStream (#426)
* Keep Document value unchanged on parse error (#439)
* Add missing return statement (#450)
* Fix Document::Parse(const Ch*) for transcoding (#478)
* encodings.h: fix typo in preprocessor condition (#495)
* Custom Microsoft headers are necessary only for Visual Studio 2012 and lower (#559)
* Fix memory leak for invalid regex (26e69ffde95ba4773ab06db6457b78f308716f4b)
* Fix a bug in schema minimum/maximum keywords for 64-bit integer (e7149d665941068ccf8c565e77495521331cf390)
* Fix a crash bug in regex (#605)
* Fix schema "required" keyword cannot handle duplicated keys (#609)
* Fix cmake CMP0054 warning (#612)
* Added missing include guards in istreamwrapper.h and ostreamwrapper.h (#634)
* Fix undefined behaviour (#646)
* Fix buffer overrun using PutN (#673)
* Fix rapidjson::value::Get<std::string>() may returns wrong data (#681)
* Add Flush() for all value types (#689)
* Handle malloc() fail in PoolAllocator (#691)
* Fix builds on x32 platform. #703
### Changed
* Clarify problematic JSON license (#392)
* Move Travis to container based infrastructure (#504, #558)
* Make whitespace array more compact (#513)
* Optimize Writer::WriteString() with SIMD (#544)
* x86-64 48-bit pointer optimization for GenericValue (#546)
* Define RAPIDJSON_HAS_CXX11_RVALUE_REFS directly in clang (#617)
* Make GenericSchemaDocument constructor explicit (#674)
* Optimize FindMember when use std::string (#690)
## [1.0.2] - 2015-05-14 ## [1.0.2] - 2015-05-14
### Added ### Added
...@@ -12,6 +89,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ...@@ -12,6 +89,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed ### Fixed
* Include rapidjson.h for all internal/error headers. * Include rapidjson.h for all internal/error headers.
* Parsing some numbers incorrectly in full-precision mode (`kFullPrecisionParseFlag`) (#342) * Parsing some numbers incorrectly in full-precision mode (`kFullPrecisionParseFlag`) (#342)
* Fix some numbers parsed incorrectly (#336)
* Fix alignment of 64bit platforms (#328) * Fix alignment of 64bit platforms (#328)
* Fix MemoryPoolAllocator::Clear() to clear user-buffer (0691502573f1afd3341073dd24b12c3db20fbde4) * Fix MemoryPoolAllocator::Clear() to clear user-buffer (0691502573f1afd3341073dd24b12c3db20fbde4)
...@@ -31,7 +109,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ...@@ -31,7 +109,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [1.0.0] - 2015-04-22 ## [1.0.0] - 2015-04-22
### Added ### 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) * Version macros (#311)
### Fixed ### Fixed
...@@ -62,7 +140,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ...@@ -62,7 +140,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Redo all documentation (English, Simplified Chinese) * Redo all documentation (English, Simplified Chinese)
### Changed ### 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) * Migrating from Premake to CMAKE (#192)
* Resolve all warning reports * Resolve all warning reports
...@@ -73,7 +151,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ...@@ -73,7 +151,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## 0.1 - 2011-11-18 ## 0.1 - 2011-11-18
[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.0.2...HEAD [Unreleased]: https://github.com/Tencent/rapidjson/compare/v1.1.0...HEAD
[1.0.2]: https://github.com/miloyip/rapidjson/compare/v1.0.1...v1.0.2 [1.1.0]: https://github.com/Tencent/rapidjson/compare/v1.0.2...v1.1.0
[1.0.1]: https://github.com/miloyip/rapidjson/compare/v1.0.0...v1.0.1 [1.0.2]: https://github.com/Tencent/rapidjson/compare/v1.0.1...v1.0.2
[1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0 [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
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
if(POLICY CMP0025)
# detect Apple's Clang
cmake_policy(SET CMP0025 NEW)
endif()
if(POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules) SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules)
PROJECT(RapidJSON CXX) PROJECT(RapidJSON CXX)
set(LIB_MAJOR_VERSION "1") set(LIB_MAJOR_VERSION "1")
set(LIB_MINOR_VERSION "0") set(LIB_MINOR_VERSION "1")
set(LIB_PATCH_VERSION "2") set(LIB_PATCH_VERSION "0")
set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}") set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}")
# compile in release with debug info mode by default # compile in release with debug info mode by default
...@@ -24,6 +32,11 @@ option(RAPIDJSON_BUILD_THIRDPARTY_GTEST ...@@ -24,6 +32,11 @@ option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON) option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON)
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) option(RAPIDJSON_HAS_STDSTRING "" OFF)
if(RAPIDJSON_HAS_STDSTRING) if(RAPIDJSON_HAS_STDSTRING)
add_definitions(-DRAPIDJSON_HAS_STDSTRING) add_definitions(-DRAPIDJSON_HAS_STDSTRING)
...@@ -39,7 +52,16 @@ if(CCACHE_FOUND) ...@@ -39,7 +52,16 @@ if(CCACHE_FOUND)
endif(CCACHE_FOUND) endif(CCACHE_FOUND)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror") if(${RAPIDJSON_ENABLE_INSTRUMENTATION_OPT})
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)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0") if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
...@@ -47,13 +69,47 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") ...@@ -47,13 +69,47 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif() endif()
endif() endif()
if (RAPIDJSON_BUILD_ASAN)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.0")
message(FATAL_ERROR "GCC < 4.8 doesn't support the address sanitizer")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
endif()
endif()
if (RAPIDJSON_BUILD_UBSAN)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0")
message(FATAL_ERROR "GCC < 4.9 doesn't support the undefined behavior sanitizer")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
endif()
endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers") 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()
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)
if (RAPIDJSON_BUILD_CXX11) if (RAPIDJSON_BUILD_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif() endif()
if (RAPIDJSON_BUILD_ASAN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
endif()
if (RAPIDJSON_BUILD_UBSAN)
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error")
else()
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) add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -qarch=auto")
endif() endif()
#add extra search paths for libraries and includes #add extra search paths for libraries and includes
...@@ -121,15 +177,37 @@ install(DIRECTORY example/ ...@@ -121,15 +177,37 @@ install(DIRECTORY example/
# Provide config and version files to be used by other applications # Provide config and version files to be used by other applications
# =============================== # ===============================
export(PACKAGE ${PROJECT_NAME}) ################################################################################
# Export package for use from the build tree
# cmake-modules EXPORT( PACKAGE ${PROJECT_NAME} )
CONFIGURE_FILE(${PROJECT_NAME}Config.cmake.in
${PROJECT_NAME}Config.cmake # Create the RapidJSONConfig.cmake file for other cmake projects.
@ONLY) # ... for the build tree
CONFIGURE_FILE(${PROJECT_NAME}ConfigVersion.cmake.in SET( CONFIG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
${PROJECT_NAME}ConfigVersion.cmake SET( CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR})
@ONLY) 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
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY)
# ... for the install tree
SET( CMAKECONFIG_INSTALL_DIR lib/cmake/${PROJECT_NAME} )
FILE( RELATIVE_PATH REL_INCLUDE_DIR
"${CMAKE_INSTALL_PREFIX}/${CMAKECONFIG_INSTALL_DIR}"
"${CMAKE_INSTALL_PREFIX}/include" )
SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_CMAKE_DIR}/${REL_INCLUDE_DIR}" )
SET( CONFIG_SOURCE_DIR )
SET( CONFIG_DIR )
CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake @ONLY )
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake"
DESTINATION ${CMAKECONFIG_INSTALL_DIR} )
# Install files
INSTALL(FILES INSTALL(FILES
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
......
SET(GTEST_SEARCH_PATH SET(GTEST_SEARCH_PATH
"${GTEST_SOURCE_DIR}" "${GTEST_SOURCE_DIR}"
"${CMAKE_CURRENT_LIST_DIR}/../thirdparty/gtest") "${CMAKE_CURRENT_LIST_DIR}/../thirdparty/gtest/googletest")
IF(UNIX) IF(UNIX)
IF(RAPIDJSON_BUILD_THIRDPARTY_GTEST) IF(RAPIDJSON_BUILD_THIRDPARTY_GTEST)
......
...@@ -3,5 +3,5 @@ includedir=@INCLUDE_INSTALL_DIR@ ...@@ -3,5 +3,5 @@ includedir=@INCLUDE_INSTALL_DIR@
Name: @PROJECT_NAME@ Name: @PROJECT_NAME@
Description: A fast JSON parser/generator for C++ with both SAX/DOM style API Description: A fast JSON parser/generator for C++ with both SAX/DOM style API
Version: @LIB_VERSION_STRING@ Version: @LIB_VERSION_STRING@
URL: https://github.com/miloyip/rapidjson URL: https://github.com/Tencent/rapidjson
Cflags: -I${includedir} Cflags: -I${includedir}
get_filename_component(RAPIDJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) ################################################################################
set(RAPIDJSON_INCLUDE_DIRS "@INCLUDE_INSTALL_DIR@") # RapidJSON source dir
message(STATUS "RapidJSON found. Headers: ${RAPIDJSON_INCLUDE_DIRS}") set( RapidJSON_SOURCE_DIR "@CONFIG_SOURCE_DIR@")
################################################################################
# RapidJSON build dir
set( RapidJSON_DIR "@CONFIG_DIR@")
################################################################################
# Compute paths
get_filename_component(RapidJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
set( RapidJSON_INCLUDE_DIR "@RapidJSON_INCLUDE_DIR@" )
set( RapidJSON_INCLUDE_DIRS "@RapidJSON_INCLUDE_DIR@" )
message(STATUS "RapidJSON found. Headers: ${RapidJSON_INCLUDE_DIRS}")
os: Visual Studio 2015 CTP os: Visual Studio 2015 CTP
version: 1.0.2.{build} version: 1.1.0.{build}
configuration: configuration:
- Debug - Debug
...@@ -30,7 +30,7 @@ environment: ...@@ -30,7 +30,7 @@ environment:
before_build: before_build:
- git submodule update --init --recursive - git submodule update --init --recursive
- cmake -H. -BBuild/VS -G "Visual Studio %VS_VERSION%" -DCMAKE_GENERATOR_PLATFORM=%VS_PLATFORM% -DBUILD_SHARED_LIBS=true -Wno-dev - cmake -H. -BBuild/VS -G "Visual Studio %VS_VERSION%" -DCMAKE_GENERATOR_PLATFORM=%VS_PLATFORM% -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=true -Wno-dev
build: build:
project: Build\VS\RapidJSON.sln project: Build\VS\RapidJSON.sln
......
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
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.
# 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).
<?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&lt;*,*&gt;">
<DisplayString Condition="(data_.f.flags &amp; 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 &amp; kTypeMask) == kStringType">{(const char*)((size_t)data_.s.str &amp; 0x0000FFFFFFFFFFFF)}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberIntFlag) == kNumberIntFlag">{data_.n.i.i}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberUintFlag) == kNumberUintFlag">{data_.n.u.u}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberInt64Flag) == kNumberInt64Flag">{data_.n.i64}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberUint64Flag) == kNumberUint64Flag">{data_.n.u64}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; 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&lt;$T1,$T2&gt;*)(((size_t)data_.o.members) &amp; 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&lt;$T1,$T2&gt;*)(((size_t)data_.a.elements) &amp; 0x0000FFFFFFFFFFFF)</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
...@@ -10,11 +10,13 @@ ELSE() ...@@ -10,11 +10,13 @@ ELSE()
CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY) CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY)
CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY) CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY)
file(GLOB DOXYFILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile*)
add_custom_command(OUTPUT html add_custom_command(OUTPUT html
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html 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}/../ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../
) )
......
...@@ -765,6 +765,7 @@ WARN_LOGFILE = ...@@ -765,6 +765,7 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = readme.md \ INPUT = readme.md \
CHANGELOG.md \
include/rapidjson/rapidjson.h \ include/rapidjson/rapidjson.h \
include/ \ include/ \
doc/features.md \ doc/features.md \
......
...@@ -765,6 +765,7 @@ WARN_LOGFILE = ...@@ -765,6 +765,7 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = readme.zh-cn.md \ INPUT = readme.zh-cn.md \
CHANGELOG.md \
include/rapidjson/rapidjson.h \ include/rapidjson/rapidjson.h \
include/ \ include/ \
doc/features.zh-cn.md \ doc/features.zh-cn.md \
...@@ -776,7 +777,7 @@ INPUT = readme.zh-cn.md \ ...@@ -776,7 +777,7 @@ INPUT = readme.zh-cn.md \
doc/sax.zh-cn.md \ doc/sax.zh-cn.md \
doc/schema.zh-cn.md \ doc/schema.zh-cn.md \
doc/performance.zh-cn.md \ doc/performance.zh-cn.md \
doc/internals.md \ doc/internals.zh-cn.md \
doc/faq.zh-cn.md doc/faq.zh-cn.md
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
......
...@@ -18,7 +18,7 @@ digraph { ...@@ -18,7 +18,7 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7] node [shape=Mrecord, style=filled, colorscheme=spectral7]
c1 [label="{contact:array|}", fillcolor=4] c1 [label="{contacts:array|}", fillcolor=4]
c11 [label="{|}"] c11 [label="{|}"]
c12 [label="{|}"] c12 [label="{|}"]
c13 [shape="none", label="...", style="solid"] c13 [shape="none", label="...", style="solid"]
...@@ -41,13 +41,13 @@ digraph { ...@@ -41,13 +41,13 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7] node [shape=Mrecord, style=filled, colorscheme=spectral7]
c2 [label="{contact:array|}", fillcolor=4] c2 [label="{contacts:array|}", fillcolor=4]
c3 [label="{array|}", fillcolor=4] c3 [label="{array|}", fillcolor=4]
c21 [label="{|}"] c21 [label="{|}"]
c22 [label="{|}"] c22 [label="{|}"]
c23 [shape=none, label="...", style="solid"] c23 [shape=none, label="...", style="solid"]
o2 [label="{o:object|}", fillcolor=3] o2 [label="{o:object|}", fillcolor=3]
cs [label="{string|\"contact\"}", fillcolor=5] cs [label="{string|\"contacts\"}", fillcolor=5]
c31 [label="{|}"] c31 [label="{|}"]
c32 [label="{|}"] c32 [label="{|}"]
c33 [shape="none", label="...", style="solid"] c33 [shape="none", label="...", style="solid"]
......
...@@ -19,7 +19,7 @@ digraph { ...@@ -19,7 +19,7 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7] node [shape=Mrecord, style=filled, colorscheme=spectral7]
c1 [label="{contact:array|}", fillcolor=4] c1 [label="{contacts:array|}", fillcolor=4]
c11 [label="{|}"] c11 [label="{|}"]
c12 [label="{|}"] c12 [label="{|}"]
c13 [shape=none, label="...", style="solid"] c13 [shape=none, label="...", style="solid"]
...@@ -42,13 +42,13 @@ digraph { ...@@ -42,13 +42,13 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7] node [shape=Mrecord, style=filled, colorscheme=spectral7]
c2 [label="{contact:null|}", fillcolor=1] c2 [label="{contacts:null|}", fillcolor=1]
c3 [label="{array|}", fillcolor=4] c3 [label="{array|}", fillcolor=4]
c21 [label="{|}"] c21 [label="{|}"]
c22 [label="{|}"] c22 [label="{|}"]
c23 [shape="none", label="...", style="solid"] c23 [shape="none", label="...", style="solid"]
o2 [label="{o:object|}", fillcolor=3] 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] c2 -> o2 [style="dashed", constraint=false, label="AddMember", style=invis]
edge [arrowhead=vee] edge [arrowhead=vee]
......
...@@ -116,6 +116,9 @@ Parse flags | Meaning ...@@ -116,6 +116,9 @@ Parse flags | Meaning
`kParseStopWhenDoneFlag` | After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate `kParseErrorDocumentRootNotSingular` error. Using this flag for parsing multiple JSONs in the same stream. `kParseStopWhenDoneFlag` | After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate `kParseErrorDocumentRootNotSingular` error. Using this flag for parsing multiple JSONs in the same stream.
`kParseFullPrecisionFlag` | Parse number in full precision (slower). If this flag is not set, the normal precision (faster) is used. Normal precision has maximum 3 [ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place) error. `kParseFullPrecisionFlag` | Parse number in full precision (slower). If this flag is not set, the normal precision (faster) is used. Normal precision has maximum 3 [ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place) error.
`kParseCommentsFlag` | Allow one-line `// ...` and multi-line `/* ... */` comments (relaxed JSON syntax). `kParseCommentsFlag` | Allow one-line `// ...` and multi-line `/* ... */` comments (relaxed JSON syntax).
`kParseNumbersAsStringsFlag` | Parse numerical type values as strings.
`kParseTrailingCommasFlag` | Allow trailing commas at the end of objects and arrays (relaxed JSON syntax).
`kParseNanAndInfFlag` | Allow parsing `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (relaxed JSON syntax).
By using a non-type template parameter, instead of a function parameter, C++ compiler can generate code which is optimized for specified combinations, improving speed, and reducing code size (if only using a single specialization). The downside is the flags needed to be determined in compile-time. By using a non-type template parameter, instead of a function parameter, C++ compiler can generate code which is optimized for specified combinations, improving speed, and reducing code size (if only using a single specialization). The downside is the flags needed to be determined in compile-time.
...@@ -125,7 +128,7 @@ And the `InputStream` is type of input stream. ...@@ -125,7 +128,7 @@ And the `InputStream` is type of input stream.
## Parse Error {#ParseError} ## 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 Parse Error Code | Description
--------------------------------------------|--------------------------------------------------- --------------------------------------------|---------------------------------------------------
...@@ -161,7 +164,7 @@ Document d; ...@@ -161,7 +164,7 @@ Document d;
if (d.Parse(json).HasParseError()) { if (d.Parse(json).HasParseError()) {
fprintf(stderr, "\nError(offset %u): %s\n", fprintf(stderr, "\nError(offset %u): %s\n",
(unsigned)d.GetErrorOffset(), (unsigned)d.GetErrorOffset(),
GetParseError_En(d.GetParseErrorCode())); GetParseError_En(d.GetParseError()));
// ... // ...
} }
~~~~~~~~~~ ~~~~~~~~~~
...@@ -238,7 +241,7 @@ Some techniques about using DOM API is discussed here. ...@@ -238,7 +241,7 @@ Some techniques about using DOM API is discussed here.
## DOM as SAX Event Publisher ## 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 ~~~~~~~~~~cpp
// ... // ...
......
This diff is collapsed.
...@@ -10,7 +10,7 @@ The earlier [RFC4627](http://www.ietf.org/rfc/rfc4627.txt) stated that, ...@@ -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. > (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] [TOC]
...@@ -131,8 +131,8 @@ StringStream source(s); ...@@ -131,8 +131,8 @@ StringStream source(s);
GenericStringBuffer<UTF16<> > target; GenericStringBuffer<UTF16<> > target;
bool hasError = false; bool hasError = false;
while (source.Peak() != '\0') while (source.Peek() != '\0')
if (!Transcoder::Transcode<UTF8<>, UTF16<> >(source, target)) { if (!Transcoder<UTF8<>, UTF16<> >::Transcode(source, target)) {
hasError = true; hasError = true;
break; break;
} }
......
This diff is collapsed.
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
4. Is RapidJSON free? 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? 5. Is RapidJSON small? What are its dependencies?
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
10. How RapidJSON is tested? 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? 11. Is RapidJSON well documented?
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
3. Does RapidJSON support relaxed syntax? 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 ## DOM and SAX
...@@ -116,7 +116,7 @@ ...@@ -116,7 +116,7 @@
~~~~~~~~~~cpp ~~~~~~~~~~cpp
Value(kObjectType).Swap(d); Value(kObjectType).Swap(d);
~~~~~~~~~~ ~~~~~~~~~~
or equivalent, but sightly longer to type: or equivalent, but slightly longer to type:
~~~~~~~~~~cpp ~~~~~~~~~~cpp
d.Swap(Value(kObjectType).Move()); d.Swap(Value(kObjectType).Move());
~~~~~~~~~~ ~~~~~~~~~~
...@@ -140,11 +140,11 @@ ...@@ -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: 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 ~~~~~~~~~~cpp
Documnet address(person.GetAllocator()); Document address(person.GetAllocator());
... ...
person["person"].AddMember("address", address["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 ...@@ -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? 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. 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 ...@@ -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? 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? 3. What is surrogate pair? Does RapidJSON support it?
...@@ -248,7 +248,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres ...@@ -248,7 +248,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
1. Is RapidJSON really fast? 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? 2. Why is it fast?
...@@ -256,19 +256,19 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres ...@@ -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? 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? 4. Does it consume a lot of memory?
The design of RapidJSON aims at reducing memory footprint. 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. 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? 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 ## Gossip
......
This diff is collapsed.
...@@ -20,11 +20,16 @@ ...@@ -20,11 +20,16 @@
## Standard compliance ## Standard compliance
* RapidJSON should be fully RFC4627/ECMA-404 compliance. * RapidJSON should be fully RFC4627/ECMA-404 compliance.
* Support JSON Pointer (RFC6901).
* Support JSON Schema Draft v4.
* Support Unicode surrogate. * Support Unicode surrogate.
* Support null character (`"\u0000"`) * Support null character (`"\u0000"`)
* For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string. * For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string.
* Support optional relaxed syntax. * Support optional relaxed syntax.
* Single line (`// ...`) and multiple line (`/* ... */`) comments. * 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/Tencent/rapidjson/blob/master/doc/npm.md).
## Unicode ## Unicode
...@@ -68,7 +73,7 @@ ...@@ -68,7 +73,7 @@
* Only store pointer instead of copying * Only store pointer instead of copying
* Optimization for "short" strings * Optimization for "short" strings
* Store short string in `Value` internally without additional allocation. * Store short string in `Value` internally without additional allocation.
* For UTF-8 string: maximum 11 characters in 32-bit, 15 characters in 64-bit. * For UTF-8 string: maximum 11 characters in 32-bit, 21 characters in 64-bit (13 characters in x86-64).
* Optionally support `std::string` (define `RAPIDJSON_HAS_STDSTRING=1`) * Optionally support `std::string` (define `RAPIDJSON_HAS_STDSTRING=1`)
## Generation ## Generation
...@@ -96,3 +101,4 @@ ...@@ -96,3 +101,4 @@
* Some C++11 support (optional) * Some C++11 support (optional)
* Rvalue reference * Rvalue reference
* `noexcept` specifier * `noexcept` specifier
* Range-based for loop
...@@ -3,49 +3,54 @@ ...@@ -3,49 +3,54 @@
## 总体 ## 总体
* 跨平台 * 跨平台
* 编译器:Visual Studio、gcc、clang等 * 编译器:Visual Studio、gcc、clang
* 架构:x86、x64、ARM等 * 架构:x86、x64、ARM
* 操作系统:Windows、Mac OS X、Linux、iOS、Android等 * 操作系统:Windows、Mac OS X、Linux、iOS、Android
* 容易安装 * 容易安装
* 只有头文件的库。只需把头文件复制至你的项目中。 * 只有头文件的库。只需把头文件复制至你的项目中。
* 独立、最小依赖 * 独立、最小依赖
* 不需依赖STL、BOOST等。 * 不需依赖 STL、BOOST 等。
* 只包含`<cstdio>`, `<cstdlib>`, `<cstring>`, `<inttypes.h>`, `<new>`, `<stdint.h>` * 只包含 `<cstdio>`, `<cstdlib>`, `<cstring>`, `<inttypes.h>`, `<new>`, `<stdint.h>`
* 没使用C++异常、RTTI * 没使用 C++ 异常、RTTI
* 高性能 * 高性能
* 使用模版及内联函数去降低函数调用开销。 * 使用模版及内联函数去降低函数调用开销。
* 内部经优化的Grisu2及浮点数解析实现。 * 内部经优化的 Grisu2 及浮点数解析实现。
* 可选的SSE2/SSE4.2支持。 * 可选的 SSE2/SSE4.2 支持。
## 符合标准 ## 符合标准
* RapidJSON应完全符合RFC4627/ECMA-404标准。 * RapidJSON 应完全符合 RFC4627/ECMA-404 标准。
* 支持Unicod代理对(surrogate pair)。 * 支持 JSON Pointer (RFC6901).
* 支持 JSON Schema Draft v4.
* 支持 Unicode 代理对(surrogate pair)。
* 支持空字符(`"\u0000"`)。 * 支持空字符(`"\u0000"`)。
* 例如,可以优雅地解析及处理`["Hello\u0000World"]`。含读写字符串长度的API。 * 例如,可以优雅地解析及处理 `["Hello\u0000World"]`。含读写字符串长度的 API。
* 支持放宽的可选语法 * 支持可选的放宽语法
* 单行(`// ...`)及多行(`/* ... */`) 注释。 * 单行(`// ...`)及多行(`/* ... */`) 注释 (`kParseCommentsFlag`)。
* 在对象和数组结束前含逗号 (`kParseTrailingCommasFlag`)。
* `NaN``Inf``Infinity``-Inf``-Infinity` 作为 `double` 值 (`kParseNanAndInfFlag`)
* [NPM 兼容](https://github.com/Tencent/rapidjson/blob/master/doc/npm.md).
## Unicode ## Unicode
* 支持UTF-8、UTF-16、UTF-32编码,包括小端序和大端序。 * 支持 UTF-8、UTF-16、UTF-32 编码,包括小端序和大端序。
* 这些编码用于输入输出流,以及内存中的表示。 * 这些编码用于输入输出流,以及内存中的表示。
* 支持从输入流自动检测编码。 * 支持从输入流自动检测编码。
* 内部支持编码的转换。 * 内部支持编码的转换。
* 例如,你可以读取一个UTF-8文件,让RapidJSON把JSON字符串转换至UTF-16的DOM。 * 例如,你可以读取一个 UTF-8 文件,让 RapidJSON 把 JSON 字符串转换至 UTF-16 的 DOM。
* 内部支持编码校验。 * 内部支持编码校验。
* 例如,你可以读取一个UTF-8文件,让RapidJSON检查是否所有JSON字符串是合法的UTF-8字节序列。 * 例如,你可以读取一个 UTF-8 文件,让 RapidJSON 检查是否所有 JSON 字符串是合法的 UTF-8 字节序列。
* 支持自定义的字符类型。 * 支持自定义的字符类型。
* 预设的字符类型是:UTF-8`char`,UTF-16为`wchar_t`,UTF32为`uint32_t` * 预设的字符类型是:UTF-8`char`,UTF-16 为 `wchar_t`,UTF32 为 `uint32_t`
* 支持自定义的编码。 * 支持自定义的编码。
## API风格 ## API 风格
* SAX(Simple API for XML)风格API * SAX(Simple API for XML)风格 API
* 类似于[SAX](http://en.wikipedia.org/wiki/Simple_API_for_XML), RapidJSON提供一个事件循序访问的解析器API(`rapidjson::GenericReader`)。RapidJSON也提供一个生成器API(`rapidjson::Writer`),可以处理相同的事件集合。 * 类似于 [SAX](http://en.wikipedia.org/wiki/Simple_API_for_XML), RapidJSON 提供一个事件循序访问的解析器 API(`rapidjson::GenericReader`)。RapidJSON 也提供一个生成器 API(`rapidjson::Writer`),可以处理相同的事件集合。
* DOM(Document Object Model)风格API * DOM(Document Object Model)风格 API
* 类似于HTML/XML的[DOM](http://en.wikipedia.org/wiki/Document_Object_Model),RapidJSON可把JSON解析至一个DOM表示方式(`rapidjson::GenericDocument`),以方便操作。如有需要,可把DOM转换(stringify)回JSON。 * 类似于 HTML/XML 的 [DOM](http://en.wikipedia.org/wiki/Document_Object_Model),RapidJSON 可把 JSON 解析至一个 DOM 表示方式(`rapidjson::GenericDocument`),以方便操作。如有需要,可把 DOM 转换(stringify)回 JSON。
* DOM风格API(`rapidjson::GenericDocument`)实际上是由SAX风格API(`rapidjson::GenericReader`)实现的。SAX更快,但有时DOM更易用。用户可根据情况作出选择。 * DOM 风格 API(`rapidjson::GenericDocument`)实际上是由 SAX 风格 API(`rapidjson::GenericReader`)实现的。SAX 更快,但有时 DOM 更易用。用户可根据情况作出选择。
## 解析 ## 解析
...@@ -53,45 +58,46 @@ ...@@ -53,45 +58,46 @@
* 递归式解析器较快,但在极端情况下可出现堆栈溢出。 * 递归式解析器较快,但在极端情况下可出现堆栈溢出。
* 迭代式解析器使用自定义的堆栈去维持解析状态。 * 迭代式解析器使用自定义的堆栈去维持解析状态。
* 支持原位(*in situ*)解析。 * 支持原位(*in situ*)解析。
*JSON字符串的值解析至原JSON之中,然后让DOM指向那些字符串。 * JSON 字符串的值解析至原 JSON 之中,然后让 DOM 指向那些字符串。
* 比常规分析更快:不需字符串的内存分配、不需复制(如字符串不含转义符)、缓存友好。 * 比常规分析更快:不需字符串的内存分配、不需复制(如字符串不含转义符)、缓存友好。
* 对于JSON数字类型,支持32-bit/64-bit的有号/无号整数,以及`double` * 对于 JSON 数字类型,支持 32-bit/64-bit 的有号/无号整数,以及 `double`
* 错误处理 * 错误处理
* 支持详尽的解析错误代号。 * 支持详尽的解析错误代号。
* 支持本地化错误信息。 * 支持本地化错误信息。
## DOM (Document) ## DOM (Document)
* RapidJSON在类型转换时会检查数值的范围。 * RapidJSON 在类型转换时会检查数值的范围。
* 字符串字面量的优化 * 字符串字面量的优化
* 只储存指针,不作复制 * 只储存指针,不作复制
* 优化“短”字符串 * 优化“短”字符串
*`Value`内储存短字符串,无需额外分配。 * `Value` 内储存短字符串,无需额外分配。
*UTF-8字符串来说,32位架构下可存储最多11字符,64位下15字符 * UTF-8 字符串来说,32 位架构下可存储最多 11 字符,64 位下 21 字符(x86-64 下 13 字符)
* 可选地支持`std::string`(定义`RAPIDJSON_HAS_STDSTRING=1` * 可选地支持 `std::string`(定义 `RAPIDJSON_HAS_STDSTRING=1`
## 生成 ## 生成
* 支持`rapidjson::PrettyWriter`去加入换行及缩进。 * 支持 `rapidjson::PrettyWriter` 去加入换行及缩进。
## 输入输出流 ## 输入输出流
* 支持`rapidjson::GenericStringBuffer`,把输出的JSON储存于字符串内。 * 支持 `rapidjson::GenericStringBuffer`,把输出的 JSON 储存于字符串内。
* 支持`rapidjson::FileReadStream``rapidjson::FileWriteStream`,使用`FILE`对象作输入输出。 * 支持 `rapidjson::FileReadStream``rapidjson::FileWriteStream`,使用 `FILE` 对象作输入输出。
* 支持自定义输入输出流。 * 支持自定义输入输出流。
## 内存 ## 内存
* 最小化DOM的内存开销。 * 最小化 DOM 的内存开销。
* 对大部分32/64位机器而言,每个JSON值只占16或20字节(不包含字符串)。 * 对大部分 32/64 位机器而言,每个 JSON 值只占 16 或 20 字节(不包含字符串)。
* 支持快速的预设分配器。 * 支持快速的预设分配器。
* 它是一个堆栈形式的分配器(顺序分配,不容许单独释放,适合解析过程之用)。 * 它是一个堆栈形式的分配器(顺序分配,不容许单独释放,适合解析过程之用)。
* 使用者也可提供一个预分配的缓冲区。(有可能达至无需CRT分配就能解析多个JSON) * 使用者也可提供一个预分配的缓冲区。(有可能达至无需 CRT 分配就能解析多个 JSON)
* 支持标准CRT(C-runtime)分配器。 * 支持标准 CRT(C-runtime)分配器。
* 支持自定义分配器。 * 支持自定义分配器。
## 其他 ## 其他
* 一些C++11的支持(可选) * 一些 C++11 的支持(可选)
* 右值引用(rvalue reference) * 右值引用(rvalue reference)
* `noexcept`修饰符 * `noexcept` 修饰符
* 范围 for 循环
...@@ -114,7 +114,7 @@ Number is a bit more complicated. For normal integer values, it can contains `kI ...@@ -114,7 +114,7 @@ Number is a bit more complicated. For normal integer values, it can contains `kI
## Short-String Optimization {#ShortString} ## Short-String Optimization {#ShortString}
Kosta (@Kosta-Github) provided a very neat short-string optimization. The optimization idea is given as follow. Excluding the `flags_`, a `Value` has 12 or 16 bytes (32-bit or 64-bit) for storing actual data. Instead of storing a pointer to a string, it is possible to store short strings in these space internally. For encoding with 1-byte character type (e.g. `char`), it can store maximum 11 or 15 characters string inside the `Value` type. [Kosta](https://github.com/Kosta-Github) provided a very neat short-string optimization. The optimization idea is given as follow. Excluding the `flags_`, a `Value` has 12 or 16 bytes (32-bit or 64-bit) for storing actual data. Instead of storing a pointer to a string, it is possible to store short strings in these space internally. For encoding with 1-byte character type (e.g. `char`), it can store maximum 11 or 15 characters string inside the `Value` type.
| ShortString (Ch=char) | |32-bit|64-bit| | ShortString (Ch=char) | |32-bit|64-bit|
|---------------------|-------------------------------------|:----:|:----:| |---------------------|-------------------------------------|:----:|:----:|
...@@ -126,7 +126,7 @@ A special technique is applied. Instead of storing the length of string directly ...@@ -126,7 +126,7 @@ A special technique is applied. Instead of storing the length of string directly
This optimization can reduce memory usage for copy-string. It can also improve cache-coherence thus improve runtime performance. This optimization can reduce memory usage for copy-string. It can also improve cache-coherence thus improve runtime performance.
# Allocator {#Allocator} # Allocator {#InternalAllocator}
`Allocator` is a concept in RapidJSON: `Allocator` is a concept in RapidJSON:
~~~cpp ~~~cpp
...@@ -158,7 +158,7 @@ Note that `Malloc()` and `Realloc()` are member functions but `Free()` is static ...@@ -158,7 +158,7 @@ Note that `Malloc()` and `Realloc()` are member functions but `Free()` is static
Internally, it allocates chunks of memory from the base allocator (by default `CrtAllocator`) and stores the chunks as a singly linked list. When user requests an allocation, it allocates memory from the following order: Internally, it allocates chunks of memory from the base allocator (by default `CrtAllocator`) and stores the chunks as a singly linked list. When user requests an allocation, it allocates memory from the following order:
1. User supplied buffer if it is available. (See [User Buffer section in DOM](dom.md)) 1. User supplied buffer if it is available. (See [User Buffer section in DOM](doc/dom.md))
2. If user supplied buffer is full, use the current memory chunk. 2. If user supplied buffer is full, use the current memory chunk.
3. If the current block is full, allocate a new block of memory. 3. If the current block is full, allocate a new block of memory.
...@@ -183,17 +183,20 @@ void SkipWhitespace(InputStream& s) { ...@@ -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. 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 ~~~cpp
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler. // __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. // 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__) #if defined(__SSE4_2__)
# define RAPIDJSON_SSE42 # define RAPIDJSON_SSE42
#elif defined(__SSE2__) #elif defined(__SSE2__)
# define RAPIDJSON_SSE2 # define RAPIDJSON_SSE2
#elif defined(__ARM_NEON)
# define RAPIDJSON_NEON
#endif #endif
~~~ ~~~
...@@ -211,7 +214,7 @@ In [Intel® 64 and IA-32 Architectures Optimization Reference Manual ...@@ -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. 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} ## Local Stream Copy {#LocalStreamCopy}
......
This diff is collapsed.
...@@ -7,21 +7,5 @@ ...@@ -7,21 +7,5 @@
</ul> </ul>
</div> </div>
<!--END GENERATE_TREEVIEW--> <!--END GENERATE_TREEVIEW-->
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES * * */
var disqus_shortname = 'rapidjson-doc';
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dt = document.createElement('div');
dt.id = "disqus_thread";
(document.getElementsByClassName('contents')[0]).appendChild(dt);
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
</body> </body>
</html> </html>
...@@ -16,18 +16,9 @@ $mathjax ...@@ -16,18 +16,9 @@ $mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" /> <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet $extrastylesheet
</head> </head>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63929386-1', 'auto');
ga('send', 'pageview');
</script>
<body> <body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! --> <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 $searchbox
<!--END TITLEAREA--> <!--END TITLEAREA-->
<!-- end header part --> <!-- end header part -->
## NPM
# package.json {#package}
~~~~~~~~~~js
{
...
"dependencies": {
...
"rapidjson": "git@github.com:Tencent/rapidjson.git"
},
...
"gypfile": true
}
~~~~~~~~~~
# binding.gyp {#binding}
~~~~~~~~~~js
{
...
'targets': [
{
...
'include_dirs': [
'<!(node -e \'require("rapidjson")\')'
]
}
]
}
~~~~~~~~~~
# Performance # Performance
There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 20 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 [1]: https://github.com/miloyip/nativejson-benchmark
...@@ -15,12 +15,12 @@ Additionally, you may refer to the following third-party benchmarks. ...@@ -15,12 +15,12 @@ Additionally, you may refer to the following third-party benchmarks.
* [json_spirit](https://github.com/cierelabs/json_spirit) * [json_spirit](https://github.com/cierelabs/json_spirit)
* [jsoncpp](http://jsoncpp.sourceforge.net/) * [jsoncpp](http://jsoncpp.sourceforge.net/)
* [libjson](http://sourceforge.net/projects/libjson/) * [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) * [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) * [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013)
* [sajson](https://github.com/chadaustin/sajson) * [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/) * [vjson](https://code.google.com/p/vjson/)
* [YAJL](http://lloyd.github.com/yajl/) * [YAJL](http://lloyd.github.com/yajl/)
* [Jansson](http://www.digip.org/jansson/) * [Jansson](http://www.digip.org/jansson/)
# 性能 # 性能
有一个[native JSON benchmark collection][1]项目,能评估20个JSON库在不同操作下的速度、內存用量及代码大小。 有一个 [native JSON benchmark collection][1] 项目,能评估 37 个 JSON 库在不同操作下的速度、內存用量及代码大小。
[1]: https://github.com/miloyip/nativejson-benchmark [1]: https://github.com/miloyip/nativejson-benchmark
RapidJSON 0.1版本的性能测试文章位于[这里](https://code.google.com/p/rapidjson/wiki/Performance). RapidJSON 0.1 版本的性能测试文章位于 [这里](https://code.google.com/p/rapidjson/wiki/Performance).
此外,你也可以参考以下这些第三方的评测。 此外,你也可以参考以下这些第三方的评测。
...@@ -15,12 +15,12 @@ RapidJSON 0.1版本的性能测试文章位于[这里](https://code.google.com/p ...@@ -15,12 +15,12 @@ RapidJSON 0.1版本的性能测试文章位于[这里](https://code.google.com/p
* [json_spirit](https://github.com/cierelabs/json_spirit) * [json_spirit](https://github.com/cierelabs/json_spirit)
* [jsoncpp](http://jsoncpp.sourceforge.net/) * [jsoncpp](http://jsoncpp.sourceforge.net/)
* [libjson](http://sourceforge.net/projects/libjson/) * [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) * [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) * [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013)
* [sajson](https://github.com/chadaustin/sajson) * [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/) * [vjson](https://code.google.com/p/vjson/)
* [YAJL](http://lloyd.github.com/yajl/) * [YAJL](http://lloyd.github.com/yajl/)
* [Jansson](http://www.digip.org/jansson/) * [Jansson](http://www.digip.org/jansson/)
# Pointer # Pointer
## Status: experimental, shall be included in v1.1 (This feature was released in v1.1.0)
JSON Pointer is a standardized ([RFC6901]) way to select a value inside a JSON Document (DOM). This can be analogous to XPath for XML document. However, JSON Pointer is much simpler, and a single JSON Pointer only pointed to a single value. JSON Pointer is a standardized ([RFC6901]) way to select a value inside a JSON Document (DOM). This can be analogous to XPath for XML document. However, JSON Pointer is much simpler, and a single JSON Pointer only pointed to a single value.
...@@ -211,7 +211,7 @@ p.Stringify(sb); ...@@ -211,7 +211,7 @@ p.Stringify(sb);
std::cout << sb.GetString() << std::endl; 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} # User-Supplied Tokens {#UserSuppliedTokens}
......
# Pointer # Pointer
## 状态: 实验性,应该会合进 v1.1 (本功能于 v1.1.0 发布)
JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON Document(DOM)中的值。这类似于 XML 的 XPath。然而,JSON Pointer 简单得多,而且每个 JSON Pointer 仅指向单个值。 JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON Document(DOM)中的值。这类似于 XML 的 XPath。然而,JSON Pointer 简单得多,而且每个 JSON Pointer 仅指向单个值。
...@@ -25,7 +25,7 @@ JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON Docu ...@@ -25,7 +25,7 @@ JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON Docu
3. `"/foo/1"``"baz"` 3. `"/foo/1"``"baz"`
4. `"/pi"``3.1416` 4. `"/pi"``3.1416`
要注意,一个空 JSON Pointer `""` (零个token)解析为整个 JSON。 要注意,一个空 JSON Pointer `""` (零个 token)解析为整个 JSON。
# 基本使用方法 {#BasicUsage} # 基本使用方法 {#BasicUsage}
...@@ -123,7 +123,7 @@ assert(success); ...@@ -123,7 +123,7 @@ assert(success);
Token `"0"` 在第一个 pointer 中被当作成员名字。它在第二个 pointer 中被当作成数组索引。 Token `"0"` 在第一个 pointer 中被当作成员名字。它在第二个 pointer 中被当作成数组索引。
其他函数会改变 DOM,包括`Create()``GetWithDefault()``Set()``Swap()`。这些函数总是成功的。若一些父值不存在,就会创建它们。若父值类型不匹配 token,也会强行改变其类型。改变类型也意味着完全移除其 DOM 子树的内容。 其他函数会改变 DOM,包括 `Create()``GetWithDefault()``Set()``Swap()`。这些函数总是成功的。若一些父值不存在,就会创建它们。若父值类型不匹配 token,也会强行改变其类型。改变类型也意味着完全移除其 DOM 子树的内容。
例如,把上面的 JSON 解译至 `d` 之后, 例如,把上面的 JSON 解译至 `d` 之后,
...@@ -185,7 +185,7 @@ private: ...@@ -185,7 +185,7 @@ private:
# URI 片段表示方式 {#URIFragment} # URI 片段表示方式 {#URIFragment}
除了我们一直在使用的字符串方式表示 JSON pointer,[RFC6901]也定义了一个 JSON Pointer 的 URI 片段(fragment)表示方式。URI 片段是定义于 [RFC3986] "Uniform Resource Identifier (URI): Generic Syntax"。 除了我们一直在使用的字符串方式表示 JSON pointer,[RFC6901] 也定义了一个 JSON Pointer 的 URI 片段(fragment)表示方式。URI 片段是定义于 [RFC3986] "Uniform Resource Identifier (URI): Generic Syntax"。
URI 片段的主要分别是必然以 `#` (pound sign)开头,而一些字符也会以百分比编码成 UTF-8 序列。例如,以下的表展示了不同表示法下的 C/C++ 字符串常数。 URI 片段的主要分别是必然以 `#` (pound sign)开头,而一些字符也会以百分比编码成 UTF-8 序列。例如,以下的表展示了不同表示法下的 C/C++ 字符串常数。
......
This diff is collapsed.
This diff is collapsed.
# Schema # Schema
## Status: experimental, shall be included in v1.1 (This feature was released in v1.1.0)
JSON Schema is a draft standard for describing the format of JSON data. The schema itself is also JSON data. By validating a JSON structure with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema. JSON Schema is a draft standard for describing the format of JSON data. The schema itself is also JSON data. By validating a JSON structure with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema.
...@@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http:// ...@@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://
[TOC] [TOC]
## Basic Usage # Basic Usage {#BasicUsage}
First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. 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 ...@@ -20,7 +20,7 @@ Secondly, construct a `SchemaValidator` with the `SchemaDocument`. It is similar
// ... // ...
Document sd; Document sd;
if (!sd.Parse(schemaJson)) { if (sd.Parse(schemaJson).HasParseError()) {
// the schema is not a valid JSON. // the schema is not a valid JSON.
// ... // ...
} }
...@@ -28,7 +28,7 @@ SchemaDocument schema(sd); // Compile a Document to SchemaDocument ...@@ -28,7 +28,7 @@ SchemaDocument schema(sd); // Compile a Document to SchemaDocument
// sd is no longer needed here. // sd is no longer needed here.
Document d; Document d;
if (!d.Parse(inputJson)) { if (d.Parse(inputJson).HasParseError()) {
// the input is not a valid JSON. // the input is not a valid JSON.
// ... // ...
} }
...@@ -49,14 +49,14 @@ if (!d.Accept(validator)) { ...@@ -49,14 +49,14 @@ if (!d.Accept(validator)) {
Some notes: 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. * 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 {#ParsingSerialization}
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. 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 {#DomParsing}
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. 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()) { ...@@ -97,7 +97,7 @@ if (!reader.GetParseResult()) {
} }
~~~ ~~~
### SAX parsing ## SAX parsing {#SaxParsing}
For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply: 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)) { ...@@ -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. It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema.
...@@ -144,20 +144,20 @@ if (!d.Accept(validator)) { ...@@ -144,20 +144,20 @@ 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`. 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 {#RemoteSchema}
JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](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: 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:
~~~js ~~~js
{ "$ref": "definitions.json#/address" } { "$ref": "definitions.json#/address" }
~~~ ~~~
As `SchemaValidator` does not know how to resolve such URI, it needs a user-provided `IRemoteSchemaDocumentProvider` instance to do so. As `SchemaDocument` does not know how to resolve such URI, it needs a user-provided `IRemoteSchemaDocumentProvider` instance to do so.
~~~ ~~~
class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider { class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
public: public:
virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp length) { virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
// Resolve the uri and returns a pointer to that schema. // Resolve the uri and returns a pointer to that schema.
} }
}; };
...@@ -165,10 +165,10 @@ public: ...@@ -165,10 +165,10 @@ public:
// ... // ...
MyRemoteSchemaDocumentProvider provider; MyRemoteSchemaDocumentProvider provider;
SchemaValidator validator(schema, &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). 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 ` ...@@ -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. 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. The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern.
...@@ -184,34 +184,34 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d ...@@ -184,34 +184,34 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d
|Syntax|Description| |Syntax|Description|
|------|-----------| |------|-----------|
|`ab` | Concatenation |`ab` | Concatenation |
|`a|b` | Alternation |<code>a&#124;b</code> | Alternation |
|`a?` | Zero or one |`a?` | Zero or one |
|`a*` | Zero or more |`a*` | Zero or more |
|`a+` | One or more |`a+` | One or more |
|`a{3}` | Exactly 3 times |`a{3}` | Exactly 3 times |
|`a{3,}` | At least 3 times |`a{3,}` | At least 3 times |
|`a{3,5}`| 3 to 5 times |`a{3,5}`| 3 to 5 times |
|`(ab)` | Grouping |`(ab)` | Grouping |
|`^a` | At the beginning |`^a` | At the beginning |
|`a$` | At the end |`a$` | At the end |
|`.` | Any character |`.` | Any character |
|`[abc]` | Character classes |`[abc]` | Character classes |
|`[a-c]` | Character class range |`[a-c]` | Character class range |
|`[a-z0-9_]` | Character class combination |`[a-z0-9_]` | Character class combination |
|`[^abc]` | Negated character classes |`[^abc]` | Negated character classes |
|`[^a-c]` | Negated character class range |`[^a-c]` | Negated character class range |
|`[\b]` | Backspace (U+0008) |`[\b]` | Backspace (U+0008) |
|`\|`, `\\`, ... | Escape characters |<code>\\&#124;</code>, `\\`, ... | Escape characters |
|`\f` | Form feed (U+000C) |`\f` | Form feed (U+000C) |
|`\n` | Line feed (U+000A) |`\n` | Line feed (U+000A) |
|`\r` | Carriage return (U+000D) |`\r` | Carriage return (U+000D) |
|`\t` | Tab (U+0009) |`\t` | Tab (U+0009) |
|`\v` | Vertical tab (U+000B) |`\v` | Vertical tab (U+000B) |
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. 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. 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.
......
# Schema # Schema
## 状态: 实验性,应该会合进 v1.1 (本功能于 v1.1.0 发布)
JSON Schema 是描述 JSON 格式的一个标准草案。一个 schema 本身也是一个 JSON。使用 JSON Schema 去校验 JSON,可以让你的代码安全地访问 DOM,而无须检查类型或键值是否存在等。这也能确保输出的 JSON 是符合指定的 schema。 JSON Schema 是描述 JSON 格式的一个标准草案。一个 schema 本身也是一个 JSON。使用 JSON Schema 去校验 JSON,可以让你的代码安全地访问 DOM,而无须检查类型或键值是否存在等。这也能确保输出的 JSON 是符合指定的 schema。
...@@ -8,7 +8,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document ...@@ -8,7 +8,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document
[TOC] [TOC]
## 基本用法 # 基本用法 {#BasicUsage}
首先,你要把 JSON Schema 解析成 `Document`,再把它编译成一个 `SchemaDocument` 首先,你要把 JSON Schema 解析成 `Document`,再把它编译成一个 `SchemaDocument`
...@@ -20,23 +20,23 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document ...@@ -20,23 +20,23 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document
// ... // ...
Document sd; Document sd;
if (!sd.Parse(schemaJson)) { if (sd.Parse(schemaJson).HasParseError()) {
// the schema is not a valid JSON. // 此 schema 不是合法的 JSON
// ... // ...
} }
SchemaDocument schema(sd); // Compile a Document to SchemaDocument SchemaDocument schema(sd); // 把一个 Document 编译至 SchemaDocument
// sd is no longer needed here. // 之后不再需要 sd
Document d; Document d;
if (!d.Parse(inputJson)) { if (d.Parse(inputJson).HasParseError()) {
// the input is not a valid JSON. // 输入不是一个合法的 JSON
// ... // ...
} }
SchemaValidator validator(schema); SchemaValidator validator(schema);
if (!d.Accept(validator)) { if (!d.Accept(validator)) {
// Input JSON is invalid according to the schema // 输入的 JSON 不合乎 schema
// Output diagnostic information // 打印诊断信息
StringBuffer sb; StringBuffer sb;
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb); validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
printf("Invalid schema: %s\n", sb.GetString()); printf("Invalid schema: %s\n", sb.GetString());
...@@ -49,14 +49,14 @@ if (!d.Accept(validator)) { ...@@ -49,14 +49,14 @@ if (!d.Accept(validator)) {
一些注意点: 一些注意点:
* 一个 `SchemaDocment` 能被多个 `SchemaValidator` 用。它不会被 `SchemaValidator` 修改。 * 一个 `SchemaDocment` 能被多个 `SchemaValidator` 用。它不会被 `SchemaValidator` 修改。
* 一个 `SchemaValidator` 可以重复使用来校验多个文件。在校验其他文件前,先调用 `validator.Reset()` * 可以重复使用一个 `SchemaValidator` 来校验多个文件。在校验其他文件前,须先调用 `validator.Reset()`
## 在解析/生成时进行校验 # 在解析/生成时进行校验 {#ParsingSerialization}
与大部分 JSON Schema 校验器有所不同,RapidJSON 提供了一个基于 SAX 的 schema 校验器实现。因此,你可以在输入流解析 JSON 的同时进行校验。若校验器遇到一个与 schema 不符的值,就会立即终止解析。这设计对于解析大型 JSON 文件时特别有用。 与大部分 JSON Schema 校验器有所不同,RapidJSON 提供了一个基于 SAX 的 schema 校验器实现。因此,你可以在输入流解析 JSON 的同时进行校验。若校验器遇到一个与 schema 不符的值,就会立即终止解析。这设计对于解析大型 JSON 文件时特别有用。
### DOM 解析 ## DOM 解析 {#DomParsing}
在使用 DOM 进行解析时,`Document` 除了接收 SAX 事件外,还需做一些准备及结束工作,因此,为了连接 `Reader``SchemaValidator``Document` 要做多一点事情。`SchemaValidatingReader` 是一个辅助类去做那些工作。 在使用 DOM 进行解析时,`Document` 除了接收 SAX 事件外,还需做一些准备及结束工作,因此,为了连接 `Reader``SchemaValidator``Document` 要做多一点事情。`SchemaValidatingReader` 是一个辅助类去做那些工作。
...@@ -64,28 +64,28 @@ if (!d.Accept(validator)) { ...@@ -64,28 +64,28 @@ if (!d.Accept(validator)) {
#include "rapidjson/filereadstream.h" #include "rapidjson/filereadstream.h"
// ... // ...
SchemaDocument schema(sd); // Compile a Document to SchemaDocument SchemaDocument schema(sd); // 把一个 Document 编译至 SchemaDocument
// Use reader to parse the JSON // 使用 reader 解析 JSON
FILE* fp = fopen("big.json", "r"); FILE* fp = fopen("big.json", "r");
FileReadStream is(fp, buffer, sizeof(buffer)); FileReadStream is(fp, buffer, sizeof(buffer));
// Parse JSON from reader, validate the SAX events, and store in d. // 用 reader 解析 JSON,校验它的 SAX 事件,并存储至 d
Document d; Document d;
SchemaValidatingReader<kParseDefaultFlags, FileReadStream, UTF8<> > reader(is, schema); SchemaValidatingReader<kParseDefaultFlags, FileReadStream, UTF8<> > reader(is, schema);
d.Populate(reader); d.Populate(reader);
if (!reader.GetParseResult()) { if (!reader.GetParseResult()) {
// Not a valid JSON // 不是一个合法的 JSON
// When reader.GetParseResult().Code() == kParseErrorTermination, // reader.GetParseResult().Code() == kParseErrorTermination,
// it may be terminated by: // 它可能是被以下原因中止:
// (1) the validator found that the JSON is invalid according to schema; or // (1) 校验器发现 JSON 不合乎 schema;或
// (2) the input stream has I/O error. // (2) 输入流有 I/O 错误。
// Check the validation result // 检查校验结果
if (!reader.IsValid()) { if (!reader.IsValid()) {
// Input JSON is invalid according to the schema // 输入的 JSON 不合乎 schema
// Output diagnostic information // 打印诊断信息
StringBuffer sb; StringBuffer sb;
reader.GetInvalidSchemaPointer().StringifyUriFragment(sb); reader.GetInvalidSchemaPointer().StringifyUriFragment(sb);
printf("Invalid schema: %s\n", sb.GetString()); printf("Invalid schema: %s\n", sb.GetString());
...@@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { ...@@ -97,7 +97,7 @@ if (!reader.GetParseResult()) {
} }
~~~ ~~~
### SAX 解析 ## SAX 解析 {#SaxParsing}
使用 SAX 解析时,情况就简单得多。若只需要校验 JSON 而无需进一步处理,那么仅需要: 使用 SAX 解析时,情况就简单得多。若只需要校验 JSON 而无需进一步处理,那么仅需要:
...@@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { ...@@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) {
} }
~~~ ~~~
### 生成 ## 生成 {#Serialization}
我们也可以在生成(serialization)的时候进行校验。这能确保输出的 JSON 符合一个 JSON Schema。 我们也可以在生成(serialization)的时候进行校验。这能确保输出的 JSON 符合一个 JSON Schema。
...@@ -144,20 +144,20 @@ if (!d.Accept(validator)) { ...@@ -144,20 +144,20 @@ if (!d.Accept(validator)) {
当然,如果你的应用仅需要 SAX 风格的生成,那么只需要把 SAX 事件由原来发送到 `Writer`,改为发送到 `SchemaValidator` 当然,如果你的应用仅需要 SAX 风格的生成,那么只需要把 SAX 事件由原来发送到 `Writer`,改为发送到 `SchemaValidator`
## 远程 Schema # 远程 Schema {#RemoteSchema}
JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个[JSON pointer](pointer.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或绝对 URI。例如: JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个 [JSON pointer](doc/pointer.zh-cn.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或绝对 URI。例如:
~~~js ~~~js
{ "$ref": "definitions.json#/address" } { "$ref": "definitions.json#/address" }
~~~ ~~~
由于 `SchemaValidator` 并不知道如何处理那些 URI,它需要使用者提供一个 `IRemoteSchemaDocumentProvider` 的实例去处理。 由于 `SchemaDocument` 并不知道如何处理那些 URI,它需要使用者提供一个 `IRemoteSchemaDocumentProvider` 的实例去处理。
~~~ ~~~
class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider { class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
public: public:
virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp length) { virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
// Resolve the uri and returns a pointer to that schema. // Resolve the uri and returns a pointer to that schema.
} }
}; };
...@@ -165,10 +165,10 @@ public: ...@@ -165,10 +165,10 @@ public:
// ... // ...
MyRemoteSchemaDocumentProvider provider; MyRemoteSchemaDocumentProvider provider;
SchemaValidator validator(schema, &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 个。 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 ...@@ -176,7 +176,7 @@ RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON
除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。 除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。
### 正则表达式 ## 正则表达式 {#RegEx}
`pattern``patternProperties` 这两个 schema 关键字使用了正则表达式去匹配所需的模式。 `pattern``patternProperties` 这两个 schema 关键字使用了正则表达式去匹配所需的模式。
...@@ -184,34 +184,34 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用 ...@@ -184,34 +184,34 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用
|语法|描述| |语法|描述|
|------|-----------| |------|-----------|
|`ab` | 串联 |`ab` | 串联 |
|`a|b` | 交替 |<code>a&#124;b</code> | 交替 |
|`a?` | 零或一次 |`a?` | 零或一次 |
|`a*` | 零或多次 |`a*` | 零或多次 |
|`a+` | 一或多次 |`a+` | 一或多次 |
|`a{3}` | 刚好 3 次 |`a{3}` | 刚好 3 次 |
|`a{3,}` | 至少 3 次 |`a{3,}` | 至少 3 次 |
|`a{3,5}`| 3 至 5 次 |`a{3,5}`| 3 至 5 次 |
|`(ab)` | 分组 |`(ab)` | 分组 |
|`^a` | 在开始处 |`^a` | 在开始处 |
|`a$` | 在结束处 |`a$` | 在结束处 |
|`.` | 任何字符 |`.` | 任何字符 |
|`[abc]` | 字符组 |`[abc]` | 字符组 |
|`[a-c]` | 字符组范围 |`[a-c]` | 字符组范围 |
|`[a-z0-9_]` | 字符组组合 |`[a-z0-9_]` | 字符组组合 |
|`[^abc]` | 字符组取反 |`[^abc]` | 字符组取反 |
|`[^a-c]` | 字符组范围取反 |`[^a-c]` | 字符组范围取反 |
|`[\b]` | 退格符 (U+0008) |`[\b]` | 退格符 (U+0008) |
|`\|`, `\\`, ... | 转义字符 |<code>\\&#124;</code>, `\\`, ... | 转义字符 |
|`\f` | 馈页 (U+000C) |`\f` | 馈页 (U+000C) |
|`\n` | 馈行 (U+000A) |`\n` | 馈行 (U+000A) |
|`\r` | 回车 (U+000D) |`\r` | 回车 (U+000D) |
|`\t` | 制表 (U+0009) |`\t` | 制表 (U+0009) |
|`\v` | 垂直制表 (U+000B) |`\v` | 垂直制表 (U+000B) |
对于使用 C++11 编译器的使用者,也可使用 `std::regex`,只需定义 `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0``RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern``patternProperties`,可以把两个宏都设为零,以禁用此功能,这样做可节省一些代码体积。 对于使用 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 库。 大部分 C++ JSON 库都未支持 JSON Schema。因此我们尝试按照 [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 去评估 RapidJSON 的 JSON Schema 校验器。该评测测试了 11 个运行在 node.js 上的 JavaScript 库。
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
if(POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
set(EXAMPLES set(EXAMPLES
capitalize capitalize
condense condense
filterkey
filterkeydom
jsonx jsonx
lookaheadparser
messagereader messagereader
parsebyparts parsebyparts
pretty pretty
...@@ -12,21 +19,21 @@ set(EXAMPLES ...@@ -12,21 +19,21 @@ set(EXAMPLES
serialize serialize
simpledom simpledom
simplereader simplereader
simplepullreader
simplewriter simplewriter
tutorial) tutorial)
include_directories("../include/") include_directories("../include/")
add_definitions(-D__STDC_FORMAT_MACROS) add_definitions(-D__STDC_FORMAT_MACROS)
set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS})
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -Werror -Wall -Wextra -Weffc++ -Wswitch-default") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
endif() endif()
add_executable(archivertest archiver/archiver.cpp archiver/archivertest.cpp)
foreach (example ${EXAMPLES}) foreach (example ${EXAMPLES})
add_executable(${example} ${example}/${example}.cpp) add_executable(${example} ${example}/${example}.cpp)
endforeach() endforeach()
......
#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
#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 = nullptr);
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:
void Next();
// PIMPL
void* mDocument; ///< DOM result of parsing.
void* mStack; ///< Stack for iterating the DOM
bool mError; ///< Whether an error is occured.
};
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:
// PIMPL idiom
void* mWriter; ///< JSON writer.
void* mStream; ///< Stream buffer.
};
#endif // ARCHIVER_H__
This diff is collapsed.
// JSON filterkey example with SAX-style API.
// This example parses JSON text from stdin with validation.
// During parsing, specified key will be filtered using a SAX handler.
// It re-output the JSON content to stdout without whitespace.
#include "rapidjson/reader.h"
#include "rapidjson/writer.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/error/en.h"
#include <stack>
using namespace rapidjson;
// This handler forwards event into an output handler, with filtering the descendent events of specified key.
template <typename OutputHandler>
class FilterKeyHandler {
public:
typedef char Ch;
FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, SizeType keyLength) :
outputHandler_(outputHandler), keyString_(keyString), keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_()
{}
bool Null() { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Null() && EndValue(); }
bool Bool(bool b) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Bool(b) && EndValue(); }
bool Int(int i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int(i) && EndValue(); }
bool Uint(unsigned u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint(u) && EndValue(); }
bool Int64(int64_t i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int64(i) && EndValue(); }
bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint64(u) && EndValue(); }
bool Double(double d) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Double(d) && EndValue(); }
bool RawNumber(const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) && EndValue(); }
bool String (const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.String (str, len, copy) && EndValue(); }
bool StartObject() {
if (filterValueDepth_ > 0) {
filterValueDepth_++;
return true;
}
else {
filteredKeyCount_.push(0);
return outputHandler_.StartObject();
}
}
bool Key(const Ch* str, SizeType len, bool copy) {
if (filterValueDepth_ > 0)
return true;
else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) {
filterValueDepth_ = 1;
return true;
}
else {
++filteredKeyCount_.top();
return outputHandler_.Key(str, len, copy);
}
}
bool EndObject(SizeType) {
if (filterValueDepth_ > 0) {
filterValueDepth_--;
return EndValue();
}
else {
// Use our own filtered memberCount
SizeType memberCount = filteredKeyCount_.top();
filteredKeyCount_.pop();
return outputHandler_.EndObject(memberCount) && EndValue();
}
}
bool StartArray() {
if (filterValueDepth_ > 0) {
filterValueDepth_++;
return true;
}
else
return outputHandler_.StartArray();
}
bool EndArray(SizeType elementCount) {
if (filterValueDepth_ > 0) {
filterValueDepth_--;
return EndValue();
}
else
return outputHandler_.EndArray(elementCount) && EndValue();
}
private:
FilterKeyHandler(const FilterKeyHandler&);
FilterKeyHandler& operator=(const FilterKeyHandler&);
bool EndValue() {
if (filterValueDepth_ == 1) // Just at the end of value after filtered key
filterValueDepth_ = 0;
return true;
}
OutputHandler& outputHandler_;
const char* keyString_;
const SizeType keyLength_;
unsigned filterValueDepth_;
std::stack<SizeType> filteredKeyCount_;
};
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "filterkey key < input.json > output.json\n");
return 1;
}
// Prepare JSON reader and input stream.
Reader reader;
char readBuffer[65536];
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
// Prepare JSON writer and output stream.
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
Writer<FileWriteStream> writer(os);
// Prepare Filter
FilterKeyHandler<Writer<FileWriteStream> > filter(writer, argv[1], static_cast<SizeType>(strlen(argv[1])));
// JSON reader parse from the input stream, filter handler filters the events, and forward to writer.
// i.e. the events flow is: reader -> filter -> writer
if (!reader.Parse(is, filter)) {
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
return 1;
}
return 0;
}
This diff is collapsed.
This diff is collapsed.
// Example of parsing JSON to document by parts. // Example of parsing JSON to document by parts.
// Using C++11 threads // Using C++11 threads
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700) // Temporarily disable for clang (older version) due to incompatibility with libstdc++
#if (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700)) && !defined(__clang__)
#include "rapidjson/document.h" #include "rapidjson/document.h"
#include "rapidjson/error/en.h" #include "rapidjson/error/en.h"
...@@ -20,12 +21,15 @@ public: ...@@ -20,12 +21,15 @@ public:
AsyncDocumentParser(Document& d) AsyncDocumentParser(Document& d)
: stream_(*this) : stream_(*this)
, d_(d) , d_(d)
, parseThread_(&AsyncDocumentParser::Parse, this) , parseThread_()
, mutex_() , mutex_()
, notEmpty_() , notEmpty_()
, finish_() , finish_()
, completed_() , completed_()
{} {
// Create and execute thread after all member variables are initialized.
parseThread_ = std::thread(&AsyncDocumentParser::Parse, this);
}
~AsyncDocumentParser() { ~AsyncDocumentParser() {
if (!parseThread_.joinable()) if (!parseThread_.joinable())
......
#include "rapidjson/reader.h"
#include <iostream>
#include <sstream>
using namespace rapidjson;
using namespace std;
// If you can require C++11, you could use std::to_string here
template <typename T> std::string stringify(T x) {
std::stringstream ss;
ss << x;
return ss.str();
}
struct MyHandler {
const char* type;
std::string data;
MyHandler() : type(), data() {}
bool Null() { type = "Null"; data.clear(); return true; }
bool Bool(bool b) { type = "Bool:"; data = b? "true": "false"; return true; }
bool Int(int i) { type = "Int:"; data = stringify(i); return true; }
bool Uint(unsigned u) { type = "Uint:"; data = stringify(u); return true; }
bool Int64(int64_t i) { type = "Int64:"; data = stringify(i); return true; }
bool Uint64(uint64_t u) { type = "Uint64:"; data = stringify(u); return true; }
bool Double(double d) { type = "Double:"; data = stringify(d); return true; }
bool RawNumber(const char* str, SizeType length, bool) { type = "Number:"; data = std::string(str, length); return true; }
bool String(const char* str, SizeType length, bool) { type = "String:"; data = std::string(str, length); return true; }
bool StartObject() { type = "StartObject"; data.clear(); return true; }
bool Key(const char* str, SizeType length, bool) { type = "Key:"; data = std::string(str, length); return true; }
bool EndObject(SizeType memberCount) { type = "EndObject:"; data = stringify(memberCount); return true; }
bool StartArray() { type = "StartArray"; data.clear(); return true; }
bool EndArray(SizeType elementCount) { type = "EndArray:"; data = stringify(elementCount); return true; }
private:
MyHandler(const MyHandler& noCopyConstruction);
MyHandler& operator=(const MyHandler& noAssignment);
};
int main() {
const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
MyHandler handler;
Reader reader;
StringStream ss(json);
reader.IterativeParseInit();
while (!reader.IterativeParseComplete()) {
reader.IterativeParseNext<kParseDefaultFlags>(ss, handler);
cout << handler.type << handler.data << endl;
}
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -85,6 +85,10 @@ public: ...@@ -85,6 +85,10 @@ public:
size_t PutEnd(Ch*) { return 0; } size_t PutEnd(Ch*) { return 0; }
MemoryStream& is_; MemoryStream& is_;
private:
EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&);
}; };
//! Output byte stream wrapper with statically bound encoding. //! Output byte stream wrapper with statically bound encoding.
...@@ -196,7 +200,7 @@ private: ...@@ -196,7 +200,7 @@ private:
// xx xx xx xx UTF-8 // xx xx xx xx UTF-8
if (!hasBOM_) { if (!hasBOM_) {
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
switch (pattern) { switch (pattern) {
case 0x08: type_ = kUTF32BE; break; case 0x08: type_ = kUTF32BE; break;
case 0x0A: type_ = kUTF16BE; break; case 0x0A: type_ = kUTF16BE; break;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment