Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/miloyip/rapidjson.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Hanson <smh@uk.ibm.com>2021-05-20 14:20:12 +0300
committerSteve Hanson <smh@uk.ibm.com>2021-05-20 14:20:12 +0300
commit3987d82f4161b0600fee349eb9559c1be782c878 (patch)
tree9d5ea22572376ba6fb2b69c7aacab913f839c0ad
parentbc026e3fb574411acc4f2be82177abb8b5b92202 (diff)
parent17aa824c928ea111e9b12a61e06d98335ce98f15 (diff)
Merge branch 'master' of https://github.com/Tencent/rapidjson into id-and-ref
-rw-r--r--.travis.yml56
-rw-r--r--CMakeLists.txt24
-rw-r--r--appveyor.yml50
-rw-r--r--bin/types/alotofkeys.json502
-rw-r--r--doc/stream.md14
-rw-r--r--doc/stream.zh-cn.md2
-rw-r--r--doc/tutorial.md30
-rw-r--r--example/traverseaspointer.cpp39
-rw-r--r--include/rapidjson/allocators.h512
-rw-r--r--include/rapidjson/document.h406
-rw-r--r--include/rapidjson/rapidjson.h71
-rw-r--r--test/perftest/perftest.h9
-rw-r--r--test/perftest/rapidjsontest.cpp22
-rw-r--r--test/unittest/CMakeLists.txt1
-rw-r--r--test/unittest/allocatorstest.cpp194
-rw-r--r--test/unittest/documenttest.cpp2
-rw-r--r--test/unittest/platformtest.cpp40
-rw-r--r--test/unittest/valuetest.cpp14
18 files changed, 1814 insertions, 174 deletions
diff --git a/.travis.yml b/.travis.yml
index 8f34664f..17d8f03d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,51 +28,69 @@ env:
matrix:
include:
# gcc
- - env: CONF=release ARCH=x86 CXX11=ON
+ - env: CONF=release ARCH=x86 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
compiler: gcc
arch: amd64
- - env: CONF=release ARCH=x86_64 CXX11=ON
+ - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
compiler: gcc
arch: amd64
- - env: CONF=debug ARCH=x86 CXX11=OFF
+ - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=ON
compiler: gcc
arch: amd64
- - env: CONF=debug ARCH=x86_64 CXX11=OFF
+ - env: CONF=debug ARCH=x86 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
compiler: gcc
arch: amd64
- - env: CONF=release ARCH=aarch64 CXX11=ON
+ - env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
+ compiler: gcc
+ arch: amd64
+ - env: CONF=debug ARCH=x86 CXX11=OFF CXX17=ON MEMBERSMAP=ON CXX_FLAGS='-D_GLIBCXX_DEBUG'
+ compiler: gcc
+ arch: amd64
+ - env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=ON MEMBERSMAP=ON CXX_FLAGS='-D_GLIBCXX_DEBUG'
+ compiler: gcc
+ arch: amd64
+ - env: CONF=release ARCH=aarch64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
compiler: gcc
arch: arm64
- - env: CONF=debug ARCH=aarch64 CXX11=OFF
+ - env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
+ compiler: gcc
+ arch: arm64
+ - env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=ON MEMBERSMAP=ON
compiler: gcc
arch: arm64
# clang
- - env: CONF=debug ARCH=x86 CXX11=ON CCACHE_CPP2=yes
+ - env: CONF=release ARCH=x86 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
+ compiler: clang
+ arch: amd64
+ - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
compiler: clang
arch: amd64
- - env: CONF=debug ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
+ - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF CCACHE_CPP2=yes
compiler: clang
arch: amd64
- - env: CONF=debug ARCH=x86 CXX11=OFF CCACHE_CPP2=yes
+ - env: CONF=debug ARCH=x86 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
compiler: clang
arch: amd64
- - env: CONF=debug ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes
+ - env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
compiler: clang
arch: amd64
- - env: CONF=release ARCH=x86 CXX11=ON CCACHE_CPP2=yes
+ - env: CONF=debug ARCH=x86 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
compiler: clang
arch: amd64
- - env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
+ - env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
compiler: clang
arch: amd64
- - env: CONF=debug ARCH=aarch64 CXX11=ON CCACHE_CPP2=yes
+ - env: CONF=debug ARCH=aarch64 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
+ compiler: clang
+ arch: arm64
+ - env: CONF=debug ARCH=aarch64 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
compiler: clang
arch: arm64
- - env: CONF=debug ARCH=aarch64 CXX11=OFF CCACHE_CPP2=yes
+ - env: CONF=debug ARCH=aarch64 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
compiler: clang
arch: arm64
# coverage report
- - env: CONF=debug ARCH=x86 CXX11=ON GCOV_FLAGS='--coverage'
+ - env: CONF=debug ARCH=x86 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=OFF CXX17=OFF
compiler: gcc
arch: amd64
cache:
@@ -81,7 +99,7 @@ matrix:
after_success:
- 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
- - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage'
+ - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=ON CXX17=OFF MEMBERSMAP=ON
compiler: gcc
arch: amd64
cache:
@@ -90,7 +108,7 @@ matrix:
after_success:
- 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
- - env: CONF=debug ARCH=aarch64 GCOV_FLAGS='--coverage'
+ - env: CONF=debug ARCH=aarch64 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=OFF CXX17=ON
compiler: gcc
arch: arm64
cache:
@@ -134,10 +152,12 @@ script:
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
(cd build && cmake
-DRAPIDJSON_HAS_STDSTRING=ON
+ -DRAPIDJSON_USE_MEMBERSMAP=$MEMBERSMAP
-DRAPIDJSON_BUILD_CXX11=$CXX11
+ -DRAPIDJSON_BUILD_CXX17=$CXX17
-DCMAKE_VERBOSE_MAKEFILE=ON
-DCMAKE_BUILD_TYPE=$CONF
- -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
+ -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS $CXX_FLAGS"
-DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS
..)
- cd build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3b9ac512..dc2072a9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,7 +35,8 @@ option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." ON)
option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
"Use gtest installation in `thirdparty/gtest` by default if available" OFF)
-option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON)
+option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11" ON)
+option(RAPIDJSON_BUILD_CXX17 "Build rapidjson with C++17" OFF)
if(RAPIDJSON_BUILD_CXX11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
@@ -51,6 +52,11 @@ if(RAPIDJSON_HAS_STDSTRING)
add_definitions(-DRAPIDJSON_HAS_STDSTRING)
endif()
+option(RAPIDJSON_USE_MEMBERSMAP "" OFF)
+if(RAPIDJSON_USE_MEMBERSMAP)
+ add_definitions(-DRAPIDJSON_USE_MEMBERSMAP=1)
+endif()
+
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
@@ -77,6 +83,8 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
+ elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
endif()
if (RAPIDJSON_BUILD_ASAN)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.0")
@@ -105,6 +113,8 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough)
if (RAPIDJSON_BUILD_CXX11 AND CMAKE_VERSION VERSION_LESS 3.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.0")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
endif()
if (RAPIDJSON_BUILD_ASAN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
@@ -119,6 +129,18 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
+ # CMake >= 3.10 should handle the above CMAKE_CXX_STANDARD fine, otherwise use /std:c++XX with MSVC >= 19.10
+ if (RAPIDJSON_BUILD_CXX11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.10")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++11")
+ elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.14")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17")
+ endif()
+ # Always compile with /WX
+ if(CMAKE_CXX_FLAGS MATCHES "/WX-")
+ string(REGEX REPLACE "/WX-" "/WX" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX")
+ endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -qarch=auto")
endif()
diff --git a/appveyor.yml b/appveyor.yml
index 376dc197..4044ba66 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -13,37 +13,85 @@ environment:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
VS_VERSION: 10 2010
VS_PLATFORM: win32
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
VS_VERSION: 10 2010
VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
VS_VERSION: 11 2012
VS_PLATFORM: win32
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
VS_VERSION: 11 2012
VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
VS_VERSION: 12 2013
VS_PLATFORM: win32
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
VS_VERSION: 12 2013
VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
VS_VERSION: 14 2015
VS_PLATFORM: win32
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
VS_VERSION: 14 2015
VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
VS_VERSION: 15 2017
VS_PLATFORM: win32
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
VS_VERSION: 15 2017
VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ VS_VERSION: 15 2017
+ VS_PLATFORM: x64
+ CXX11: ON
+ CXX17: OFF
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ VS_VERSION: 15 2017
+ VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: ON
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ VS_VERSION: 16 2019
+ VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: ON
+ MEMBERSMAP: ON
before_build:
- git submodule update --init --recursive
-- cmake -H. -BBuild/VS -G "Visual Studio %VS_VERSION%" -DCMAKE_GENERATOR_PLATFORM=%VS_PLATFORM% -DCMAKE_VERBOSE_MAKEFILE=ON -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 -DRAPIDJSON_BUILD_CXX11=%CXX11% -DRAPIDJSON_BUILD_CXX17=%CXX17% -DRAPIDJSON_USE_MEMBERSMAP=%MEMBERSMAP% -Wno-dev
build:
project: Build\VS\RapidJSON.sln
diff --git a/bin/types/alotofkeys.json b/bin/types/alotofkeys.json
new file mode 100644
index 00000000..3fc052e3
--- /dev/null
+++ b/bin/types/alotofkeys.json
@@ -0,0 +1,502 @@
+{
+ "4BABQZ5SZJSO3KFKBOG36EIXXTOF34HVFCELHA2DWOMIL44K": null,
+ "RSZNOTRIJFCHRKG4IKNOW4ZEBMVXPDBYBXBGDGNWTSVLMJ2U": null,
+ "AOGQPY32FQ7T7WZWQPON3X6GU74GOYI6HHVNPATDTBXRUQ4G": null,
+ "3PMTZEGLZNHSOWWJ23BE6PWOXD2VZRDN7MMLUMQ4EIRERVCG": null,
+ "PD2FMQGI5HTGK6MT76OYS2ER2LXFBON44WOMELDY5MRKQI6I": null,
+ "6L6QMMVSE4UQLB4OGX3LVDRNGAL6MOJ6S3RBBUSQ3F5PPHYR": null,
+ "LYVVXT7U7WN7PGGUHCLFXVOBJBSSR6ES2P7AY7XGBXEBLTDD": null,
+ "G5RWOLHDDZOXYEFGGSVWG3C2UHYDW6UOFVBQQLQJVZNCF4TB": null,
+ "3QPIK2M3ZPICZQFQTX22A7VDCAFIGAX2PXIXKDOZX7XUM32R": null,
+ "JR75L2BXOA5LVLNKT4EEZO2P45OHWRPMMWMFENTFFIY7A2V3": null,
+ "TESL546MN7IR7AT3C5HRSESIFHZ5NW6TNRWZXZ43OSRYOZKP": null,
+ "62EJKIAFWGFGPUS6YP2X6E26AV2TZCTCAJMZNWBBNFRPCCRN": null,
+ "5ZDD3KPTPGE2CAWR3MTFUSBMGQAS4ZP5WZKXJTXUNFSYABD6": null,
+ "XQ7TMN5YMQLAND54B4VIVWJAHU3TNZKT2S4SVRW6WKHNJBX2": null,
+ "O456GV3HBAWFDQRCECX6HY3PBTP6WNQIDSKVP2MZIPV3TCBL": null,
+ "WXCN25EBQH5WWN2JBHWNFNDUTYSFDLIAOWO5AE6D5HDO7VNE": null,
+ "THO3I3KDRIMTD6DKNIETIOWDY7FXQ5GJ3P2KUQJWYAEL3LXV": null,
+ "7OMI7VIOKFRZATMNLGIWH7ZBDARZ6ARXIAH5S3GPG5KV52IC": null,
+ "ESUPY3ELKCEGFRSYFGPGFBJOAUGXMYZ6XCWXDFOKHBJHNGVR": null,
+ "TNXSJIEFJLUFUDTR2S5LV73PD6ACFYNHOCRZPUSDPXDD3B7M": null,
+ "T6TISG6P4W66F37634QU4BNJY4RZ77QXXNPGTYH5LCCRDSX6": null,
+ "QTVAA56JKNDYTMV7DXAIL4QVLZPW3UHGLTKDI2BED6S3MGDQ": null,
+ "DTJREAQBCS6I2AJ6MOGTPIXK3ADB4BPNDIHI2YSQP6Y2BMH7": null,
+ "XDGH2OYCTAJ75IEMZ32O644YLT73PRYDORFKBLYEMCHOQ7Q6": null,
+ "4KDDQZRBLNS33DRHZHDMENCWGMNFEJGBZJXSGIQW7VBWOTHT": null,
+ "5KSH3GKWFNXV55KI2FPUDSD57O25N52UTZAAYDFVMFUSEE6O": null,
+ "7AGEUBM5FQZ2JCMUSKTEI6COA3Q5CE5WYB7TP2F5OX3ETMTK": null,
+ "HFHZ5ZE5TC45W4WIF6H7ONTHXKAVWRY2LXN2GN2TXZPIP6PQ": null,
+ "S3U2JJBPKZHZNOM3SWVFQ7OMS7F5M2KDJHHHZKXHZXQRNUSE": null,
+ "YHJBGJ6T6A7PMK5AYXDITDV37BJJIM4TP7I2XHSVYN76724O": null,
+ "TH42A7M3645OUKC54JQMDB5BTGS3URFUCYJ2VOEM6IAGZ5QQ": null,
+ "OYBKULFLWL2MER745QTDL2X2HJNR77QGH2M2P6TSCHVGUJLV": null,
+ "JDU37GHQUOCYA5I5LFS3WAEKKR6C55XJCCLJCCCQJEGUJEP6": null,
+ "CB5HEJZNJ2SWZM426TWIWLHTWAPWPT2AVVHBILEVGFD6NPHI": null,
+ "D4A5SJA2VRB4JGJFC7PHT35S7XAMHPZZ2PZC5YYVV7RLKSUQ": null,
+ "BBVT6NRRU55KNRK5G745FNMZVIFHVZJICEMODF4ZBJFQ3EGL": null,
+ "XBV57OEMT4GYPTTH56A6XKF2ZPMXSMHY7L3LUIS5ZZWRP2OB": null,
+ "GTFJ3NP4VJR6HG2DRNTDKVIWTMIALYUQIQTBJMKVM2I3QKGE": null,
+ "77BMBFMRGASXE5XXT6BRH2DRBNJMIAUDDMEXIJT3RMHTUPI4": null,
+ "FWZZMG7I2JWAHX4LBYAK2G4L4TZYLHXMJWIDGT6JC5TEBCPJ": null,
+ "J3324OXU2BG2NGFMSOYMVKXE6OEJNGENI7EESHDSEWSUVDVV": null,
+ "C636AVNC5C5EKILXT2AQPXYLSNH7LCAJKVDHP67MVHULFSQN": null,
+ "OXTDOQG2VIEVYFC23SKOBSSPGE55AVZZADK6PIHP3APVPHND": null,
+ "JLQVKV4Q2BQHK355NQXZVX4WJBPFOWSD7WIJX2P433KYO4SO": null,
+ "E4XHPOPWH3PRCV5MGQHR3BCTKZMOK46OH4Q6STZDPF2FG6SD": null,
+ "J5IP4A3DV3BHGGU3J72JVVTWNIQOLNC6GQES22MVATK5H7BZ": null,
+ "HHCCDMLNGOU2ABP57ION5TC33UF3NUHL2L3WUYCGZDWLDNTL": null,
+ "54Q67RURG4THOANPT3RAVF72TGKJE425GC5GD3EOKPY6MKVW": null,
+ "TG3BH3HBKFEXAUM5O67VVDTXZA6MHWSVNNLXLXIL2SE2ZEDO": null,
+ "Q5KJ25G2A4CWNGPPYXBZM6QVYA466MQX3HCUMUO5Z24D5JX3": null,
+ "QQZET7VFHGJROUQZSWSRDI5ADXVH26KEPDVL6PZ36ISHOKMQ": null,
+ "KWNJME4V365ZIC7SA7BYCVQUAG6URC2T6MHSO3OVDBJAUPFB": null,
+ "XHQYKGYVLE2PFNXQPD4OUWBASZO5OFVZISCVEFTU6K6KDKHS": null,
+ "Z4SPXMJIAMYD2H4U4F23FALBDZP6NRLUBDFU4PRGZ4SXGTI2": null,
+ "HSCK3PEXH3I3XMMEMIHTM7SDJD3GOKXUMCGOL6UXJXLCSCGN": null,
+ "BIUYMIDY4EVGRLZ6OLJK2CE2FS5TTELIWSEA6UHKUDUYX5LM": null,
+ "IJJDLN5ANXTMX54P6GW2J2EJGGWG257YEAOZMXUSWK7D76LH": null,
+ "CLMTO3VSAOBAOBSA5IGOO4W7KEMLOFUOIR564IBKMJA7RWEY": null,
+ "JU5DNSHLUW34DT3IQ36JBV6M7EPILLMBALURDAB2KJXF6HQB": null,
+ "VXZXWLNQZFJPNQVPTOFWUPLORZD2XRAFXRVRNLUYTPBO22U5": null,
+ "HNACM55ZSGJ2FGRMOTXLVVLA32BC333QGC4HFCDSZ335YA4N": null,
+ "6J5GIOVKU4PKHHU35DWL3D7GTJFF75FF4FKSP2HPGJ7SQ2DP": null,
+ "O3NJM537IQSKKWM3K7EOQSNQDTR6XKUA7ZR7CWYHYYLHKH63": null,
+ "B4QMXK2EAR5E7KGHLODCP56DX5HW7IQVXWHFFCZ4SPSSNGJK": null,
+ "A5AUZBXKF67OXO34ZSEGVXI5PAIG6W2VG3U5C2Q72SNWYNEI": null,
+ "ZGDQ2AA2IFBSU3APKAFL5AO4C4DXY2YBEHXE5UPPVCTFZ36K": null,
+ "N3XZ5FYZEO3ZX37OMUJX3PIWEEV7TVEXX64KKEZEJICKXMTB": null,
+ "3EVOEEWTD7OABLQJIJYLOSVHBS4SB6QGX7GPDFGWI2DGAWKR": null,
+ "HNAEL3D7E2S7IYLKLIK4CGI56DRGAXA5S6KG3RX75PMJ6BVI": null,
+ "VGVW32CIRX3M45J2CPCUPPHNRGNG55MKAU7YF3CDNMGONW2T": null,
+ "QV5MW2W6WQSHNC6OYMWJAWEQM7LHXRMGWCJ7RI5WQ3JGHARW": null,
+ "IND2PUTLFWXTEUY4MMEXCFJA7JN7DODE5HVWC5CL5ED5IEUB": null,
+ "W2IA75XHJRBRKXLHGB7LXD7ECYEZI4V5N5I37UFXJMFWQMYR": null,
+ "AWTZO6OG6TCOUVYYJCWVP2JYEXRXZ7S7F7QKUKZS7JLPKN3H": null,
+ "TCARJATK42Y66SPMGOZ2LHLT2ZPZW7MHGXL5IVTS272FJV4U": null,
+ "XVHBOY5WQDOTWXVFZYQKZ6GNRWMITJDDLXSJ2T3UWF6PFOHL": null,
+ "CY5FGDYLB4UFR4AJRGLGPQT3W3OERGCXC4JHYKJ4HKSFTGK6": null,
+ "B3SJGD67GKIEAOZISX7HWENPDBYJHNJ47JCREGXQ6G2RXPUZ": null,
+ "LWVJYH7M5KXMLPFAHTMF6FKT3PSIW2GRC37AHF65PQY7OUE4": null,
+ "UUFKWC2DOV4ZQHPDPQPRCBEYNAX6OFZ7ZVJNYGW5YZCMSQIS": null,
+ "K5EC26CUN365DZ3LE2NHOINGZHXQ752A3VTPN5IMSRYSTOMT": null,
+ "22RV6RSSZIAFXOZIRAWJAIMMVHYWGL2TY42U3TG2SPFN3I6P": null,
+ "Q7VEOUC52OLXL53CR4XQSGGR5QZ2QXZTRCBACHQFP2HKN4SZ": null,
+ "OZ2ZBCTBC32VOHHBDABY2U462OHUEUS724RUS7Z6TW5K5ZFQ": null,
+ "EYXYWTX2UYI6MUK5L65WSTX2FDOJASIMG6ER22NLABNGAEMI": null,
+ "U4FJU7RQMXXDMHG7B5WFLXCZBNE5PMV43CE5X4RJSJUABT3U": null,
+ "K3T56AL7IXTAGTVIWZHYRKVPHLLD7UVHV4UNU76F764VGY75": null,
+ "U2BRKWY2RBYV5S3XVZTUZXT55CXMB45KDMNFMVY6LENW2DH5": null,
+ "YKLPZ7SDAG2O6NSJFLVGFVCYMY4WZKXQGHH7OO2BKGGVLQNP": null,
+ "WSC2BHA7H6Q62HJIIGQFX2OU64QX4AEU2RZQVIC7LSIO2JSJ": null,
+ "QIFNFKPJJCYPITMAYDAOEXBVEDAKBBR3DV5ZB7DAVBIAWI5K": null,
+ "NMBGIDIK3BMS5ZPZS6ATTID5BOAXZAH2VUED52JSC5XGI42P": null,
+ "LTSG7BGZVBLLXM5U2QDW5LNNPM3B5EQZPHES7JXU2EAQG266": null,
+ "5MZMVLLM7YHR4PTQCGDGWFQQLNN532WMTFGX5CFTDURBYEOH": null,
+ "UOMT2ERDBVXC3LRYKCVVUNROBWPGFHFWKFCW65HAPXN2H4FD": null,
+ "RFYZPAIVYHTITTR5AKOBAMYKOA3VSKRTK4P4ZOS7JFSVEY53": null,
+ "QQJGQV6BSW6PL4DZGQDWWVTF7U5MEVPQABOA4IRP7NOD4V4V": null,
+ "EFOSJBHVPSGTB3O374JFJW6MVW47ODOZQNKYSWHR5W6UZECP": null,
+ "YTL42MLIGIUD6Q3AMVMJ6ZMWNSXSUWCKV4ZUQWSGTEOATQC4": null,
+ "F5IL5OV3Y6E4QEE7JMQTKV6ULJ5AQQKQPZ23VXK72AV2P7XG": null,
+ "AZEV37T65EWVWQJSISCHTYHLWRXWCR6XD4LJ4KFLJ6RAOPF5": null,
+ "T5TAAFPNZLVDYHSNNHIJW4KBZWNFT5CMIPIWW3EFKPU4REYG": null,
+ "W326OLSKXRLU6MEIVUTKFFHFGXEH3VM43F353L3NHQP6HE2Q": null,
+ "MIIUZQ4KGTLA66VIE7WPN4T43SR6Q42YUKWEP6467AYWKU62": null,
+ "AXSJHLTL4FXCMLLJTQS4HIBRGUY6ATR3GZPV4MGXLWNFHDYU": null,
+ "MC2CMWSKD2HMTVIWCMSPZWHEGW73RWEZKU3IFZJM33IW3VI6": null,
+ "ZGOZHC22WZN6LSY3KK4HK6RF6F73VWSB7U47KZSLTYOQZAVH": null,
+ "HU26VJYM5YNEXCOCWCVEQNNZ2WAPFEVYK67JZOHMSZIOUWJN": null,
+ "6ZA46O27SWCAX5MQUHZYFV5UNQUDLZG4LDA6VILK6YRQMMZ5": null,
+ "LMGGW3CAN4T6DSVJZB46LOBI6KTZN7CKHNZ6BMWRBL5PVYXX": null,
+ "RZKIP3F5SY2P4NWANAQZJHPH34CU3GMQ4VCN4QXMP7ZBSQ43": null,
+ "CMUAX53FME5Y62VC7T7ZOUZMOPHBDFVLMVVMHYDDBZEHMOOA": null,
+ "ORTA47K5MLIHEUXQTFFTQNW2RMYQSTVDJXUNIF334SAJJYMC": null,
+ "XEGLAWIOOPE25FDXHN65P4FYJVB46M4NGGXFAWZ5VDWBBMU4": null,
+ "WZGXOCCN6GENKYYAYCH6UQD45BIPSYMQOZYAYRU3S2JNJLU3": null,
+ "MXDDSZA6VTTYU56ONDE4QZMB3L2D7A5SCRCIVBYYVIKFDFLU": null,
+ "JJMW475CTRXRR4R3GEZ77STHMKHTQZYFZHFUFXEB77SV2W3H": null,
+ "J3TNJVNF7QSTIJDEEZMLTQECNOES4PXQALSR5ZPYDTIVVKUB": null,
+ "Q5EHPI6GHPPZBATKHYYEXNDSYMW6QVAVKKHC2XO7RU7XXKQ3": null,
+ "B6WGKJEZH7XBZ4VFFRCBFYKC2Z2ZQXMY2HJQUH4LVI3EDMMU": null,
+ "NZ737IT3LUIMH56R66WFETEHFDOZSNVPTHMQTW3JHVTN562C": null,
+ "B52PWLRNPFN73AA63O6JFLEYSPFQEIHQ6AI6YC7KWOYFE5OW": null,
+ "7UTTRFE2I5WB2XZA37L6F7RWCII6S6HLXZRTLSJYFOENAYPI": null,
+ "TJJDGG7R4RNVAOXWRZRZB5K7W2Y6XB7LUYBDOY6H5IDRM3ML": null,
+ "TOG35JU7ULNRY3DE2XYDZ25WZETRSO5WSFFYSZT5IIALO3ZP": null,
+ "2QZKK4CMZNIKUWZZB22ASDR2BYNRAMTNS7MVLBA7Z7RDKZDV": null,
+ "US4C6FXHKR4GCRU6IJQHSAJXLNQGUDCDEPEQDU5C5D76I6XX": null,
+ "QOPUXM3ZKXTPVGMVVDMUZZ75KH2S7DKYXSFCQ3R5RYO5WP2J": null,
+ "GZ2T37SKRE3ZX7FARFWWF3WG443LVP5X6ENDLDHO7GBWYHHM": null,
+ "VSOOUSBMGIPEVAPYAGWZOLDUW5HSTRMTBRTUYLQNHKVUBLJ7": null,
+ "45HJFJQ3YKDBFDZPNDO46YT7DLG754XZWMGJQ7YPJXQ4G4N4": null,
+ "4KY77KV2OWWFEVIBSUZRGZF2V47BEFFHIHNMAQVK65E34ZF3": null,
+ "NB334WI2DNPLWHGXBNHSU4436ZYDQ4D2S3JMLDOM35QINZTR": null,
+ "7K23M4FJGIQFWUMPRDZIK32MF7HZULYYSS5Z7N7QTEJGET3D": null,
+ "ZBMNFKSEG2PXKJZIXIK2MHJQ2ONRJUJVCDBOCHNERPGMN2NQ": null,
+ "YMCOX2NMBDL4J6Z7JBEWHFSCWON4ZSBSBU2WONEYYOYRA75K": null,
+ "GDOVKPAWZFHLAPQ5YHCFWL4NAMC5G2DDXFWUTR27XQ7LEOOQ": null,
+ "CYBYK7ESXTUUHYQVPMDI7VWAZO5TVGLIB3GB7NYRYVDLMYKG": null,
+ "4IYLX3IDNUJ2DWT4RM3QJ3IMVE22X67EW5KWSMZHIU4W2W5B": null,
+ "EBWXJZ3PX7LE4JNB2XWJJNXL5QBVSJQSXAUJMJ34YJKR3JJU": null,
+ "LEKOXMXHU57JTRZUKMCW4WDCAKEOXPHJ34ULXN5P6DIEOYLL": null,
+ "BESPMR4LBE3G4MTWR22CVBYH6NW43HO4ILTSV3P543JZUBD7": null,
+ "5SYIBXIHGJGE4WHL2HYUNK3X4JUGOJOUMKVJMMXSQDKJZHFJ": null,
+ "XN42HP3QOV34GMJA5VINVW3O7KWW2GV7VDKAZDFBCC6SSHNQ": null,
+ "326BDEDWGYW3IMEHP63I6LVGSRMS6DUUNMPY3YVWXCH3YA67": null,
+ "FYNTVFBPC37FYGOXFIXJP57FNX5MYDGUWIMUYMFOJSOXRRDS": null,
+ "7DRCBIQP4EXAVNEMWOZHAEZ2W2EIMKD77PH6JJWP2BDN6NFN": null,
+ "7Z7LWVFB2Z26EVYZPLQAOQ7LXLADTHUA7QGKDRFLXRQ3ZJUX": null,
+ "EOZ2S4T75U62LD4QUZNTOHP7SNVJUNNSE7WWGHCMC75O4XPW": null,
+ "TVG4ZY3YVNQV7WPZ2CEW26QTGWUBVJV7FTRF4TE54446J5SI": null,
+ "MQ62OHPXMGGASRXKOH5MEVGLYHKNWBT3DC7XSXPXFHFXFO5C": null,
+ "MBRTEJLOZ6U43EOO2IS3AHNDCT7WUEK4XN5ZRMTPBKUFXUWU": null,
+ "24WJGDPNT4E7SQT2IBSTHJGYBMEBKS7VPGJYBRRAT5YXNBC4": null,
+ "3KD7I6FOTRB4U2JBT7CIJOPD5XHFWHESYJJQTQVUQ3IGIPVZ": null,
+ "25XHQ7A3DWKVDBX2ZFNIHKOGJCXY73N4Q6PUBEWGH2I55XVP": null,
+ "GE3YTUBPOT5CFJU2LQVMZVC67NFNLXVWNTV4ERN6BHVGCGYL": null,
+ "VXE2WHW6UWRE4WYTAVFAQ75IBYUPNZVMHJC44DGDPIAEOVVE": null,
+ "5JRWFOAEX5TNCAMYGF44C72EWF5NTXIRSVST5J3N6N5SLGFF": null,
+ "TYNIMWTDY2D565BJUNMFXTJHBUMWOTD4YSAFILKXPKX6FKRO": null,
+ "RDUDIY6N4RRUA6YEBBBFPBNYFZQUWRVURNYGJPEU6EHJA64H": null,
+ "MMRLX63PFJLWBJUTXCSLALIGK5YOHTLAY64WFQIYQJCX4QID": null,
+ "P4T7UPQNUAFMAJ3G4KBRHOQP5GCJP46XXYKPTTENUI36YQEP": null,
+ "VNAKVK3A4TN7WEZAJBJVMUVIKIUWCNH7B373DP7WAM7ZXYDD": null,
+ "VAPNA5BJL7OF7VRVSUEFAG6RZWENO5VOGMFVN6AB4A7H4VU3": null,
+ "TLVHDKN7326OHNXMBBJIVQW5FFFGPXSUR2IVTMPLOLPPJQW2": null,
+ "LD4OK3CY7MQGHUMQOMPAJY2NZUASJLSLWVSIIKIYYYAFYHIK": null,
+ "DXHC3XJCJJG2SMU4O2HDPMJHO4PNNYGIMLB5KSCQPNLBAJER": null,
+ "SANGKO55HOXMBC627JYHVBE3FH6KJL74ITOVF5GYODRRMEMP": null,
+ "TOQW7HYYWSFH3NKL7SITPX5H4HLAH7BKL35ECCAILLJ5B4TA": null,
+ "WUKAWAQHSBKAUAYEQ4UA5PKFB4676VQNQFLXUIX6UCDFZ472": null,
+ "BDU5VYNLNHR6HOLMZI4XSDERPTMVJ4LBUX5XP6W2BQWH3NLR": null,
+ "R6BT3RGKODHZN2AEX26XHNSLCHGPGMQ7IS2ONRTZEPJECW7A": null,
+ "E7Z4FLW3UW2ALRLPSMHQWJWBK7VWS63H3AUZZL6LHCIG3Q5B": null,
+ "FUZAITDO5EH4BU3ZAN55R2RQZ75LRAYI4X3MEJKJD44VHOT7": null,
+ "7SZ7VZ5O2OFPJL3K5JJKH3C2ZYAJCWW5GYXSLVFHRRATZDFA": null,
+ "6H7VKVPSP4MHB6P7H5KLQQN3Q6ZSS65OMK6GJ3JIUMHQINMC": null,
+ "QNCN75MNVAVH2OQR3JE53SGCKLXPSB2XBTZ55J3AX37AV5HT": null,
+ "JCSYRKMHDGVUVZO65VQVAV5SGQS5IRS4UGFNFKMYP6CXMHXN": null,
+ "JXX5VCQU2Q73TK5ICSFX3QIGA6E4IFRTGKPZZY32UTB2RY2Z": null,
+ "BMUAPYFGRJO7ZQAMMSSEADU2RC3LPAAXTORXLSIUCXCSSC2P": null,
+ "3SPFCAR2V2PQA3RWOY5ZZXI2V6UEUCZWL6SNCGEAGNR2JQZV": null,
+ "KUW7Z4ZHRUX6DI6Y3ME7A33SXUAQPXFAHRG4IEU32ETMGTLC": null,
+ "64F67UZGQHZUXLN6HCATAAX2FUQNK2WVOEJGBQ27H5DVZFC3": null,
+ "GHMJSW2TE6E3JLFDD7T6FI67HBDHNDVLGEKATAO5G33TID57": null,
+ "6BZEOJR372ZLNXUMEQQUKHHDCAOE5W4YDT3VWGI3YYPYDC5R": null,
+ "62JOKD5O25I7DBDFMM2BRQP4HI2VJTUHMEF3G3C7JFJF2VNL": null,
+ "NEF5ANHSBNEXLOP7FFH7ZVHPDOCHQQ6EYOG64JDZNIHBT44L": null,
+ "ZKLJACJIQT6M7KUY3VWTMQ4WD7RETAWN7LDUB7UQA3NZHZLC": null,
+ "VBZVHDFHE464JTYWCLYNAA65RDMVURJHVZHWRL3IKTNT6AH6": null,
+ "FHBYZO5SUBQ56J72DWYOUZSDKXE3SKDRWBEGLQPHWUGVSW5B": null,
+ "HHWRIAY52UXIOIKQOL3PBERZFDCQXAAUIDT4RTZF2VETEY3Q": null,
+ "JALKMRCQEIXX3JPLOACUZ2DKA5I2RWSSSIYDVSURW475XHR7": null,
+ "IMQUFG6JBGWA7R3D3NRMJNOF5MKE2NU4H2LAI6UPIHUEY2ZD": null,
+ "GWSUUFLKG23Z4BXTLB2HJHYVRWAWHKV5MA5RVOEE77Z65ILK": null,
+ "ILKEEWZSHVZSQ5M5VAZH6MJPBVQVV63SCQSX73YGTOQZBFKB": null,
+ "TBU3SS7AG7QISWIK2KKNE77ISJUEVH3ZV7QZJAEHLMAOUCEZ": null,
+ "EPN2PRVPXZGZ6WRX5ZMG6UPIM2V2NEA4BBC7ZDAIVCEKMHR5": null,
+ "Z7GJAUSWDAH2JUMVX6IZB2PRSIUHYUKXGKJDM7FXVFDJNDUU": null,
+ "APOEQP3DLJGKFU7424CJJBFDTWODGF45H7HSXT3GO2UC3VCI": null,
+ "LCYBWI4HYCSVGBSWWDJYDCWQZGJP2KVSXUUJBO3XFUWOS4SA": null,
+ "KOTWM653HSOQ2JHNAZGZZA5FGBBJCCBYPDVDE7WDXXIHTULF": null,
+ "TIPJO4GHBUJQKWKVHK5RF2NI5Z6FAIEBGFPR5L4SSCLS6IE6": null,
+ "QJZMGE4B6UPJ35KTTNIAHWTFV7DFQZ2QMF6DLHB2AHZQ45CD": null,
+ "SDV2RDMAXCYWHJJRPTEIZVE6SJST7KQJB57AXCWFVO54E2GX": null,
+ "4NW6WJDWXCXG2TS24H4I7WF2IGROPO4UBN2HJ64M3CWBU2M7": null,
+ "GJPMFWNBHZ63VB5XWIM52UO22ANEXDYLHTF24LGBC7XXI4SH": null,
+ "I3TPFLVZ47TOOMM2G35JFQAYHLAIU3OXV4SXZEP67DNGYXN3": null,
+ "QMPKHHYWWSV32R2LHCWFKBFDXUDUXTZ7FRZK3TCF25CSFNWD": null,
+ "J3C6XZSMIXH2SQMBUEVWEI6UZVX2GJZCAYSPD74BBUUK45RS": null,
+ "WHK5HZ42VH6IJ4U4EUKKVLRAID2FH2YISR7IV6FMNHQPPSH7": null,
+ "C62NUQB2FUJTY5VRNI6ND26FXCUVACSUTTR6NZMNQPYK6357": null,
+ "2JXXJE7WN7QWO6X3ESQCSDDBTZXOY43L5AODQUIR5P6Y4PZB": null,
+ "FQVJ4Y4GES3RGRABQCJIDIYEUNTIGETQ5EOXW25SZSYNJENT": null,
+ "IH2YJNGRU5Y3ODZHMWNV3TIU2MGCNLIPV75QL3JL4I7PH5ZI": null,
+ "RYUBMVYE4PL6JJOSBM57NE2RFKCY2EB3EQR3QU45MJHEX5IN": null,
+ "KRVCQJ6VSHM52MLDNS65PKDYHNBJAHCONQCNLXBD76LDCOFY": null,
+ "W7MB2FYKYWXDXNOKVWJW7TSUANZIGE25NABNIAK7VLPLKQQH": null,
+ "QUJNQSAHDXMNHKHHIRBEFONX6NRV4NA7NKFRDI72ZKVZXR32": null,
+ "SRQAJHTEQYVNHCJDTYHA72VSYS4FPTHXGPFYP6CQRTEUIWVN": null,
+ "GYQMORZKT4JGWGOD4KBEMUB3XZNUM7H4G5IRA6SYDZOGAPVF": null,
+ "73P37OKSAJ5SWM5NJ2QWCTKPTFNLORRRGBNJWR7BTCRLKNCO": null,
+ "D7YVGR63MRZ5YS3UTCUZ7REPWGB6EMGNI3LXZUDAYBSZVGHZ": null,
+ "JNUZON5EE4CF5UIPXIAU5HKQSBN6O2C3OXJ5IT6HPZMUBXRK": null,
+ "3UMKRHCWRV2WNUWPF4WKESLI6EOHPFC6FOXF2MGP6E7GPKF7": null,
+ "ZPWCDBHEOCZRBAVIQNGRQ4WNKSE4XCXWH3PQSBJWVTMLP6AD": null,
+ "RCOP6UXD6CG5XYUXFXT7HDAWQA2LRA52R2NVABFBB574N62D": null,
+ "6EHQW3VGWSY5MQKBQ4PWU2YD4KKXPBUFJCBEEY6GKOGGGT4P": null,
+ "V72EUDLMYSS47DCO7XIEYQO4S6KK7ME4C6VN6IWLZALPDIR2": null,
+ "EX6JHHNN4R7BQVBTVXYRD54J6BLOJTRHM64QBK3DHUWW37KF": null,
+ "6GGFMOEZN5PBE67AJM6XJKDL7V6X26X3TH2WVOO4X2MEQJKO": null,
+ "LYM2NDKVFTJ2IJV2G5HTDDXFDAAHVHVMVTNGBAOABW4JLB7V": null,
+ "5GPR3EHGCAFLKH4CTOZK3JBHCJSEEFD2Y5GS5Y3B5FPXAK6H": null,
+ "3TVZ6BP47YPHI4HKRIK43AJPRVM5UO736FF7WEXI6FJMTKY7": null,
+ "XDL7LZWG4CIO574WINYHCXMGRRZV5BMZQH6GPTTVPBWGV4MD": null,
+ "OHDX42IVKOGGQVXFE7Q3DKX2HNXGIZRAZ5TVVKQ34BO7UKPB": null,
+ "QHSOVA5SCRL5AK65IALQZWLHPSMLOOHHS6JN3LHDCN7DEHJ7": null,
+ "EI2J32TUZKPKSWOYH7EPPKHISCJ5SPTUFJXENKZJFAPEFQJL": null,
+ "3FFPGZBSH57RTBR326VUSL4G3DELAIPWCCHB77LFG5CBS2YU": null,
+ "VOLJPHGJOQKGKQ3PQGRLYJBZCIF3T355GXCQQKV34USNOXNX": null,
+ "ZASYP4G3K3DX6MMU2CK2P6GJ2PKRQFQGFVEZGTMIRAZBDMOC": null,
+ "MSLOXTCY6MPU6XRGIJ7ZGFBB5J4RTGTEC2UW2LO5MIKPXFJO": null,
+ "DM3ZAC4JV4IDN7ZZ2OLHAUCUEWYTMLZSQQEARJF4JVBUTE2D": null,
+ "KWIXQOXXGHTUPBDCHXV6ET4YZXIDCYZEQTFIRHD7DTMSGZ3X": null,
+ "SOF4BRIWEU5XLSXVFE6IHVVDYG73RK5HJACKPUNFRNEDHRWS": null,
+ "4FECMJE2AGQGN54LFXTIQFZC6ZVJN3LY62YCS4E65PMW2K5J": null,
+ "VDCWL2B5OEDDB2YGM7Y23WLJPJBFESITFU5AWDPUKDUMFPBO": null,
+ "W6VC6MV4GBWJ7IDAX4DQHWJSBUJHJN7ADFJ53NBVND3TXUCZ": null,
+ "Z3TTBMVW3FCTJPLHXITOVK4LPLUFJJY3CIYKJ4QY2DANJ53R": null,
+ "O6N3PZGXI5B6NBTOFPB5WWIRJ66O4FYLSGHDIJLVPT25YPWK": null,
+ "RXCNDGG7CDEMAOGCALTPXWLUL7A67D3JSKOZSZEQBLDW2F3S": null,
+ "XVKBWW7HRXDBW3YXSBMO7WVEUPVQ7LRZ44RVFI27PYZO3NTS": null,
+ "XUSRB4YQDOYJALL7CK2OYFPL7GKI6XOFYHP7HTW5H3PF333V": null,
+ "PCCHIGPV6SWW2O4YRPMFMNF5YVW6QY5IF7JPYAULF5WPTYKB": null,
+ "MHRU7JFEPHHUAULYL34RAEAGBU2ARZG63TGIIS7MHEQUKWPY": null,
+ "Y6EDYRAB7V6NAP57DRIKQ3SB57XBPN7MAWD7F3DM4DKWIAMA": null,
+ "JQXEFOTP5HPBTKL4VAXYCMJFZVGSAM3JVLFJPQ6KHVLCRXFI": null,
+ "U53PDNGH4IKMP4PW6AJV6K5Q43PYB6VUZ3IJVEKZK32IR5WJ": null,
+ "52CB2E7VQJ3JJ2SXPHQZZMER64TM2JQBSW3JMX7XITCNSWDT": null,
+ "3JLBHZFBPZQTO3MLCW6S5N3RIR42N6RGDHMP4U6IO6STOOVT": null,
+ "YTFVKDUY6LHHBY5JBBTT75RYI73Y2Y2DFT5PBMOLEVBJEN4Y": null,
+ "TAHMINQIUDTCEBCJ4UH2PUXO5TYMIIZTH4BX26S4NRMPFD6Q": null,
+ "4VJIQ6FLWV6ONBHRWDR34KXCTHL7HIXSQAF3FAKOMZ2C7QV7": null,
+ "IQWFFVGP6CPSAQWMKA3SWYOXAUL2YCD3EJYRQ56S3VXWAMUF": null,
+ "J2FABCRQ7HZFV4FKZKY2UOXRUO4FYXANTTWL27ANRYY6XZC2": null,
+ "G3TOY5CIOYIELRC2S35CGAS2E36TDLTO5XYXHFVKZNDFQC6F": null,
+ "SDKQB4B47LL6CAFDDYJWDS4X7COKTZOCQ6ELJBL2YF6RHZJC": null,
+ "L76D3LKKTUAWNPDXKTWE7JCFCRFVI4UX6NKQS3CAA2OWVF4K": null,
+ "QVYYK2GQF7DHSJACSOZPOQUCWWIYTRGEWMBIR5RRCV2EPQ5X": null,
+ "UM3PJVMZNDU2GJ6KVY5VQ2HPGMSJKVAQBDRKZKHBPBRCU5SO": null,
+ "RDIJQSPXHAUB7XSQQPOL3CNUR5AJAJEWAFYFSDO5G4QWZQCV": null,
+ "3CAVVDQOCSMOPC54JWKI5ITUIHAOV6SKAIIAAPAAJLBDTXEM": null,
+ "JHLSLTDSRVKDHWRGT55OZ5NC6YHGD35WHW4GPK77VZWPNVKN": null,
+ "6K266T5MHDGFA2XECSFBMTQDEE2C4S45S53XBODESR4ERZQ2": null,
+ "VJVWAFFKWR2KSTFIWGAKDUG5VQTO3BPTI7YFYZWZSBMMQOIN": null,
+ "LBSXWCQNCHYUG5M255T3W72NBPR5MBEPO7DFBCD277HSH4DU": null,
+ "WHJGXILLMK23VGXI2OY76SYJQOQHQOM6OSLT4BWU2KSD3OAD": null,
+ "DVNEV7ANOMDRQDHTEMD6CXCTO7NOY2MQQOLI47U4DDOJ2A2M": null,
+ "TV752NASHG7FG2JOGS5P6QLJ7E4W5NX7F3OYYRPOEFZ2NREE": null,
+ "S4DHHYVQ4RQ7HBAXW5ZKISZMULMLCFTSBFICXNLI2OD7YNF6": null,
+ "HSRHOS56TX6EEDHUZX7K4K6Y3R2UNHRINXWVK5WBWHDPE5HF": null,
+ "I67YQZJ4PXHFWHNHMK5SKUEFIL4EEP5B4BH3TJNHZPQOUXDM": null,
+ "5AJTMUDFBWW3EGM2TH2YAJYXIR6GKM7RPBYBRV6KEQPDDLM6": null,
+ "6V3SAQQC44I3CSDERRKA2533GYIWWHUZVR67JAWIBPJJBDBI": null,
+ "5I6EFWIWLDNJQAZNZN326TUHCUY5YOD4ITIT6NL7LWIK6RP4": null,
+ "NVT5LE35FIT6LKWBI5XZO2Q7CTQBFJ3IOIAFNXI7PGVHEE5W": null,
+ "E5I534XUV7GRNCMHBVFI7FMTSPYBGXKOFVXXSEQYYLVGCASL": null,
+ "3XDVU325YQTEXC7HFJKKKH7CTCCNNJZMV6VRT5GVED7HFKMZ": null,
+ "3UJYDR6QUVSSCRHJT6WWNEHC5OMYXOPL3EF26PU2A5HESFG5": null,
+ "UPRVTQXNXYCZG4JZIR7GZCCYTXR5VTUR2OKAJXEWGATCSIOH": null,
+ "2QLXXZPU57ZXMLJHEYDS6IHFLQHOKANOE5URI2TRNFNSIFUG": null,
+ "JFL3SN7LZ7M4RUZXRTYFQTUMYWYHO4P3ZKBGFDC2GGWZBPEA": null,
+ "SBLHOHHAOCNEVQI3UPBY5S4UKTTIH3DEJEDJHWMJ6VEWWTCL": null,
+ "TIE3GNWA2BE2WGFA7Y3KEHF4IF77M5XHZB3DIQLOE3GG4VQM": null,
+ "BB7XBWIYV33TZGTKHTBL4PDPH5ZQ6X7ZCMHS3KIQEJOLOXVH": null,
+ "6WO2JPOCRLCUSXS7BHNKFBDGFSEXCWYUFPK5SDZJTFJAEJRV": null,
+ "RCJUMHWKL3IBJ4ZVWHK4RCZ4RCVVTMG5ZO2KWZOIVZLJTSMT": null,
+ "YIXCNMIMZBA7NK2A5QOCLE77QFF6QDS7NGIHKMILIUB37EMH": null,
+ "ZSI25IY4L2U7CRPBLOYY5TCSAVG22XHHZFC7JZCRAVY46BWH": null,
+ "HUSGTJENHNIBJ7VSWZPOWFHHKKYH7H2YSP32LLQ2N7CWKRME": null,
+ "WTIJK6LZPBOCIJFBZEG26BETKTY5PJKQK5D3M5WVPWVSV7LN": null,
+ "ITSWONDXALFBD4WMGSMRKQXCVTL7JRKVFEHOAOODRQEFFSWC": null,
+ "IY3RQGYC2ME2TEUBYAQG5WJ7WOAJV5GTO6P3FKXWOLSJWGCD": null,
+ "MDSHVZ5WHCTCYB34ZABEUJJRXHQDKO5MSC5YVTGPMNJRXQK7": null,
+ "KHNSXQTOSCRSTX63S7OVO2LGMD7OVR6PZIGEKL5ZDYPCEKK6": null,
+ "LECVNJKLFT6P2HWX3H7ZC5DKJSSRZ7PWZVBN735K7I45SOX4": null,
+ "HFEO55KM3XH34UWCRYM5CFNQ6OFRAKM3U6TABNQDP74DT4JQ": null,
+ "QZOWC3TAAU67PVSBRJOOVZCBSRIOZCMLPB3FH4GS37WOSTEZ": null,
+ "TSB72AJ4HHOBEYK4CGFX3W4RW3SIECQYJMYISHTPPCGQNLFD": null,
+ "6AB4YKYVMU2PXRABAUBBBF4BJ3IOFKYWBJ2IMFMRVLCBI4S4": null,
+ "E3TI3V725PEP7U2CYZUUKJEBPAHOEI5SYCR3YZCMGD5EGYHF": null,
+ "APKJUBCO5NHY6QBYNA2ADB5TTPLCNZMHG7HGXXOLRBOZD46Y": null,
+ "QKL26OQG6L54OCKFPLMXI6M3EG2HI4EG34D7BNI5SBZG6OF7": null,
+ "W4KKIH4RPYXL4JZY24JWLHOATFNENBMSEQQ3DI7WW4PQIJQ3": null,
+ "4XJPWCDQXS6MSKI4EMFPENOX5FV7KMKKZ77LV6GJ6S7ZBVB2": null,
+ "LWMCTL5CEAVQDT5PEXFKRK7Q264CNVV6AU657OQ3SSPCDGSQ": null,
+ "CBMCT6STEYDOVXT6OW34OXGZBN2A77OGBPDRN5AZK4RXNEV5": null,
+ "OUGRMVL7PTQ3GJNWQ5WP7XXNYBIMVWKSNQ2QZH5RZRDEGUND": null,
+ "XKVAYVNQL7KW5EHGEWYRPSWDXNUEKP3YC3OXGEHKG7PGNZHL": null,
+ "ZLO6BOTXUEEW7UOENY2NVIFLSG37YPUETQBYYCQBJM5VXNG4": null,
+ "QMZJWAJYYE6WZQX3OKY34BPU7ZZN6ECDNIZOIXREE6AP3WJF": null,
+ "B5FU7VNVUSA3ODDEUDVTKE7GWPU3JQXWHRWYGLT6VFKSFYAA": null,
+ "HLHSAJUSHU5EY26UTR2UDJAM3BIHYYHF46MNLTQZJWDAUCDO": null,
+ "N73SLU2EDTPQ54MY5NWT7KPSVTO3TOGPO3DGX4HQYPZMFYJV": null,
+ "7B47MDGTJA3P2WX3KWLLESWTC7RJUSVUSBI42SATEYZVPL5K": null,
+ "YYLWTHMS5POBP3WVX5Q4NXQ77STWJTAHE6QK7GYMBIJU3TSX": null,
+ "JI7Q6GUWUTSJPHKUII5IVOUZ2QQ53EWNWCUM4PKECXWSVSEK": null,
+ "XR4W6GZYNYIDAFU7MWMIGFGF63OLKU4FWQZ4RAN3HWNXUINB": null,
+ "3KX2TVZZAQSYQHLDSWMVZVF4UAXYONTXXFWSGI6CJ56DXU6O": null,
+ "UR6JGWK36D4CU63DYI722UFUKLB2S52ZI4OAVZM7CVGGY3SW": null,
+ "VGQOGZH3H5IAFESOYWHOQGU5FHP4BJAUUK2B7AKDCJX3PUE5": null,
+ "Y5GO3VITRDTHWTMUULEA44BVX3GHVLIWFMTNUY2APWRL3JLD": null,
+ "F7U4AV4VU7YAEDK6SI64JJUNEHG2MEFLKNOI77IVDQS7BGJK": null,
+ "D77762UIMSS52GNAPWFCEEFPWGYLBPKWMBN75S3HCOI2SYCL": null,
+ "NNRBK2PM7FI7MVFBSUUCZVFTDOKXLNVK6I4MMUXU4AKDPTCK": null,
+ "YSGZXEZQRGZ3DSMNCNH6GSWGCRWQSIRD3IOR5E3XEUH5RORJ": null,
+ "P6KRZXZTESTNZHYLZFTDLZMIGIN5H74H2KYUTNRIC3JWCNJ2": null,
+ "QK36OWDC6RHQIASJXU2HZVIBARNIESSCWKICTRQ4B3OFUB6D": null,
+ "JQBWWRLDDMH3HACHKR7EKXFCAAR5E62DX3ALK22Y5AFA4JDZ": null,
+ "WWOLYDEZIQARIEC65MFSVB5RH3236B3E2YSGNEN2QY6A2G54": null,
+ "QT5UVU5QUPEY7VCTTW26JTO2FBUUBCRBYZORWGTYQZ2JZSCH": null,
+ "PJQFD75BGF35X4N33WD423KSDLIAWJNAZUBXQTUGHOW4PTXJ": null,
+ "A5VRG2DRN3CKKTP2DN5YNILXVCZRTKFXWILKWLZ6PNVKJTM5": null,
+ "TY4YPLWS4MDSKPG2HHIRSAWK37LFVB357RGGBRFP2P332HJL": null,
+ "SUC7ZGB6YKDYNAP6NTUZVEVNDL22KBCRZIGAWSOBUAL55LDE": null,
+ "Z5I7WKVA6754S4G7QWWXYTRZ3SGEG4B3KG5MLHP3GJDI3H7M": null,
+ "VLGCWOT665AT2R6EMOAVHNKVM2NKPSV4KI4CMNEUZ2YMI3UP": null,
+ "YJMQW3C2NIIZKTJY34XRL4HQ5A7EUMLMXTJFHHRE3NR3QGZF": null,
+ "TOEB56GVW7OQ7QLL25ZY3ABP4ZQS2ZZMIJRNTILE5CWA2IZB": null,
+ "5RGLCKE6D2MM5YH74OJBDHTOZIM7LN3EIYBLXVF4PGNBZON4": null,
+ "QMQPPFLB6NCEBYCQ5U2YWVYWRKZSFJLCDAAPYSPURDLXAU6G": null,
+ "UTAFBURT6XHHZV3Y5OZJBJJQT4342SSCOLWT35GZIJUPWTTM": null,
+ "XCIXTAB5SB5EMQLZW7GCBUS2N3XU44YELMLSYIFAJHHGP3VS": null,
+ "LWL5AM7Q4JPEDEORTLNDWUF5X4AIUI4QC5S4CWUXKXIWP6FP": null,
+ "M4RONO5HAPE25Q46SSRBVQLEXPCVQLKOKX2NYQWX2SNNGEVB": null,
+ "UVSHBLSXOHEF3AGG5PDTTDFVXNQPRHCNUTXYDEXJVXI7JCPL": null,
+ "C3PB24XOHCI52DU64XQL2V2OKZZYG5B4T6PUU44DZCH4DMSS": null,
+ "VGACAPDUB2J7KLW5PA474JQZWZ6QCDYYB2I32ZFYGXR64M2Y": null,
+ "NNDVFWEC2OE56D5PLJWEEVG25TMXCXISOUOYDOUEMUZRMZK4": null,
+ "57TIZBR3DXRX74YXCSJ2RXLZRXKX3K7H6WPS7DVONX7DOJY3": null,
+ "RFSCST6ITGG53EAZEBXD2VFQTJ53ATEOORQV6SQG5OSDR3FM": null,
+ "YLIXTKYNMODZNBM3L2EL435GD2LRJ5XAJBDZSYCU3OPZ4N4V": null,
+ "FBEPPECF3L4RB6QBQLGL44JDBCQCTQ5MOFYFCUQVNL4DCQYV": null,
+ "PAJST32KEXY6I2Y57OASSUFLF2BLPQQ7NZMVN6EVR7JS5LY3": null,
+ "76MHL43MEQWH6R552TULI3TLBOR22YDMJC5ZYQVWCNI4BWF2": null,
+ "A6KZM4OXBKW2NJ7X545F4LIDSC7LIAFYJ4CJSWW2BWSIRWUY": null,
+ "VND76C7TCKQT6R4X56OD4UYSOBZGC5BQ3LR6RXOX6LA3I5F6": null,
+ "CE2NODHXCRS4ML26HTI77Q57R7ZXKZO433LHHA66I5U3Y5GP": null,
+ "3DGAXWQDLZBPUYZPBGMRZG5DOBPTIHKAXFSCBLMEQHZ2A4W2": null,
+ "NAOTRV3ZNB2PK6RZJZ4UEQVF5M3YISGJNFZQQWPV2S5RL7XM": null,
+ "HLCSR65OBO7BJQPOA65Q6BRDVFPOL7FJII2LOANRJNUM2DDU": null,
+ "YCBI6X4JLTHKGAFR7XYKELWE7JW6VHLMFJIWF2ZC7BPCQFFR": null,
+ "QEF3LB5GFEMHAUDKPPNYGRKUUV6PAWU5XXYCFIHXI7PLGVGW": null,
+ "ABBQK5JKJZLMX4KGFODWSEHOPDTRHGDZCBO3ULBVOGUIAAGI": null,
+ "HZLWUQNBAZJSDZEB6IPXQIUMVWUPYVMVP2N72NJ4MOZFUKGT": null,
+ "7SQCYMGSMYW47TXUWC2J5674L4CRDIAO34D342D7IJ6OE23F": null,
+ "YAQCDYBXIOY3KZGFJCPS5VD7YQBPBFFFYEA4DPWFWJCWCJXA": null,
+ "HCZ7SSO422NW6O3ARCBUGNBCMUVEAHXMVKAJSDBHAQSFXIMV": null,
+ "DPX2FNJNMFQT34DLAOEIN4KMWJYLOEGV7U4VDH635AG6UA5T": null,
+ "QUO6FPOFFXUUKAZXYRN7N2MMT7IOJEG6NLFIH7B5JI5V2Y44": null,
+ "UJ6G5JMOINYVRLVISHWTGQDDDWA6X3QDFICKY4QQIHG3QMF4": null,
+ "ZR3VRUOZMQE4EMVT2WDB45TJ7KB5AGU5UBBPNL2A2D255MOL": null,
+ "2AFEUH4R6YAJZEODKJBMLDM4ANLCKRU2C33HFSVU2LLXZW5Y": null,
+ "3S4PV2VOBFB6GFRPG5SB3EHMZE5M7VAAFRJ3JQYHZEFTEKFX": null,
+ "6EFK4THSCBEG4LDSVE5N5FXSQJTYB5SQ7LKJRBL6IYIREWTN": null,
+ "HHYCWLKLIII7MJ4MYU7CJZ4YPOOUVWOKLXHZV5NT6LU7WWGX": null,
+ "XYRSXFI6XRY3YACAIVIZJAVKFTZPRH5FXD7E4P4LYUGX6I5U": null,
+ "6W72FMK5AP56TNCZ3LE5OTYZ3WYPARBB5AOXDVHGCBOTWZTO": null,
+ "7YNUW4DUCHUDJSSAWSYOYM2QXWTVSJWGDPIG2EAABTU4QLU5": null,
+ "HNVXP5XULHDT666ND2M3X2APGXOBCB7SCQB2D7MFQKKNVOS4": null,
+ "MLCMV4777C55OEVW3SFO4VHH56O7BSIDLZFYYTY3JXNN4DWG": null,
+ "MSNRSOCYC3HQCUXRLCBYFYQOMJFBDOSHJ3HYYYOHEPODETEE": null,
+ "BJB2U3W5ZF7WQVTL6R2F542WSS6FQDSVDMXNYWIC5PHED4HH": null,
+ "E26RFAVZYOV5WZ6WQDVINCGNG6ZYU2XCV4FPEKR45IASGARQ": null,
+ "4BK33GLSBFLRZHOHECAVVYT3LJHSQ5RFBSMKLMGTK4Z5RGZO": null,
+ "5I3526BP3QPLNDBEIPVQL2GOAMRBAYWOMILMQK5IT7RES3EV": null,
+ "IBHOZ4VNFYMLMUNOZIGK743IVASI3DXHCY2RH6SO4EKNGR4A": null,
+ "CCZT4EOMTISCMIVGMB2ZRUGFIR3R6WKU3ISSJ3VZVA6SBLFC": null,
+ "OGJUH7B3WKG3W2UFEBL63KLQGPSPRNIHUUKWTKQMBN5QG42E": null,
+ "Y6JCIA2AYVA3RDOUQFYWI4EMF64H5FIFNAHSKZ6LXCRXCFGW": null,
+ "VX3OCLLJZPGXWTLGERIMK5IS4OXKU65SMC4YS5JZND6VEPO7": null,
+ "UXWF26BRES53JKXYXEG5DWJXCR6USGPBWQBDJEVEBA2PPUAI": null,
+ "IB5SSNMYSFCNB4ODT5OQ2GAGPIVDWOBEI3P3EBWI7AUGC7BR": null,
+ "ASIAQKC3VSFJE7ZW472ZOAXX2T7JTCLZBN5BYEOAE7E67F5Z": null,
+ "BKQ3GY255BDDVZ52IIR5K3NFIEKV6GXBVTX3ROY3IN7XDAHA": null,
+ "JTV5ULWFJJOSFTX32FA6DJWADX5UL3NV4RZZS3Z64IPXDZNK": null,
+ "GSZ7MZXCFKAWFBXKRVYUDULPJEH3WSI2K634LAAA36M2FRF3": null,
+ "HSPTZMNCONTGJGIUWP7ZR277AYWTDIKPAWO4RODOIHQGEUF3": null,
+ "4ABCWRBBUAO5TVOSOZDF3KMCUCKIUCRJSBGH4WGKDHWH3LLN": null,
+ "K3BK4XFUTDJLS7KY4WJBS7RTZ65HY4N5NJ6AMKNKGO3K6DXG": null,
+ "S4VZEKYRNOXUITHJENCBKJN6CC6QV7Y4MIHQ6NLN24OJFMBP": null,
+ "MRM4HMHS2KAISLXU2XYFQCQH7XRVVC3EXSP6JU7FIM2DJHVV": null,
+ "QMNCR2JQYOST5MD3HI2I4MCTSJDFCAGUTEE6XKM2THC4WXI3": null,
+ "ANIF4DT5IA4IY7M5OISD4IW4J2TDVHHFIPEONUU4CV75LOFZ": null,
+ "TQHJIX3NKO5CMVRNOG4WP3YDSGPLTTCRBA3RDBPECWO6EN5U": null,
+ "6KI4L4RRXZ6WL3TRMCZLAA2W7AQRXDCC43O6AGYJ75NUEQO6": null,
+ "VL57QTQMHQOAX5MFQTX7GUWOECHVTLYJHIBRKMWIRF4QMN6M": null,
+ "JFTGBEP2LSZGDDFGV6IV2JAS3J3HB7BDRB6WEYHSC5EIFNA3": null,
+ "WLEZIN5PPCJE4W2LGEPW4N6AWQ4RLE2AOGFBTETY5HNRSZCY": null,
+ "LUJRHNRDNK7YOKST7KRVQGVE2ERU3LUVPZLC5YYLCUAX2EEU": null,
+ "F2OOXAP3FFVMQMJP5IVDLRVV6IP2NUTGT5MGZCJMR2IFNA55": null,
+ "SVL525L4TVBTLMH22DTXVCNECAZVUTMMYDTA3UQGV7U6P3YU": null,
+ "546BD77L33PUPQ7TW3GJJVVJTYKHIIKF7YOO4SSGIIIOIJ2Z": null,
+ "FCZRNOURTDJI2BE7HJ3P4MMY4WYAPFFBCTVFXVTYSK4UB4JK": null,
+ "S2U5XQEC7I4HOUUR6HFXUF2PR2CLNF5UEIPJHTNF2JM5BZUJ": null,
+ "JTQGSOTIPVYKGYJBUQC3Y44RWE372S7MPMFDETMH6OEGUJWA": null,
+ "W3DTWDN6YOEPVUJVUDNPWCLQMXXCLXQPVYU27675LZM4ONDF": null,
+ "LJ7P7AJNNHJE24PNWQDK7J4VGGNZKKR3OPVRFV5A4U6LRFRW": null,
+ "I4QO3SZC4455G5PQIJPUUNI4A2BPJKTH5MBA7LN3HRIW6EFZ": null,
+ "NNR3EXDDDPBTOKTRBPR5SO4OFPXU376ZIEHA6YHEJK57ZRGH": null,
+ "4MBIV5HD4ZMXY5NIKZQIFKFO7S642PC7CWVX7ATXAXWQWNGU": null,
+ "A6S5KTN66UWYBWG5CZXJVCJ2F2EA22BCZDFQMM523DU7VFBG": null,
+ "AOAPML4IEVJZSZUOONTTDYSEN465IHW7MZXHSQ55E47TJ2NW": null,
+ "ZIW5DXTPGQLTTRHPRQB7SADQPCSTXQRMKHZIXA6T6YW2BMRS": null,
+ "OUHF6P7JPB5Z2C2E5MEPNQ5R3NY56KNQFHG3RYGWXBYKRRI7": null,
+ "M3JXOC3CTIEMVHTQW7HB2WQ7L7Q54AWFY6F2UBTSZMDXHTDI": null,
+ "WQQA7JW5NTSAI73WVQMMAJ4IO6OKZR32GTQTMUWE2HLC7DRH": null,
+ "WGDVRLD5YWTXFOFTGBBEFCG455EK3BZCZEE2POAX56O3EOQW": null,
+ "6KAR3LTBYTJ6WRGOUQ2TEPZKWVVBPGCO4OVAN2ADNDNLTOSM": null,
+ "VEWL2DORBATRWF5HJ7LG66NYWMXH37JJU6XWVGJNDVL3OSAM": null,
+ "B4HXCGMG5S3VEOZR5IUYOZAEFL6WPRLXB26SLWZHRY3WL3ZU": null,
+ "REKI5EIO6TNXBWJIENJDQ5CAYEYZC2GXVPAOIWGVXKN2K3OE": null,
+ "RBOY2SVFDRIKJZWTWVEGSJLHGIMAZXIF5HNBZAKPVRTEFR3A": null,
+ "SIOSHIHS52CHIB73RFONJOM2HJBTRLGGDFW6JAWTR6UPJBVB": null,
+ "ZGHKTW43CXC3CBOLSENIMDQUIR22VNXSE6HFBT6ZUA3TPODL": null,
+ "XA576OGJNZK3AXE3FJLSSGN5MGRK4FJJ2XX3UHHFI6NO7P25": null,
+ "22VL7B7ZI53VMYEYHKBI7XYNKRQW634B6RLBRXRJN4CQJA6G": null,
+ "YVHEMU6OLF3FI2MTMZ25QKT5F2OUO3H6CX4WRNEXVH4BO3WZ": null,
+ "3VJOBPUJI5DUFHNRM456UWSAHIZYXICY7ZFYMECCUHDTG444": null,
+ "BXLYOEBYW7R4MWPNTOZ2ZJPDDXBHV7JMH75NCD26VGS2VRH7": null,
+ "GCZOZTTLMHTAKVUQ4TSDOOPHEGK6PH4JQ3ULKZCUIEDW2HLX": null,
+ "TE6B4JOPAY2CEQ46KJV7N6MY7OAI4VA3UBBXGPOELN7KY5T7": null,
+ "62BPAKDHZ7ZRJOMVZ2SX2WAKFQATUQLKDQ7YGACJPL2NP4UR": null,
+ "6U3MTBST24MIPS3HSZJPTBSZJ54T63GMZGZQPGFBS7JGBUVX": null,
+ "SXBYC5BKXYT4DFNVSS4OVRYLNA5JY4TXMVTIFSCRT6Q5C265": null,
+ "TAMMZOCU5GDDOIRG6U53NW3UUEUGI3QWW6YY6GWNE7WIHRNE": null,
+ "O37BSKPNGDUUN24XFSCR2IQHWFYUZJBPWSNC4L43MH5HV272": null,
+ "AZFWV3I3DANXV3HJB66QMCFJ3UTVJGS3R3IP7VROF2D5JF6U": null,
+ "W2BLY5MU4PA7HSENYW4MO6VHHPBXUFCFMSBWTCL5F3BIPBFT": null,
+ "ILFL3JG2XQGZCFBJHZFQRZMLGHZWVRBX3M5Z3HXW2A4GDMNK": null,
+ "O7VDC3EDG5I567RK5BKXMKA2R6XPHQQPDXQTCZP7BHKV5BK6": null,
+ "5ZMIJOTL3NPRKBEPS7542ICCNHHUJ2BNOZ7LSL2ICTCUFGSC": null,
+ "FCTKLPX7PYRSVVBH4KN46HEYLJEYSRTQ3PCUU5RY3BROUZKU": null,
+ "7EAMJ4C7NUA3XMDDOF3YRJA7Q2BFXFCI4J24ZXSVE7REBRFU": null,
+ "NOQ6OL6G7QD4ILQ3FAEMEMROBCK4OK3LX3CRMHMA6GG5YIYK": null,
+ "N3XXFRDRYPWGZ3LDGLIXGLLJYKEHPW4565BUUL67OLMXP554": null,
+ "GFHEEY3HHESZDI2YHTDDCBKGE3ZPWPXW2WE5AKNL2Y2TJCNJ": null,
+ "JTUQIEPPBM2QC6XBY3KP2NSDM6WUCJMORCBXNU6ZPXPOHEIW": null,
+ "V5VTVJ36JZDDO5FIOEZNAKYWPRQSUSTEZAKARDOHQEIFLACE": null,
+ "KUTOUNOS2QL4O6HF266ANCBNYUSIT66TANXCGYALCPZXULQH": null,
+ "CJILUW3VUBZCSO5DXTSE4HSVW5UJAJHHCSHGHADKCQE5OTBU": null,
+ "HD72YVUCR4IY5MG3E73UM35ARFCUIHEPIMUSQXOKLVTT2V67": null,
+ "ELVTZXW3ZAKR76K6IV6ZHX7WTMKPKIFRPHIU3LK67WQR6IQG": null,
+ "NIZTNRLCIS4JDLMOTEAKPA6B2JOE76ZBQDEUUGXENEJBYJFV": null,
+ "FE743ELPJYDYWTJ374PZVE4TNGZPDZWSNUO5PATNYUYBDTBJ": null,
+ "FIT3JHSZMFJ7N2E7BL6PHEUUHSBHU55YBIH763TGSZQTIAZY": null,
+ "AP7SXAQ6HW373QPCHKKA4R7NFFUCD7CFB7EERZBNXRGM2Z7R": null,
+ "BAW6TALQRWXK2OWS2O2UV72BKZGBZCUPR6AXKFZ7WHZXZXWX": null,
+ "SM3FE7H4NI76AS5YCH6O34LTROZKJ7FEP4IKL33JUBI7FWZJ": null,
+ "BNO2EJXVMAPFDVF34NBTPSIYKI3UPFI5G2K6KGVU35TIHOQL": null,
+ "INHCLRC6WPTE2U7OQRSSRGCN4B5K4BUVSGFHEKG5DWJWICOF": null,
+ "OEHWM7QZ3H67QC4ZQY2USKQA62NLMESA543KWPBUKV7N65TQ": null,
+ "BN3U5KDJP3QGOSBX3TH5R2DR6PZA5Z7BEGVG6MYRW5GWUCGT": null,
+ "ID7S7JEGBCI7ES3ZN7PIW5NEP67WTL5H5IB6WVRYS47EEEJ2": null,
+ "BG4MHZNCCLZQN563CZ2D72CPT5TASZZ6N6L4JOW2XPR7GIDQ": null,
+ "IAQKAEEUCCT3ZZY5LCO4AZW6F6ZNGUAF56UCD43OPOKSMBHR": null,
+ "LFCSYYMAFZ5IAB5O4QIEN5GERYIGTH4JH266LORQ36SB2A26": null,
+ "J7W62H5B42N3YUEFS5F2MECESYBUVHXSIGRMZL6ZNQMCYQMQ": null,
+ "J24FG5J3MUQOCDAVVCHM6BJWZW4Y7VCSC73DW32TMKIUOXPB": null,
+ "DGJE6OPBSV3JW45P5WC3EGUMIETVT7MIZX4EA5SCY2F3JKFL": null,
+ "KWTJYJJT2LMBHE6WH4LNJEHNMNJVOEQ7SLLXGJKWPGOFDYHQ": null,
+ "7XZDDO3CCV34UECRKEM344EDKKUFD6YDUJ7EW4OAETABTYWV": null,
+ "BPS2OSY2SOAFFPRY24IEXGZVBEUNVIWZYTVVZRUWT7XM727T": null,
+ "6GRVGHI3FMCQ5MQ4JR7ORANBXK6GMSI4XRQVE35LPH44XROO": null,
+ "MZHRR2BS6HII6JD3H32DPSYTTHCVXE4WSC7NUURU43Z5SD56": null,
+ "QJBSWHFQKABG4CALELT62JWLMW2JVZP35RDYHWHQPZYTIX5M": null,
+ "K2Y3YRBFB7F5PJJUFJDH5Z5NL2MYOQWGT5T5VI5SP7TVM5NW": null,
+ "QLONNH4NMZX5WLEJPQEWJECL5JTLTWDSK234NU5H55GA6PFG": null,
+ "NSSRUR3GI6B7NBK77ZQIIHOA4TEEA5UXVVMRWVLMRIP6SN3T": null,
+ "WB2TXRE7EPSBGACXUA4YE23M4WLMG3PVRMD2OOCIHNGQVDRY": null,
+ "3MDCQC5BPGFGGFDO4C4IY53NPTWZMRK5MWLJG2KX7OWVQNFO": null
+}
diff --git a/doc/stream.md b/doc/stream.md
index 04c865c7..5d0b0f35 100644
--- a/doc/stream.md
+++ b/doc/stream.md
@@ -1,6 +1,6 @@
# Stream
-In RapidJSON, `rapidjson::Stream` is a concept for reading/writing JSON. Here we first show how to use streams provided. And then see how to create a custom stream.
+In RapidJSON, `rapidjson::Stream` is a concept for reading/writing JSON. Here we'll first show you how to use provided streams. And then see how to create a custom stream.
[TOC]
@@ -51,7 +51,7 @@ d.Accept(writer);
const char* output = buffer.GetString();
~~~~~~~~~~
-When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and a initial capacity.
+When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and an initial capacity.
~~~~~~~~~~cpp
StringBuffer buffer1(0, 1024); // Use its allocator, initial size = 1024
@@ -89,7 +89,7 @@ d.ParseStream(is);
fclose(fp);
~~~~~~~~~~
-Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. It will be discussed very soon.
+Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. We will discuss more about this later in this tutorial.
Apart from reading file, user can also use `FileReadStream` to read `stdin`.
@@ -119,11 +119,11 @@ d.Accept(writer);
fclose(fp);
~~~~~~~~~~
-It can also directs the output to `stdout`.
+It can also redirect the output to `stdout`.
# iostream Wrapper {#iostreamWrapper}
-Due to users' requests, RapidJSON provided official wrappers for `std::basic_istream` and `std::basic_ostream`. However, please note that the performance will be much lower than the other streams above.
+Due to users' requests, RapidJSON also provides official wrappers for `std::basic_istream` and `std::basic_ostream`. However, please note that the performance will be much lower than the other streams above.
## IStreamWrapper {#IStreamWrapper}
@@ -181,7 +181,7 @@ As mentioned above, UTF-8 byte streams can be read directly. However, UTF-16 and
Besides, it also need to handle [byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark). When reading from a byte stream, it is needed to detect or just consume the BOM if exists. When writing to a byte stream, it can optionally write BOM.
-If the encoding of stream is known in compile-time, you may use `EncodedInputStream` and `EncodedOutputStream`. If the stream can be UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE JSON, and it is only known in runtime, you may use `AutoUTFInputStream` and `AutoUTFOutputStream`. These streams are defined in `rapidjson/encodedstream.h`.
+If the encoding of stream is known during compile-time, you may use `EncodedInputStream` and `EncodedOutputStream`. If the stream can be UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE JSON, and it is only known in runtime, you may use `AutoUTFInputStream` and `AutoUTFOutputStream`. These streams are defined in `rapidjson/encodedstream.h`.
Note that, these encoded streams can be applied to streams other than file. For example, you may have a file in memory, or a custom byte stream, be wrapped in encoded streams.
@@ -231,7 +231,7 @@ FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
OutputStream eos(bos, true); // Write BOM
-Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
+Writer<OutputStream, UTF8<>, UTF32LE<>> writer(eos);
d.Accept(writer); // This generates UTF32-LE file from UTF-8 in memory
fclose(fp);
diff --git a/doc/stream.zh-cn.md b/doc/stream.zh-cn.md
index 7f2f356f..6e379bbd 100644
--- a/doc/stream.zh-cn.md
+++ b/doc/stream.zh-cn.md
@@ -231,7 +231,7 @@ FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
OutputStream eos(bos, true); // 写入 BOM
-Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
+Writer<OutputStream, UTF8<>, UTF32LE<>> writer(eos);
d.Accept(writer); // 这里从内存的 UTF-8 生成 UTF32-LE 文件
fclose(fp);
diff --git a/doc/tutorial.md b/doc/tutorial.md
index 4bde2faf..a86aafdf 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -12,7 +12,7 @@ Each JSON value is stored in a type called `Value`. A `Document`, representing t
# Query Value {#QueryValue}
-In this section, we will use excerpt of `example/tutorial/tutorial.cpp`.
+In this section, we will use excerpt from `example/tutorial/tutorial.cpp`.
Assume we have the following JSON stored in a C string (`const char* json`):
~~~~~~~~~~js
@@ -85,7 +85,7 @@ assert(document["i"].IsNumber());
// In this case, IsUint()/IsInt64()/IsUint64() also return true.
assert(document["i"].IsInt());
printf("i = %d\n", document["i"].GetInt());
-// Alternative (int)document["i"]
+// Alternatively (int)document["i"]
assert(document["pi"].IsNumber());
assert(document["pi"].IsDouble());
@@ -113,7 +113,7 @@ a[2] = 3
a[3] = 4
~~~~~~~~~~
-Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined.
+Note that, RapidJSON does not automatically convert values between JSON types. For example, if a value is a string, it is invalid to call `GetInt()`. In debug mode it will fail on assertion. In release mode, the behavior is undefined.
In the following sections we discuss details about querying individual types.
@@ -168,9 +168,9 @@ Type of member pi is Number
Type of member a is Array
~~~~~~~~~~
-Note that, when `operator[](const char*)` cannot find the member, it will fail an assertion.
+Note that, when `operator[](const char*)` cannot find the member, it will fail on assertion.
-If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain its value at once:
+If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of a member and obtain its value at once:
~~~~~~~~~~cpp
Value::ConstMemberIterator itr = document.FindMember("hello");
@@ -221,18 +221,18 @@ When obtaining the numeric values, `GetDouble()` will convert internal integer r
## Query String {#QueryString}
-In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why.
+In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why:
-According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats ``\0'` as the terminator symbol.
+According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats `\0` as the terminator symbol.
-To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` to obtain the correct string length.
+To conform with RFC 4627, RapidJSON supports string containing `U+0000` character. If you need to handle this, you can use `GetStringLength()` to obtain the correct string length.
-For example, after parsing a the following JSON to `Document d`:
+For example, after parsing the following JSON to `Document d`:
~~~~~~~~~~js
{ "s" : "a\u0000b" }
~~~~~~~~~~
-The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1.
+The correct length of the string `"a\u0000b"` is 3, as returned by `GetStringLength()`. But `strlen()` returns 1.
`GetStringLength()` can also improve performance, as user may often need to call `strlen()` for allocating buffer.
@@ -246,7 +246,7 @@ which accepts the length of string as parameter. This constructor supports stori
## Comparing values
-You can use `==` and `!=` to compare values. Two values are equal if and only if they are have same type and contents. You can also compare values with primitive types. Here is an example.
+You can use `==` and `!=` to compare values. Two values are equal if and only if they have same type and contents. You can also compare values with primitive types. Here is an example:
~~~~~~~~~~cpp
if (document["hello"] == document["n"]) /*...*/; // Compare values
@@ -264,7 +264,7 @@ Note that, currently if an object contains duplicated named member, comparing eq
There are several ways to create values. After a DOM tree is created and/or modified, it can be saved as JSON again using `Writer`.
## Change Value Type {#ChangeValueType}
-When creating a Value or Document by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:
+When creating a `Value` or `Document` by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:
~~~~~~~~~~cpp
Document d; // Null
@@ -285,7 +285,7 @@ Value u(123u); // calls Value(unsigned)
Value d(1.5); // calls Value(double)
~~~~~~~~~~
-To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one shot:
+To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one call:
~~~~~~~~~~cpp
Value o(kObjectType);
@@ -299,7 +299,7 @@ A very special decision during design of RapidJSON is that, assignment of value
~~~~~~~~~~cpp
Value a(123);
Value b(456);
-b = a; // a becomes a Null value, b becomes number 123.
+a = b; // b becomes a Null value, a becomes number 456.
~~~~~~~~~~
![Assignment with move semantics.](diagram/move1.png)
@@ -367,7 +367,7 @@ RapidJSON provides two strategies for storing string.
Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing a string literal, and for in-situ parsing which will be mentioned in the DOM section.
-To make memory allocation customizable, RapidJSON requires users to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value.
+To make memory allocation customizable, RapidJSON requires users to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing an allocator (or Document) pointer per Value.
Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator:
diff --git a/example/traverseaspointer.cpp b/example/traverseaspointer.cpp
new file mode 100644
index 00000000..7e0c8992
--- /dev/null
+++ b/example/traverseaspointer.cpp
@@ -0,0 +1,39 @@
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/pointer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+
+void traverse(const Value& v, const Pointer& p) {
+ StringBuffer sb;
+ p.Stringify(sb);
+ std::cout << sb.GetString() << std::endl;
+
+ switch (v.GetType()) {
+ case kArrayType:
+ for (SizeType i = 0; i != v.Size(); ++i)
+ traverse(v[i], p.Append(i));
+ break;
+ case kObjectType:
+ for (Value::ConstMemberIterator m = v.MemberBegin(); m != v.MemberEnd(); ++m)
+ traverse(m->value, p.Append(m->name.GetString(), m->name.GetStringLength()));
+ break;
+ default:
+ break;
+ }
+}
+
+int main(int, char*[]) {
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+ Document d;
+ d.ParseStream(is);
+
+ Pointer root;
+ traverse(d, root);
+
+ return 0;
+}
diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h
index 44ec5295..12bc5baf 100644
--- a/include/rapidjson/allocators.h
+++ b/include/rapidjson/allocators.h
@@ -16,6 +16,13 @@
#define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h"
+#include "internal/meta.h"
+
+#include <memory>
+
+#if RAPIDJSON_HAS_CXX11
+#include <type_traits>
+#endif
RAPIDJSON_NAMESPACE_BEGIN
@@ -89,7 +96,14 @@ public:
}
return RAPIDJSON_REALLOC(originalPtr, newSize);
}
- static void Free(void *ptr) { RAPIDJSON_FREE(ptr); }
+ static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
+
+ bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
+ return true;
+ }
+ bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
+ return false;
+ }
};
///////////////////////////////////////////////////////////////////////////////
@@ -113,16 +127,64 @@ public:
*/
template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
+ //! Chunk header for perpending to each chunk.
+ /*! Chunks are stored as a singly linked list.
+ */
+ struct ChunkHeader {
+ size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
+ size_t size; //!< Current size of allocated memory in bytes.
+ ChunkHeader *next; //!< Next chunk in the linked list.
+ };
+
+ struct SharedData {
+ ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+ BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
+ size_t refcount;
+ bool ownBuffer;
+ };
+
+ static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
+ static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
+
+ static inline ChunkHeader *GetChunkHead(SharedData *shared)
+ {
+ return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
+ }
+ static inline uint8_t *GetChunkBuffer(SharedData *shared)
+ {
+ return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
+ }
+
+ static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
+
public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+ static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
+ explicit
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
- chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ chunk_capacity_(chunkSize),
+ baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
+ shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
{
+ RAPIDJSON_ASSERT(baseAllocator_ != 0);
+ RAPIDJSON_ASSERT(shared_ != 0);
+ if (baseAllocator) {
+ shared_->ownBaseAllocator = 0;
+ }
+ else {
+ shared_->ownBaseAllocator = baseAllocator_;
+ }
+ shared_->chunkHead = GetChunkHead(shared_);
+ shared_->chunkHead->capacity = 0;
+ shared_->chunkHead->size = 0;
+ shared_->chunkHead->next = 0;
+ shared_->ownBuffer = true;
+ shared_->refcount = 1;
}
//! Constructor with user-supplied buffer.
@@ -136,41 +198,101 @@ public:
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
- chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ chunk_capacity_(chunkSize),
+ baseAllocator_(baseAllocator),
+ shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
+ {
+ RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
+ shared_->chunkHead = GetChunkHead(shared_);
+ shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
+ shared_->chunkHead->size = 0;
+ shared_->chunkHead->next = 0;
+ shared_->ownBaseAllocator = 0;
+ shared_->ownBuffer = false;
+ shared_->refcount = 1;
+ }
+
+ MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
+ chunk_capacity_(rhs.chunk_capacity_),
+ baseAllocator_(rhs.baseAllocator_),
+ shared_(rhs.shared_)
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+ ++shared_->refcount;
+ }
+ MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
{
- RAPIDJSON_ASSERT(buffer != 0);
- RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
- chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
- chunkHead_->capacity = size - sizeof(ChunkHeader);
- chunkHead_->size = 0;
- chunkHead_->next = 0;
+ RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+ ++rhs.shared_->refcount;
+ this->~MemoryPoolAllocator();
+ baseAllocator_ = rhs.baseAllocator_;
+ chunk_capacity_ = rhs.chunk_capacity_;
+ shared_ = rhs.shared_;
+ return *this;
}
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
+ chunk_capacity_(rhs.chunk_capacity_),
+ baseAllocator_(rhs.baseAllocator_),
+ shared_(rhs.shared_)
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+ rhs.shared_ = 0;
+ }
+ MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+ this->~MemoryPoolAllocator();
+ baseAllocator_ = rhs.baseAllocator_;
+ chunk_capacity_ = rhs.chunk_capacity_;
+ shared_ = rhs.shared_;
+ rhs.shared_ = 0;
+ return *this;
+ }
+#endif
+
//! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/
- ~MemoryPoolAllocator() {
+ ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
+ if (!shared_) {
+ // do nothing if moved
+ return;
+ }
+ if (shared_->refcount > 1) {
+ --shared_->refcount;
+ return;
+ }
Clear();
- RAPIDJSON_DELETE(ownBaseAllocator_);
+ BaseAllocator *a = shared_->ownBaseAllocator;
+ if (shared_->ownBuffer) {
+ baseAllocator_->Free(shared_);
+ }
+ RAPIDJSON_DELETE(a);
}
- //! Deallocates all memory chunks, excluding the user-supplied buffer.
- void Clear() {
- while (chunkHead_ && chunkHead_ != userBuffer_) {
- ChunkHeader* next = chunkHead_->next;
- baseAllocator_->Free(chunkHead_);
- chunkHead_ = next;
+ //! Deallocates all memory chunks, excluding the first/user one.
+ void Clear() RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+ for (;;) {
+ ChunkHeader* c = shared_->chunkHead;
+ if (!c->next) {
+ break;
+ }
+ shared_->chunkHead = c->next;
+ baseAllocator_->Free(c);
}
- if (chunkHead_ && chunkHead_ == userBuffer_)
- chunkHead_->size = 0; // Clear user buffer
+ shared_->chunkHead->size = 0;
}
//! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes.
*/
- size_t Capacity() const {
+ size_t Capacity() const RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t capacity = 0;
- for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
capacity += c->capacity;
return capacity;
}
@@ -178,25 +300,35 @@ public:
//! Computes the memory blocks allocated.
/*! \return total used bytes.
*/
- size_t Size() const {
+ size_t Size() const RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t size = 0;
- for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
size += c->size;
return size;
}
+ //! Whether the allocator is shared.
+ /*! \return true or false.
+ */
+ bool Shared() const RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+ return shared_->refcount > 1;
+ }
+
//! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size);
- if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+ if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL;
- void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
- chunkHead_->size += size;
+ void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
+ shared_->chunkHead->size += size;
return buffer;
}
@@ -205,6 +337,7 @@ public:
if (originalPtr == 0)
return Malloc(newSize);
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (newSize == 0)
return NULL;
@@ -216,10 +349,10 @@ public:
return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space
- if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+ if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize);
- if (chunkHead_->size + increment <= chunkHead_->capacity) {
- chunkHead_->size += increment;
+ if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
+ shared_->chunkHead->size += increment;
return originalPtr;
}
}
@@ -235,50 +368,325 @@ public:
}
//! Frees a memory block (concept Allocator)
- static void Free(void *ptr) { (void)ptr; } // Do nothing
+ static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
-private:
- //! Copy constructor is not permitted.
- MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
- //! Copy assignment operator is not permitted.
- MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+ //! Compare (equality) with another MemoryPoolAllocator
+ bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+ RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+ return shared_ == rhs.shared_;
+ }
+ //! Compare (inequality) with another MemoryPoolAllocator
+ bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
+ return !operator==(rhs);
+ }
+private:
//! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes.
\return true if success.
*/
bool AddChunk(size_t capacity) {
if (!baseAllocator_)
- ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
- if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
+ shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
+ if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
chunk->capacity = capacity;
chunk->size = 0;
- chunk->next = chunkHead_;
- chunkHead_ = chunk;
+ chunk->next = shared_->chunkHead;
+ shared_->chunkHead = chunk;
return true;
}
else
return false;
}
- static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
-
- //! Chunk header for perpending to each chunk.
- /*! Chunks are stored as a singly linked list.
- */
- struct ChunkHeader {
- size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
- size_t size; //!< Current size of allocated memory in bytes.
- ChunkHeader *next; //!< Next chunk in the linked list.
- };
+ static inline void* AlignBuffer(void* buf, size_t &size)
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
+ const uintptr_t mask = sizeof(void*) - 1;
+ const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
+ if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
+ const uintptr_t abuf = (ubuf + mask) & ~mask;
+ RAPIDJSON_ASSERT(size >= abuf - ubuf);
+ buf = reinterpret_cast<void*>(abuf);
+ size -= abuf - ubuf;
+ }
+ return buf;
+ }
- ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
- void *userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
- BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
+ SharedData *shared_; //!< The shared data of the allocator
};
+namespace internal {
+ template<typename, typename = void>
+ struct IsRefCounted :
+ public FalseType
+ { };
+ template<typename T>
+ struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
+ public TrueType
+ { };
+}
+
+template<typename T, typename A>
+inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
+{
+ RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T));
+ return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
+}
+
+template<typename T, typename A>
+inline T *Malloc(A& a, size_t n = 1)
+{
+ return Realloc<T, A>(a, NULL, 0, n);
+}
+
+template<typename T, typename A>
+inline void Free(A& a, T *p, size_t n = 1)
+{
+ static_cast<void>(Realloc<T, A>(a, p, n, 0));
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
+#endif
+
+template <typename T, typename BaseAllocator = CrtAllocator>
+class StdAllocator :
+ public std::allocator<T>
+{
+ typedef std::allocator<T> allocator_type;
+#if RAPIDJSON_HAS_CXX11
+ typedef std::allocator_traits<allocator_type> traits_type;
+#else
+ typedef allocator_type traits_type;
+#endif
+
+public:
+ typedef BaseAllocator BaseAllocatorType;
+
+ StdAllocator() RAPIDJSON_NOEXCEPT :
+ allocator_type(),
+ baseAllocator_()
+ { }
+
+ StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(rhs),
+ baseAllocator_(rhs.baseAllocator_)
+ { }
+
+ template<typename U>
+ StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(rhs),
+ baseAllocator_(rhs.baseAllocator_)
+ { }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(std::move(rhs)),
+ baseAllocator_(std::move(rhs.baseAllocator_))
+ { }
+#endif
+#if RAPIDJSON_HAS_CXX11
+ using propagate_on_container_move_assignment = std::true_type;
+ using propagate_on_container_swap = std::true_type;
+#endif
+
+ /* implicit */
+ StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT :
+ allocator_type(),
+ baseAllocator_(allocator)
+ { }
+
+ ~StdAllocator() RAPIDJSON_NOEXCEPT
+ { }
+
+ template<typename U>
+ struct rebind {
+ typedef StdAllocator<U, BaseAllocator> other;
+ };
+
+ typedef typename traits_type::size_type size_type;
+ typedef typename traits_type::difference_type difference_type;
+
+ typedef typename traits_type::value_type value_type;
+ typedef typename traits_type::pointer pointer;
+ typedef typename traits_type::const_pointer const_pointer;
+
+#if RAPIDJSON_HAS_CXX11
+
+ typedef typename std::add_lvalue_reference<value_type>::type &reference;
+ typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference;
+
+ pointer address(reference r) const RAPIDJSON_NOEXCEPT
+ {
+ return std::addressof(r);
+ }
+ const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
+ {
+ return std::addressof(r);
+ }
+
+ size_type max_size() const RAPIDJSON_NOEXCEPT
+ {
+ return traits_type::max_size(*this);
+ }
+
+ template <typename ...Args>
+ void construct(pointer p, Args&&... args)
+ {
+ traits_type::construct(*this, p, std::forward<Args>(args)...);
+ }
+ void destroy(pointer p)
+ {
+ traits_type::destroy(*this, p);
+ }
+
+#else // !RAPIDJSON_HAS_CXX11
+
+ typedef typename allocator_type::reference reference;
+ typedef typename allocator_type::const_reference const_reference;
+
+ pointer address(reference r) const RAPIDJSON_NOEXCEPT
+ {
+ return allocator_type::address(r);
+ }
+ const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
+ {
+ return allocator_type::address(r);
+ }
+
+ size_type max_size() const RAPIDJSON_NOEXCEPT
+ {
+ return allocator_type::max_size();
+ }
+
+ void construct(pointer p, const_reference r)
+ {
+ allocator_type::construct(p, r);
+ }
+ void destroy(pointer p)
+ {
+ allocator_type::destroy(p);
+ }
+
+#endif // !RAPIDJSON_HAS_CXX11
+
+ template <typename U>
+ U* allocate(size_type n = 1, const void* = 0)
+ {
+ return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
+ }
+ template <typename U>
+ void deallocate(U* p, size_type n = 1)
+ {
+ RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
+ }
+
+ pointer allocate(size_type n = 1, const void* = 0)
+ {
+ return allocate<value_type>(n);
+ }
+ void deallocate(pointer p, size_type n = 1)
+ {
+ deallocate<value_type>(p, n);
+ }
+
+#if RAPIDJSON_HAS_CXX11
+ using is_always_equal = std::is_empty<BaseAllocator>;
+#endif
+
+ template<typename U>
+ bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
+ {
+ return baseAllocator_ == rhs.baseAllocator_;
+ }
+ template<typename U>
+ bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
+ {
+ return !operator==(rhs);
+ }
+
+ //! rapidjson Allocator concept
+ static const bool kNeedFree = BaseAllocator::kNeedFree;
+ static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value;
+ void* Malloc(size_t size)
+ {
+ return baseAllocator_.Malloc(size);
+ }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
+ {
+ return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
+ }
+ static void Free(void *ptr) RAPIDJSON_NOEXCEPT
+ {
+ BaseAllocator::Free(ptr);
+ }
+
+private:
+ template <typename, typename>
+ friend class StdAllocator; // access to StdAllocator<!T>.*
+
+ BaseAllocator baseAllocator_;
+};
+
+#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
+template <typename BaseAllocator>
+class StdAllocator<void, BaseAllocator> :
+ public std::allocator<void>
+{
+ typedef std::allocator<void> allocator_type;
+
+public:
+ typedef BaseAllocator BaseAllocatorType;
+
+ StdAllocator() RAPIDJSON_NOEXCEPT :
+ allocator_type(),
+ baseAllocator_()
+ { }
+
+ StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(rhs),
+ baseAllocator_(rhs.baseAllocator_)
+ { }
+
+ template<typename U>
+ StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(rhs),
+ baseAllocator_(rhs.baseAllocator_)
+ { }
+
+ /* implicit */
+ StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
+ allocator_type(),
+ baseAllocator_(baseAllocator)
+ { }
+
+ ~StdAllocator() RAPIDJSON_NOEXCEPT
+ { }
+
+ template<typename U>
+ struct rebind {
+ typedef StdAllocator<U, BaseAllocator> other;
+ };
+
+ typedef typename allocator_type::value_type value_type;
+
+private:
+ template <typename, typename>
+ friend class StdAllocator; // access to StdAllocator<!T>.*
+
+ BaseAllocator baseAllocator_;
+};
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h
index 1dad630e..e2cc6000 100644
--- a/include/rapidjson/document.h
+++ b/include/rapidjson/document.h
@@ -42,12 +42,21 @@ RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible lo
RAPIDJSON_DIAG_OFF(effc++)
#endif // __GNUC__
+#ifdef GetObject
+// see https://github.com/Tencent/rapidjson/issues/1448
+// a former included windows.h might have defined a macro called GetObject, which affects
+// GetObject defined here. This ensures the macro does not get applied
+#pragma push_macro("GetObject")
+#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
+#undef GetObject
+#endif
+
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#include <iterator> // std::random_access_iterator_tag
#endif
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
-#include <utility> // std::move
+#if RAPIDJSON_USE_MEMBERSMAP
+#include <map> // std::multimap
#endif
RAPIDJSON_NAMESPACE_BEGIN
@@ -732,18 +741,8 @@ public:
template <typename SourceAllocator>
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
switch (rhs.GetType()) {
- case kObjectType: {
- SizeType count = rhs.data_.o.size;
- Member* lm = reinterpret_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
- const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
- for (SizeType i = 0; i < count; i++) {
- new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
- new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
- }
- data_.f.flags = kObjectFlag;
- data_.o.size = data_.o.capacity = count;
- SetMembersPointer(lm);
- }
+ case kObjectType:
+ DoCopyMembers(rhs, allocator, copyConstStrings);
break;
case kArrayType: {
SizeType count = rhs.data_.a.size;
@@ -879,25 +878,30 @@ public:
/*! Need to destruct elements of array, members of object, or copy-string.
*/
~GenericValue() {
- if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release
+ // their Allocator if it's refcounted (e.g. MemoryPoolAllocator).
+ if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 &&
+ internal::IsRefCounted<Allocator>::Value)) {
switch(data_.f.flags) {
case kArrayFlag:
{
GenericValue* e = GetElementsPointer();
for (GenericValue* v = e; v != e + data_.a.size; ++v)
v->~GenericValue();
- Allocator::Free(e);
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ Allocator::Free(e);
+ }
}
break;
case kObjectFlag:
- for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
- m->~Member();
- Allocator::Free(GetMembersPointer());
+ DoFreeMembers();
break;
case kCopyStringFlag:
- Allocator::Free(const_cast<Ch*>(GetStringPointer()));
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ Allocator::Free(const_cast<Ch*>(GetStringPointer()));
+ }
break;
default:
@@ -916,8 +920,13 @@ public:
*/
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
if (RAPIDJSON_LIKELY(this != &rhs)) {
+ // Can't destroy "this" before assigning "rhs", otherwise "rhs"
+ // could be used after free if it's an sub-Value of "this",
+ // hence the temporary danse.
+ GenericValue temp;
+ temp.RawAssign(rhs);
this->~GenericValue();
- RawAssign(rhs);
+ RawAssign(temp);
}
return *this;
}
@@ -1260,10 +1269,7 @@ public:
*/
GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
RAPIDJSON_ASSERT(IsObject());
- if (newCapacity > data_.o.capacity) {
- SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
- data_.o.capacity = newCapacity;
- }
+ DoReserveMembers(newCapacity, allocator);
return *this;
}
@@ -1337,11 +1343,7 @@ public:
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
- MemberIterator member = MemberBegin();
- for ( ; member != MemberEnd(); ++member)
- if (name.StringEqual(member->name))
- break;
- return member;
+ return DoFindMember(name);
}
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
@@ -1370,14 +1372,7 @@ public:
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
-
- ObjectData& o = data_.o;
- if (o.size >= o.capacity)
- MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
- Member* members = GetMembersPointer();
- members[o.size].name.RawAssign(name);
- members[o.size].value.RawAssign(value);
- o.size++;
+ DoAddMember(name, value, allocator);
return *this;
}
@@ -1511,9 +1506,7 @@ public:
*/
void RemoveAllMembers() {
RAPIDJSON_ASSERT(IsObject());
- for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
- m->~Member();
- data_.o.size = 0;
+ DoClearMembers();
}
//! Remove a member in object by its name.
@@ -1557,14 +1550,7 @@ public:
RAPIDJSON_ASSERT(data_.o.size > 0);
RAPIDJSON_ASSERT(GetMembersPointer() != 0);
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
-
- MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
- if (data_.o.size > 1 && m != last)
- *m = *last; // Move the last one to this place
- else
- m->~Member(); // Only one left, just destroy
- --data_.o.size;
- return m;
+ return DoRemoveMember(m);
}
//! Remove a member from an object by iterator.
@@ -1596,13 +1582,7 @@ public:
RAPIDJSON_ASSERT(first >= MemberBegin());
RAPIDJSON_ASSERT(first <= last);
RAPIDJSON_ASSERT(last <= MemberEnd());
-
- MemberIterator pos = MemberBegin() + (first - MemberBegin());
- for (MemberIterator itr = pos; itr != last; ++itr)
- itr->~Member();
- std::memmove(static_cast<void*>(&*pos), &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
- data_.o.size -= static_cast<SizeType>(last - first);
- return pos;
+ return DoEraseMembers(first, last);
}
//! Erase a member in object by its name.
@@ -1631,7 +1611,9 @@ public:
}
Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
+ Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
+ ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
//@}
@@ -1853,12 +1835,12 @@ public:
//!@name String
//@{
- const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); }
//! Get the length of string.
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
*/
- SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); }
//! Set this value as a string without copying source string.
/*! This version has better performance with supplied length, and also support string containing null character.
@@ -2107,6 +2089,13 @@ private:
Flag f;
}; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
+ static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) {
+ return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str);
+ }
+ static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) {
+ return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length;
+ }
+
RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
@@ -2114,6 +2103,286 @@ private:
RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
+#if RAPIDJSON_USE_MEMBERSMAP
+
+ struct MapTraits {
+ struct Less {
+ bool operator()(const Data& s1, const Data& s2) const {
+ SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2);
+ int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2));
+ return cmp < 0 || (cmp == 0 && n1 < n2);
+ }
+ };
+ typedef std::pair<const Data, SizeType> Pair;
+ typedef std::multimap<Data, SizeType, Less, StdAllocator<Pair, Allocator> > Map;
+ typedef typename Map::iterator Iterator;
+ };
+ typedef typename MapTraits::Map Map;
+ typedef typename MapTraits::Less MapLess;
+ typedef typename MapTraits::Pair MapPair;
+ typedef typename MapTraits::Iterator MapIterator;
+
+ //
+ // Layout of the members' map/array, re(al)located according to the needed capacity:
+ //
+ // {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]}
+ //
+ // (where <> stands for the RAPIDJSON_ALIGN-ment, if needed)
+ //
+
+ static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) {
+ return RAPIDJSON_ALIGN(sizeof(Map*)) +
+ RAPIDJSON_ALIGN(sizeof(SizeType)) +
+ RAPIDJSON_ALIGN(capacity * sizeof(Member)) +
+ capacity * sizeof(MapIterator);
+ }
+
+ static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) {
+ return *reinterpret_cast<SizeType*>(reinterpret_cast<uintptr_t>(&map) +
+ RAPIDJSON_ALIGN(sizeof(Map*)));
+ }
+
+ static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) {
+ return reinterpret_cast<Member*>(reinterpret_cast<uintptr_t>(&map) +
+ RAPIDJSON_ALIGN(sizeof(Map*)) +
+ RAPIDJSON_ALIGN(sizeof(SizeType)));
+ }
+
+ static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) {
+ return reinterpret_cast<MapIterator*>(reinterpret_cast<uintptr_t>(&map) +
+ RAPIDJSON_ALIGN(sizeof(Map*)) +
+ RAPIDJSON_ALIGN(sizeof(SizeType)) +
+ RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member)));
+ }
+
+ static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) {
+ RAPIDJSON_ASSERT(members != 0);
+ return *reinterpret_cast<Map**>(reinterpret_cast<uintptr_t>(members) -
+ RAPIDJSON_ALIGN(sizeof(SizeType)) -
+ RAPIDJSON_ALIGN(sizeof(Map*)));
+ }
+
+ // Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting..
+ RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) {
+#if RAPIDJSON_HAS_CXX11
+ MapIterator ret = std::move(rhs);
+#else
+ MapIterator ret = rhs;
+#endif
+ rhs.~MapIterator();
+ return ret;
+ }
+
+ Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) {
+ Map **newMap = static_cast<Map**>(allocator.Malloc(GetMapLayoutSize(newCapacity)));
+ GetMapCapacity(*newMap) = newCapacity;
+ if (!oldMap) {
+ *newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator);
+ }
+ else {
+ *newMap = *oldMap;
+ size_t count = (*oldMap)->size();
+ std::memcpy(static_cast<void*>(GetMapMembers(*newMap)),
+ static_cast<void*>(GetMapMembers(*oldMap)),
+ count * sizeof(Member));
+ MapIterator *oldIt = GetMapIterators(*oldMap),
+ *newIt = GetMapIterators(*newMap);
+ while (count--) {
+ new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count]));
+ }
+ Allocator::Free(oldMap);
+ }
+ return *newMap;
+ }
+
+ RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
+ return GetMapMembers(DoReallocMap(0, capacity, allocator));
+ }
+
+ void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
+ ObjectData& o = data_.o;
+ if (newCapacity > o.capacity) {
+ Member* oldMembers = GetMembersPointer();
+ Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0,
+ *&newMap = DoReallocMap(oldMap, newCapacity, allocator);
+ RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap));
+ o.capacity = newCapacity;
+ }
+ }
+
+ template <typename SourceAllocator>
+ MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ if (Member* members = GetMembersPointer()) {
+ Map* &map = GetMap(members);
+ MapIterator mit = map->find(reinterpret_cast<const Data&>(name.data_));
+ if (mit != map->end()) {
+ return MemberIterator(&members[mit->second]);
+ }
+ }
+ return MemberEnd();
+ }
+
+ void DoClearMembers() {
+ if (Member* members = GetMembersPointer()) {
+ Map* &map = GetMap(members);
+ MapIterator* mit = GetMapIterators(map);
+ for (SizeType i = 0; i < data_.o.size; i++) {
+ map->erase(DropMapIterator(mit[i]));
+ members[i].~Member();
+ }
+ data_.o.size = 0;
+ }
+ }
+
+ void DoFreeMembers() {
+ if (Member* members = GetMembersPointer()) {
+ GetMap(members)->~Map();
+ for (SizeType i = 0; i < data_.o.size; i++) {
+ members[i].~Member();
+ }
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ Map** map = &GetMap(members);
+ Allocator::Free(*map);
+ Allocator::Free(map);
+ }
+ }
+ }
+
+#else // !RAPIDJSON_USE_MEMBERSMAP
+
+ RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
+ return Malloc<Member>(allocator, capacity);
+ }
+
+ void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
+ ObjectData& o = data_.o;
+ if (newCapacity > o.capacity) {
+ Member* newMembers = Realloc<Member>(allocator, GetMembersPointer(), o.capacity, newCapacity);
+ RAPIDJSON_SETPOINTER(Member, o.members, newMembers);
+ o.capacity = newCapacity;
+ }
+ }
+
+ template <typename SourceAllocator>
+ MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator member = MemberBegin();
+ for ( ; member != MemberEnd(); ++member)
+ if (name.StringEqual(member->name))
+ break;
+ return member;
+ }
+
+ void DoClearMembers() {
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ data_.o.size = 0;
+ }
+
+ void DoFreeMembers() {
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ Allocator::Free(GetMembersPointer());
+ }
+
+#endif // !RAPIDJSON_USE_MEMBERSMAP
+
+ void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+ ObjectData& o = data_.o;
+ if (o.size >= o.capacity)
+ DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator);
+ Member* members = GetMembersPointer();
+ Member* m = members + o.size;
+ m->name.RawAssign(name);
+ m->value.RawAssign(value);
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(members);
+ MapIterator* mit = GetMapIterators(map);
+ new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size)));
+#endif
+ ++o.size;
+ }
+
+ MemberIterator DoRemoveMember(MemberIterator m) {
+ ObjectData& o = data_.o;
+ Member* members = GetMembersPointer();
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(members);
+ MapIterator* mit = GetMapIterators(map);
+ SizeType mpos = static_cast<SizeType>(&*m - members);
+ map->erase(DropMapIterator(mit[mpos]));
+#endif
+ MemberIterator last(members + (o.size - 1));
+ if (o.size > 1 && m != last) {
+#if RAPIDJSON_USE_MEMBERSMAP
+ new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members]));
+ mit[mpos]->second = mpos;
+#endif
+ *m = *last; // Move the last one to this place
+ }
+ else {
+ m->~Member(); // Only one left, just destroy
+ }
+ --o.size;
+ return m;
+ }
+
+ MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) {
+ ObjectData& o = data_.o;
+ MemberIterator beg = MemberBegin(),
+ pos = beg + (first - beg),
+ end = MemberEnd();
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(GetMembersPointer());
+ MapIterator* mit = GetMapIterators(map);
+#endif
+ for (MemberIterator itr = pos; itr != last; ++itr) {
+#if RAPIDJSON_USE_MEMBERSMAP
+ map->erase(DropMapIterator(mit[itr - beg]));
+#endif
+ itr->~Member();
+ }
+#if RAPIDJSON_USE_MEMBERSMAP
+ if (first != last) {
+ // Move remaining members/iterators
+ MemberIterator next = pos + (last - first);
+ for (MemberIterator itr = pos; next != end; ++itr, ++next) {
+ std::memcpy(static_cast<void*>(&*itr), &*next, sizeof(Member));
+ SizeType mpos = static_cast<SizeType>(itr - beg);
+ new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg]));
+ mit[mpos]->second = mpos;
+ }
+ }
+#else
+ std::memmove(static_cast<void*>(&*pos), &*last,
+ static_cast<size_t>(end - last) * sizeof(Member));
+#endif
+ o.size -= static_cast<SizeType>(last - first);
+ return pos;
+ }
+
+ template <typename SourceAllocator>
+ void DoCopyMembers(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings) {
+ RAPIDJSON_ASSERT(rhs.GetType() == kObjectType);
+
+ data_.f.flags = kObjectFlag;
+ SizeType count = rhs.data_.o.size;
+ Member* lm = DoAllocMembers(count, allocator);
+ const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(lm);
+ MapIterator* mit = GetMapIterators(map);
+#endif
+ for (SizeType i = 0; i < count; i++) {
+ new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
+ new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
+#if RAPIDJSON_USE_MEMBERSMAP
+ new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i)));
+#endif
+ }
+ data_.o.size = data_.o.capacity = count;
+ SetMembersPointer(lm);
+ }
+
// Initialize this value as array with initial data, without calling destructor.
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
data_.f.flags = kArrayFlag;
@@ -2131,9 +2400,16 @@ private:
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
data_.f.flags = kObjectFlag;
if (count) {
- Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
+ Member* m = DoAllocMembers(count, allocator);
SetMembersPointer(m);
std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(m);
+ MapIterator* mit = GetMapIterators(map);
+ for (SizeType i = 0; i < count; i++) {
+ new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i)));
+ }
+#endif
}
else
SetMembersPointer(0);
@@ -2254,6 +2530,13 @@ public:
#endif
~GenericDocument() {
+ // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType()
+ // runs last and may access its elements or members which would be freed
+ // with an allocator like MemoryPoolAllocator (CrtAllocator does not
+ // free its data when destroyed, but MemoryPoolAllocator does).
+ if (ownAllocator_) {
+ ValueType::SetNull();
+ }
Destroy();
}
@@ -2736,4 +3019,9 @@ private:
RAPIDJSON_NAMESPACE_END
RAPIDJSON_DIAG_POP
+#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
+#pragma pop_macro("GetObject")
+#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
+#endif
+
#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h
index 78aa89a0..a4e89532 100644
--- a/include/rapidjson/rapidjson.h
+++ b/include/rapidjson/rapidjson.h
@@ -125,6 +125,19 @@
#endif
///////////////////////////////////////////////////////////////////////////////
+// __cplusplus macro
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+
+#if defined(_MSC_VER)
+#define RAPIDJSON_CPLUSPLUS _MSVC_LANG
+#else
+#define RAPIDJSON_CPLUSPLUS __cplusplus
+#endif
+
+//!@endcond
+
+///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_HAS_STDSTRING
#ifndef RAPIDJSON_HAS_STDSTRING
@@ -150,6 +163,24 @@
#endif // RAPIDJSON_HAS_STDSTRING
///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_USE_MEMBERSMAP
+
+/*! \def RAPIDJSON_USE_MEMBERSMAP
+ \ingroup RAPIDJSON_CONFIG
+ \brief Enable RapidJSON support for object members handling in a \c std::multimap
+
+ By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object
+ members are stored in a \c std::multimap for faster lookup and deletion times, a
+ trade off with a slightly slower insertion time and a small object allocat(or)ed
+ memory overhead.
+
+ \hideinitializer
+*/
+#ifndef RAPIDJSON_USE_MEMBERSMAP
+#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NO_INT64DEFINE
/*! \def RAPIDJSON_NO_INT64DEFINE
@@ -411,7 +442,7 @@ RAPIDJSON_NAMESPACE_END
// Prefer C++11 static_assert, if available
#ifndef RAPIDJSON_STATIC_ASSERT
-#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
+#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
#define RAPIDJSON_STATIC_ASSERT(x) \
static_assert(x, RAPIDJSON_STRINGIFY(x))
#endif // C++11
@@ -541,8 +572,14 @@ RAPIDJSON_NAMESPACE_END
///////////////////////////////////////////////////////////////////////////////
// C++11 features
+#ifndef RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L)
+#endif
+
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
-#if defined(__clang__)
+#if RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#elif defined(__clang__)
#if __has_feature(cxx_rvalue_references) && \
(defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
@@ -559,8 +596,14 @@ RAPIDJSON_NAMESPACE_END
#endif
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
-#if defined(__clang__)
+#if RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
+#elif defined(__clang__)
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1900) || \
@@ -570,11 +613,13 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
#endif
#endif
+#ifndef RAPIDJSON_NOEXCEPT
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
#define RAPIDJSON_NOEXCEPT noexcept
#else
-#define RAPIDJSON_NOEXCEPT /* noexcept */
+#define RAPIDJSON_NOEXCEPT throw()
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+#endif
// no automatic detection, yet
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
@@ -600,9 +645,17 @@ RAPIDJSON_NAMESPACE_END
///////////////////////////////////////////////////////////////////////////////
// C++17 features
-#if defined(__has_cpp_attribute)
-# if __has_cpp_attribute(fallthrough)
-# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
+#ifndef RAPIDJSON_HAS_CXX17
+#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L)
+#endif
+
+#if RAPIDJSON_HAS_CXX17
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
+#elif defined(__has_cpp_attribute)
+# if __has_cpp_attribute(clang::fallthrough)
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]]
+# elif __has_cpp_attribute(fallthrough)
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough))
# else
# define RAPIDJSON_DELIBERATE_FALLTHROUGH
# endif
@@ -628,12 +681,8 @@ RAPIDJSON_NAMESPACE_END
#ifndef RAPIDJSON_NOEXCEPT_ASSERT
#ifdef RAPIDJSON_ASSERT_THROWS
-#if RAPIDJSON_HAS_CXX11_NOEXCEPT
-#define RAPIDJSON_NOEXCEPT_ASSERT(x)
-#else
#include <cassert>
#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x)
-#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
#else
#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
#endif // RAPIDJSON_ASSERT_THROWS
diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h
index a83a6ed5..31e3ca63 100644
--- a/test/perftest/perftest.h
+++ b/test/perftest/perftest.h
@@ -130,7 +130,8 @@ public:
"integers.json",
"mixed.json",
"nulls.json",
- "paragraphs.json"
+ "paragraphs.json",
+ "alotofkeys.json"
};
for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) {
@@ -158,7 +159,7 @@ public:
free(whitespace_);
json_ = 0;
whitespace_ = 0;
- for (size_t i = 0; i < 7; i++) {
+ for (size_t i = 0; i < 8; i++) {
free(types_[i]);
types_[i] = 0;
}
@@ -174,8 +175,8 @@ protected:
size_t length_;
char *whitespace_;
size_t whitespace_length_;
- char *types_[7];
- size_t typesLength_[7];
+ char *types_[8];
+ size_t typesLength_[8];
static const size_t kTrialCount = 1000;
};
diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp
index 24e7120e..ce41c109 100644
--- a/test/perftest/rapidjsontest.cpp
+++ b/test/perftest/rapidjsontest.cpp
@@ -26,6 +26,7 @@
#include "rapidjson/memorystream.h"
#include <fstream>
+#include <vector>
#ifdef RAPIDJSON_SSE2
#define SIMD_SUFFIX(name) name##_SSE2
@@ -52,7 +53,7 @@ public:
// Parse as a document
EXPECT_FALSE(doc_.Parse(json_).HasParseError());
- for (size_t i = 0; i < 7; i++)
+ for (size_t i = 0; i < 8; i++)
EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError());
}
@@ -68,7 +69,7 @@ private:
protected:
char *temp_;
Document doc_;
- Document typesDoc_[7];
+ Document typesDoc_[8];
};
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) {
@@ -335,6 +336,23 @@ TEST_F(RapidJson, DocumentAccept) {
}
}
+TEST_F(RapidJson, DocumentFind) {
+ typedef Document::ValueType ValueType;
+ typedef ValueType::ConstMemberIterator ConstMemberIterator;
+ const Document &doc = typesDoc_[7]; // alotofkeys.json
+ if (doc.IsObject()) {
+ std::vector<const ValueType*> keys;
+ for (ConstMemberIterator it = doc.MemberBegin(); it != doc.MemberEnd(); ++it) {
+ keys.push_back(&it->name);
+ }
+ for (size_t i = 0; i < kTrialCount; i++) {
+ for (size_t j = 0; j < keys.size(); j++) {
+ EXPECT_TRUE(doc.FindMember(*keys[j]) != doc.MemberEnd());
+ }
+ }
+ }
+}
+
struct NullStream {
typedef char Ch;
diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt
index 6439c361..565ed982 100644
--- a/test/unittest/CMakeLists.txt
+++ b/test/unittest/CMakeLists.txt
@@ -16,6 +16,7 @@ set(UNITTEST_SOURCES
jsoncheckertest.cpp
namespacetest.cpp
pointertest.cpp
+ platformtest.cpp
prettywritertest.cpp
ostreamwrappertest.cpp
readertest.cpp
diff --git a/test/unittest/allocatorstest.cpp b/test/unittest/allocatorstest.cpp
index c541f04e..2ffc3254 100644
--- a/test/unittest/allocatorstest.cpp
+++ b/test/unittest/allocatorstest.cpp
@@ -16,6 +16,11 @@
#include "rapidjson/allocators.h"
+#include <map>
+#include <string>
+#include <utility>
+#include <functional>
+
using namespace rapidjson;
template <typename Allocator>
@@ -47,19 +52,206 @@ void TestAllocator(Allocator& a) {
EXPECT_TRUE(a.Realloc(a.Malloc(1), 1, 0) == 0);
}
+struct TestStdAllocatorData {
+ TestStdAllocatorData(int &constructions, int &destructions) :
+ constructions_(&constructions),
+ destructions_(&destructions)
+ {
+ ++*constructions_;
+ }
+ TestStdAllocatorData(const TestStdAllocatorData& rhs) :
+ constructions_(rhs.constructions_),
+ destructions_(rhs.destructions_)
+ {
+ ++*constructions_;
+ }
+ TestStdAllocatorData& operator=(const TestStdAllocatorData& rhs)
+ {
+ this->~TestStdAllocatorData();
+ constructions_ = rhs.constructions_;
+ destructions_ = rhs.destructions_;
+ ++*constructions_;
+ return *this;
+ }
+ ~TestStdAllocatorData()
+ {
+ ++*destructions_;
+ }
+private:
+ TestStdAllocatorData();
+ int *constructions_,
+ *destructions_;
+};
+
+template <typename Allocator>
+void TestStdAllocator(const Allocator& a) {
+#if RAPIDJSON_HAS_CXX17
+ typedef StdAllocator<bool, Allocator> BoolAllocator;
+#else
+ typedef StdAllocator<void, Allocator> VoidAllocator;
+ typedef typename VoidAllocator::template rebind<bool>::other BoolAllocator;
+#endif
+ BoolAllocator ba(a), ba2(a);
+ EXPECT_TRUE(ba == ba2);
+ EXPECT_FALSE(ba!= ba2);
+ ba.deallocate(ba.allocate());
+ EXPECT_TRUE(ba == ba2);
+ EXPECT_FALSE(ba != ba2);
+
+ unsigned long long ll = 0, *llp = &ll;
+ const unsigned long long cll = 0, *cllp = &cll;
+ StdAllocator<unsigned long long, Allocator> lla(a);
+ EXPECT_EQ(lla.address(ll), llp);
+ EXPECT_EQ(lla.address(cll), cllp);
+ EXPECT_TRUE(lla.max_size() > 0 && lla.max_size() <= SIZE_MAX / sizeof(unsigned long long));
+
+ int *arr;
+ StdAllocator<int, Allocator> ia(a);
+ arr = ia.allocate(10 * sizeof(int));
+ EXPECT_TRUE(arr != 0);
+ for (int i = 0; i < 10; ++i) {
+ arr[i] = 0x0f0f0f0f;
+ }
+ ia.deallocate(arr, 10);
+ arr = Malloc<int>(ia, 10);
+ EXPECT_TRUE(arr != 0);
+ for (int i = 0; i < 10; ++i) {
+ arr[i] = 0x0f0f0f0f;
+ }
+ arr = Realloc<int>(ia, arr, 10, 20);
+ EXPECT_TRUE(arr != 0);
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(arr[i], 0x0f0f0f0f);
+ }
+ for (int i = 10; i < 20; i++) {
+ arr[i] = 0x0f0f0f0f;
+ }
+ Free<int>(ia, arr, 20);
+
+ int cons = 0, dest = 0;
+ StdAllocator<TestStdAllocatorData, Allocator> da(a);
+ for (int i = 1; i < 10; i++) {
+ TestStdAllocatorData *d = da.allocate();
+ EXPECT_TRUE(d != 0);
+
+ da.destroy(new(d) TestStdAllocatorData(cons, dest));
+ EXPECT_EQ(cons, i);
+ EXPECT_EQ(dest, i);
+
+ da.deallocate(d);
+ }
+
+ typedef StdAllocator<char, Allocator> CharAllocator;
+ typedef std::basic_string<char, std::char_traits<char>, CharAllocator> String;
+#if RAPIDJSON_HAS_CXX11
+ String s(CharAllocator{a});
+#else
+ CharAllocator ca(a);
+ String s(ca);
+#endif
+ for (int i = 0; i < 26; i++) {
+ s.push_back(static_cast<char>('A' + i));
+ }
+ EXPECT_TRUE(s == "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+ typedef StdAllocator<std::pair<const int, bool>, Allocator> MapAllocator;
+ typedef std::map<int, bool, std::less<int>, MapAllocator> Map;
+#if RAPIDJSON_HAS_CXX11
+ Map map(std::less<int>(), MapAllocator{a});
+#else
+ MapAllocator ma(a);
+ Map map(std::less<int>(), ma);
+#endif
+ for (int i = 0; i < 10; i++) {
+ map.insert(std::make_pair(i, (i % 2) == 0));
+ }
+ EXPECT_TRUE(map.size() == 10);
+ for (int i = 0; i < 10; i++) {
+ typename Map::iterator it = map.find(i);
+ EXPECT_TRUE(it != map.end());
+ EXPECT_TRUE(it->second == ((i % 2) == 0));
+ }
+}
+
TEST(Allocator, CrtAllocator) {
CrtAllocator a;
+
TestAllocator(a);
+ TestStdAllocator(a);
+
+ CrtAllocator a2;
+ EXPECT_TRUE(a == a2);
+ EXPECT_FALSE(a != a2);
+ a2.Free(a2.Malloc(1));
+ EXPECT_TRUE(a == a2);
+ EXPECT_FALSE(a != a2);
}
TEST(Allocator, MemoryPoolAllocator) {
- MemoryPoolAllocator<> a;
+ const size_t capacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY;
+ MemoryPoolAllocator<> a(capacity);
+
+ a.Clear(); // noop
+ EXPECT_EQ(a.Size(), 0u);
+ EXPECT_EQ(a.Capacity(), 0u);
+ EXPECT_EQ(a.Shared(), false);
+ {
+ MemoryPoolAllocator<> a2(a);
+ EXPECT_EQ(a2.Shared(), true);
+ EXPECT_EQ(a.Shared(), true);
+ EXPECT_TRUE(a == a2);
+ EXPECT_FALSE(a != a2);
+ a2.Free(a2.Malloc(1));
+ EXPECT_TRUE(a == a2);
+ EXPECT_FALSE(a != a2);
+ }
+ EXPECT_EQ(a.Shared(), false);
+ EXPECT_EQ(a.Capacity(), capacity);
+ EXPECT_EQ(a.Size(), 8u); // aligned
+ a.Clear();
+ EXPECT_EQ(a.Capacity(), 0u);
+ EXPECT_EQ(a.Size(), 0u);
+
TestAllocator(a);
+ TestStdAllocator(a);
for (size_t i = 1; i < 1000; i++) {
EXPECT_TRUE(a.Malloc(i) != 0);
EXPECT_LE(a.Size(), a.Capacity());
}
+
+ CrtAllocator baseAllocator;
+ a = MemoryPoolAllocator<>(capacity, &baseAllocator);
+ EXPECT_EQ(a.Capacity(), 0u);
+ EXPECT_EQ(a.Size(), 0u);
+ a.Free(a.Malloc(1));
+ EXPECT_EQ(a.Capacity(), capacity);
+ EXPECT_EQ(a.Size(), 8u); // aligned
+
+ {
+ a.Clear();
+ const size_t bufSize = 1024;
+ char *buffer = (char *)a.Malloc(bufSize);
+ MemoryPoolAllocator<> aligned_a(buffer, bufSize);
+ EXPECT_TRUE(aligned_a.Capacity() > 0 && aligned_a.Capacity() <= bufSize);
+ EXPECT_EQ(aligned_a.Size(), 0u);
+ aligned_a.Free(aligned_a.Malloc(1));
+ EXPECT_TRUE(aligned_a.Capacity() > 0 && aligned_a.Capacity() <= bufSize);
+ EXPECT_EQ(aligned_a.Size(), 8u); // aligned
+ }
+
+ {
+ a.Clear();
+ const size_t bufSize = 1024;
+ char *buffer = (char *)a.Malloc(bufSize);
+ RAPIDJSON_ASSERT(bufSize % sizeof(void*) == 0);
+ MemoryPoolAllocator<> unaligned_a(buffer + 1, bufSize - 1);
+ EXPECT_TRUE(unaligned_a.Capacity() > 0 && unaligned_a.Capacity() <= bufSize - sizeof(void*));
+ EXPECT_EQ(unaligned_a.Size(), 0u);
+ unaligned_a.Free(unaligned_a.Malloc(1));
+ EXPECT_TRUE(unaligned_a.Capacity() > 0 && unaligned_a.Capacity() <= bufSize - sizeof(void*));
+ EXPECT_EQ(unaligned_a.Size(), 8u); // aligned
+ }
}
TEST(Allocator, Alignment) {
diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp
index 472165fd..c3d1e484 100644
--- a/test/unittest/documenttest.cpp
+++ b/test/unittest/documenttest.cpp
@@ -325,6 +325,8 @@ TEST(Document, Swap) {
EXPECT_TRUE(d1.IsNull());
// reset document, including allocator
+ // so clear o before so that it doesnt contain dangling elements
+ o.Clear();
Document().Swap(d2);
EXPECT_TRUE(d2.IsNull());
EXPECT_NE(&d2.GetAllocator(), &a);
diff --git a/test/unittest/platformtest.cpp b/test/unittest/platformtest.cpp
new file mode 100644
index 00000000..05eba3f5
--- /dev/null
+++ b/test/unittest/platformtest.cpp
@@ -0,0 +1,40 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2021 THL A29 Limited, a Tencent company, and Milo Yip.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+// see https://github.com/Tencent/rapidjson/issues/1448
+// including windows.h on purpose to provoke a compile time problem as GetObject is a
+// macro that gets defined when windows.h is included
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include "rapidjson/document.h"
+#undef GetObject
+
+using namespace rapidjson;
+
+TEST(Platform, GetObject) {
+ Document doc;
+ doc.Parse(" { \"object\" : { \"pi\": 3.1416} } ");
+ EXPECT_TRUE(doc.IsObject());
+ EXPECT_TRUE(doc.HasMember("object"));
+ const Document::ValueType& o = doc["object"];
+ EXPECT_TRUE(o.IsObject());
+ Value::ConstObject sub = o.GetObject();
+ EXPECT_TRUE(sub.HasMember("pi"));
+ Value::ConstObject sub2 = o.GetObj();
+ EXPECT_TRUE(sub2.HasMember("pi"));
+}
diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp
index 00f06528..0a6b325f 100644
--- a/test/unittest/valuetest.cpp
+++ b/test/unittest/valuetest.cpp
@@ -1078,9 +1078,9 @@ static void TestArray(T& x, Allocator& allocator) {
}
TEST(Value, Array) {
+ Value::AllocatorType allocator;
Value x(kArrayType);
const Value& y = x;
- Value::AllocatorType allocator;
EXPECT_EQ(kArrayType, x.GetType());
EXPECT_TRUE(x.IsArray());
@@ -1119,6 +1119,16 @@ TEST(Value, Array) {
z.SetArray();
EXPECT_TRUE(z.IsArray());
EXPECT_TRUE(z.Empty());
+
+ // PR #1503: assign from inner Value
+ {
+ CrtAllocator a; // Free() is not a noop
+ GenericValue<UTF8<>, CrtAllocator> nullValue;
+ GenericValue<UTF8<>, CrtAllocator> arrayValue(kArrayType);
+ arrayValue.PushBack(nullValue, a);
+ arrayValue = arrayValue[0]; // shouldn't crash (use after free)
+ EXPECT_TRUE(arrayValue.IsNull());
+ }
}
TEST(Value, ArrayHelper) {
@@ -1481,9 +1491,9 @@ static void TestObject(T& x, Allocator& allocator) {
}
TEST(Value, Object) {
+ Value::AllocatorType allocator;
Value x(kObjectType);
const Value& y = x; // const version
- Value::AllocatorType allocator;
EXPECT_EQ(kObjectType, x.GetType());
EXPECT_TRUE(x.IsObject());