mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-14 23:07:55 +02:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b31d224fd6 | ||
![]() |
a901a04c28 | ||
![]() |
c9afea87e3 | ||
![]() |
edf9369493 | ||
![]() |
18ae85b44c | ||
![]() |
bd2aa77b94 | ||
![]() |
6a12fb8999 | ||
![]() |
a1ca466e04 | ||
![]() |
5a14ab5ea3 |
23
.gitignore
vendored
23
.gitignore
vendored
@@ -10,27 +10,4 @@
|
|||||||
/libs/
|
/libs/
|
||||||
/doc/doxyfile
|
/doc/doxyfile
|
||||||
/dist/
|
/dist/
|
||||||
#/version
|
|
||||||
#/include/json/version.h
|
#/include/json/version.h
|
||||||
|
|
||||||
# MSVC project files:
|
|
||||||
*.sln
|
|
||||||
*.vcxproj
|
|
||||||
*.filters
|
|
||||||
*.user
|
|
||||||
*.sdf
|
|
||||||
*.opensdf
|
|
||||||
*.suo
|
|
||||||
|
|
||||||
# MSVC build files:
|
|
||||||
*.lib
|
|
||||||
*.obj
|
|
||||||
*.tlog/
|
|
||||||
*.pdb
|
|
||||||
|
|
||||||
# CMake-generated files:
|
|
||||||
CMakeFiles/
|
|
||||||
CTestTestFile.cmake
|
|
||||||
cmake_install.cmake
|
|
||||||
pkg-config/jsoncpp.pc
|
|
||||||
jsoncpp_lib_static.dir/
|
|
||||||
|
@@ -7,7 +7,7 @@ language: cpp
|
|||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- gcc
|
||||||
- clang
|
- clang
|
||||||
script: cmake -DJSONCPP_WITH_CMAKE_PACKAGE=$CMAKE_PKG -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIB -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make && make jsoncpp_check
|
script: cmake -DJSONCPP_WITH_CMAKE_PACKAGE=$CMAKE_PKG -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIB -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
- SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
|
- SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
# vim: et ts=4 sts=4 sw=4 tw=0
|
|
||||||
|
|
||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5)
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5)
|
||||||
PROJECT(jsoncpp)
|
PROJECT(jsoncpp)
|
||||||
ENABLE_TESTING()
|
ENABLE_TESTING()
|
||||||
|
|
||||||
OPTION(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON)
|
OPTION(JSONCPP_WITH_TESTS "Compile and run JsonCpp test executables" ON)
|
||||||
OPTION(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON)
|
OPTION(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON)
|
||||||
OPTION(JSONCPP_WITH_WARNING_AS_ERROR "Force compilation to fail if a warning occurs" OFF)
|
OPTION(JSONCPP_WITH_WARNING_AS_ERROR "Force compilation to fail if a warning occurs" OFF)
|
||||||
OPTION(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON)
|
OPTION(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON)
|
||||||
@@ -56,24 +54,17 @@ MACRO(jsoncpp_parse_version VERSION_TEXT OUPUT_PREFIX)
|
|||||||
ENDMACRO(jsoncpp_parse_version)
|
ENDMACRO(jsoncpp_parse_version)
|
||||||
|
|
||||||
# Read out version from "version" file
|
# Read out version from "version" file
|
||||||
#FILE(STRINGS "version" JSONCPP_VERSION)
|
FILE(STRINGS "version" JSONCPP_VERSION)
|
||||||
#SET( JSONCPP_VERSION_MAJOR X )
|
|
||||||
#SET( JSONCPP_VERSION_MINOR Y )
|
|
||||||
#SET( JSONCPP_VERSION_PATCH Z )
|
|
||||||
SET( JSONCPP_VERSION 1.10.0 )
|
|
||||||
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
|
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
|
||||||
#IF(NOT JSONCPP_VERSION_FOUND)
|
IF(NOT JSONCPP_VERSION_FOUND)
|
||||||
# MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
|
MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
|
||||||
#ENDIF(NOT JSONCPP_VERSION_FOUND)
|
ENDIF(NOT JSONCPP_VERSION_FOUND)
|
||||||
|
|
||||||
MESSAGE(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}")
|
MESSAGE(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}")
|
||||||
# File version.h is only regenerated on CMake configure step
|
# File version.h is only regenerated on CMake configure step
|
||||||
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/src/lib_json/version.h.in"
|
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/src/lib_json/version.h.in"
|
||||||
"${PROJECT_SOURCE_DIR}/include/json/version.h"
|
"${PROJECT_SOURCE_DIR}/include/json/version.h" )
|
||||||
NEWLINE_STYLE UNIX )
|
|
||||||
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/version.in"
|
|
||||||
"${PROJECT_SOURCE_DIR}/version"
|
|
||||||
NEWLINE_STYLE UNIX )
|
|
||||||
|
|
||||||
macro(UseCompilationWarningAsError)
|
macro(UseCompilationWarningAsError)
|
||||||
if ( MSVC )
|
if ( MSVC )
|
||||||
|
42
README.md
42
README.md
@@ -7,20 +7,17 @@ pairs.
|
|||||||
|
|
||||||
[json-org]: http://json.org/
|
[json-org]: http://json.org/
|
||||||
|
|
||||||
[JsonCpp][] is a C++ library that allows manipulating JSON values, including
|
JsonCpp is a C++ library that allows manipulating JSON values, including
|
||||||
serialization and deserialization to and from strings. It can also preserve
|
serialization and deserialization to and from strings. It can also preserve
|
||||||
existing comment in unserialization/serialization steps, making it a convenient
|
existing comment in unserialization/serialization steps, making it a convenient
|
||||||
format to store user input files.
|
format to store user input files.
|
||||||
|
|
||||||
[JsonCpp]: http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html
|
|
||||||
|
|
||||||
## A note on backward-compatibility
|
## A note on backward-compatibility
|
||||||
* `1.y.z` is built with C++11.
|
Very soon, we are switching to C++11 only. For older compilers, try the `pre-C++11` branch.
|
||||||
* `0.y.z` can be used with older compilers.
|
|
||||||
* Major versions maintain binary-compatibility.
|
|
||||||
|
|
||||||
Using JsonCpp in your project
|
Using JsonCpp in your project
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
The recommended approach to integrating JsonCpp in your project is to build
|
The recommended approach to integrating JsonCpp in your project is to build
|
||||||
the amalgamated source (a single `.cpp` file) with your own build system. This
|
the amalgamated source (a single `.cpp` file) with your own build system. This
|
||||||
ensures consistency of compilation flags and ABI compatibility. See the section
|
ensures consistency of compilation flags and ABI compatibility. See the section
|
||||||
@@ -31,11 +28,13 @@ should be included as follow:
|
|||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
If JsonCpp was built as a dynamic library on Windows, then your project needs to
|
If JsonCpp was build as a dynamic library on Windows, then your project needs to
|
||||||
define the macro `JSON_DLL`.
|
define the macro `JSON_DLL`.
|
||||||
|
|
||||||
Building and testing with CMake
|
|
||||||
-------------------------------
|
Building and testing with new CMake
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
[CMake][] is a C++ Makefiles/Solution generator. It is usually available on most
|
[CMake][] is a C++ Makefiles/Solution generator. It is usually available on most
|
||||||
Linux system as package. On Ubuntu:
|
Linux system as package. On Ubuntu:
|
||||||
|
|
||||||
@@ -76,8 +75,10 @@ the `-G` option).
|
|||||||
By default CMake hides compilation commands. This can be modified by specifying
|
By default CMake hides compilation commands. This can be modified by specifying
|
||||||
`-DCMAKE_VERBOSE_MAKEFILE=true` when generating makefiles.
|
`-DCMAKE_VERBOSE_MAKEFILE=true` when generating makefiles.
|
||||||
|
|
||||||
|
|
||||||
Building and testing with SCons
|
Building and testing with SCons
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
**Note:** The SCons-based build system is deprecated. Please use CMake; see the
|
**Note:** The SCons-based build system is deprecated. Please use CMake; see the
|
||||||
section above.
|
section above.
|
||||||
|
|
||||||
@@ -106,7 +107,14 @@ If you are building with Microsoft Visual Studio 2008, you need to set up the
|
|||||||
environment by running `vcvars32.bat` (e.g. MSVC 2008 command prompt) before
|
environment by running `vcvars32.bat` (e.g. MSVC 2008 command prompt) before
|
||||||
running SCons.
|
running SCons.
|
||||||
|
|
||||||
# Running the tests manually
|
|
||||||
|
Running the tests manually
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Note that test can be run using SCons using the `check` target:
|
||||||
|
|
||||||
|
scons platform=$PLATFORM check
|
||||||
|
|
||||||
You need to run tests manually only if you are troubleshooting an issue.
|
You need to run tests manually only if you are troubleshooting an issue.
|
||||||
|
|
||||||
In the instructions below, replace `path/to/jsontest` with the path of the
|
In the instructions below, replace `path/to/jsontest` with the path of the
|
||||||
@@ -129,21 +137,20 @@ In the instructions below, replace `path/to/jsontest` with the path of the
|
|||||||
# You can run the tests using valgrind:
|
# You can run the tests using valgrind:
|
||||||
python rununittests.py --valgrind path/to/test_lib_json
|
python rununittests.py --valgrind path/to/test_lib_json
|
||||||
|
|
||||||
## Running the tests using scons
|
|
||||||
Note that tests can be run using SCons using the `check` target:
|
|
||||||
|
|
||||||
scons platform=$PLATFORM check
|
|
||||||
|
|
||||||
Building the documentation
|
Building the documentation
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
Run the Python script `doxybuild.py` from the top directory:
|
Run the Python script `doxybuild.py` from the top directory:
|
||||||
|
|
||||||
python doxybuild.py --doxygen=$(which doxygen) --open --with-dot
|
python doxybuild.py --doxygen=$(which doxygen) --open --with-dot
|
||||||
|
|
||||||
See `doxybuild.py --help` for options.
|
See `doxybuild.py --help` for options.
|
||||||
|
|
||||||
|
|
||||||
Generating amalgamated source and header
|
Generating amalgamated source and header
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
JsonCpp is provided with a script to generate a single header and a single
|
JsonCpp is provided with a script to generate a single header and a single
|
||||||
source file to ease inclusion into an existing project. The amalgamated source
|
source file to ease inclusion into an existing project. The amalgamated source
|
||||||
can be generated at any time by running the following command from the
|
can be generated at any time by running the following command from the
|
||||||
@@ -165,8 +172,10 @@ The amalgamated sources are generated by concatenating JsonCpp source in the
|
|||||||
correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion
|
correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion
|
||||||
of other headers.
|
of other headers.
|
||||||
|
|
||||||
|
|
||||||
Adding a reader/writer test
|
Adding a reader/writer test
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
To add a test, you need to create two files in test/data:
|
To add a test, you need to create two files in test/data:
|
||||||
|
|
||||||
* a `TESTNAME.json` file, that contains the input document in JSON format.
|
* a `TESTNAME.json` file, that contains the input document in JSON format.
|
||||||
@@ -186,8 +195,10 @@ The `TESTNAME.expected` file format is as follows:
|
|||||||
See the examples `test_complex_01.json` and `test_complex_01.expected` to better
|
See the examples `test_complex_01.json` and `test_complex_01.expected` to better
|
||||||
understand element paths.
|
understand element paths.
|
||||||
|
|
||||||
|
|
||||||
Understanding reader/writer test output
|
Understanding reader/writer test output
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
When a test is run, output files are generated beside the input test files.
|
When a test is run, output files are generated beside the input test files.
|
||||||
Below is a short description of the content of each file:
|
Below is a short description of the content of each file:
|
||||||
|
|
||||||
@@ -204,7 +215,10 @@ Below is a short description of the content of each file:
|
|||||||
* `test_complex_01.process-output`: `jsontest` output, typically useful for
|
* `test_complex_01.process-output`: `jsontest` output, typically useful for
|
||||||
understanding parsing errors.
|
understanding parsing errors.
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
See the `LICENSE` file for details. In summary, JsonCpp is licensed under the
|
See the `LICENSE` file for details. In summary, JsonCpp is licensed under the
|
||||||
MIT license, or public domain if desired and recognized in your jurisdiction.
|
MIT license, or public domain if desired and recognized in your jurisdiction.
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
"""Amalgate json-cpp library sources into a single source and header file.
|
"""Amalgate json-cpp library sources into a single source and header file.
|
||||||
|
|
||||||
Works with python2.6+ and python3.4+.
|
Requires Python 2.6
|
||||||
|
|
||||||
Example of invocation (must be invoked from json-cpp top directory):
|
Example of invocation (must be invoked from json-cpp top directory):
|
||||||
python amalgate.py
|
python amalgate.py
|
||||||
@@ -59,7 +59,7 @@ def amalgamate_source(source_top_dir=None,
|
|||||||
print("Amalgating header...")
|
print("Amalgating header...")
|
||||||
header = AmalgamationFile(source_top_dir)
|
header = AmalgamationFile(source_top_dir)
|
||||||
header.add_text("/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).")
|
header.add_text("/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).")
|
||||||
header.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
|
header.add_text("/// It is intented to be used with #include <%s>" % header_include_path)
|
||||||
header.add_file("LICENSE", wrap_in_comment=True)
|
header.add_file("LICENSE", wrap_in_comment=True)
|
||||||
header.add_text("#ifndef JSON_AMALGATED_H_INCLUDED")
|
header.add_text("#ifndef JSON_AMALGATED_H_INCLUDED")
|
||||||
header.add_text("# define JSON_AMALGATED_H_INCLUDED")
|
header.add_text("# define JSON_AMALGATED_H_INCLUDED")
|
||||||
@@ -85,7 +85,7 @@ def amalgamate_source(source_top_dir=None,
|
|||||||
print("Amalgating forward header...")
|
print("Amalgating forward header...")
|
||||||
header = AmalgamationFile(source_top_dir)
|
header = AmalgamationFile(source_top_dir)
|
||||||
header.add_text("/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).")
|
header.add_text("/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).")
|
||||||
header.add_text('/// It is intended to be used with #include "%s"' % forward_header_include_path)
|
header.add_text("/// It is intented to be used with #include <%s>" % forward_header_include_path)
|
||||||
header.add_text("/// This header provides forward declaration for all JsonCpp types.")
|
header.add_text("/// This header provides forward declaration for all JsonCpp types.")
|
||||||
header.add_file("LICENSE", wrap_in_comment=True)
|
header.add_file("LICENSE", wrap_in_comment=True)
|
||||||
header.add_text("#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED")
|
header.add_text("#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED")
|
||||||
@@ -105,19 +105,15 @@ def amalgamate_source(source_top_dir=None,
|
|||||||
print("Amalgating source...")
|
print("Amalgating source...")
|
||||||
source = AmalgamationFile(source_top_dir)
|
source = AmalgamationFile(source_top_dir)
|
||||||
source.add_text("/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).")
|
source.add_text("/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).")
|
||||||
source.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
|
source.add_text("/// It is intented to be used with #include <%s>" % header_include_path)
|
||||||
source.add_file("LICENSE", wrap_in_comment=True)
|
source.add_file("LICENSE", wrap_in_comment=True)
|
||||||
source.add_text("")
|
source.add_text("")
|
||||||
source.add_text('#include "%s"' % header_include_path)
|
source.add_text("#include <%s>" % header_include_path)
|
||||||
source.add_text("""
|
|
||||||
#ifndef JSON_IS_AMALGAMATION
|
|
||||||
#error "Compile with -I PATH_TO_JSON_DIRECTORY"
|
|
||||||
#endif
|
|
||||||
""")
|
|
||||||
source.add_text("")
|
source.add_text("")
|
||||||
lib_json = "src/lib_json"
|
lib_json = "src/lib_json"
|
||||||
source.add_file(os.path.join(lib_json, "json_tool.h"))
|
source.add_file(os.path.join(lib_json, "json_tool.h"))
|
||||||
source.add_file(os.path.join(lib_json, "json_reader.cpp"))
|
source.add_file(os.path.join(lib_json, "json_reader.cpp"))
|
||||||
|
source.add_file(os.path.join(lib_json, "json_batchallocator.h"))
|
||||||
source.add_file(os.path.join(lib_json, "json_valueiterator.inl"))
|
source.add_file(os.path.join(lib_json, "json_valueiterator.inl"))
|
||||||
source.add_file(os.path.join(lib_json, "json_value.cpp"))
|
source.add_file(os.path.join(lib_json, "json_value.cpp"))
|
||||||
source.add_file(os.path.join(lib_json, "json_writer.cpp"))
|
source.add_file(os.path.join(lib_json, "json_writer.cpp"))
|
||||||
|
22
dev.makefile
22
dev.makefile
@@ -1,19 +1,5 @@
|
|||||||
# This is only for jsoncpp developers/contributors.
|
all: build test-amalgamate
|
||||||
# We use this to sign releases, generate documentation, etc.
|
|
||||||
VER?=$(shell cat version)
|
|
||||||
|
|
||||||
default:
|
|
||||||
@echo "VER=${VER}"
|
|
||||||
sign: jsoncpp-${VER}.tar.gz
|
|
||||||
gpg --armor --detach-sign $<
|
|
||||||
gpg --verify $<.asc
|
|
||||||
# Then upload .asc to the release.
|
|
||||||
jsoncpp-%.tar.gz:
|
|
||||||
curl https://github.com/open-source-parsers/jsoncpp/archive/$*.tar.gz -o $@
|
|
||||||
dox:
|
|
||||||
python doxybuild.py --doxygen=$$(which doxygen) --in doc/web_doxyfile.in
|
|
||||||
rsync -va --delete dist/doxygen/jsoncpp-api-html-${VER}/ ../jsoncpp-docs/doxygen/
|
|
||||||
# Then 'git add -A' and 'git push' in jsoncpp-docs.
|
|
||||||
build:
|
build:
|
||||||
mkdir -p build/debug
|
mkdir -p build/debug
|
||||||
cd build/debug; cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=ON -G "Unix Makefiles" ../..
|
cd build/debug; cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=ON -G "Unix Makefiles" ../..
|
||||||
@@ -21,12 +7,8 @@ build:
|
|||||||
|
|
||||||
# Currently, this depends on include/json/version.h generated
|
# Currently, this depends on include/json/version.h generated
|
||||||
# by cmake.
|
# by cmake.
|
||||||
test-amalgamate:
|
test-amalgamate: build
|
||||||
python2.7 amalgamate.py
|
python2.7 amalgamate.py
|
||||||
python3.4 amalgamate.py
|
python3.4 amalgamate.py
|
||||||
cd dist; gcc -I. -c jsoncpp.cpp
|
|
||||||
|
|
||||||
clean:
|
|
||||||
\rm -rf *.gz *.asc dist/
|
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
|
@@ -1946,7 +1946,8 @@ INCLUDE_FILE_PATTERNS = *.h
|
|||||||
PREDEFINED = "_MSC_VER=1400" \
|
PREDEFINED = "_MSC_VER=1400" \
|
||||||
_CPPRTTI \
|
_CPPRTTI \
|
||||||
_WIN32 \
|
_WIN32 \
|
||||||
JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
JSONCPP_DOC_EXCLUDE_IMPLEMENTATION \
|
||||||
|
JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
|
@@ -56,24 +56,20 @@ std::cin >> root;
|
|||||||
// You can also read into a particular sub-value.
|
// You can also read into a particular sub-value.
|
||||||
std::cin >> root["subtree"];
|
std::cin >> root["subtree"];
|
||||||
|
|
||||||
// Get the value of the member of root named 'encoding',
|
// Get the value of the member of root named 'encoding', return 'UTF-8' if there is no
|
||||||
// and return 'UTF-8' if there is no such member.
|
// such member.
|
||||||
std::string encoding = root.get("encoding", "UTF-8" ).asString();
|
std::string encoding = root.get("encoding", "UTF-8" ).asString();
|
||||||
|
// Get the value of the member of root named 'encoding'; return a 'null' value if
|
||||||
// Get the value of the member of root named 'plug-ins'; return a 'null' value if
|
|
||||||
// there is no such member.
|
// there is no such member.
|
||||||
const Json::Value plugins = root["plug-ins"];
|
const Json::Value plugins = root["plug-ins"];
|
||||||
|
for ( int index = 0; index < plugins.size(); ++index ) // Iterates over the sequence elements.
|
||||||
// Iterate over the sequence elements.
|
|
||||||
for ( int index = 0; index < plugins.size(); ++index )
|
|
||||||
loadPlugIn( plugins[index].asString() );
|
loadPlugIn( plugins[index].asString() );
|
||||||
|
|
||||||
// Try other datatypes. Some are auto-convertible to others.
|
|
||||||
foo::setIndentLength( root["indent"].get("length", 3).asInt() );
|
foo::setIndentLength( root["indent"].get("length", 3).asInt() );
|
||||||
foo::setIndentUseSpace( root["indent"].get("use_space", true).asBool() );
|
foo::setIndentUseSpace( root["indent"].get("use_space", true).asBool() );
|
||||||
|
|
||||||
// Since Json::Value has an implicit constructor for all value types, it is not
|
// Since Json::Value has implicit constructor for all value types, it is not
|
||||||
// necessary to explicitly construct the Json::Value object.
|
// necessary to explicitly construct the Json::Value object:
|
||||||
root["encoding"] = foo::getCurrentEncoding();
|
root["encoding"] = foo::getCurrentEncoding();
|
||||||
root["indent"]["length"] = foo::getCurrentIndentLength();
|
root["indent"]["length"] = foo::getCurrentIndentLength();
|
||||||
root["indent"]["use_space"] = foo::getCurrentIndentUseSpace();
|
root["indent"]["use_space"] = foo::getCurrentIndentUseSpace();
|
||||||
@@ -96,13 +92,13 @@ features without losing binary-compatibility.
|
|||||||
\code
|
\code
|
||||||
// For convenience, use `writeString()` with a specialized builder.
|
// For convenience, use `writeString()` with a specialized builder.
|
||||||
Json::StreamWriterBuilder wbuilder;
|
Json::StreamWriterBuilder wbuilder;
|
||||||
wbuilder["indentation"] = "\t";
|
wbuilder.settings_["indentation"] = "\t"; // simple Json::Value
|
||||||
std::string document = Json::writeString(wbuilder, root);
|
std::string document = Json::writeString(wbuilder, root);
|
||||||
|
|
||||||
// Here, using a specialized Builder, we discard comments and
|
// Here, using a specialized Builder, we discard comments and
|
||||||
// record errors as we parse.
|
// record errors as we parse.
|
||||||
Json::CharReaderBuilder rbuilder;
|
Json::CharReaderBuilder rbuilder;
|
||||||
rbuilder["collectComments"] = false;
|
rbuilder.settings_["collectComments"] = false; // simple Json::Value
|
||||||
std::string errs;
|
std::string errs;
|
||||||
bool ok = Json::parseFromStream(rbuilder, std::cin, &root, &errs);
|
bool ok = Json::parseFromStream(rbuilder, std::cin, &root, &errs);
|
||||||
\endcode
|
\endcode
|
||||||
@@ -156,7 +152,6 @@ Basically JsonCpp is licensed under MIT license, or public domain if desired
|
|||||||
and recognized in your jurisdiction.
|
and recognized in your jurisdiction.
|
||||||
|
|
||||||
\author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
|
\author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
|
||||||
\author Christopher Dunn <cdunn2001@gmail.com> (primary maintainer)
|
|
||||||
\version \include version
|
\version \include version
|
||||||
We make strong guarantees about binary-compatibility, consistent with
|
We make strong guarantees about binary-compatibility, consistent with
|
||||||
<a href="http://apr.apache.org/versioning.html">the Apache versioning scheme</a>.
|
<a href="http://apr.apache.org/versioning.html">the Apache versioning scheme</a>.
|
||||||
|
@@ -1946,7 +1946,8 @@ INCLUDE_FILE_PATTERNS = *.h
|
|||||||
PREDEFINED = "_MSC_VER=1400" \
|
PREDEFINED = "_MSC_VER=1400" \
|
||||||
_CPPRTTI \
|
_CPPRTTI \
|
||||||
_WIN32 \
|
_WIN32 \
|
||||||
JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
JSONCPP_DOC_EXCLUDE_IMPLEMENTATION \
|
||||||
|
JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
|
@@ -13,30 +13,18 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
/** It should not be possible for a maliciously designed file to
|
|
||||||
* cause an abort() or seg-fault, so these macros are used only
|
|
||||||
* for pre-condition violations and internal logic errors.
|
|
||||||
*/
|
|
||||||
#if JSON_USE_EXCEPTION
|
#if JSON_USE_EXCEPTION
|
||||||
|
#include <stdexcept>
|
||||||
// @todo <= add detail about condition in exception
|
#define JSON_ASSERT(condition) \
|
||||||
# define JSON_ASSERT(condition) \
|
assert(condition); // @todo <= change this into an exception throw
|
||||||
{if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
|
#define JSON_FAIL_MESSAGE(message) do{std::ostringstream oss; oss << message; throw std::runtime_error(oss.str());}while(0)
|
||||||
|
//#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message)
|
||||||
# define JSON_FAIL_MESSAGE(message) \
|
|
||||||
{ \
|
|
||||||
std::ostringstream oss; oss << message; \
|
|
||||||
Json::throwLogicError(oss.str()); \
|
|
||||||
abort(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // JSON_USE_EXCEPTION
|
#else // JSON_USE_EXCEPTION
|
||||||
|
#define JSON_ASSERT(condition) assert(condition);
|
||||||
# define JSON_ASSERT(condition) assert(condition)
|
|
||||||
|
|
||||||
// The call to assert() will show the failure message in debug builds. In
|
// The call to assert() will show the failure message in debug builds. In
|
||||||
// release builds we abort, for a core-dump or debugger.
|
// release bugs we abort, for a core-dump or debugger.
|
||||||
# define JSON_FAIL_MESSAGE(message) \
|
#define JSON_FAIL_MESSAGE(message) \
|
||||||
{ \
|
{ \
|
||||||
std::ostringstream oss; oss << message; \
|
std::ostringstream oss; oss << message; \
|
||||||
assert(false && oss.str().c_str()); \
|
assert(false && oss.str().c_str()); \
|
||||||
|
@@ -15,6 +15,17 @@
|
|||||||
/// std::map
|
/// std::map
|
||||||
/// as Value container.
|
/// as Value container.
|
||||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||||
|
/// If defined, indicates that Json specific container should be used
|
||||||
|
/// (hash table & simple deque container with customizable allocator).
|
||||||
|
/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
|
||||||
|
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
||||||
|
/// Force usage of standard new/malloc based allocator instead of memory pool
|
||||||
|
/// based allocator.
|
||||||
|
/// The memory pools allocator used optimization (initializing Value and
|
||||||
|
/// ValueInternalLink
|
||||||
|
/// as if it was a POD) that may cause some validation tool to report errors.
|
||||||
|
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
|
||||||
|
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
||||||
|
|
||||||
// If non-zero, the library uses exceptions to report bad input instead of C
|
// If non-zero, the library uses exceptions to report bad input instead of C
|
||||||
// assertion macros. The default is to use exceptions.
|
// assertion macros. The default is to use exceptions.
|
||||||
@@ -70,14 +81,6 @@
|
|||||||
#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
|
#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
|
||||||
/// Indicates that the following function is deprecated.
|
/// Indicates that the following function is deprecated.
|
||||||
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||||
#elif defined(__clang__) && defined(__has_feature)
|
|
||||||
#if __has_feature(attribute_deprecated_with_message)
|
|
||||||
#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
|
|
||||||
#endif
|
|
||||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
|
||||||
#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
|
|
||||||
#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
|
||||||
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(JSONCPP_DEPRECATED)
|
#if !defined(JSONCPP_DEPRECATED)
|
||||||
|
@@ -31,6 +31,12 @@ class Value;
|
|||||||
class ValueIteratorBase;
|
class ValueIteratorBase;
|
||||||
class ValueIterator;
|
class ValueIterator;
|
||||||
class ValueConstIterator;
|
class ValueConstIterator;
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
class ValueMapAllocator;
|
||||||
|
class ValueInternalLink;
|
||||||
|
class ValueInternalArray;
|
||||||
|
class ValueInternalMap;
|
||||||
|
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
|
@@ -98,7 +98,7 @@ public:
|
|||||||
* during parsing.
|
* during parsing.
|
||||||
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||||
*/
|
*/
|
||||||
JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
|
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
|
||||||
std::string getFormatedErrorMessages() const;
|
std::string getFormatedErrorMessages() const;
|
||||||
|
|
||||||
/** \brief Returns a user friendly string that list errors in the parsed
|
/** \brief Returns a user friendly string that list errors in the parsed
|
||||||
@@ -226,7 +226,6 @@ public:
|
|||||||
|
|
||||||
class Factory {
|
class Factory {
|
||||||
public:
|
public:
|
||||||
virtual ~Factory() {}
|
|
||||||
/** \brief Allocate a CharReader via operator new().
|
/** \brief Allocate a CharReader via operator new().
|
||||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||||
*/
|
*/
|
||||||
@@ -236,11 +235,13 @@ public:
|
|||||||
|
|
||||||
/** \brief Build a CharReader implementation.
|
/** \brief Build a CharReader implementation.
|
||||||
|
|
||||||
|
\deprecated This is experimental and will be altered before the next release.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
\code
|
\code
|
||||||
using namespace Json;
|
using namespace Json;
|
||||||
CharReaderBuilder builder;
|
CharReaderBuilder builder;
|
||||||
builder["collectComments"] = false;
|
builder.settings_["collectComments"] = false;
|
||||||
Value value;
|
Value value;
|
||||||
std::string errs;
|
std::string errs;
|
||||||
bool ok = parseFromStream(builder, std::cin, &value, &errs);
|
bool ok = parseFromStream(builder, std::cin, &value, &errs);
|
||||||
@@ -253,30 +254,21 @@ public:
|
|||||||
/** Configuration of this builder.
|
/** Configuration of this builder.
|
||||||
These are case-sensitive.
|
These are case-sensitive.
|
||||||
Available settings (case-sensitive):
|
Available settings (case-sensitive):
|
||||||
- `"collectComments": false or true`
|
- "collectComments": false or true
|
||||||
- true to collect comment and allow writing them
|
- true to collect comment and allow writing them
|
||||||
back during serialization, false to discard comments.
|
back during serialization, false to discard comments.
|
||||||
This parameter is ignored if allowComments is false.
|
This parameter is ignored if allowComments is false.
|
||||||
- `"allowComments": false or true`
|
- "allowComments": false or true
|
||||||
- true if comments are allowed.
|
- true if comments are allowed.
|
||||||
- `"strictRoot": false or true`
|
- "strictRoot": false or true
|
||||||
- true if root must be either an array or an object value
|
- true if root must be either an array or an object value
|
||||||
- `"allowDroppedNullPlaceholders": false or true`
|
- "allowDroppedNullPlaceholders": false or true
|
||||||
- true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
|
- true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
|
||||||
- `"allowNumericKeys": false or true`
|
- "allowNumericKeys": false or true
|
||||||
- true if numeric object keys are allowed.
|
- true if numeric object keys are allowed.
|
||||||
- `"allowSingleQuotes": false or true`
|
- "stackLimit": integer
|
||||||
- true if '' are allowed for strings (both keys and values)
|
|
||||||
- `"stackLimit": integer`
|
|
||||||
- Exceeding stackLimit (recursive depth of `readValue()`) will
|
|
||||||
cause an exception.
|
|
||||||
- This is a security issue (seg-faults caused by deeply nested JSON),
|
- This is a security issue (seg-faults caused by deeply nested JSON),
|
||||||
so the default is low.
|
so the default is low.
|
||||||
- `"failIfExtra": false or true`
|
|
||||||
- If true, `parse()` returns false when extra non-whitespace trails
|
|
||||||
the JSON value in the input string.
|
|
||||||
- `"rejectDupKeys": false or true`
|
|
||||||
- If true, `parse()` returns false when a key is duplicated within an object.
|
|
||||||
|
|
||||||
You can examine 'settings_` yourself
|
You can examine 'settings_` yourself
|
||||||
to see the defaults. You can also write and read them just like any
|
to see the defaults. You can also write and read them just like any
|
||||||
@@ -294,11 +286,6 @@ public:
|
|||||||
* otherwise, indicate bad settings via 'invalid'.
|
* otherwise, indicate bad settings via 'invalid'.
|
||||||
*/
|
*/
|
||||||
bool validate(Json::Value* invalid) const;
|
bool validate(Json::Value* invalid) const;
|
||||||
|
|
||||||
/** A simple way to update a specific setting.
|
|
||||||
*/
|
|
||||||
Value& operator[](std::string key);
|
|
||||||
|
|
||||||
/** Called by ctor, but you can use this to reset settings_.
|
/** Called by ctor, but you can use this to reset settings_.
|
||||||
* \pre 'settings' != NULL (but Json::null is fine)
|
* \pre 'settings' != NULL (but Json::null is fine)
|
||||||
* \remark Defaults:
|
* \remark Defaults:
|
||||||
@@ -317,7 +304,7 @@ public:
|
|||||||
* Someday we might have a real StreamReader, but for now this
|
* Someday we might have a real StreamReader, but for now this
|
||||||
* is convenient.
|
* is convenient.
|
||||||
*/
|
*/
|
||||||
bool JSON_API parseFromStream(
|
bool parseFromStream(
|
||||||
CharReader::Factory const&,
|
CharReader::Factory const&,
|
||||||
std::istream&,
|
std::istream&,
|
||||||
Value* root, std::string* errs);
|
Value* root, std::string* errs);
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
#ifndef JSON_USE_CPPTL_SMALLMAP
|
#ifndef JSON_USE_CPPTL_SMALLMAP
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -33,31 +32,6 @@
|
|||||||
*/
|
*/
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
/** Base class for all exceptions we throw.
|
|
||||||
*
|
|
||||||
* We use nothing but these internally. Of course, STL can throw others.
|
|
||||||
*/
|
|
||||||
class JSON_API Exception;
|
|
||||||
/** Exceptions which the user cannot easily avoid.
|
|
||||||
*
|
|
||||||
* E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
|
|
||||||
*
|
|
||||||
* \remark derived from Json::Exception
|
|
||||||
*/
|
|
||||||
class JSON_API RuntimeError;
|
|
||||||
/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
|
|
||||||
*
|
|
||||||
* These are precondition-violations (user bugs) and internal errors (our bugs).
|
|
||||||
*
|
|
||||||
* \remark derived from Json::Exception
|
|
||||||
*/
|
|
||||||
class JSON_API LogicError;
|
|
||||||
|
|
||||||
/// used internally
|
|
||||||
void throwRuntimeError(std::string const& msg);
|
|
||||||
/// used internally
|
|
||||||
void throwLogicError(std::string const& msg);
|
|
||||||
|
|
||||||
/** \brief Type of the value held by a Value object.
|
/** \brief Type of the value held by a Value object.
|
||||||
*/
|
*/
|
||||||
enum ValueType {
|
enum ValueType {
|
||||||
@@ -100,14 +74,14 @@ enum CommentPlacement {
|
|||||||
*/
|
*/
|
||||||
class JSON_API StaticString {
|
class JSON_API StaticString {
|
||||||
public:
|
public:
|
||||||
explicit StaticString(const char* czstring) : c_str_(czstring) {}
|
explicit StaticString(const char* czstring) : str_(czstring) {}
|
||||||
|
|
||||||
operator const char*() const { return c_str_; }
|
operator const char*() const { return str_; }
|
||||||
|
|
||||||
const char* c_str() const { return c_str_; }
|
const char* c_str() const { return str_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* c_str_;
|
const char* str_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
|
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
|
||||||
@@ -125,27 +99,26 @@ private:
|
|||||||
* The type of the held value is represented by a #ValueType and
|
* The type of the held value is represented by a #ValueType and
|
||||||
* can be obtained using type().
|
* can be obtained using type().
|
||||||
*
|
*
|
||||||
* Values of an #objectValue or #arrayValue can be accessed using operator[]()
|
* values of an #objectValue or #arrayValue can be accessed using operator[]()
|
||||||
* methods.
|
*methods.
|
||||||
* Non-const methods will automatically create the a #nullValue element
|
* Non const methods will automatically create the a #nullValue element
|
||||||
* if it does not exist.
|
* if it does not exist.
|
||||||
* The sequence of an #arrayValue will be automatically resized and initialized
|
* The sequence of an #arrayValue will be automatically resize and initialized
|
||||||
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
|
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
|
||||||
*
|
*
|
||||||
* The get() methods can be used to obtain default value in the case the
|
* The get() methods can be used to obtanis default value in the case the
|
||||||
* required element does not exist.
|
*required element
|
||||||
|
* does not exist.
|
||||||
*
|
*
|
||||||
* It is possible to iterate over the list of a #objectValue values using
|
* It is possible to iterate over the list of a #objectValue values using
|
||||||
* the getMemberNames() method.
|
* the getMemberNames() method.
|
||||||
*
|
|
||||||
* \note #Value string-length fit in size_t, but keys must be < 2^30.
|
|
||||||
* (The reason is an implementation detail.) A #CharReader will raise an
|
|
||||||
* exception if a bound is exceeded to avoid security holes in your app,
|
|
||||||
* but the Value API does *not* check bounds. That is the responsibility
|
|
||||||
* of the caller.
|
|
||||||
*/
|
*/
|
||||||
class JSON_API Value {
|
class JSON_API Value {
|
||||||
friend class ValueIteratorBase;
|
friend class ValueIteratorBase;
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
friend class ValueInternalLink;
|
||||||
|
friend class ValueInternalMap;
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
typedef std::vector<std::string> Members;
|
typedef std::vector<std::string> Members;
|
||||||
typedef ValueIterator iterator;
|
typedef ValueIterator iterator;
|
||||||
@@ -190,6 +163,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
class CZString {
|
class CZString {
|
||||||
public:
|
public:
|
||||||
enum DuplicationPolicy {
|
enum DuplicationPolicy {
|
||||||
@@ -198,31 +172,20 @@ private:
|
|||||||
duplicateOnCopy
|
duplicateOnCopy
|
||||||
};
|
};
|
||||||
CZString(ArrayIndex index);
|
CZString(ArrayIndex index);
|
||||||
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
CZString(const char* cstr, DuplicationPolicy allocate);
|
||||||
CZString(CZString const& other);
|
CZString(const CZString& other);
|
||||||
~CZString();
|
~CZString();
|
||||||
CZString& operator=(CZString other);
|
CZString &operator=(const CZString &other);
|
||||||
bool operator<(CZString const& other) const;
|
bool operator<(const CZString& other) const;
|
||||||
bool operator==(CZString const& other) const;
|
bool operator==(const CZString& other) const;
|
||||||
ArrayIndex index() const;
|
ArrayIndex index() const;
|
||||||
//const char* c_str() const; ///< \deprecated
|
const char* c_str() const;
|
||||||
char const* data() const;
|
|
||||||
unsigned length() const;
|
|
||||||
bool isStaticString() const;
|
bool isStaticString() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void swap(CZString& other);
|
void swap(CZString& other);
|
||||||
|
const char* cstr_;
|
||||||
struct StringStorage {
|
ArrayIndex index_;
|
||||||
DuplicationPolicy policy_: 2;
|
|
||||||
unsigned length_: 30; // 1GB max
|
|
||||||
};
|
|
||||||
|
|
||||||
char const* cstr_; // actually, a prefixed string, unless policy is noDup
|
|
||||||
union {
|
|
||||||
ArrayIndex index_;
|
|
||||||
StringStorage storage_;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -231,6 +194,7 @@ public:
|
|||||||
#else
|
#else
|
||||||
typedef CppTL::SmallMap<CZString, Value> ObjectValues;
|
typedef CppTL::SmallMap<CZString, Value> ObjectValues;
|
||||||
#endif // ifndef JSON_USE_CPPTL_SMALLMAP
|
#endif // ifndef JSON_USE_CPPTL_SMALLMAP
|
||||||
|
#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -257,25 +221,20 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
Value(UInt64 value);
|
Value(UInt64 value);
|
||||||
#endif // if defined(JSON_HAS_INT64)
|
#endif // if defined(JSON_HAS_INT64)
|
||||||
Value(double value);
|
Value(double value);
|
||||||
Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
|
Value(const char* value);
|
||||||
Value(const char* beginValue, const char* endValue); ///< Copy all, incl zeroes.
|
Value(const char* beginValue, const char* endValue);
|
||||||
/** \brief Constructs a value from a static string.
|
/** \brief Constructs a value from a static string.
|
||||||
|
|
||||||
* Like other value string constructor but do not duplicate the string for
|
* Like other value string constructor but do not duplicate the string for
|
||||||
* internal storage. The given string must remain alive after the call to this
|
* internal storage. The given string must remain alive after the call to this
|
||||||
* constructor.
|
* constructor.
|
||||||
* \note This works only for null-terminated strings. (We cannot change the
|
|
||||||
* size of this class, so we have nowhere to store the length,
|
|
||||||
* which might be computed later for various operations.)
|
|
||||||
*
|
|
||||||
* Example of usage:
|
* Example of usage:
|
||||||
* \code
|
* \code
|
||||||
* static StaticString foo("some text");
|
* Json::Value aValue( StaticString("some text") );
|
||||||
* Json::Value aValue(foo);
|
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
Value(const StaticString& value);
|
Value(const StaticString& value);
|
||||||
Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too.
|
Value(const std::string& value);
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
Value(const CppTL::ConstString& value);
|
Value(const CppTL::ConstString& value);
|
||||||
#endif
|
#endif
|
||||||
@@ -284,8 +243,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
Value(const Value& other);
|
Value(const Value& other);
|
||||||
~Value();
|
~Value();
|
||||||
|
|
||||||
/// Deep copy, then swap(other).
|
// Deep copy, then swap(other).
|
||||||
/// \note Over-write existing comments. To preserve comments, use #swapPayload().
|
|
||||||
Value &operator=(const Value &other);
|
Value &operator=(const Value &other);
|
||||||
/// Swap everything.
|
/// Swap everything.
|
||||||
void swap(Value& other);
|
void swap(Value& other);
|
||||||
@@ -303,13 +261,8 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
bool operator!=(const Value& other) const;
|
bool operator!=(const Value& other) const;
|
||||||
int compare(const Value& other) const;
|
int compare(const Value& other) const;
|
||||||
|
|
||||||
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
|
const char* asCString() const;
|
||||||
std::string asString() const; ///< Embedded zeroes are possible.
|
std::string asString() const;
|
||||||
/** Get raw char* of string-value.
|
|
||||||
* \return false if !string. (Seg-fault if str or end are NULL.)
|
|
||||||
*/
|
|
||||||
bool getString(
|
|
||||||
char const** str, char const** end) const;
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
CppTL::ConstString asConstString() const;
|
CppTL::ConstString asConstString() const;
|
||||||
#endif
|
#endif
|
||||||
@@ -400,23 +353,19 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
Value& append(const Value& value);
|
Value& append(const Value& value);
|
||||||
|
|
||||||
/// Access an object value by name, create a null member if it does not exist.
|
/// Access an object value by name, create a null member if it does not exist.
|
||||||
/// \note Because of our implementation, keys are limited to 2^30 -1 chars.
|
|
||||||
/// Exceeding that will cause an exception.
|
|
||||||
Value& operator[](const char* key);
|
Value& operator[](const char* key);
|
||||||
/// Access an object value by name, returns null if there is no member with
|
/// Access an object value by name, returns null if there is no member with
|
||||||
/// that name.
|
/// that name.
|
||||||
const Value& operator[](const char* key) const;
|
const Value& operator[](const char* key) const;
|
||||||
/// Access an object value by name, create a null member if it does not exist.
|
/// Access an object value by name, create a null member if it does not exist.
|
||||||
/// \param key may contain embedded nulls.
|
|
||||||
Value& operator[](const std::string& key);
|
Value& operator[](const std::string& key);
|
||||||
/// Access an object value by name, returns null if there is no member with
|
/// Access an object value by name, returns null if there is no member with
|
||||||
/// that name.
|
/// that name.
|
||||||
/// \param key may contain embedded nulls.
|
|
||||||
const Value& operator[](const std::string& key) const;
|
const Value& operator[](const std::string& key) const;
|
||||||
/** \brief Access an object value by name, create a null member if it does not
|
/** \brief Access an object value by name, create a null member if it does not
|
||||||
exist.
|
exist.
|
||||||
|
|
||||||
* If the object has no entry for that name, then the member name used to store
|
* If the object as no entry for that name, then the member name used to store
|
||||||
* the new entry is not duplicated.
|
* the new entry is not duplicated.
|
||||||
* Example of use:
|
* Example of use:
|
||||||
* \code
|
* \code
|
||||||
@@ -434,29 +383,13 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
const Value& operator[](const CppTL::ConstString& key) const;
|
const Value& operator[](const CppTL::ConstString& key) const;
|
||||||
#endif
|
#endif
|
||||||
/// Return the member named key if it exist, defaultValue otherwise.
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
/// \note deep copy
|
|
||||||
Value get(const char* key, const Value& defaultValue) const;
|
Value get(const char* key, const Value& defaultValue) const;
|
||||||
/// Return the member named key if it exist, defaultValue otherwise.
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
/// \note deep copy
|
|
||||||
/// \param key may contain embedded nulls.
|
|
||||||
Value get(const char* key, const char* end, const Value& defaultValue) const;
|
|
||||||
/// Return the member named key if it exist, defaultValue otherwise.
|
|
||||||
/// \note deep copy
|
|
||||||
/// \param key may contain embedded nulls.
|
|
||||||
Value get(const std::string& key, const Value& defaultValue) const;
|
Value get(const std::string& key, const Value& defaultValue) const;
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
/// Return the member named key if it exist, defaultValue otherwise.
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
/// \note deep copy
|
|
||||||
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
|
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
|
||||||
#endif
|
#endif
|
||||||
/// Most general and efficient version of isMember()const, get()const,
|
|
||||||
/// and operator[]const
|
|
||||||
/// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30
|
|
||||||
Value const* find(char const* key, char const* end) const;
|
|
||||||
/// Most general and efficient version of object-mutators.
|
|
||||||
/// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30
|
|
||||||
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
|
|
||||||
Value const* demand(char const* key, char const* end);
|
|
||||||
/// \brief Remove and return the named member.
|
/// \brief Remove and return the named member.
|
||||||
///
|
///
|
||||||
/// Do nothing if it did not exist.
|
/// Do nothing if it did not exist.
|
||||||
@@ -466,21 +399,14 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
/// \deprecated
|
/// \deprecated
|
||||||
Value removeMember(const char* key);
|
Value removeMember(const char* key);
|
||||||
/// Same as removeMember(const char*)
|
/// Same as removeMember(const char*)
|
||||||
/// \param key may contain embedded nulls.
|
|
||||||
/// \deprecated
|
/// \deprecated
|
||||||
Value removeMember(const std::string& key);
|
Value removeMember(const std::string& key);
|
||||||
/// Same as removeMember(const char* key, const char* end, Value* removed),
|
|
||||||
/// but 'key' is null-terminated.
|
|
||||||
bool removeMember(const char* key, Value* removed);
|
|
||||||
/** \brief Remove the named map member.
|
/** \brief Remove the named map member.
|
||||||
|
|
||||||
Update 'removed' iff removed.
|
Update 'removed' iff removed.
|
||||||
\param key may contain embedded nulls.
|
|
||||||
\return true iff removed (no exceptions)
|
\return true iff removed (no exceptions)
|
||||||
*/
|
*/
|
||||||
bool removeMember(std::string const& key, Value* removed);
|
bool removeMember(const char* key, Value* removed);
|
||||||
/// Same as removeMember(std::string const& key, Value* removed)
|
|
||||||
bool removeMember(const char* key, const char* end, Value* removed);
|
|
||||||
/** \brief Remove the indexed array element.
|
/** \brief Remove the indexed array element.
|
||||||
|
|
||||||
O(n) expensive operations.
|
O(n) expensive operations.
|
||||||
@@ -490,13 +416,9 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
bool removeIndex(ArrayIndex i, Value* removed);
|
bool removeIndex(ArrayIndex i, Value* removed);
|
||||||
|
|
||||||
/// Return true if the object has a member named key.
|
/// Return true if the object has a member named key.
|
||||||
/// \note 'key' must be null-terminated.
|
|
||||||
bool isMember(const char* key) const;
|
bool isMember(const char* key) const;
|
||||||
/// Return true if the object has a member named key.
|
/// Return true if the object has a member named key.
|
||||||
/// \param key may contain embedded nulls.
|
|
||||||
bool isMember(const std::string& key) const;
|
bool isMember(const std::string& key) const;
|
||||||
/// Same as isMember(std::string const& key)const
|
|
||||||
bool isMember(const char* key, const char* end) const;
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
/// Return true if the object has a member named key.
|
/// Return true if the object has a member named key.
|
||||||
bool isMember(const CppTL::ConstString& key) const;
|
bool isMember(const CppTL::ConstString& key) const;
|
||||||
@@ -515,7 +437,6 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
//# endif
|
//# endif
|
||||||
|
|
||||||
/// \deprecated Always pass len.
|
/// \deprecated Always pass len.
|
||||||
JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.")
|
|
||||||
void setComment(const char* comment, CommentPlacement placement);
|
void setComment(const char* comment, CommentPlacement placement);
|
||||||
/// Comments must be //... or /* ... */
|
/// Comments must be //... or /* ... */
|
||||||
void setComment(const char* comment, size_t len, CommentPlacement placement);
|
void setComment(const char* comment, size_t len, CommentPlacement placement);
|
||||||
@@ -536,9 +457,21 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
private:
|
private:
|
||||||
void initBasic(ValueType type, bool allocated = false);
|
void initBasic(ValueType type, bool allocated = false);
|
||||||
|
|
||||||
Value& resolveReference(const char* key);
|
Value& resolveReference(const char* key, bool isStatic);
|
||||||
Value& resolveReference(const char* key, const char* end);
|
|
||||||
|
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
inline bool isItemAvailable() const { return itemIsUsed_ == 0; }
|
||||||
|
|
||||||
|
inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; }
|
||||||
|
|
||||||
|
inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; }
|
||||||
|
|
||||||
|
inline void setMemberNameIsStatic(bool isStatic) {
|
||||||
|
memberNameIsStatic_ = isStatic ? 1 : 0;
|
||||||
|
}
|
||||||
|
#endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
|
private:
|
||||||
struct CommentInfo {
|
struct CommentInfo {
|
||||||
CommentInfo();
|
CommentInfo();
|
||||||
~CommentInfo();
|
~CommentInfo();
|
||||||
@@ -562,12 +495,20 @@ private:
|
|||||||
LargestUInt uint_;
|
LargestUInt uint_;
|
||||||
double real_;
|
double real_;
|
||||||
bool bool_;
|
bool bool_;
|
||||||
char* string_; // actually ptr to unsigned, followed by str, unless !allocated_
|
char* string_;
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
ValueInternalArray* array_;
|
||||||
|
ValueInternalMap* map_;
|
||||||
|
#else
|
||||||
ObjectValues* map_;
|
ObjectValues* map_;
|
||||||
|
#endif
|
||||||
} value_;
|
} value_;
|
||||||
ValueType type_ : 8;
|
ValueType type_ : 8;
|
||||||
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||||
// If not allocated_, string_ must be null-terminated.
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
|
||||||
|
unsigned int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
||||||
|
#endif
|
||||||
CommentInfo* comments_;
|
CommentInfo* comments_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -634,6 +575,345 @@ private:
|
|||||||
Args args_;
|
Args args_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
/** \brief Allocator to customize Value internal map.
|
||||||
|
* Below is an example of a simple implementation (default implementation
|
||||||
|
actually
|
||||||
|
* use memory pool for speed).
|
||||||
|
* \code
|
||||||
|
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||||
|
{
|
||||||
|
public: // overridden from ValueMapAllocator
|
||||||
|
virtual ValueInternalMap *newMap()
|
||||||
|
{
|
||||||
|
return new ValueInternalMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||||
|
{
|
||||||
|
return new ValueInternalMap( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructMap( ValueInternalMap *map )
|
||||||
|
{
|
||||||
|
delete map;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||||
|
{
|
||||||
|
return new ValueInternalLink[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||||
|
{
|
||||||
|
delete [] links;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalLink *allocateMapLink()
|
||||||
|
{
|
||||||
|
return new ValueInternalLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapLink( ValueInternalLink *link )
|
||||||
|
{
|
||||||
|
delete link;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
class JSON_API ValueMapAllocator {
|
||||||
|
public:
|
||||||
|
virtual ~ValueMapAllocator();
|
||||||
|
virtual ValueInternalMap* newMap() = 0;
|
||||||
|
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) = 0;
|
||||||
|
virtual void destructMap(ValueInternalMap* map) = 0;
|
||||||
|
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) = 0;
|
||||||
|
virtual void releaseMapBuckets(ValueInternalLink* links) = 0;
|
||||||
|
virtual ValueInternalLink* allocateMapLink() = 0;
|
||||||
|
virtual void releaseMapLink(ValueInternalLink* link) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
|
||||||
|
* \internal previous_ & next_ allows for bidirectional traversal.
|
||||||
|
*/
|
||||||
|
class JSON_API ValueInternalLink {
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
itemPerLink = 6
|
||||||
|
}; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
|
||||||
|
enum InternalFlags {
|
||||||
|
flagAvailable = 0,
|
||||||
|
flagUsed = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
ValueInternalLink();
|
||||||
|
|
||||||
|
~ValueInternalLink();
|
||||||
|
|
||||||
|
Value items_[itemPerLink];
|
||||||
|
char* keys_[itemPerLink];
|
||||||
|
ValueInternalLink* previous_;
|
||||||
|
ValueInternalLink* next_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief A linked page based hash-table implementation used internally by
|
||||||
|
*Value.
|
||||||
|
* \internal ValueInternalMap is a tradional bucket based hash-table, with a
|
||||||
|
*linked
|
||||||
|
* list in each bucket to handle collision. There is an addional twist in that
|
||||||
|
* each node of the collision linked list is a page containing a fixed amount of
|
||||||
|
* value. This provides a better compromise between memory usage and speed.
|
||||||
|
*
|
||||||
|
* Each bucket is made up of a chained list of ValueInternalLink. The last
|
||||||
|
* link of a given bucket can be found in the 'previous_' field of the following
|
||||||
|
*bucket.
|
||||||
|
* The last link of the last bucket is stored in tailLink_ as it has no
|
||||||
|
*following bucket.
|
||||||
|
* Only the last link of a bucket may contains 'available' item. The last link
|
||||||
|
*always
|
||||||
|
* contains at least one element unless is it the bucket one very first link.
|
||||||
|
*/
|
||||||
|
class JSON_API ValueInternalMap {
|
||||||
|
friend class ValueIteratorBase;
|
||||||
|
friend class Value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef unsigned int HashKey;
|
||||||
|
typedef unsigned int BucketIndex;
|
||||||
|
|
||||||
|
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
struct IteratorState {
|
||||||
|
IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {}
|
||||||
|
ValueInternalMap* map_;
|
||||||
|
ValueInternalLink* link_;
|
||||||
|
BucketIndex itemIndex_;
|
||||||
|
BucketIndex bucketIndex_;
|
||||||
|
};
|
||||||
|
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
ValueInternalMap();
|
||||||
|
ValueInternalMap(const ValueInternalMap& other);
|
||||||
|
ValueInternalMap& operator=(ValueInternalMap other);
|
||||||
|
~ValueInternalMap();
|
||||||
|
|
||||||
|
void swap(ValueInternalMap& other);
|
||||||
|
|
||||||
|
BucketIndex size() const;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
bool reserveDelta(BucketIndex growth);
|
||||||
|
|
||||||
|
bool reserve(BucketIndex newItemCount);
|
||||||
|
|
||||||
|
const Value* find(const char* key) const;
|
||||||
|
|
||||||
|
Value* find(const char* key);
|
||||||
|
|
||||||
|
Value& resolveReference(const char* key, bool isStatic);
|
||||||
|
|
||||||
|
void remove(const char* key);
|
||||||
|
|
||||||
|
void doActualRemove(ValueInternalLink* link,
|
||||||
|
BucketIndex index,
|
||||||
|
BucketIndex bucketIndex);
|
||||||
|
|
||||||
|
ValueInternalLink*& getLastLinkInBucket(BucketIndex bucketIndex);
|
||||||
|
|
||||||
|
Value& setNewItem(const char* key,
|
||||||
|
bool isStatic,
|
||||||
|
ValueInternalLink* link,
|
||||||
|
BucketIndex index);
|
||||||
|
|
||||||
|
Value& unsafeAdd(const char* key, bool isStatic, HashKey hashedKey);
|
||||||
|
|
||||||
|
HashKey hash(const char* key) const;
|
||||||
|
|
||||||
|
int compare(const ValueInternalMap& other) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void makeBeginIterator(IteratorState& it) const;
|
||||||
|
void makeEndIterator(IteratorState& it) const;
|
||||||
|
static bool equals(const IteratorState& x, const IteratorState& other);
|
||||||
|
static void increment(IteratorState& iterator);
|
||||||
|
static void incrementBucket(IteratorState& iterator);
|
||||||
|
static void decrement(IteratorState& iterator);
|
||||||
|
static const char* key(const IteratorState& iterator);
|
||||||
|
static const char* key(const IteratorState& iterator, bool& isStatic);
|
||||||
|
static Value& value(const IteratorState& iterator);
|
||||||
|
static int distance(const IteratorState& x, const IteratorState& y);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueInternalLink* buckets_;
|
||||||
|
ValueInternalLink* tailLink_;
|
||||||
|
BucketIndex bucketsSize_;
|
||||||
|
BucketIndex itemCount_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief A simplified deque implementation used internally by Value.
|
||||||
|
* \internal
|
||||||
|
* It is based on a list of fixed "page", each page contains a fixed number of
|
||||||
|
*items.
|
||||||
|
* Instead of using a linked-list, a array of pointer is used for fast item
|
||||||
|
*look-up.
|
||||||
|
* Look-up for an element is as follow:
|
||||||
|
* - compute page index: pageIndex = itemIndex / itemsPerPage
|
||||||
|
* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
|
||||||
|
*
|
||||||
|
* Insertion is amortized constant time (only the array containing the index of
|
||||||
|
*pointers
|
||||||
|
* need to be reallocated when items are appended).
|
||||||
|
*/
|
||||||
|
class JSON_API ValueInternalArray {
|
||||||
|
friend class Value;
|
||||||
|
friend class ValueIteratorBase;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
itemsPerPage = 8
|
||||||
|
}; // should be a power of 2 for fast divide and modulo.
|
||||||
|
typedef Value::ArrayIndex ArrayIndex;
|
||||||
|
typedef unsigned int PageIndex;
|
||||||
|
|
||||||
|
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
struct IteratorState // Must be a POD
|
||||||
|
{
|
||||||
|
IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {}
|
||||||
|
ValueInternalArray* array_;
|
||||||
|
Value** currentPageIndex_;
|
||||||
|
unsigned int currentItemIndex_;
|
||||||
|
};
|
||||||
|
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
ValueInternalArray();
|
||||||
|
ValueInternalArray(const ValueInternalArray& other);
|
||||||
|
ValueInternalArray& operator=(ValueInternalArray other);
|
||||||
|
~ValueInternalArray();
|
||||||
|
void swap(ValueInternalArray& other);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void resize(ArrayIndex newSize);
|
||||||
|
|
||||||
|
Value& resolveReference(ArrayIndex index);
|
||||||
|
|
||||||
|
Value* find(ArrayIndex index) const;
|
||||||
|
|
||||||
|
ArrayIndex size() const;
|
||||||
|
|
||||||
|
int compare(const ValueInternalArray& other) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool equals(const IteratorState& x, const IteratorState& other);
|
||||||
|
static void increment(IteratorState& iterator);
|
||||||
|
static void decrement(IteratorState& iterator);
|
||||||
|
static Value& dereference(const IteratorState& iterator);
|
||||||
|
static Value& unsafeDereference(const IteratorState& iterator);
|
||||||
|
static int distance(const IteratorState& x, const IteratorState& y);
|
||||||
|
static ArrayIndex indexOf(const IteratorState& iterator);
|
||||||
|
void makeBeginIterator(IteratorState& it) const;
|
||||||
|
void makeEndIterator(IteratorState& it) const;
|
||||||
|
void makeIterator(IteratorState& it, ArrayIndex index) const;
|
||||||
|
|
||||||
|
void makeIndexValid(ArrayIndex index);
|
||||||
|
|
||||||
|
Value** pages_;
|
||||||
|
ArrayIndex size_;
|
||||||
|
PageIndex pageCount_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Experimental: do not use. Allocator to customize Value internal
|
||||||
|
array.
|
||||||
|
* Below is an example of a simple implementation (actual implementation use
|
||||||
|
* memory pool).
|
||||||
|
\code
|
||||||
|
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||||
|
{
|
||||||
|
public: // overridden from ValueArrayAllocator
|
||||||
|
virtual ~DefaultValueArrayAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalArray *newArray()
|
||||||
|
{
|
||||||
|
return new ValueInternalArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||||
|
{
|
||||||
|
return new ValueInternalArray( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destruct( ValueInternalArray *array )
|
||||||
|
{
|
||||||
|
delete array;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||||
|
ValueInternalArray::PageIndex
|
||||||
|
&indexCount,
|
||||||
|
ValueInternalArray::PageIndex
|
||||||
|
minNewIndexCount )
|
||||||
|
{
|
||||||
|
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||||
|
if ( minNewIndexCount > newIndexCount )
|
||||||
|
newIndexCount = minNewIndexCount;
|
||||||
|
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||||
|
if ( !newIndexes )
|
||||||
|
throw std::bad_alloc();
|
||||||
|
indexCount = newIndexCount;
|
||||||
|
indexes = static_cast<Value **>( newIndexes );
|
||||||
|
}
|
||||||
|
virtual void releaseArrayPageIndex( Value **indexes,
|
||||||
|
ValueInternalArray::PageIndex indexCount )
|
||||||
|
{
|
||||||
|
if ( indexes )
|
||||||
|
free( indexes );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Value *allocateArrayPage()
|
||||||
|
{
|
||||||
|
return static_cast<Value *>( malloc( sizeof(Value) *
|
||||||
|
ValueInternalArray::itemsPerPage ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseArrayPage( Value *value )
|
||||||
|
{
|
||||||
|
if ( value )
|
||||||
|
free( value );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
class JSON_API ValueArrayAllocator {
|
||||||
|
public:
|
||||||
|
virtual ~ValueArrayAllocator();
|
||||||
|
virtual ValueInternalArray* newArray() = 0;
|
||||||
|
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) = 0;
|
||||||
|
virtual void destructArray(ValueInternalArray* array) = 0;
|
||||||
|
/** \brief Reallocate array page index.
|
||||||
|
* Reallocates an array of pointer on each page.
|
||||||
|
* \param indexes [input] pointer on the current index. May be \c NULL.
|
||||||
|
* [output] pointer on the new index of at least
|
||||||
|
* \a minNewIndexCount pages.
|
||||||
|
* \param indexCount [input] current number of pages in the index.
|
||||||
|
* [output] number of page the reallocated index can handle.
|
||||||
|
* \b MUST be >= \a minNewIndexCount.
|
||||||
|
* \param minNewIndexCount Minimum number of page the new index must be able
|
||||||
|
* to
|
||||||
|
* handle.
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
reallocateArrayPageIndex(Value**& indexes,
|
||||||
|
ValueInternalArray::PageIndex& indexCount,
|
||||||
|
ValueInternalArray::PageIndex minNewIndexCount) = 0;
|
||||||
|
virtual void
|
||||||
|
releaseArrayPageIndex(Value** indexes,
|
||||||
|
ValueInternalArray::PageIndex indexCount) = 0;
|
||||||
|
virtual Value* allocateArrayPage() = 0;
|
||||||
|
virtual void releaseArrayPage(Value* value) = 0;
|
||||||
|
};
|
||||||
|
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
/** \brief base class for Value iterators.
|
/** \brief base class for Value iterators.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -645,37 +925,31 @@ public:
|
|||||||
typedef ValueIteratorBase SelfType;
|
typedef ValueIteratorBase SelfType;
|
||||||
|
|
||||||
ValueIteratorBase();
|
ValueIteratorBase();
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
||||||
|
#else
|
||||||
|
ValueIteratorBase(const ValueInternalArray::IteratorState& state);
|
||||||
|
ValueIteratorBase(const ValueInternalMap::IteratorState& state);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool operator==(const SelfType& other) const { return isEqual(other); }
|
bool operator==(const SelfType& other) const { return isEqual(other); }
|
||||||
|
|
||||||
bool operator!=(const SelfType& other) const { return !isEqual(other); }
|
bool operator!=(const SelfType& other) const { return !isEqual(other); }
|
||||||
|
|
||||||
difference_type operator-(const SelfType& other) const {
|
difference_type operator-(const SelfType& other) const {
|
||||||
return other.computeDistance(*this);
|
return computeDistance(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return either the index or the member name of the referenced value as a
|
/// Return either the index or the member name of the referenced value as a
|
||||||
/// Value.
|
/// Value.
|
||||||
Value key() const;
|
Value key() const;
|
||||||
|
|
||||||
/// Return the index of the referenced Value, or -1 if it is not an arrayValue.
|
/// Return the index of the referenced Value. -1 if it is not an arrayValue.
|
||||||
UInt index() const;
|
UInt index() const;
|
||||||
|
|
||||||
/// Return the member name of the referenced Value, or "" if it is not an
|
|
||||||
/// objectValue.
|
|
||||||
/// \note Avoid `c_str()` on result, as embedded zeroes are possible.
|
|
||||||
std::string name() const;
|
|
||||||
|
|
||||||
/// Return the member name of the referenced Value. "" if it is not an
|
/// Return the member name of the referenced Value. "" if it is not an
|
||||||
/// objectValue.
|
/// objectValue.
|
||||||
/// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
|
const char* memberName() const;
|
||||||
JSONCPP_DEPRECATED("Use `key = name();` instead.")
|
|
||||||
char const* memberName() const;
|
|
||||||
/// Return the member name of the referenced Value, or NULL if it is not an
|
|
||||||
/// objectValue.
|
|
||||||
/// \note Better version than memberName(). Allows embedded nulls.
|
|
||||||
char const* memberName(char const** end) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Value& deref() const;
|
Value& deref() const;
|
||||||
@@ -691,9 +965,17 @@ protected:
|
|||||||
void copy(const SelfType& other);
|
void copy(const SelfType& other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
Value::ObjectValues::iterator current_;
|
Value::ObjectValues::iterator current_;
|
||||||
// Indicates that iterator is for a null value.
|
// Indicates that iterator is for a null value.
|
||||||
bool isNull_;
|
bool isNull_;
|
||||||
|
#else
|
||||||
|
union {
|
||||||
|
ValueInternalArray::IteratorState array_;
|
||||||
|
ValueInternalMap::IteratorState map_;
|
||||||
|
} iterator_;
|
||||||
|
bool isArray_;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief const iterator for object and array value.
|
/** \brief const iterator for object and array value.
|
||||||
@@ -704,8 +986,8 @@ class JSON_API ValueConstIterator : public ValueIteratorBase {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
typedef const Value value_type;
|
typedef const Value value_type;
|
||||||
//typedef unsigned int size_t;
|
typedef unsigned int size_t;
|
||||||
//typedef int difference_type;
|
typedef int difference_type;
|
||||||
typedef const Value& reference;
|
typedef const Value& reference;
|
||||||
typedef const Value* pointer;
|
typedef const Value* pointer;
|
||||||
typedef ValueConstIterator SelfType;
|
typedef ValueConstIterator SelfType;
|
||||||
@@ -715,7 +997,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
/*! \internal Use by Value to create an iterator.
|
/*! \internal Use by Value to create an iterator.
|
||||||
*/
|
*/
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
|
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
|
||||||
|
#else
|
||||||
|
ValueConstIterator(const ValueInternalArray::IteratorState& state);
|
||||||
|
ValueConstIterator(const ValueInternalMap::IteratorState& state);
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
SelfType& operator=(const ValueIteratorBase& other);
|
SelfType& operator=(const ValueIteratorBase& other);
|
||||||
|
|
||||||
@@ -766,7 +1053,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
/*! \internal Use by Value to create an iterator.
|
/*! \internal Use by Value to create an iterator.
|
||||||
*/
|
*/
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
explicit ValueIterator(const Value::ObjectValues::iterator& current);
|
explicit ValueIterator(const Value::ObjectValues::iterator& current);
|
||||||
|
#else
|
||||||
|
ValueIterator(const ValueInternalArray::IteratorState& state);
|
||||||
|
ValueIterator(const ValueInternalMap::IteratorState& state);
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
SelfType& operator=(const SelfType& other);
|
SelfType& operator=(const SelfType& other);
|
||||||
|
|
||||||
|
@@ -4,9 +4,9 @@
|
|||||||
#ifndef JSON_VERSION_H_INCLUDED
|
#ifndef JSON_VERSION_H_INCLUDED
|
||||||
# define JSON_VERSION_H_INCLUDED
|
# define JSON_VERSION_H_INCLUDED
|
||||||
|
|
||||||
# define JSONCPP_VERSION_STRING "1.10.0"
|
# define JSONCPP_VERSION_STRING "0.8.0"
|
||||||
# define JSONCPP_VERSION_MAJOR 1
|
# define JSONCPP_VERSION_MAJOR 0
|
||||||
# define JSONCPP_VERSION_MINOR 10
|
# define JSONCPP_VERSION_MINOR 8
|
||||||
# define JSONCPP_VERSION_PATCH 0
|
# define JSONCPP_VERSION_PATCH 0
|
||||||
# define JSONCPP_VERSION_QUALIFIER
|
# define JSONCPP_VERSION_QUALIFIER
|
||||||
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
||||||
|
@@ -46,7 +46,7 @@ public:
|
|||||||
/** Write Value into document as configured in sub-class.
|
/** Write Value into document as configured in sub-class.
|
||||||
Do not take ownership of sout, but maintain a reference during function.
|
Do not take ownership of sout, but maintain a reference during function.
|
||||||
\pre sout != NULL
|
\pre sout != NULL
|
||||||
\return zero on success (For now, we always return zero, so check the stream instead.)
|
\return zero on success
|
||||||
\throw std::exception possibly, depending on configuration
|
\throw std::exception possibly, depending on configuration
|
||||||
*/
|
*/
|
||||||
virtual int write(Value const& root, std::ostream* sout) = 0;
|
virtual int write(Value const& root, std::ostream* sout) = 0;
|
||||||
@@ -66,7 +66,7 @@ public:
|
|||||||
/** \brief Write into stringstream, then return string, for convenience.
|
/** \brief Write into stringstream, then return string, for convenience.
|
||||||
* A StreamWriter will be created from the factory, used, and then deleted.
|
* A StreamWriter will be created from the factory, used, and then deleted.
|
||||||
*/
|
*/
|
||||||
std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root);
|
std::string writeString(StreamWriter::Factory const& factory, Value const& root);
|
||||||
|
|
||||||
|
|
||||||
/** \brief Build a StreamWriter implementation.
|
/** \brief Build a StreamWriter implementation.
|
||||||
@@ -76,8 +76,8 @@ Usage:
|
|||||||
using namespace Json;
|
using namespace Json;
|
||||||
Value value = ...;
|
Value value = ...;
|
||||||
StreamWriterBuilder builder;
|
StreamWriterBuilder builder;
|
||||||
builder["commentStyle"] = "None";
|
builder.settings_["commentStyle"] = "None";
|
||||||
builder["indentation"] = " "; // or whatever you like
|
builder.settings_["indentation"] = " "; // or whatever you like
|
||||||
std::unique_ptr<Json::StreamWriter> writer(
|
std::unique_ptr<Json::StreamWriter> writer(
|
||||||
builder.newStreamWriter());
|
builder.newStreamWriter());
|
||||||
writer->write(value, &std::cout);
|
writer->write(value, &std::cout);
|
||||||
@@ -119,10 +119,6 @@ public:
|
|||||||
* otherwise, indicate bad settings via 'invalid'.
|
* otherwise, indicate bad settings via 'invalid'.
|
||||||
*/
|
*/
|
||||||
bool validate(Json::Value* invalid) const;
|
bool validate(Json::Value* invalid) const;
|
||||||
/** A simple way to update a specific setting.
|
|
||||||
*/
|
|
||||||
Value& operator[](std::string key);
|
|
||||||
|
|
||||||
/** Called by ctor, but you can use this to reset settings_.
|
/** Called by ctor, but you can use this to reset settings_.
|
||||||
* \pre 'settings' != NULL (but Json::null is fine)
|
* \pre 'settings' != NULL (but Json::null is fine)
|
||||||
* \remark Defaults:
|
* \remark Defaults:
|
||||||
@@ -132,7 +128,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Abstract class for writers.
|
/** \brief Abstract class for writers.
|
||||||
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
* \deprecated Use StreamWriter.
|
||||||
*/
|
*/
|
||||||
class JSON_API Writer {
|
class JSON_API Writer {
|
||||||
public:
|
public:
|
||||||
@@ -151,7 +147,6 @@ public:
|
|||||||
* \deprecated Use StreamWriterBuilder.
|
* \deprecated Use StreamWriterBuilder.
|
||||||
*/
|
*/
|
||||||
class JSON_API FastWriter : public Writer {
|
class JSON_API FastWriter : public Writer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FastWriter();
|
FastWriter();
|
||||||
virtual ~FastWriter() {}
|
virtual ~FastWriter() {}
|
||||||
|
@@ -178,6 +178,15 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\json\json.h">
|
RelativePath="..\..\include\json\json.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\lib_json\json_batchallocator.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\lib_json\json_internalarray.inl">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\lib_json\json_internalmap.inl">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\lib_json\json_reader.cpp">
|
RelativePath="..\..\src\lib_json\json_reader.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
FIND_PACKAGE(PythonInterp 2.6)
|
FIND_PACKAGE(PythonInterp 2.6 REQUIRED)
|
||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
IF(JSONCPP_LIB_BUILD_SHARED)
|
||||||
ADD_DEFINITIONS( -DJSON_DLL )
|
ADD_DEFINITIONS( -DJSON_DLL )
|
||||||
@@ -20,7 +20,7 @@ IF(PYTHONINTERP_FOUND)
|
|||||||
# Run end to end parser/writer tests
|
# Run end to end parser/writer tests
|
||||||
SET(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../test)
|
SET(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../test)
|
||||||
SET(RUNJSONTESTS_PATH ${TEST_DIR}/runjsontests.py)
|
SET(RUNJSONTESTS_PATH ${TEST_DIR}/runjsontests.py)
|
||||||
ADD_CUSTOM_TARGET(jsoncpp_readerwriter_tests
|
ADD_CUSTOM_TARGET(jsoncpp_readerwriter_tests ALL
|
||||||
"${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
|
"${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
|
||||||
DEPENDS jsontestrunner_exe jsoncpp_test
|
DEPENDS jsontestrunner_exe jsoncpp_test
|
||||||
)
|
)
|
||||||
|
@@ -34,6 +34,7 @@ SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} )
|
|||||||
SET(jsoncpp_sources
|
SET(jsoncpp_sources
|
||||||
json_tool.h
|
json_tool.h
|
||||||
json_reader.cpp
|
json_reader.cpp
|
||||||
|
json_batchallocator.h
|
||||||
json_valueiterator.inl
|
json_valueiterator.inl
|
||||||
json_value.cpp
|
json_value.cpp
|
||||||
json_writer.cpp
|
json_writer.cpp
|
||||||
|
121
src/lib_json/json_batchallocator.h
Normal file
121
src/lib_json/json_batchallocator.h
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
#define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/* Fast memory allocator.
|
||||||
|
*
|
||||||
|
* This memory allocator allocates memory for a batch of object (specified by
|
||||||
|
* the page size, the number of object in each page).
|
||||||
|
*
|
||||||
|
* It does not allow the destruction of a single object. All the allocated
|
||||||
|
* objects can be destroyed at once. The memory can be either released or reused
|
||||||
|
* for future allocation.
|
||||||
|
*
|
||||||
|
* The in-place new operator must be used to construct the object using the
|
||||||
|
* pointer returned by allocate.
|
||||||
|
*/
|
||||||
|
template <typename AllocatedType, const unsigned int objectPerAllocation>
|
||||||
|
class BatchAllocator {
|
||||||
|
public:
|
||||||
|
BatchAllocator(unsigned int objectsPerPage = 255)
|
||||||
|
: freeHead_(0), objectsPerPage_(objectsPerPage) {
|
||||||
|
// printf( "Size: %d => %s\n", sizeof(AllocatedType),
|
||||||
|
// typeid(AllocatedType).name() );
|
||||||
|
assert(sizeof(AllocatedType) * objectPerAllocation >=
|
||||||
|
sizeof(AllocatedType*)); // We must be able to store a slist in the
|
||||||
|
// object free space.
|
||||||
|
assert(objectsPerPage >= 16);
|
||||||
|
batches_ = allocateBatch(0); // allocated a dummy page
|
||||||
|
currentBatch_ = batches_;
|
||||||
|
}
|
||||||
|
|
||||||
|
~BatchAllocator() {
|
||||||
|
for (BatchInfo* batch = batches_; batch;) {
|
||||||
|
BatchInfo* nextBatch = batch->next_;
|
||||||
|
free(batch);
|
||||||
|
batch = nextBatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// allocate space for an array of objectPerAllocation object.
|
||||||
|
/// @warning it is the responsability of the caller to call objects
|
||||||
|
/// constructors.
|
||||||
|
AllocatedType* allocate() {
|
||||||
|
if (freeHead_) // returns node from free list.
|
||||||
|
{
|
||||||
|
AllocatedType* object = freeHead_;
|
||||||
|
freeHead_ = *(AllocatedType**)object;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
if (currentBatch_->used_ == currentBatch_->end_) {
|
||||||
|
currentBatch_ = currentBatch_->next_;
|
||||||
|
while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_)
|
||||||
|
currentBatch_ = currentBatch_->next_;
|
||||||
|
|
||||||
|
if (!currentBatch_) // no free batch found, allocate a new one
|
||||||
|
{
|
||||||
|
currentBatch_ = allocateBatch(objectsPerPage_);
|
||||||
|
currentBatch_->next_ = batches_; // insert at the head of the list
|
||||||
|
batches_ = currentBatch_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AllocatedType* allocated = currentBatch_->used_;
|
||||||
|
currentBatch_->used_ += objectPerAllocation;
|
||||||
|
return allocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Release the object.
|
||||||
|
/// @warning it is the responsability of the caller to actually destruct the
|
||||||
|
/// object.
|
||||||
|
void release(AllocatedType* object) {
|
||||||
|
assert(object != 0);
|
||||||
|
*(AllocatedType**)object = freeHead_;
|
||||||
|
freeHead_ = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct BatchInfo {
|
||||||
|
BatchInfo* next_;
|
||||||
|
AllocatedType* used_;
|
||||||
|
AllocatedType* end_;
|
||||||
|
AllocatedType buffer_[objectPerAllocation];
|
||||||
|
};
|
||||||
|
|
||||||
|
// disabled copy constructor and assignement operator.
|
||||||
|
BatchAllocator(const BatchAllocator&);
|
||||||
|
void operator=(const BatchAllocator&);
|
||||||
|
|
||||||
|
static BatchInfo* allocateBatch(unsigned int objectsPerPage) {
|
||||||
|
const unsigned int mallocSize =
|
||||||
|
sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation +
|
||||||
|
sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
||||||
|
BatchInfo* batch = static_cast<BatchInfo*>(malloc(mallocSize));
|
||||||
|
batch->next_ = 0;
|
||||||
|
batch->used_ = batch->buffer_;
|
||||||
|
batch->end_ = batch->buffer_ + objectsPerPage;
|
||||||
|
return batch;
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchInfo* batches_;
|
||||||
|
BatchInfo* currentBatch_;
|
||||||
|
/// Head of a single linked list within the allocated space of freeed object
|
||||||
|
AllocatedType* freeHead_;
|
||||||
|
unsigned int objectsPerPage_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
360
src/lib_json/json_internalarray.inl
Normal file
360
src/lib_json/json_internalarray.inl
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
// included by json_value.cpp
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueInternalArray
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ValueArrayAllocator::~ValueArrayAllocator() {}
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class DefaultValueArrayAllocator
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
class DefaultValueArrayAllocator : public ValueArrayAllocator {
|
||||||
|
public: // overridden from ValueArrayAllocator
|
||||||
|
virtual ~DefaultValueArrayAllocator() {}
|
||||||
|
|
||||||
|
virtual ValueInternalArray* newArray() { return new ValueInternalArray(); }
|
||||||
|
|
||||||
|
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
|
||||||
|
return new ValueInternalArray(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructArray(ValueInternalArray* array) { delete array; }
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
reallocateArrayPageIndex(Value**& indexes,
|
||||||
|
ValueInternalArray::PageIndex& indexCount,
|
||||||
|
ValueInternalArray::PageIndex minNewIndexCount) {
|
||||||
|
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
|
||||||
|
if (minNewIndexCount > newIndexCount)
|
||||||
|
newIndexCount = minNewIndexCount;
|
||||||
|
void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
|
||||||
|
JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
|
||||||
|
indexCount = newIndexCount;
|
||||||
|
indexes = static_cast<Value**>(newIndexes);
|
||||||
|
}
|
||||||
|
virtual void releaseArrayPageIndex(Value** indexes,
|
||||||
|
ValueInternalArray::PageIndex indexCount) {
|
||||||
|
if (indexes)
|
||||||
|
free(indexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Value* allocateArrayPage() {
|
||||||
|
return static_cast<Value*>(
|
||||||
|
malloc(sizeof(Value) * ValueInternalArray::itemsPerPage));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseArrayPage(Value* value) {
|
||||||
|
if (value)
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||||
|
class DefaultValueArrayAllocator : public ValueArrayAllocator {
|
||||||
|
public: // overridden from ValueArrayAllocator
|
||||||
|
virtual ~DefaultValueArrayAllocator() {}
|
||||||
|
|
||||||
|
virtual ValueInternalArray* newArray() {
|
||||||
|
ValueInternalArray* array = arraysAllocator_.allocate();
|
||||||
|
new (array) ValueInternalArray(); // placement new
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
|
||||||
|
ValueInternalArray* array = arraysAllocator_.allocate();
|
||||||
|
new (array) ValueInternalArray(other); // placement new
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructArray(ValueInternalArray* array) {
|
||||||
|
if (array) {
|
||||||
|
array->~ValueInternalArray();
|
||||||
|
arraysAllocator_.release(array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
reallocateArrayPageIndex(Value**& indexes,
|
||||||
|
ValueInternalArray::PageIndex& indexCount,
|
||||||
|
ValueInternalArray::PageIndex minNewIndexCount) {
|
||||||
|
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
|
||||||
|
if (minNewIndexCount > newIndexCount)
|
||||||
|
newIndexCount = minNewIndexCount;
|
||||||
|
void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
|
||||||
|
JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
|
||||||
|
indexCount = newIndexCount;
|
||||||
|
indexes = static_cast<Value**>(newIndexes);
|
||||||
|
}
|
||||||
|
virtual void releaseArrayPageIndex(Value** indexes,
|
||||||
|
ValueInternalArray::PageIndex indexCount) {
|
||||||
|
if (indexes)
|
||||||
|
free(indexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Value* allocateArrayPage() {
|
||||||
|
return static_cast<Value*>(pagesAllocator_.allocate());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseArrayPage(Value* value) {
|
||||||
|
if (value)
|
||||||
|
pagesAllocator_.release(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BatchAllocator<ValueInternalArray, 1> arraysAllocator_;
|
||||||
|
BatchAllocator<Value, ValueInternalArray::itemsPerPage> pagesAllocator_;
|
||||||
|
};
|
||||||
|
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
|
||||||
|
static ValueArrayAllocator*& arrayAllocator() {
|
||||||
|
static DefaultValueArrayAllocator defaultAllocator;
|
||||||
|
static ValueArrayAllocator* arrayAllocator = &defaultAllocator;
|
||||||
|
return arrayAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct DummyArrayAllocatorInitializer {
|
||||||
|
DummyArrayAllocatorInitializer() {
|
||||||
|
arrayAllocator(); // ensure arrayAllocator() statics are initialized before
|
||||||
|
// main().
|
||||||
|
}
|
||||||
|
} dummyArrayAllocatorInitializer;
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueInternalArray
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
bool ValueInternalArray::equals(const IteratorState& x,
|
||||||
|
const IteratorState& other) {
|
||||||
|
return x.array_ == other.array_ &&
|
||||||
|
x.currentItemIndex_ == other.currentItemIndex_ &&
|
||||||
|
x.currentPageIndex_ == other.currentPageIndex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::increment(IteratorState& it) {
|
||||||
|
JSON_ASSERT_MESSAGE(
|
||||||
|
it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
|
||||||
|
it.currentItemIndex_ !=
|
||||||
|
it.array_->size_,
|
||||||
|
"ValueInternalArray::increment(): moving iterator beyond end");
|
||||||
|
++(it.currentItemIndex_);
|
||||||
|
if (it.currentItemIndex_ == itemsPerPage) {
|
||||||
|
it.currentItemIndex_ = 0;
|
||||||
|
++(it.currentPageIndex_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::decrement(IteratorState& it) {
|
||||||
|
JSON_ASSERT_MESSAGE(
|
||||||
|
it.array_ && it.currentPageIndex_ == it.array_->pages_ &&
|
||||||
|
it.currentItemIndex_ == 0,
|
||||||
|
"ValueInternalArray::decrement(): moving iterator beyond end");
|
||||||
|
if (it.currentItemIndex_ == 0) {
|
||||||
|
it.currentItemIndex_ = itemsPerPage - 1;
|
||||||
|
--(it.currentPageIndex_);
|
||||||
|
} else {
|
||||||
|
--(it.currentItemIndex_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value& ValueInternalArray::unsafeDereference(const IteratorState& it) {
|
||||||
|
return (*(it.currentPageIndex_))[it.currentItemIndex_];
|
||||||
|
}
|
||||||
|
|
||||||
|
Value& ValueInternalArray::dereference(const IteratorState& it) {
|
||||||
|
JSON_ASSERT_MESSAGE(
|
||||||
|
it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
|
||||||
|
it.currentItemIndex_ <
|
||||||
|
it.array_->size_,
|
||||||
|
"ValueInternalArray::dereference(): dereferencing invalid iterator");
|
||||||
|
return unsafeDereference(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::makeBeginIterator(IteratorState& it) const {
|
||||||
|
it.array_ = const_cast<ValueInternalArray*>(this);
|
||||||
|
it.currentItemIndex_ = 0;
|
||||||
|
it.currentPageIndex_ = pages_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::makeIterator(IteratorState& it,
|
||||||
|
ArrayIndex index) const {
|
||||||
|
it.array_ = const_cast<ValueInternalArray*>(this);
|
||||||
|
it.currentItemIndex_ = index % itemsPerPage;
|
||||||
|
it.currentPageIndex_ = pages_ + index / itemsPerPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::makeEndIterator(IteratorState& it) const {
|
||||||
|
makeIterator(it, size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalArray::ValueInternalArray() : pages_(0), size_(0), pageCount_(0) {}
|
||||||
|
|
||||||
|
ValueInternalArray::ValueInternalArray(const ValueInternalArray& other)
|
||||||
|
: pages_(0), size_(other.size_), pageCount_(0) {
|
||||||
|
PageIndex minNewPages = other.size_ / itemsPerPage;
|
||||||
|
arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
|
||||||
|
JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
|
||||||
|
"ValueInternalArray::reserve(): bad reallocation");
|
||||||
|
IteratorState itOther;
|
||||||
|
other.makeBeginIterator(itOther);
|
||||||
|
Value* value;
|
||||||
|
for (ArrayIndex index = 0; index < size_; ++index, increment(itOther)) {
|
||||||
|
if (index % itemsPerPage == 0) {
|
||||||
|
PageIndex pageIndex = index / itemsPerPage;
|
||||||
|
value = arrayAllocator()->allocateArrayPage();
|
||||||
|
pages_[pageIndex] = value;
|
||||||
|
}
|
||||||
|
new (value) Value(dereference(itOther));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalArray& ValueInternalArray::operator=(ValueInternalArray other) {
|
||||||
|
swap(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalArray::~ValueInternalArray() {
|
||||||
|
// destroy all constructed items
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
makeBeginIterator(it);
|
||||||
|
makeEndIterator(itEnd);
|
||||||
|
for (; !equals(it, itEnd); increment(it)) {
|
||||||
|
Value* value = &dereference(it);
|
||||||
|
value->~Value();
|
||||||
|
}
|
||||||
|
// release all pages
|
||||||
|
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||||
|
for (PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex)
|
||||||
|
arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
|
||||||
|
// release pages index
|
||||||
|
arrayAllocator()->releaseArrayPageIndex(pages_, pageCount_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::swap(ValueInternalArray& other) {
|
||||||
|
Value** tempPages = pages_;
|
||||||
|
pages_ = other.pages_;
|
||||||
|
other.pages_ = tempPages;
|
||||||
|
ArrayIndex tempSize = size_;
|
||||||
|
size_ = other.size_;
|
||||||
|
other.size_ = tempSize;
|
||||||
|
PageIndex tempPageCount = pageCount_;
|
||||||
|
pageCount_ = other.pageCount_;
|
||||||
|
other.pageCount_ = tempPageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::clear() {
|
||||||
|
ValueInternalArray dummy;
|
||||||
|
swap(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::resize(ArrayIndex newSize) {
|
||||||
|
if (newSize == 0)
|
||||||
|
clear();
|
||||||
|
else if (newSize < size_) {
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
makeIterator(it, newSize);
|
||||||
|
makeIterator(itEnd, size_);
|
||||||
|
for (; !equals(it, itEnd); increment(it)) {
|
||||||
|
Value* value = &dereference(it);
|
||||||
|
value->~Value();
|
||||||
|
}
|
||||||
|
PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
|
||||||
|
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||||
|
for (; pageIndex < lastPageIndex; ++pageIndex)
|
||||||
|
arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
|
||||||
|
size_ = newSize;
|
||||||
|
} else if (newSize > size_)
|
||||||
|
resolveReference(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalArray::makeIndexValid(ArrayIndex index) {
|
||||||
|
// Need to enlarge page index ?
|
||||||
|
if (index >= pageCount_ * itemsPerPage) {
|
||||||
|
PageIndex minNewPages = (index + 1) / itemsPerPage;
|
||||||
|
arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
|
||||||
|
JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
|
||||||
|
"ValueInternalArray::reserve(): bad reallocation");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to allocate new pages ?
|
||||||
|
ArrayIndex nextPageIndex = (size_ % itemsPerPage) != 0
|
||||||
|
? size_ - (size_ % itemsPerPage) + itemsPerPage
|
||||||
|
: size_;
|
||||||
|
if (nextPageIndex <= index) {
|
||||||
|
PageIndex pageIndex = nextPageIndex / itemsPerPage;
|
||||||
|
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
|
||||||
|
for (; pageToAllocate-- > 0; ++pageIndex)
|
||||||
|
pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize all new entries
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
makeIterator(it, size_);
|
||||||
|
size_ = index + 1;
|
||||||
|
makeIterator(itEnd, size_);
|
||||||
|
for (; !equals(it, itEnd); increment(it)) {
|
||||||
|
Value* value = &dereference(it);
|
||||||
|
new (value) Value(); // Construct a default value using placement new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value& ValueInternalArray::resolveReference(ArrayIndex index) {
|
||||||
|
if (index >= size_)
|
||||||
|
makeIndexValid(index);
|
||||||
|
return pages_[index / itemsPerPage][index % itemsPerPage];
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* ValueInternalArray::find(ArrayIndex index) const {
|
||||||
|
if (index >= size_)
|
||||||
|
return 0;
|
||||||
|
return &(pages_[index / itemsPerPage][index % itemsPerPage]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalArray::ArrayIndex ValueInternalArray::size() const {
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ValueInternalArray::distance(const IteratorState& x,
|
||||||
|
const IteratorState& y) {
|
||||||
|
return indexOf(y) - indexOf(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalArray::ArrayIndex
|
||||||
|
ValueInternalArray::indexOf(const IteratorState& iterator) {
|
||||||
|
if (!iterator.array_)
|
||||||
|
return ArrayIndex(-1);
|
||||||
|
return ArrayIndex((iterator.currentPageIndex_ - iterator.array_->pages_) *
|
||||||
|
itemsPerPage +
|
||||||
|
iterator.currentItemIndex_);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ValueInternalArray::compare(const ValueInternalArray& other) const {
|
||||||
|
int sizeDiff(size_ - other.size_);
|
||||||
|
if (sizeDiff != 0)
|
||||||
|
return sizeDiff;
|
||||||
|
|
||||||
|
for (ArrayIndex index = 0; index < size_; ++index) {
|
||||||
|
int diff = pages_[index / itemsPerPage][index % itemsPerPage].compare(
|
||||||
|
other.pages_[index / itemsPerPage][index % itemsPerPage]);
|
||||||
|
if (diff != 0)
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Json
|
473
src/lib_json/json_internalmap.inl
Normal file
473
src/lib_json/json_internalmap.inl
Normal file
@@ -0,0 +1,473 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
// included by json_value.cpp
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueInternalMap
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/** \internal MUST be safely initialized using memset( this, 0,
|
||||||
|
* sizeof(ValueInternalLink) );
|
||||||
|
* This optimization is used by the fast allocator.
|
||||||
|
*/
|
||||||
|
ValueInternalLink::ValueInternalLink() : previous_(0), next_(0) {}
|
||||||
|
|
||||||
|
ValueInternalLink::~ValueInternalLink() {
|
||||||
|
for (int index = 0; index < itemPerLink; ++index) {
|
||||||
|
if (!items_[index].isItemAvailable()) {
|
||||||
|
if (!items_[index].isMemberNameStatic())
|
||||||
|
free(keys_[index]);
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueMapAllocator::~ValueMapAllocator() {}
|
||||||
|
|
||||||
|
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
class DefaultValueMapAllocator : public ValueMapAllocator {
|
||||||
|
public: // overridden from ValueMapAllocator
|
||||||
|
virtual ValueInternalMap* newMap() { return new ValueInternalMap(); }
|
||||||
|
|
||||||
|
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
|
||||||
|
return new ValueInternalMap(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructMap(ValueInternalMap* map) { delete map; }
|
||||||
|
|
||||||
|
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
|
||||||
|
return new ValueInternalLink[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
|
||||||
|
|
||||||
|
virtual ValueInternalLink* allocateMapLink() {
|
||||||
|
return new ValueInternalLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapLink(ValueInternalLink* link) { delete link; }
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||||
|
class DefaultValueMapAllocator : public ValueMapAllocator {
|
||||||
|
public: // overridden from ValueMapAllocator
|
||||||
|
virtual ValueInternalMap* newMap() {
|
||||||
|
ValueInternalMap* map = mapsAllocator_.allocate();
|
||||||
|
new (map) ValueInternalMap(); // placement new
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
|
||||||
|
ValueInternalMap* map = mapsAllocator_.allocate();
|
||||||
|
new (map) ValueInternalMap(other); // placement new
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructMap(ValueInternalMap* map) {
|
||||||
|
if (map) {
|
||||||
|
map->~ValueInternalMap();
|
||||||
|
mapsAllocator_.release(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
|
||||||
|
return new ValueInternalLink[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
|
||||||
|
|
||||||
|
virtual ValueInternalLink* allocateMapLink() {
|
||||||
|
ValueInternalLink* link = linksAllocator_.allocate();
|
||||||
|
memset(link, 0, sizeof(ValueInternalLink));
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapLink(ValueInternalLink* link) {
|
||||||
|
link->~ValueInternalLink();
|
||||||
|
linksAllocator_.release(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BatchAllocator<ValueInternalMap, 1> mapsAllocator_;
|
||||||
|
BatchAllocator<ValueInternalLink, 1> linksAllocator_;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static ValueMapAllocator*& mapAllocator() {
|
||||||
|
static DefaultValueMapAllocator defaultAllocator;
|
||||||
|
static ValueMapAllocator* mapAllocator = &defaultAllocator;
|
||||||
|
return mapAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct DummyMapAllocatorInitializer {
|
||||||
|
DummyMapAllocatorInitializer() {
|
||||||
|
mapAllocator(); // ensure mapAllocator() statics are initialized before
|
||||||
|
// main().
|
||||||
|
}
|
||||||
|
} dummyMapAllocatorInitializer;
|
||||||
|
|
||||||
|
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
|
||||||
|
|
||||||
|
/*
|
||||||
|
use linked list hash map.
|
||||||
|
buckets array is a container.
|
||||||
|
linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
|
||||||
|
value have extra state: valid, available, deleted
|
||||||
|
*/
|
||||||
|
|
||||||
|
ValueInternalMap::ValueInternalMap()
|
||||||
|
: buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {}
|
||||||
|
|
||||||
|
ValueInternalMap::ValueInternalMap(const ValueInternalMap& other)
|
||||||
|
: buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {
|
||||||
|
reserve(other.itemCount_);
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
other.makeBeginIterator(it);
|
||||||
|
other.makeEndIterator(itEnd);
|
||||||
|
for (; !equals(it, itEnd); increment(it)) {
|
||||||
|
bool isStatic;
|
||||||
|
const char* memberName = key(it, isStatic);
|
||||||
|
const Value& aValue = value(it);
|
||||||
|
resolveReference(memberName, isStatic) = aValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalMap& ValueInternalMap::operator=(ValueInternalMap other) {
|
||||||
|
swap(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalMap::~ValueInternalMap() {
|
||||||
|
if (buckets_) {
|
||||||
|
for (BucketIndex bucketIndex = 0; bucketIndex < bucketsSize_;
|
||||||
|
++bucketIndex) {
|
||||||
|
ValueInternalLink* link = buckets_[bucketIndex].next_;
|
||||||
|
while (link) {
|
||||||
|
ValueInternalLink* linkToRelease = link;
|
||||||
|
link = link->next_;
|
||||||
|
mapAllocator()->releaseMapLink(linkToRelease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mapAllocator()->releaseMapBuckets(buckets_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::swap(ValueInternalMap& other) {
|
||||||
|
ValueInternalLink* tempBuckets = buckets_;
|
||||||
|
buckets_ = other.buckets_;
|
||||||
|
other.buckets_ = tempBuckets;
|
||||||
|
ValueInternalLink* tempTailLink = tailLink_;
|
||||||
|
tailLink_ = other.tailLink_;
|
||||||
|
other.tailLink_ = tempTailLink;
|
||||||
|
BucketIndex tempBucketsSize = bucketsSize_;
|
||||||
|
bucketsSize_ = other.bucketsSize_;
|
||||||
|
other.bucketsSize_ = tempBucketsSize;
|
||||||
|
BucketIndex tempItemCount = itemCount_;
|
||||||
|
itemCount_ = other.itemCount_;
|
||||||
|
other.itemCount_ = tempItemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::clear() {
|
||||||
|
ValueInternalMap dummy;
|
||||||
|
swap(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalMap::BucketIndex ValueInternalMap::size() const {
|
||||||
|
return itemCount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValueInternalMap::reserveDelta(BucketIndex growth) {
|
||||||
|
return reserve(itemCount_ + growth);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValueInternalMap::reserve(BucketIndex newItemCount) {
|
||||||
|
if (!buckets_ && newItemCount > 0) {
|
||||||
|
buckets_ = mapAllocator()->allocateMapBuckets(1);
|
||||||
|
bucketsSize_ = 1;
|
||||||
|
tailLink_ = &buckets_[0];
|
||||||
|
}
|
||||||
|
// BucketIndex idealBucketCount = (newItemCount +
|
||||||
|
// ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Value* ValueInternalMap::find(const char* key) const {
|
||||||
|
if (!bucketsSize_)
|
||||||
|
return 0;
|
||||||
|
HashKey hashedKey = hash(key);
|
||||||
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
|
for (const ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
|
||||||
|
current = current->next_) {
|
||||||
|
for (BucketIndex index = 0; index < ValueInternalLink::itemPerLink;
|
||||||
|
++index) {
|
||||||
|
if (current->items_[index].isItemAvailable())
|
||||||
|
return 0;
|
||||||
|
if (strcmp(key, current->keys_[index]) == 0)
|
||||||
|
return ¤t->items_[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* ValueInternalMap::find(const char* key) {
|
||||||
|
const ValueInternalMap* constThis = this;
|
||||||
|
return const_cast<Value*>(constThis->find(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
Value& ValueInternalMap::resolveReference(const char* key, bool isStatic) {
|
||||||
|
HashKey hashedKey = hash(key);
|
||||||
|
if (bucketsSize_) {
|
||||||
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
|
ValueInternalLink** previous = 0;
|
||||||
|
BucketIndex index;
|
||||||
|
for (ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
|
||||||
|
previous = ¤t->next_, current = current->next_) {
|
||||||
|
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
||||||
|
if (current->items_[index].isItemAvailable())
|
||||||
|
return setNewItem(key, isStatic, current, index);
|
||||||
|
if (strcmp(key, current->keys_[index]) == 0)
|
||||||
|
return current->items_[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reserveDelta(1);
|
||||||
|
return unsafeAdd(key, isStatic, hashedKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::remove(const char* key) {
|
||||||
|
HashKey hashedKey = hash(key);
|
||||||
|
if (!bucketsSize_)
|
||||||
|
return;
|
||||||
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
|
for (ValueInternalLink* link = &buckets_[bucketIndex]; link != 0;
|
||||||
|
link = link->next_) {
|
||||||
|
BucketIndex index;
|
||||||
|
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
||||||
|
if (link->items_[index].isItemAvailable())
|
||||||
|
return;
|
||||||
|
if (strcmp(key, link->keys_[index]) == 0) {
|
||||||
|
doActualRemove(link, index, bucketIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::doActualRemove(ValueInternalLink* link,
|
||||||
|
BucketIndex index,
|
||||||
|
BucketIndex bucketIndex) {
|
||||||
|
// find last item of the bucket and swap it with the 'removed' one.
|
||||||
|
// set removed items flags to 'available'.
|
||||||
|
// if last page only contains 'available' items, then desallocate it (it's
|
||||||
|
// empty)
|
||||||
|
ValueInternalLink*& lastLink = getLastLinkInBucket(index);
|
||||||
|
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
|
||||||
|
for (; lastItemIndex < ValueInternalLink::itemPerLink;
|
||||||
|
++lastItemIndex) // may be optimized with dicotomic search
|
||||||
|
{
|
||||||
|
if (lastLink->items_[lastItemIndex].isItemAvailable())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BucketIndex lastUsedIndex = lastItemIndex - 1;
|
||||||
|
Value* valueToDelete = &link->items_[index];
|
||||||
|
Value* valueToPreserve = &lastLink->items_[lastUsedIndex];
|
||||||
|
if (valueToDelete != valueToPreserve)
|
||||||
|
valueToDelete->swap(*valueToPreserve);
|
||||||
|
if (lastUsedIndex == 0) // page is now empty
|
||||||
|
{ // remove it from bucket linked list and delete it.
|
||||||
|
ValueInternalLink* linkPreviousToLast = lastLink->previous_;
|
||||||
|
if (linkPreviousToLast != 0) // can not deleted bucket link.
|
||||||
|
{
|
||||||
|
mapAllocator()->releaseMapLink(lastLink);
|
||||||
|
linkPreviousToLast->next_ = 0;
|
||||||
|
lastLink = linkPreviousToLast;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Value dummy;
|
||||||
|
valueToPreserve->swap(dummy); // restore deleted to default Value.
|
||||||
|
valueToPreserve->setItemUsed(false);
|
||||||
|
}
|
||||||
|
--itemCount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalLink*&
|
||||||
|
ValueInternalMap::getLastLinkInBucket(BucketIndex bucketIndex) {
|
||||||
|
if (bucketIndex == bucketsSize_ - 1)
|
||||||
|
return tailLink_;
|
||||||
|
ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_;
|
||||||
|
if (!previous)
|
||||||
|
previous = &buckets_[bucketIndex];
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value& ValueInternalMap::setNewItem(const char* key,
|
||||||
|
bool isStatic,
|
||||||
|
ValueInternalLink* link,
|
||||||
|
BucketIndex index) {
|
||||||
|
char* duplicatedKey = makeMemberName(key);
|
||||||
|
++itemCount_;
|
||||||
|
link->keys_[index] = duplicatedKey;
|
||||||
|
link->items_[index].setItemUsed();
|
||||||
|
link->items_[index].setMemberNameIsStatic(isStatic);
|
||||||
|
return link->items_[index]; // items already default constructed.
|
||||||
|
}
|
||||||
|
|
||||||
|
Value&
|
||||||
|
ValueInternalMap::unsafeAdd(const char* key, bool isStatic, HashKey hashedKey) {
|
||||||
|
JSON_ASSERT_MESSAGE(bucketsSize_ > 0,
|
||||||
|
"ValueInternalMap::unsafeAdd(): internal logic error.");
|
||||||
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
|
ValueInternalLink*& previousLink = getLastLinkInBucket(bucketIndex);
|
||||||
|
ValueInternalLink* link = previousLink;
|
||||||
|
BucketIndex index;
|
||||||
|
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
||||||
|
if (link->items_[index].isItemAvailable())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (index == ValueInternalLink::itemPerLink) // need to add a new page
|
||||||
|
{
|
||||||
|
ValueInternalLink* newLink = mapAllocator()->allocateMapLink();
|
||||||
|
index = 0;
|
||||||
|
link->next_ = newLink;
|
||||||
|
previousLink = newLink;
|
||||||
|
link = newLink;
|
||||||
|
}
|
||||||
|
return setNewItem(key, isStatic, link, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalMap::HashKey ValueInternalMap::hash(const char* key) const {
|
||||||
|
HashKey hash = 0;
|
||||||
|
while (*key)
|
||||||
|
hash += *key++ * 37;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ValueInternalMap::compare(const ValueInternalMap& other) const {
|
||||||
|
int sizeDiff(itemCount_ - other.itemCount_);
|
||||||
|
if (sizeDiff != 0)
|
||||||
|
return sizeDiff;
|
||||||
|
// Strict order guaranty is required. Compare all keys FIRST, then compare
|
||||||
|
// values.
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
makeBeginIterator(it);
|
||||||
|
makeEndIterator(itEnd);
|
||||||
|
for (; !equals(it, itEnd); increment(it)) {
|
||||||
|
if (!other.find(key(it)))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All keys are equals, let's compare values
|
||||||
|
makeBeginIterator(it);
|
||||||
|
for (; !equals(it, itEnd); increment(it)) {
|
||||||
|
const Value* otherValue = other.find(key(it));
|
||||||
|
int valueDiff = value(it).compare(*otherValue);
|
||||||
|
if (valueDiff != 0)
|
||||||
|
return valueDiff;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::makeBeginIterator(IteratorState& it) const {
|
||||||
|
it.map_ = const_cast<ValueInternalMap*>(this);
|
||||||
|
it.bucketIndex_ = 0;
|
||||||
|
it.itemIndex_ = 0;
|
||||||
|
it.link_ = buckets_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::makeEndIterator(IteratorState& it) const {
|
||||||
|
it.map_ = const_cast<ValueInternalMap*>(this);
|
||||||
|
it.bucketIndex_ = bucketsSize_;
|
||||||
|
it.itemIndex_ = 0;
|
||||||
|
it.link_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValueInternalMap::equals(const IteratorState& x,
|
||||||
|
const IteratorState& other) {
|
||||||
|
return x.map_ == other.map_ && x.bucketIndex_ == other.bucketIndex_ &&
|
||||||
|
x.link_ == other.link_ && x.itemIndex_ == other.itemIndex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::incrementBucket(IteratorState& iterator) {
|
||||||
|
++iterator.bucketIndex_;
|
||||||
|
JSON_ASSERT_MESSAGE(
|
||||||
|
iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
|
||||||
|
"ValueInternalMap::increment(): attempting to iterate beyond end.");
|
||||||
|
if (iterator.bucketIndex_ == iterator.map_->bucketsSize_)
|
||||||
|
iterator.link_ = 0;
|
||||||
|
else
|
||||||
|
iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
|
||||||
|
iterator.itemIndex_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::increment(IteratorState& iterator) {
|
||||||
|
JSON_ASSERT_MESSAGE(iterator.map_,
|
||||||
|
"Attempting to iterator using invalid iterator.");
|
||||||
|
++iterator.itemIndex_;
|
||||||
|
if (iterator.itemIndex_ == ValueInternalLink::itemPerLink) {
|
||||||
|
JSON_ASSERT_MESSAGE(
|
||||||
|
iterator.link_ != 0,
|
||||||
|
"ValueInternalMap::increment(): attempting to iterate beyond end.");
|
||||||
|
iterator.link_ = iterator.link_->next_;
|
||||||
|
if (iterator.link_ == 0)
|
||||||
|
incrementBucket(iterator);
|
||||||
|
} else if (iterator.link_->items_[iterator.itemIndex_].isItemAvailable()) {
|
||||||
|
incrementBucket(iterator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueInternalMap::decrement(IteratorState& iterator) {
|
||||||
|
if (iterator.itemIndex_ == 0) {
|
||||||
|
JSON_ASSERT_MESSAGE(iterator.map_,
|
||||||
|
"Attempting to iterate using invalid iterator.");
|
||||||
|
if (iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_]) {
|
||||||
|
JSON_ASSERT_MESSAGE(iterator.bucketIndex_ > 0,
|
||||||
|
"Attempting to iterate beyond beginning.");
|
||||||
|
--(iterator.bucketIndex_);
|
||||||
|
}
|
||||||
|
iterator.link_ = iterator.link_->previous_;
|
||||||
|
iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ValueInternalMap::key(const IteratorState& iterator) {
|
||||||
|
JSON_ASSERT_MESSAGE(iterator.link_,
|
||||||
|
"Attempting to iterate using invalid iterator.");
|
||||||
|
return iterator.link_->keys_[iterator.itemIndex_];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ValueInternalMap::key(const IteratorState& iterator,
|
||||||
|
bool& isStatic) {
|
||||||
|
JSON_ASSERT_MESSAGE(iterator.link_,
|
||||||
|
"Attempting to iterate using invalid iterator.");
|
||||||
|
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
|
||||||
|
return iterator.link_->keys_[iterator.itemIndex_];
|
||||||
|
}
|
||||||
|
|
||||||
|
Value& ValueInternalMap::value(const IteratorState& iterator) {
|
||||||
|
JSON_ASSERT_MESSAGE(iterator.link_,
|
||||||
|
"Attempting to iterate using invalid iterator.");
|
||||||
|
return iterator.link_->items_[iterator.itemIndex_];
|
||||||
|
}
|
||||||
|
|
||||||
|
int ValueInternalMap::distance(const IteratorState& x, const IteratorState& y) {
|
||||||
|
int offset = 0;
|
||||||
|
IteratorState it = x;
|
||||||
|
while (!equals(it, y))
|
||||||
|
increment(it);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Json
|
@@ -17,6 +17,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@@ -144,7 +145,7 @@ bool Reader::readValue() {
|
|||||||
// But this deprecated class has a security problem: Bad input can
|
// But this deprecated class has a security problem: Bad input can
|
||||||
// cause a seg-fault. This seems like a fair, binary-compatible way
|
// cause a seg-fault. This seems like a fair, binary-compatible way
|
||||||
// to prevent the problem.
|
// to prevent the problem.
|
||||||
if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
|
if (stackDepth_g >= stackLimit_g) throw std::runtime_error("Exceeded stackLimit in readValue().");
|
||||||
++stackDepth_g;
|
++stackDepth_g;
|
||||||
|
|
||||||
Token token;
|
Token token;
|
||||||
@@ -819,14 +820,12 @@ std::string Reader::getFormattedErrorMessages() const {
|
|||||||
class OurFeatures {
|
class OurFeatures {
|
||||||
public:
|
public:
|
||||||
static OurFeatures all();
|
static OurFeatures all();
|
||||||
|
static OurFeatures strictMode();
|
||||||
OurFeatures();
|
OurFeatures();
|
||||||
bool allowComments_;
|
bool allowComments_;
|
||||||
bool strictRoot_;
|
bool strictRoot_;
|
||||||
bool allowDroppedNullPlaceholders_;
|
bool allowDroppedNullPlaceholders_;
|
||||||
bool allowNumericKeys_;
|
bool allowNumericKeys_;
|
||||||
bool allowSingleQuotes_;
|
|
||||||
bool failIfExtra_;
|
|
||||||
bool rejectDupKeys_;
|
|
||||||
int stackLimit_;
|
int stackLimit_;
|
||||||
}; // OurFeatures
|
}; // OurFeatures
|
||||||
|
|
||||||
@@ -834,15 +833,20 @@ public:
|
|||||||
// ////////////////////////////////
|
// ////////////////////////////////
|
||||||
|
|
||||||
OurFeatures::OurFeatures()
|
OurFeatures::OurFeatures()
|
||||||
: allowComments_(true), strictRoot_(false)
|
: allowComments_(true), strictRoot_(false),
|
||||||
, allowDroppedNullPlaceholders_(false), allowNumericKeys_(false)
|
allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
|
||||||
, allowSingleQuotes_(false)
|
|
||||||
, failIfExtra_(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
OurFeatures OurFeatures::all() { return OurFeatures(); }
|
OurFeatures OurFeatures::all() { return OurFeatures(); }
|
||||||
|
|
||||||
|
OurFeatures OurFeatures::strictMode() {
|
||||||
|
OurFeatures features;
|
||||||
|
features.allowComments_ = false;
|
||||||
|
features.strictRoot_ = true;
|
||||||
|
features.allowDroppedNullPlaceholders_ = false;
|
||||||
|
features.allowNumericKeys_ = false;
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
// Implementation of class Reader
|
// Implementation of class Reader
|
||||||
// ////////////////////////////////
|
// ////////////////////////////////
|
||||||
|
|
||||||
@@ -908,7 +912,6 @@ private:
|
|||||||
bool readCStyleComment();
|
bool readCStyleComment();
|
||||||
bool readCppStyleComment();
|
bool readCppStyleComment();
|
||||||
bool readString();
|
bool readString();
|
||||||
bool readStringSingleQuote();
|
|
||||||
void readNumber();
|
void readNumber();
|
||||||
bool readValue();
|
bool readValue();
|
||||||
bool readObject(Token& token);
|
bool readObject(Token& token);
|
||||||
@@ -988,12 +991,6 @@ bool OurReader::parse(const char* beginDoc,
|
|||||||
bool successful = readValue();
|
bool successful = readValue();
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens(token);
|
skipCommentTokens(token);
|
||||||
if (features_.failIfExtra_) {
|
|
||||||
if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
|
|
||||||
addError("Extra non-whitespace after JSON value.", token);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (collectComments_ && !commentsBefore_.empty())
|
if (collectComments_ && !commentsBefore_.empty())
|
||||||
root.setComment(commentsBefore_, commentAfter);
|
root.setComment(commentsBefore_, commentAfter);
|
||||||
if (features_.strictRoot_) {
|
if (features_.strictRoot_) {
|
||||||
@@ -1013,7 +1010,7 @@ bool OurReader::parse(const char* beginDoc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool OurReader::readValue() {
|
bool OurReader::readValue() {
|
||||||
if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
|
if (stackDepth_ >= features_.stackLimit_) throw std::runtime_error("Exceeded stackLimit in readValue().");
|
||||||
++stackDepth_;
|
++stackDepth_;
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens(token);
|
skipCommentTokens(token);
|
||||||
@@ -1056,8 +1053,6 @@ bool OurReader::readValue() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tokenArraySeparator:
|
case tokenArraySeparator:
|
||||||
case tokenObjectEnd:
|
|
||||||
case tokenArrayEnd:
|
|
||||||
if (features_.allowDroppedNullPlaceholders_) {
|
if (features_.allowDroppedNullPlaceholders_) {
|
||||||
// "Un-read" the current token and mark the current value as a null
|
// "Un-read" the current token and mark the current value as a null
|
||||||
// token.
|
// token.
|
||||||
@@ -1065,7 +1060,8 @@ bool OurReader::readValue() {
|
|||||||
Value v;
|
Value v;
|
||||||
currentValue().swapPayload(v);
|
currentValue().swapPayload(v);
|
||||||
break;
|
break;
|
||||||
} // else, fall through ...
|
}
|
||||||
|
// Else, fall through...
|
||||||
default:
|
default:
|
||||||
return addError("Syntax error: value, object or array expected.", token);
|
return addError("Syntax error: value, object or array expected.", token);
|
||||||
}
|
}
|
||||||
@@ -1111,12 +1107,6 @@ bool OurReader::readToken(Token& token) {
|
|||||||
token.type_ = tokenString;
|
token.type_ = tokenString;
|
||||||
ok = readString();
|
ok = readString();
|
||||||
break;
|
break;
|
||||||
case '\'':
|
|
||||||
if (features_.allowSingleQuotes_) {
|
|
||||||
token.type_ = tokenString;
|
|
||||||
ok = readStringSingleQuote();
|
|
||||||
break;
|
|
||||||
} // else continue
|
|
||||||
case '/':
|
case '/':
|
||||||
token.type_ = tokenComment;
|
token.type_ = tokenComment;
|
||||||
ok = readComment();
|
ok = readComment();
|
||||||
@@ -1268,6 +1258,7 @@ void OurReader::readNumber() {
|
|||||||
c = (current_ = p) < end_ ? *p++ : 0;
|
c = (current_ = p) < end_ ? *p++ : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OurReader::readString() {
|
bool OurReader::readString() {
|
||||||
Char c = 0;
|
Char c = 0;
|
||||||
while (current_ != end_) {
|
while (current_ != end_) {
|
||||||
@@ -1280,19 +1271,6 @@ bool OurReader::readString() {
|
|||||||
return c == '"';
|
return c == '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool OurReader::readStringSingleQuote() {
|
|
||||||
Char c = 0;
|
|
||||||
while (current_ != end_) {
|
|
||||||
c = getNextChar();
|
|
||||||
if (c == '\\')
|
|
||||||
getNextChar();
|
|
||||||
else if (c == '\'')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return c == '\'';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OurReader::readObject(Token& tokenStart) {
|
bool OurReader::readObject(Token& tokenStart) {
|
||||||
Token tokenName;
|
Token tokenName;
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -1324,12 +1302,6 @@ bool OurReader::readObject(Token& tokenStart) {
|
|||||||
return addErrorAndRecover(
|
return addErrorAndRecover(
|
||||||
"Missing ':' after object member name", colon, tokenObjectEnd);
|
"Missing ':' after object member name", colon, tokenObjectEnd);
|
||||||
}
|
}
|
||||||
if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
|
|
||||||
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
|
|
||||||
std::string msg = "Duplicate key: '" + name + "'";
|
|
||||||
return addErrorAndRecover(
|
|
||||||
msg, tokenName, tokenObjectEnd);
|
|
||||||
}
|
|
||||||
Value& value = currentValue()[name];
|
Value& value = currentValue()[name];
|
||||||
nodes_.push(&value);
|
nodes_.push(&value);
|
||||||
bool ok = readValue();
|
bool ok = readValue();
|
||||||
@@ -1731,10 +1703,7 @@ CharReader* CharReaderBuilder::newCharReader() const
|
|||||||
features.strictRoot_ = settings_["strictRoot"].asBool();
|
features.strictRoot_ = settings_["strictRoot"].asBool();
|
||||||
features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
|
features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
|
||||||
features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
|
features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
|
||||||
features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
|
|
||||||
features.stackLimit_ = settings_["stackLimit"].asInt();
|
features.stackLimit_ = settings_["stackLimit"].asInt();
|
||||||
features.failIfExtra_ = settings_["failIfExtra"].asBool();
|
|
||||||
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
|
|
||||||
return new OurCharReader(collectComments, features);
|
return new OurCharReader(collectComments, features);
|
||||||
}
|
}
|
||||||
static void getValidReaderKeys(std::set<std::string>* valid_keys)
|
static void getValidReaderKeys(std::set<std::string>* valid_keys)
|
||||||
@@ -1745,16 +1714,14 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
|
|||||||
valid_keys->insert("strictRoot");
|
valid_keys->insert("strictRoot");
|
||||||
valid_keys->insert("allowDroppedNullPlaceholders");
|
valid_keys->insert("allowDroppedNullPlaceholders");
|
||||||
valid_keys->insert("allowNumericKeys");
|
valid_keys->insert("allowNumericKeys");
|
||||||
valid_keys->insert("allowSingleQuotes");
|
|
||||||
valid_keys->insert("stackLimit");
|
valid_keys->insert("stackLimit");
|
||||||
valid_keys->insert("failIfExtra");
|
|
||||||
valid_keys->insert("rejectDupKeys");
|
|
||||||
}
|
}
|
||||||
bool CharReaderBuilder::validate(Json::Value* invalid) const
|
bool CharReaderBuilder::validate(Json::Value* invalid) const
|
||||||
{
|
{
|
||||||
Json::Value my_invalid;
|
Json::Value my_invalid;
|
||||||
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
|
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
|
||||||
Json::Value& inv = *invalid;
|
Json::Value& inv = *invalid;
|
||||||
|
bool valid = true;
|
||||||
std::set<std::string> valid_keys;
|
std::set<std::string> valid_keys;
|
||||||
getValidReaderKeys(&valid_keys);
|
getValidReaderKeys(&valid_keys);
|
||||||
Value::Members keys = settings_.getMemberNames();
|
Value::Members keys = settings_.getMemberNames();
|
||||||
@@ -1765,11 +1732,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const
|
|||||||
inv[key] = settings_[key];
|
inv[key] = settings_[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0u == inv.size();
|
return valid;
|
||||||
}
|
|
||||||
Value& CharReaderBuilder::operator[](std::string key)
|
|
||||||
{
|
|
||||||
return settings_[key];
|
|
||||||
}
|
}
|
||||||
// static
|
// static
|
||||||
void CharReaderBuilder::strictMode(Json::Value* settings)
|
void CharReaderBuilder::strictMode(Json::Value* settings)
|
||||||
@@ -1779,9 +1742,6 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
|
|||||||
(*settings)["strictRoot"] = true;
|
(*settings)["strictRoot"] = true;
|
||||||
(*settings)["allowDroppedNullPlaceholders"] = false;
|
(*settings)["allowDroppedNullPlaceholders"] = false;
|
||||||
(*settings)["allowNumericKeys"] = false;
|
(*settings)["allowNumericKeys"] = false;
|
||||||
(*settings)["allowSingleQuotes"] = false;
|
|
||||||
(*settings)["failIfExtra"] = true;
|
|
||||||
(*settings)["rejectDupKeys"] = true;
|
|
||||||
//! [CharReaderBuilderStrictMode]
|
//! [CharReaderBuilderStrictMode]
|
||||||
}
|
}
|
||||||
// static
|
// static
|
||||||
@@ -1793,10 +1753,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
|
|||||||
(*settings)["strictRoot"] = false;
|
(*settings)["strictRoot"] = false;
|
||||||
(*settings)["allowDroppedNullPlaceholders"] = false;
|
(*settings)["allowDroppedNullPlaceholders"] = false;
|
||||||
(*settings)["allowNumericKeys"] = false;
|
(*settings)["allowNumericKeys"] = false;
|
||||||
(*settings)["allowSingleQuotes"] = false;
|
|
||||||
(*settings)["stackLimit"] = 1000;
|
(*settings)["stackLimit"] = 1000;
|
||||||
(*settings)["failIfExtra"] = false;
|
|
||||||
(*settings)["rejectDupKeys"] = false;
|
|
||||||
//! [CharReaderBuilderDefaults]
|
//! [CharReaderBuilderDefaults]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1826,7 +1783,7 @@ std::istream& operator>>(std::istream& sin, Value& root) {
|
|||||||
"Error from reader: %s",
|
"Error from reader: %s",
|
||||||
errs.c_str());
|
errs.c_str());
|
||||||
|
|
||||||
throwRuntimeError("reader error");
|
JSON_FAIL_MESSAGE("reader error");
|
||||||
}
|
}
|
||||||
return sin;
|
return sin;
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,9 @@
|
|||||||
#include <json/assertions.h>
|
#include <json/assertions.h>
|
||||||
#include <json/value.h>
|
#include <json/value.h>
|
||||||
#include <json/writer.h>
|
#include <json/writer.h>
|
||||||
|
#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
#include "json_batchallocator.h"
|
||||||
|
#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -17,7 +20,6 @@
|
|||||||
#include <cpptl/conststring.h>
|
#include <cpptl/conststring.h>
|
||||||
#endif
|
#endif
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <algorithm> // min()
|
|
||||||
|
|
||||||
#define JSON_ASSERT_UNREACHABLE assert(false)
|
#define JSON_ASSERT_UNREACHABLE assert(false)
|
||||||
|
|
||||||
@@ -30,7 +32,7 @@ namespace Json {
|
|||||||
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
||||||
#else
|
#else
|
||||||
// This exists for binary compatibility only. Use nullRef.
|
// This exists for binary compatibility only. Use nullRef.
|
||||||
const Value Value::null;
|
static const Value null;
|
||||||
#define ALIGNAS(byte_alignment)
|
#define ALIGNAS(byte_alignment)
|
||||||
#endif
|
#endif
|
||||||
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
||||||
@@ -53,6 +55,9 @@ const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
|
|||||||
const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
|
const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
|
||||||
const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
|
const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
|
||||||
|
|
||||||
|
/// Unknown size marker
|
||||||
|
static const unsigned int unknown = (unsigned)-1;
|
||||||
|
|
||||||
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
static inline bool InRange(double d, T min, U max) {
|
static inline bool InRange(double d, T min, U max) {
|
||||||
@@ -81,59 +86,25 @@ static inline bool InRange(double d, T min, U max) {
|
|||||||
* @return Pointer on the duplicate instance of string.
|
* @return Pointer on the duplicate instance of string.
|
||||||
*/
|
*/
|
||||||
static inline char* duplicateStringValue(const char* value,
|
static inline char* duplicateStringValue(const char* value,
|
||||||
size_t length) {
|
unsigned int length = unknown) {
|
||||||
|
if (length == unknown)
|
||||||
|
length = (unsigned int)strlen(value);
|
||||||
|
|
||||||
// Avoid an integer overflow in the call to malloc below by limiting length
|
// Avoid an integer overflow in the call to malloc below by limiting length
|
||||||
// to a sane value.
|
// to a sane value.
|
||||||
if (length >= (size_t)Value::maxInt)
|
if (length >= (unsigned)Value::maxInt)
|
||||||
length = Value::maxInt - 1;
|
length = Value::maxInt - 1;
|
||||||
|
|
||||||
char* newString = static_cast<char*>(malloc(length + 1));
|
char* newString = static_cast<char*>(malloc(length + 1));
|
||||||
if (newString == NULL) {
|
JSON_ASSERT_MESSAGE(newString != 0,
|
||||||
throwRuntimeError(
|
"in Json::Value::duplicateStringValue(): "
|
||||||
"in Json::Value::duplicateStringValue(): "
|
"Failed to allocate string value buffer");
|
||||||
"Failed to allocate string value buffer");
|
|
||||||
}
|
|
||||||
memcpy(newString, value, length);
|
memcpy(newString, value, length);
|
||||||
newString[length] = 0;
|
newString[length] = 0;
|
||||||
return newString;
|
return newString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record the length as a prefix.
|
/** Free the string duplicated by duplicateStringValue().
|
||||||
*/
|
|
||||||
static inline char* duplicateAndPrefixStringValue(
|
|
||||||
const char* value,
|
|
||||||
unsigned int length)
|
|
||||||
{
|
|
||||||
// Avoid an integer overflow in the call to malloc below by limiting length
|
|
||||||
// to a sane value.
|
|
||||||
JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U,
|
|
||||||
"in Json::Value::duplicateAndPrefixStringValue(): "
|
|
||||||
"length too big for prefixing");
|
|
||||||
unsigned actualLength = length + sizeof(unsigned) + 1U;
|
|
||||||
char* newString = static_cast<char*>(malloc(actualLength));
|
|
||||||
if (newString == 0) {
|
|
||||||
throwRuntimeError(
|
|
||||||
"in Json::Value::duplicateAndPrefixStringValue(): "
|
|
||||||
"Failed to allocate string value buffer");
|
|
||||||
}
|
|
||||||
*reinterpret_cast<unsigned*>(newString) = length;
|
|
||||||
memcpy(newString + sizeof(unsigned), value, length);
|
|
||||||
newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
|
|
||||||
return newString;
|
|
||||||
}
|
|
||||||
inline static void decodePrefixedString(
|
|
||||||
bool isPrefixed, char const* prefixed,
|
|
||||||
unsigned* length, char const** value)
|
|
||||||
{
|
|
||||||
if (!isPrefixed) {
|
|
||||||
*length = strlen(prefixed);
|
|
||||||
*value = prefixed;
|
|
||||||
} else {
|
|
||||||
*length = *reinterpret_cast<unsigned const*>(prefixed);
|
|
||||||
*value = prefixed + sizeof(unsigned);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
|
|
||||||
*/
|
*/
|
||||||
static inline void releaseStringValue(char* value) { free(value); }
|
static inline void releaseStringValue(char* value) { free(value); }
|
||||||
|
|
||||||
@@ -147,53 +118,16 @@ static inline void releaseStringValue(char* value) { free(value); }
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
#include "json_internalarray.inl"
|
||||||
|
#include "json_internalmap.inl"
|
||||||
|
#endif // JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
#include "json_valueiterator.inl"
|
#include "json_valueiterator.inl"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
class JSON_API Exception : public std::exception {
|
|
||||||
public:
|
|
||||||
Exception(std::string const& msg);
|
|
||||||
virtual ~Exception() throw();
|
|
||||||
virtual char const* what() const throw();
|
|
||||||
protected:
|
|
||||||
std::string const msg_;
|
|
||||||
};
|
|
||||||
class JSON_API RuntimeError : public Exception {
|
|
||||||
public:
|
|
||||||
RuntimeError(std::string const& msg);
|
|
||||||
};
|
|
||||||
class JSON_API LogicError : public Exception {
|
|
||||||
public:
|
|
||||||
LogicError(std::string const& msg);
|
|
||||||
};
|
|
||||||
|
|
||||||
Exception::Exception(std::string const& msg)
|
|
||||||
: msg_(msg)
|
|
||||||
{}
|
|
||||||
Exception::~Exception() throw()
|
|
||||||
{}
|
|
||||||
char const* Exception::what() const throw()
|
|
||||||
{
|
|
||||||
return msg_.c_str();
|
|
||||||
}
|
|
||||||
RuntimeError::RuntimeError(std::string const& msg)
|
|
||||||
: Exception(msg)
|
|
||||||
{}
|
|
||||||
LogicError::LogicError(std::string const& msg)
|
|
||||||
: Exception(msg)
|
|
||||||
{}
|
|
||||||
void throwRuntimeError(std::string const& msg)
|
|
||||||
{
|
|
||||||
throw RuntimeError(msg);
|
|
||||||
}
|
|
||||||
void throwLogicError(std::string const& msg)
|
|
||||||
{
|
|
||||||
throw LogicError(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@@ -229,34 +163,28 @@ void Value::CommentInfo::setComment(const char* text, size_t len) {
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
// Notes: policy_ indicates if the string was allocated when
|
// Notes: index_ indicates if the string was allocated when
|
||||||
// a string is stored.
|
// a string is stored.
|
||||||
|
|
||||||
Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {}
|
Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {}
|
||||||
|
|
||||||
Value::CZString::CZString(char const* str, unsigned length, DuplicationPolicy allocate)
|
Value::CZString::CZString(const char* cstr, DuplicationPolicy allocate)
|
||||||
: cstr_(str)
|
: cstr_(allocate == duplicate ? duplicateStringValue(cstr) : cstr),
|
||||||
{
|
index_(allocate) {}
|
||||||
// allocate != duplicate
|
|
||||||
storage_.policy_ = allocate;
|
|
||||||
storage_.length_ = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value::CZString::CZString(const CZString& other)
|
Value::CZString::CZString(const CZString& other)
|
||||||
: cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0
|
: cstr_(other.index_ != noDuplication && other.cstr_ != 0
|
||||||
? duplicateStringValue(other.cstr_, other.storage_.length_)
|
? duplicateStringValue(other.cstr_)
|
||||||
: other.cstr_)
|
: other.cstr_),
|
||||||
{
|
index_(other.cstr_
|
||||||
storage_.policy_ = (other.cstr_
|
? static_cast<ArrayIndex>(other.index_ == noDuplication
|
||||||
? (other.storage_.policy_ == noDuplication
|
|
||||||
? noDuplication : duplicate)
|
? noDuplication : duplicate)
|
||||||
: other.storage_.policy_);
|
: other.index_) {}
|
||||||
storage_.length_ = other.storage_.length_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value::CZString::~CZString() {
|
Value::CZString::~CZString() {
|
||||||
if (cstr_ && storage_.policy_ == duplicate)
|
if (cstr_ && index_ == duplicate)
|
||||||
releaseStringValue(const_cast<char*>(cstr_));
|
releaseStringValue(const_cast<char*>(cstr_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,41 +193,31 @@ void Value::CZString::swap(CZString& other) {
|
|||||||
std::swap(index_, other.index_);
|
std::swap(index_, other.index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::CZString& Value::CZString::operator=(CZString other) {
|
Value::CZString &Value::CZString::operator=(const CZString &other) {
|
||||||
swap(other);
|
CZString temp(other);
|
||||||
|
swap(temp);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::CZString::operator<(const CZString& other) const {
|
bool Value::CZString::operator<(const CZString& other) const {
|
||||||
if (!cstr_) return index_ < other.index_;
|
if (cstr_)
|
||||||
//return strcmp(cstr_, other.cstr_) < 0;
|
return strcmp(cstr_, other.cstr_) < 0;
|
||||||
// Assume both are strings.
|
return index_ < other.index_;
|
||||||
unsigned this_len = this->storage_.length_;
|
|
||||||
unsigned other_len = other.storage_.length_;
|
|
||||||
unsigned min_len = std::min(this_len, other_len);
|
|
||||||
int comp = memcmp(this->cstr_, other.cstr_, min_len);
|
|
||||||
if (comp < 0) return true;
|
|
||||||
if (comp > 0) return false;
|
|
||||||
return (this_len < other_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::CZString::operator==(const CZString& other) const {
|
bool Value::CZString::operator==(const CZString& other) const {
|
||||||
if (!cstr_) return index_ == other.index_;
|
if (cstr_)
|
||||||
//return strcmp(cstr_, other.cstr_) == 0;
|
return strcmp(cstr_, other.cstr_) == 0;
|
||||||
// Assume both are strings.
|
return index_ == other.index_;
|
||||||
unsigned this_len = this->storage_.length_;
|
|
||||||
unsigned other_len = other.storage_.length_;
|
|
||||||
if (this_len != other_len) return false;
|
|
||||||
int comp = memcmp(this->cstr_, other.cstr_, this_len);
|
|
||||||
return comp == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayIndex Value::CZString::index() const { return index_; }
|
ArrayIndex Value::CZString::index() const { return index_; }
|
||||||
|
|
||||||
//const char* Value::CZString::c_str() const { return cstr_; }
|
const char* Value::CZString::c_str() const { return cstr_; }
|
||||||
const char* Value::CZString::data() const { return cstr_; }
|
|
||||||
unsigned Value::CZString::length() const { return storage_.length_; }
|
bool Value::CZString::isStaticString() const { return index_ == noDuplication; }
|
||||||
bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
|
|
||||||
|
#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@@ -328,10 +246,19 @@ Value::Value(ValueType type) {
|
|||||||
case stringValue:
|
case stringValue:
|
||||||
value_.string_ = 0;
|
value_.string_ = 0;
|
||||||
break;
|
break;
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
value_.map_ = new ObjectValues();
|
value_.map_ = new ObjectValues();
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
case arrayValue:
|
||||||
|
value_.array_ = arrayAllocator()->newArray();
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
value_.map_ = mapAllocator()->newMap();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case booleanValue:
|
case booleanValue:
|
||||||
value_.bool_ = false;
|
value_.bool_ = false;
|
||||||
break;
|
break;
|
||||||
@@ -367,19 +294,19 @@ Value::Value(double value) {
|
|||||||
|
|
||||||
Value::Value(const char* value) {
|
Value::Value(const char* value) {
|
||||||
initBasic(stringValue, true);
|
initBasic(stringValue, true);
|
||||||
value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
|
value_.string_ = duplicateStringValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(const char* beginValue, const char* endValue) {
|
Value::Value(const char* beginValue, const char* endValue) {
|
||||||
initBasic(stringValue, true);
|
initBasic(stringValue, true);
|
||||||
value_.string_ =
|
value_.string_ =
|
||||||
duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
|
duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(const std::string& value) {
|
Value::Value(const std::string& value) {
|
||||||
initBasic(stringValue, true);
|
initBasic(stringValue, true);
|
||||||
value_.string_ =
|
value_.string_ =
|
||||||
duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
|
duplicateStringValue(value.c_str(), (unsigned int)value.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(const StaticString& value) {
|
Value::Value(const StaticString& value) {
|
||||||
@@ -390,7 +317,7 @@ Value::Value(const StaticString& value) {
|
|||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
Value::Value(const CppTL::ConstString& value) {
|
Value::Value(const CppTL::ConstString& value) {
|
||||||
initBasic(stringValue, true);
|
initBasic(stringValue, true);
|
||||||
value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
|
value_.string_ = duplicateStringValue(value, value.length());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -399,11 +326,14 @@ Value::Value(bool value) {
|
|||||||
value_.bool_ = value;
|
value_.bool_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(Value const& other)
|
Value::Value(const Value& other)
|
||||||
: type_(other.type_), allocated_(false)
|
: type_(other.type_), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
,
|
,
|
||||||
comments_(0)
|
itemIsUsed_(0)
|
||||||
{
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0) {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case nullValue:
|
case nullValue:
|
||||||
case intValue:
|
case intValue:
|
||||||
@@ -413,22 +343,27 @@ Value::Value(Value const& other)
|
|||||||
value_ = other.value_;
|
value_ = other.value_;
|
||||||
break;
|
break;
|
||||||
case stringValue:
|
case stringValue:
|
||||||
if (other.value_.string_ && other.allocated_) {
|
if (other.value_.string_) {
|
||||||
unsigned len;
|
value_.string_ = duplicateStringValue(other.value_.string_);
|
||||||
char const* str;
|
|
||||||
decodePrefixedString(other.allocated_, other.value_.string_,
|
|
||||||
&len, &str);
|
|
||||||
value_.string_ = duplicateAndPrefixStringValue(str, len);
|
|
||||||
allocated_ = true;
|
allocated_ = true;
|
||||||
} else {
|
} else {
|
||||||
value_.string_ = other.value_.string_;
|
value_.string_ = 0;
|
||||||
allocated_ = false;
|
allocated_ = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
value_.map_ = new ObjectValues(*other.value_.map_);
|
value_.map_ = new ObjectValues(*other.value_.map_);
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
case arrayValue:
|
||||||
|
value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_);
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
@@ -455,10 +390,19 @@ Value::~Value() {
|
|||||||
if (allocated_)
|
if (allocated_)
|
||||||
releaseStringValue(value_.string_);
|
releaseStringValue(value_.string_);
|
||||||
break;
|
break;
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
delete value_.map_;
|
delete value_.map_;
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
case arrayValue:
|
||||||
|
arrayAllocator()->destructArray(value_.array_);
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
mapAllocator()->destructMap(value_.map_);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
@@ -514,23 +458,10 @@ bool Value::operator<(const Value& other) const {
|
|||||||
case booleanValue:
|
case booleanValue:
|
||||||
return value_.bool_ < other.value_.bool_;
|
return value_.bool_ < other.value_.bool_;
|
||||||
case stringValue:
|
case stringValue:
|
||||||
{
|
return (value_.string_ == 0 && other.value_.string_) ||
|
||||||
if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
|
(other.value_.string_ && value_.string_ &&
|
||||||
if (other.value_.string_) return true;
|
strcmp(value_.string_, other.value_.string_) < 0);
|
||||||
else return false;
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
}
|
|
||||||
unsigned this_len;
|
|
||||||
unsigned other_len;
|
|
||||||
char const* this_str;
|
|
||||||
char const* other_str;
|
|
||||||
decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
|
|
||||||
decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
|
|
||||||
unsigned min_len = std::min(this_len, other_len);
|
|
||||||
int comp = memcmp(this_str, other_str, min_len);
|
|
||||||
if (comp < 0) return true;
|
|
||||||
if (comp > 0) return false;
|
|
||||||
return (this_len < other_len);
|
|
||||||
}
|
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue: {
|
case objectValue: {
|
||||||
int delta = int(value_.map_->size() - other.value_.map_->size());
|
int delta = int(value_.map_->size() - other.value_.map_->size());
|
||||||
@@ -538,6 +469,12 @@ bool Value::operator<(const Value& other) const {
|
|||||||
return delta < 0;
|
return delta < 0;
|
||||||
return (*value_.map_) < (*other.value_.map_);
|
return (*value_.map_) < (*other.value_.map_);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
case arrayValue:
|
||||||
|
return value_.array_->compare(*(other.value_.array_)) < 0;
|
||||||
|
case objectValue:
|
||||||
|
return value_.map_->compare(*(other.value_.map_)) < 0;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
@@ -570,24 +507,20 @@ bool Value::operator==(const Value& other) const {
|
|||||||
case booleanValue:
|
case booleanValue:
|
||||||
return value_.bool_ == other.value_.bool_;
|
return value_.bool_ == other.value_.bool_;
|
||||||
case stringValue:
|
case stringValue:
|
||||||
{
|
return (value_.string_ == other.value_.string_) ||
|
||||||
if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
|
(other.value_.string_ && value_.string_ &&
|
||||||
return (value_.string_ == other.value_.string_);
|
strcmp(value_.string_, other.value_.string_) == 0);
|
||||||
}
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
unsigned this_len;
|
|
||||||
unsigned other_len;
|
|
||||||
char const* this_str;
|
|
||||||
char const* other_str;
|
|
||||||
decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
|
|
||||||
decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
|
|
||||||
if (this_len != other_len) return false;
|
|
||||||
int comp = memcmp(this_str, other_str, this_len);
|
|
||||||
return comp == 0;
|
|
||||||
}
|
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
return value_.map_->size() == other.value_.map_->size() &&
|
return value_.map_->size() == other.value_.map_->size() &&
|
||||||
(*value_.map_) == (*other.value_.map_);
|
(*value_.map_) == (*other.value_.map_);
|
||||||
|
#else
|
||||||
|
case arrayValue:
|
||||||
|
return value_.array_->compare(*(other.value_.array_)) == 0;
|
||||||
|
case objectValue:
|
||||||
|
return value_.map_->compare(*(other.value_.map_)) == 0;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
@@ -599,20 +532,7 @@ bool Value::operator!=(const Value& other) const { return !(*this == other); }
|
|||||||
const char* Value::asCString() const {
|
const char* Value::asCString() const {
|
||||||
JSON_ASSERT_MESSAGE(type_ == stringValue,
|
JSON_ASSERT_MESSAGE(type_ == stringValue,
|
||||||
"in Json::Value::asCString(): requires stringValue");
|
"in Json::Value::asCString(): requires stringValue");
|
||||||
if (value_.string_ == 0) return 0;
|
return value_.string_;
|
||||||
unsigned this_len;
|
|
||||||
char const* this_str;
|
|
||||||
decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
|
|
||||||
return this_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Value::getString(char const** str, char const** end) const {
|
|
||||||
if (type_ != stringValue) return false;
|
|
||||||
if (value_.string_ == 0) return false;
|
|
||||||
unsigned length;
|
|
||||||
decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
|
|
||||||
*end = *str + length;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Value::asString() const {
|
std::string Value::asString() const {
|
||||||
@@ -620,13 +540,7 @@ std::string Value::asString() const {
|
|||||||
case nullValue:
|
case nullValue:
|
||||||
return "";
|
return "";
|
||||||
case stringValue:
|
case stringValue:
|
||||||
{
|
return value_.string_ ? value_.string_ : "";
|
||||||
if (value_.string_ == 0) return "";
|
|
||||||
unsigned this_len;
|
|
||||||
char const* this_str;
|
|
||||||
decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
|
|
||||||
return std::string(this_str, this_len);
|
|
||||||
}
|
|
||||||
case booleanValue:
|
case booleanValue:
|
||||||
return value_.bool_ ? "true" : "false";
|
return value_.bool_ ? "true" : "false";
|
||||||
case intValue:
|
case intValue:
|
||||||
@@ -642,11 +556,7 @@ std::string Value::asString() const {
|
|||||||
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
CppTL::ConstString Value::asConstString() const {
|
CppTL::ConstString Value::asConstString() const {
|
||||||
unsigned len;
|
return CppTL::ConstString(asString().c_str());
|
||||||
char const* str;
|
|
||||||
decodePrefixedString(allocated_, value_.string_,
|
|
||||||
&len, &str);
|
|
||||||
return CppTL::ConstString(str, len);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -860,6 +770,7 @@ ArrayIndex Value::size() const {
|
|||||||
case booleanValue:
|
case booleanValue:
|
||||||
case stringValue:
|
case stringValue:
|
||||||
return 0;
|
return 0;
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
case arrayValue: // size of the array is highest index + 1
|
case arrayValue: // size of the array is highest index + 1
|
||||||
if (!value_.map_->empty()) {
|
if (!value_.map_->empty()) {
|
||||||
ObjectValues::const_iterator itLast = value_.map_->end();
|
ObjectValues::const_iterator itLast = value_.map_->end();
|
||||||
@@ -869,6 +780,12 @@ ArrayIndex Value::size() const {
|
|||||||
return 0;
|
return 0;
|
||||||
case objectValue:
|
case objectValue:
|
||||||
return ArrayIndex(value_.map_->size());
|
return ArrayIndex(value_.map_->size());
|
||||||
|
#else
|
||||||
|
case arrayValue:
|
||||||
|
return Int(value_.array_->size());
|
||||||
|
case objectValue:
|
||||||
|
return Int(value_.map_->size());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
return 0; // unreachable;
|
return 0; // unreachable;
|
||||||
@@ -888,10 +805,19 @@ void Value::clear() {
|
|||||||
type_ == objectValue,
|
type_ == objectValue,
|
||||||
"in Json::Value::clear(): requires complex value");
|
"in Json::Value::clear(): requires complex value");
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
value_.map_->clear();
|
value_.map_->clear();
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
case arrayValue:
|
||||||
|
value_.array_->clear();
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
value_.map_->clear();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -902,6 +828,7 @@ void Value::resize(ArrayIndex newSize) {
|
|||||||
"in Json::Value::resize(): requires arrayValue");
|
"in Json::Value::resize(): requires arrayValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
*this = Value(arrayValue);
|
*this = Value(arrayValue);
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
ArrayIndex oldSize = size();
|
ArrayIndex oldSize = size();
|
||||||
if (newSize == 0)
|
if (newSize == 0)
|
||||||
clear();
|
clear();
|
||||||
@@ -913,6 +840,9 @@ void Value::resize(ArrayIndex newSize) {
|
|||||||
}
|
}
|
||||||
assert(size() == newSize);
|
assert(size() == newSize);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
value_.array_->resize(newSize);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator[](ArrayIndex index) {
|
Value& Value::operator[](ArrayIndex index) {
|
||||||
@@ -921,6 +851,7 @@ Value& Value::operator[](ArrayIndex index) {
|
|||||||
"in Json::Value::operator[](ArrayIndex): requires arrayValue");
|
"in Json::Value::operator[](ArrayIndex): requires arrayValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
*this = Value(arrayValue);
|
*this = Value(arrayValue);
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
CZString key(index);
|
CZString key(index);
|
||||||
ObjectValues::iterator it = value_.map_->lower_bound(key);
|
ObjectValues::iterator it = value_.map_->lower_bound(key);
|
||||||
if (it != value_.map_->end() && (*it).first == key)
|
if (it != value_.map_->end() && (*it).first == key)
|
||||||
@@ -929,6 +860,9 @@ Value& Value::operator[](ArrayIndex index) {
|
|||||||
ObjectValues::value_type defaultValue(key, nullRef);
|
ObjectValues::value_type defaultValue(key, nullRef);
|
||||||
it = value_.map_->insert(it, defaultValue);
|
it = value_.map_->insert(it, defaultValue);
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
|
#else
|
||||||
|
return value_.array_->resolveReference(index);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator[](int index) {
|
Value& Value::operator[](int index) {
|
||||||
@@ -944,11 +878,16 @@ const Value& Value::operator[](ArrayIndex index) const {
|
|||||||
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
|
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
return nullRef;
|
return nullRef;
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
CZString key(index);
|
CZString key(index);
|
||||||
ObjectValues::const_iterator it = value_.map_->find(key);
|
ObjectValues::const_iterator it = value_.map_->find(key);
|
||||||
if (it == value_.map_->end())
|
if (it == value_.map_->end())
|
||||||
return nullRef;
|
return nullRef;
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
|
#else
|
||||||
|
Value* value = value_.array_->find(index);
|
||||||
|
return value ? *value : nullRef;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const Value& Value::operator[](int index) const {
|
const Value& Value::operator[](int index) const {
|
||||||
@@ -958,43 +897,28 @@ const Value& Value::operator[](int index) const {
|
|||||||
return (*this)[ArrayIndex(index)];
|
return (*this)[ArrayIndex(index)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value& Value::operator[](const char* key) {
|
||||||
|
return resolveReference(key, false);
|
||||||
|
}
|
||||||
|
|
||||||
void Value::initBasic(ValueType type, bool allocated) {
|
void Value::initBasic(ValueType type, bool allocated) {
|
||||||
type_ = type;
|
type_ = type;
|
||||||
allocated_ = allocated;
|
allocated_ = allocated;
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
itemIsUsed_ = 0;
|
||||||
|
#endif
|
||||||
comments_ = 0;
|
comments_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access an object value by name, create a null member if it does not exist.
|
Value& Value::resolveReference(const char* key, bool isStatic) {
|
||||||
// @pre Type of '*this' is object or null.
|
|
||||||
// @param key is null-terminated.
|
|
||||||
Value& Value::resolveReference(const char* key) {
|
|
||||||
JSON_ASSERT_MESSAGE(
|
JSON_ASSERT_MESSAGE(
|
||||||
type_ == nullValue || type_ == objectValue,
|
type_ == nullValue || type_ == objectValue,
|
||||||
"in Json::Value::resolveReference(): requires objectValue");
|
"in Json::Value::resolveReference(): requires objectValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
*this = Value(objectValue);
|
*this = Value(objectValue);
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
CZString actualKey(
|
CZString actualKey(
|
||||||
key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
|
key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy);
|
||||||
ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
|
|
||||||
if (it != value_.map_->end() && (*it).first == actualKey)
|
|
||||||
return (*it).second;
|
|
||||||
|
|
||||||
ObjectValues::value_type defaultValue(actualKey, nullRef);
|
|
||||||
it = value_.map_->insert(it, defaultValue);
|
|
||||||
Value& value = (*it).second;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @param key is not null-terminated.
|
|
||||||
Value& Value::resolveReference(char const* key, char const* end)
|
|
||||||
{
|
|
||||||
JSON_ASSERT_MESSAGE(
|
|
||||||
type_ == nullValue || type_ == objectValue,
|
|
||||||
"in Json::Value::resolveReference(key, end): requires objectValue");
|
|
||||||
if (type_ == nullValue)
|
|
||||||
*this = Value(objectValue);
|
|
||||||
CZString actualKey(
|
|
||||||
key, static_cast<unsigned>(end-key), CZString::duplicateOnCopy);
|
|
||||||
ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
|
ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
|
||||||
if (it != value_.map_->end() && (*it).first == actualKey)
|
if (it != value_.map_->end() && (*it).first == actualKey)
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
@@ -1003,6 +927,9 @@ Value& Value::resolveReference(char const* key, char const* end)
|
|||||||
it = value_.map_->insert(it, defaultValue);
|
it = value_.map_->insert(it, defaultValue);
|
||||||
Value& value = (*it).second;
|
Value& value = (*it).second;
|
||||||
return value;
|
return value;
|
||||||
|
#else
|
||||||
|
return value_.map_->resolveReference(key, isStatic);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
||||||
@@ -1012,105 +939,94 @@ Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
|||||||
|
|
||||||
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
|
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
|
||||||
|
|
||||||
Value const* Value::find(char const* key, char const* end) const
|
const Value& Value::operator[](const char* key) const {
|
||||||
{
|
|
||||||
JSON_ASSERT_MESSAGE(
|
JSON_ASSERT_MESSAGE(
|
||||||
type_ == nullValue || type_ == objectValue,
|
type_ == nullValue || type_ == objectValue,
|
||||||
"in Json::Value::find(key, end, found): requires objectValue or nullValue");
|
"in Json::Value::operator[](char const*)const: requires objectValue");
|
||||||
if (type_ == nullValue) return NULL;
|
if (type_ == nullValue)
|
||||||
CZString actualKey(key, static_cast<unsigned>(end-key), CZString::noDuplication);
|
return nullRef;
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
CZString actualKey(key, CZString::noDuplication);
|
||||||
ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
||||||
if (it == value_.map_->end()) return NULL;
|
if (it == value_.map_->end())
|
||||||
return &(*it).second;
|
return nullRef;
|
||||||
}
|
return (*it).second;
|
||||||
const Value& Value::operator[](const char* key) const
|
#else
|
||||||
{
|
const Value* value = value_.map_->find(key);
|
||||||
Value const* found = find(key, key + strlen(key));
|
return value ? *value : nullRef;
|
||||||
if (!found) return nullRef;
|
#endif
|
||||||
return *found;
|
|
||||||
}
|
|
||||||
Value const& Value::operator[](std::string const& key) const
|
|
||||||
{
|
|
||||||
Value const* found = find(key.data(), key.data() + key.length());
|
|
||||||
if (!found) return nullRef;
|
|
||||||
return *found;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value& Value::operator[](const char* key) {
|
|
||||||
return resolveReference(key, key + strlen(key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator[](const std::string& key) {
|
Value& Value::operator[](const std::string& key) {
|
||||||
return resolveReference(key.data(), key.data() + key.length());
|
return (*this)[key.c_str()];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Value& Value::operator[](const std::string& key) const {
|
||||||
|
return (*this)[key.c_str()];
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator[](const StaticString& key) {
|
Value& Value::operator[](const StaticString& key) {
|
||||||
return resolveReference(key.c_str());
|
return resolveReference(key, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
Value& Value::operator[](const CppTL::ConstString& key) {
|
Value& Value::operator[](const CppTL::ConstString& key) {
|
||||||
return resolveReference(key.c_str(), key.end_c_str());
|
return (*this)[key.c_str()];
|
||||||
}
|
}
|
||||||
Value const& Value::operator[](CppTL::ConstString const& key) const
|
|
||||||
{
|
const Value& Value::operator[](const CppTL::ConstString& key) const {
|
||||||
Value const* found = find(key.c_str(), key.end_c_str());
|
return (*this)[key.c_str()];
|
||||||
if (!found) return nullRef;
|
|
||||||
return *found;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Value& Value::append(const Value& value) { return (*this)[size()] = value; }
|
Value& Value::append(const Value& value) { return (*this)[size()] = value; }
|
||||||
|
|
||||||
Value Value::get(char const* key, char const* end, Value const& defaultValue) const
|
Value Value::get(const char* key, const Value& defaultValue) const {
|
||||||
{
|
const Value* value = &((*this)[key]);
|
||||||
Value const* found = find(key, end);
|
return value == &nullRef ? defaultValue : *value;
|
||||||
return !found ? defaultValue : *found;
|
|
||||||
}
|
}
|
||||||
Value Value::get(char const* key, Value const& defaultValue) const
|
|
||||||
{
|
Value Value::get(const std::string& key, const Value& defaultValue) const {
|
||||||
return get(key, key + strlen(key), defaultValue);
|
return get(key.c_str(), defaultValue);
|
||||||
}
|
|
||||||
Value Value::get(std::string const& key, Value const& defaultValue) const
|
|
||||||
{
|
|
||||||
return get(key.data(), key.data() + key.length(), defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Value::removeMember(const char* key, const char* end, Value* removed)
|
bool Value::removeMember(const char* key, Value* removed) {
|
||||||
{
|
|
||||||
if (type_ != objectValue) {
|
if (type_ != objectValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CZString actualKey(key, static_cast<unsigned>(end-key), CZString::noDuplication);
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
CZString actualKey(key, CZString::noDuplication);
|
||||||
ObjectValues::iterator it = value_.map_->find(actualKey);
|
ObjectValues::iterator it = value_.map_->find(actualKey);
|
||||||
if (it == value_.map_->end())
|
if (it == value_.map_->end())
|
||||||
return false;
|
return false;
|
||||||
*removed = it->second;
|
*removed = it->second;
|
||||||
value_.map_->erase(it);
|
value_.map_->erase(it);
|
||||||
return true;
|
return true;
|
||||||
|
#else
|
||||||
|
Value* value = value_.map_->find(key);
|
||||||
|
if (value) {
|
||||||
|
*removed = *value;
|
||||||
|
value_.map_.remove(key);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
bool Value::removeMember(const char* key, Value* removed)
|
|
||||||
{
|
Value Value::removeMember(const char* key) {
|
||||||
return removeMember(key, key + strlen(key), removed);
|
|
||||||
}
|
|
||||||
bool Value::removeMember(std::string const& key, Value* removed)
|
|
||||||
{
|
|
||||||
return removeMember(key.data(), key.data() + key.length(), removed);
|
|
||||||
}
|
|
||||||
Value Value::removeMember(const char* key)
|
|
||||||
{
|
|
||||||
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
|
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
|
||||||
"in Json::Value::removeMember(): requires objectValue");
|
"in Json::Value::removeMember(): requires objectValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
return nullRef;
|
return nullRef;
|
||||||
|
|
||||||
Value removed; // null
|
Value removed; // null
|
||||||
removeMember(key, key + strlen(key), &removed);
|
removeMember(key, &removed);
|
||||||
return removed; // still null if removeMember() did nothing
|
return removed; // still null if removeMember() did nothing
|
||||||
}
|
}
|
||||||
Value Value::removeMember(const std::string& key)
|
|
||||||
{
|
Value Value::removeMember(const std::string& key) {
|
||||||
return removeMember(key.c_str());
|
return removeMember(key.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1118,6 +1034,10 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
|||||||
if (type_ != arrayValue) {
|
if (type_ != arrayValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
JSON_FAIL_MESSAGE("removeIndex is not implemented for ValueInternalArray.");
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
CZString key(index);
|
CZString key(index);
|
||||||
ObjectValues::iterator it = value_.map_->find(key);
|
ObjectValues::iterator it = value_.map_->find(key);
|
||||||
if (it == value_.map_->end()) {
|
if (it == value_.map_->end()) {
|
||||||
@@ -1135,32 +1055,28 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
|||||||
ObjectValues::iterator itLast = value_.map_->find(keyLast);
|
ObjectValues::iterator itLast = value_.map_->find(keyLast);
|
||||||
value_.map_->erase(itLast);
|
value_.map_->erase(itLast);
|
||||||
return true;
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
Value Value::get(const CppTL::ConstString& key,
|
Value Value::get(const CppTL::ConstString& key,
|
||||||
const Value& defaultValue) const {
|
const Value& defaultValue) const {
|
||||||
return get(key.c_str(), key.end_c_str(), defaultValue);
|
return get(key.c_str(), defaultValue);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool Value::isMember(char const* key, char const* end) const
|
bool Value::isMember(const char* key) const {
|
||||||
{
|
const Value* value = &((*this)[key]);
|
||||||
Value const* value = find(key, end);
|
return value != &nullRef;
|
||||||
return NULL != value;
|
|
||||||
}
|
}
|
||||||
bool Value::isMember(char const* key) const
|
|
||||||
{
|
bool Value::isMember(const std::string& key) const {
|
||||||
return isMember(key, key + strlen(key));
|
return isMember(key.c_str());
|
||||||
}
|
|
||||||
bool Value::isMember(std::string const& key) const
|
|
||||||
{
|
|
||||||
return isMember(key.data(), key.data() + key.length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
bool Value::isMember(const CppTL::ConstString& key) const {
|
bool Value::isMember(const CppTL::ConstString& key) const {
|
||||||
return isMember(key.c_str(), key.end_c_str());
|
return isMember(key.c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1172,12 +1088,19 @@ Value::Members Value::getMemberNames() const {
|
|||||||
return Value::Members();
|
return Value::Members();
|
||||||
Members members;
|
Members members;
|
||||||
members.reserve(value_.map_->size());
|
members.reserve(value_.map_->size());
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
ObjectValues::const_iterator it = value_.map_->begin();
|
ObjectValues::const_iterator it = value_.map_->begin();
|
||||||
ObjectValues::const_iterator itEnd = value_.map_->end();
|
ObjectValues::const_iterator itEnd = value_.map_->end();
|
||||||
for (; it != itEnd; ++it) {
|
for (; it != itEnd; ++it)
|
||||||
members.push_back(std::string((*it).first.data(),
|
members.push_back(std::string((*it).first.c_str()));
|
||||||
(*it).first.length()));
|
#else
|
||||||
}
|
ValueInternalMap::IteratorState it;
|
||||||
|
ValueInternalMap::IteratorState itEnd;
|
||||||
|
value_.map_->makeBeginIterator(it);
|
||||||
|
value_.map_->makeEndIterator(itEnd);
|
||||||
|
for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it))
|
||||||
|
members.push_back(std::string(ValueInternalMap::key(it)));
|
||||||
|
#endif
|
||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -1338,11 +1261,28 @@ std::string Value::toStyledString() const {
|
|||||||
|
|
||||||
Value::const_iterator Value::begin() const {
|
Value::const_iterator Value::begin() const {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
case arrayValue:
|
||||||
|
if (value_.array_) {
|
||||||
|
ValueInternalArray::IteratorState it;
|
||||||
|
value_.array_->makeBeginIterator(it);
|
||||||
|
return const_iterator(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
if (value_.map_) {
|
||||||
|
ValueInternalMap::IteratorState it;
|
||||||
|
value_.map_->makeBeginIterator(it);
|
||||||
|
return const_iterator(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#else
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
if (value_.map_)
|
if (value_.map_)
|
||||||
return const_iterator(value_.map_->begin());
|
return const_iterator(value_.map_->begin());
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1351,11 +1291,28 @@ Value::const_iterator Value::begin() const {
|
|||||||
|
|
||||||
Value::const_iterator Value::end() const {
|
Value::const_iterator Value::end() const {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
case arrayValue:
|
||||||
|
if (value_.array_) {
|
||||||
|
ValueInternalArray::IteratorState it;
|
||||||
|
value_.array_->makeEndIterator(it);
|
||||||
|
return const_iterator(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
if (value_.map_) {
|
||||||
|
ValueInternalMap::IteratorState it;
|
||||||
|
value_.map_->makeEndIterator(it);
|
||||||
|
return const_iterator(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#else
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
if (value_.map_)
|
if (value_.map_)
|
||||||
return const_iterator(value_.map_->end());
|
return const_iterator(value_.map_->end());
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1364,11 +1321,28 @@ Value::const_iterator Value::end() const {
|
|||||||
|
|
||||||
Value::iterator Value::begin() {
|
Value::iterator Value::begin() {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
case arrayValue:
|
||||||
|
if (value_.array_) {
|
||||||
|
ValueInternalArray::IteratorState it;
|
||||||
|
value_.array_->makeBeginIterator(it);
|
||||||
|
return iterator(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
if (value_.map_) {
|
||||||
|
ValueInternalMap::IteratorState it;
|
||||||
|
value_.map_->makeBeginIterator(it);
|
||||||
|
return iterator(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#else
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
if (value_.map_)
|
if (value_.map_)
|
||||||
return iterator(value_.map_->begin());
|
return iterator(value_.map_->begin());
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1377,11 +1351,28 @@ Value::iterator Value::begin() {
|
|||||||
|
|
||||||
Value::iterator Value::end() {
|
Value::iterator Value::end() {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
case arrayValue:
|
||||||
|
if (value_.array_) {
|
||||||
|
ValueInternalArray::IteratorState it;
|
||||||
|
value_.array_->makeEndIterator(it);
|
||||||
|
return iterator(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
if (value_.map_) {
|
||||||
|
ValueInternalMap::IteratorState it;
|
||||||
|
value_.map_->makeEndIterator(it);
|
||||||
|
return iterator(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#else
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
if (value_.map_)
|
if (value_.map_)
|
||||||
return iterator(value_.map_->end());
|
return iterator(value_.map_->end());
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -16,29 +16,68 @@ namespace Json {
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ValueIteratorBase::ValueIteratorBase()
|
ValueIteratorBase::ValueIteratorBase()
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
: current_(), isNull_(true) {
|
: current_(), isNull_(true) {
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
: isArray_(true), isNull_(true) {
|
||||||
|
iterator_.array_ = ValueInternalArray::IteratorState();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
ValueIteratorBase::ValueIteratorBase(
|
ValueIteratorBase::ValueIteratorBase(
|
||||||
const Value::ObjectValues::iterator& current)
|
const Value::ObjectValues::iterator& current)
|
||||||
: current_(current), isNull_(false) {}
|
: current_(current), isNull_(false) {}
|
||||||
|
#else
|
||||||
|
ValueIteratorBase::ValueIteratorBase(
|
||||||
|
const ValueInternalArray::IteratorState& state)
|
||||||
|
: isArray_(true) {
|
||||||
|
iterator_.array_ = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueIteratorBase::ValueIteratorBase(
|
||||||
|
const ValueInternalMap::IteratorState& state)
|
||||||
|
: isArray_(false) {
|
||||||
|
iterator_.map_ = state;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Value& ValueIteratorBase::deref() const {
|
Value& ValueIteratorBase::deref() const {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
return current_->second;
|
return current_->second;
|
||||||
|
#else
|
||||||
|
if (isArray_)
|
||||||
|
return ValueInternalArray::dereference(iterator_.array_);
|
||||||
|
return ValueInternalMap::value(iterator_.map_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::increment() {
|
void ValueIteratorBase::increment() {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
++current_;
|
++current_;
|
||||||
|
#else
|
||||||
|
if (isArray_)
|
||||||
|
ValueInternalArray::increment(iterator_.array_);
|
||||||
|
ValueInternalMap::increment(iterator_.map_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::decrement() {
|
void ValueIteratorBase::decrement() {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
--current_;
|
--current_;
|
||||||
|
#else
|
||||||
|
if (isArray_)
|
||||||
|
ValueInternalArray::decrement(iterator_.array_);
|
||||||
|
ValueInternalMap::decrement(iterator_.map_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueIteratorBase::difference_type
|
ValueIteratorBase::difference_type
|
||||||
ValueIteratorBase::computeDistance(const SelfType& other) const {
|
ValueIteratorBase::computeDistance(const SelfType& other) const {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
#ifdef JSON_USE_CPPTL_SMALLMAP
|
#ifdef JSON_USE_CPPTL_SMALLMAP
|
||||||
return other.current_ - current_;
|
return current_ - other.current_;
|
||||||
#else
|
#else
|
||||||
// Iterator for null value are initialized using the default
|
// Iterator for null value are initialized using the default
|
||||||
// constructor, which initialize current_ to the default
|
// constructor, which initialize current_ to the default
|
||||||
@@ -61,58 +100,80 @@ ValueIteratorBase::computeDistance(const SelfType& other) const {
|
|||||||
}
|
}
|
||||||
return myDistance;
|
return myDistance;
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
if (isArray_)
|
||||||
|
return ValueInternalArray::distance(iterator_.array_,
|
||||||
|
other.iterator_.array_);
|
||||||
|
return ValueInternalMap::distance(iterator_.map_, other.iterator_.map_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValueIteratorBase::isEqual(const SelfType& other) const {
|
bool ValueIteratorBase::isEqual(const SelfType& other) const {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
if (isNull_) {
|
if (isNull_) {
|
||||||
return other.isNull_;
|
return other.isNull_;
|
||||||
}
|
}
|
||||||
return current_ == other.current_;
|
return current_ == other.current_;
|
||||||
|
#else
|
||||||
|
if (isArray_)
|
||||||
|
return ValueInternalArray::equals(iterator_.array_, other.iterator_.array_);
|
||||||
|
return ValueInternalMap::equals(iterator_.map_, other.iterator_.map_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::copy(const SelfType& other) {
|
void ValueIteratorBase::copy(const SelfType& other) {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
current_ = other.current_;
|
current_ = other.current_;
|
||||||
isNull_ = other.isNull_;
|
isNull_ = other.isNull_;
|
||||||
|
#else
|
||||||
|
if (isArray_)
|
||||||
|
iterator_.array_ = other.iterator_.array_;
|
||||||
|
iterator_.map_ = other.iterator_.map_;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ValueIteratorBase::key() const {
|
Value ValueIteratorBase::key() const {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
const Value::CZString czstring = (*current_).first;
|
const Value::CZString czstring = (*current_).first;
|
||||||
if (czstring.data()) {
|
if (czstring.c_str()) {
|
||||||
if (czstring.isStaticString())
|
if (czstring.isStaticString())
|
||||||
return Value(StaticString(czstring.data()));
|
return Value(StaticString(czstring.c_str()));
|
||||||
return Value(czstring.data(), czstring.data() + czstring.length());
|
return Value(czstring.c_str());
|
||||||
}
|
}
|
||||||
return Value(czstring.index());
|
return Value(czstring.index());
|
||||||
|
#else
|
||||||
|
if (isArray_)
|
||||||
|
return Value(ValueInternalArray::indexOf(iterator_.array_));
|
||||||
|
bool isStatic;
|
||||||
|
const char* memberName = ValueInternalMap::key(iterator_.map_, isStatic);
|
||||||
|
if (isStatic)
|
||||||
|
return Value(StaticString(memberName));
|
||||||
|
return Value(memberName);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt ValueIteratorBase::index() const {
|
UInt ValueIteratorBase::index() const {
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
const Value::CZString czstring = (*current_).first;
|
const Value::CZString czstring = (*current_).first;
|
||||||
if (!czstring.data())
|
if (!czstring.c_str())
|
||||||
return czstring.index();
|
return czstring.index();
|
||||||
return Value::UInt(-1);
|
return Value::UInt(-1);
|
||||||
|
#else
|
||||||
|
if (isArray_)
|
||||||
|
return Value::UInt(ValueInternalArray::indexOf(iterator_.array_));
|
||||||
|
return Value::UInt(-1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ValueIteratorBase::name() const {
|
const char* ValueIteratorBase::memberName() const {
|
||||||
char const* key;
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
char const* end;
|
const char* name = (*current_).first.c_str();
|
||||||
key = memberName(&end);
|
|
||||||
if (!key) return std::string();
|
|
||||||
return std::string(key, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
char const* ValueIteratorBase::memberName() const {
|
|
||||||
const char* name = (*current_).first.data();
|
|
||||||
return name ? name : "";
|
return name ? name : "";
|
||||||
}
|
#else
|
||||||
|
if (!isArray_)
|
||||||
char const* ValueIteratorBase::memberName(char const** end) const {
|
return ValueInternalMap::key(iterator_.map_);
|
||||||
const char* name = (*current_).first.data();
|
return "";
|
||||||
if (!name) {
|
#endif
|
||||||
*end = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*end = name + (*current_).first.length();
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@@ -125,9 +186,19 @@ char const* ValueIteratorBase::memberName(char const** end) const {
|
|||||||
|
|
||||||
ValueConstIterator::ValueConstIterator() {}
|
ValueConstIterator::ValueConstIterator() {}
|
||||||
|
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
ValueConstIterator::ValueConstIterator(
|
ValueConstIterator::ValueConstIterator(
|
||||||
const Value::ObjectValues::iterator& current)
|
const Value::ObjectValues::iterator& current)
|
||||||
: ValueIteratorBase(current) {}
|
: ValueIteratorBase(current) {}
|
||||||
|
#else
|
||||||
|
ValueConstIterator::ValueConstIterator(
|
||||||
|
const ValueInternalArray::IteratorState& state)
|
||||||
|
: ValueIteratorBase(state) {}
|
||||||
|
|
||||||
|
ValueConstIterator::ValueConstIterator(
|
||||||
|
const ValueInternalMap::IteratorState& state)
|
||||||
|
: ValueIteratorBase(state) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
ValueConstIterator& ValueConstIterator::
|
ValueConstIterator& ValueConstIterator::
|
||||||
operator=(const ValueIteratorBase& other) {
|
operator=(const ValueIteratorBase& other) {
|
||||||
@@ -145,8 +216,16 @@ operator=(const ValueIteratorBase& other) {
|
|||||||
|
|
||||||
ValueIterator::ValueIterator() {}
|
ValueIterator::ValueIterator() {}
|
||||||
|
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
||||||
: ValueIteratorBase(current) {}
|
: ValueIteratorBase(current) {}
|
||||||
|
#else
|
||||||
|
ValueIterator::ValueIterator(const ValueInternalArray::IteratorState& state)
|
||||||
|
: ValueIteratorBase(state) {}
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator(const ValueInternalMap::IteratorState& state)
|
||||||
|
: ValueIteratorBase(state) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
||||||
: ValueIteratorBase(other) {}
|
: ValueIteratorBase(other) {}
|
||||||
|
@@ -12,25 +12,16 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <cassert>
|
#include <stdexcept>
|
||||||
#include <cstring>
|
#include <assert.h>
|
||||||
#include <cstdio>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
|
#include <string.h>
|
||||||
#include <float.h>
|
|
||||||
#define isfinite _finite
|
|
||||||
#elif defined(__sun) && defined(__SVR4) //Solaris
|
|
||||||
#include <ieeefp.h>
|
|
||||||
#define isfinite finite
|
|
||||||
#else
|
|
||||||
#include <cmath>
|
|
||||||
#define isfinite std::isfinite
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||||
|
#include <float.h>
|
||||||
|
#define isfinite _finite
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
#else
|
|
||||||
#define snprintf std::snprintf
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
|
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
|
||||||
@@ -38,6 +29,11 @@
|
|||||||
#pragma warning(disable : 4996)
|
#pragma warning(disable : 4996)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__sun) && defined(__SVR4) //Solaris
|
||||||
|
#include <ieeefp.h>
|
||||||
|
#define isfinite finite
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
@@ -54,16 +50,6 @@ static bool containsControlCharacter(const char* str) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool containsControlCharacter0(const char* str, unsigned len) {
|
|
||||||
char const* end = str + len;
|
|
||||||
while (end != str) {
|
|
||||||
if (isControlCharacter(*str) || 0==*str)
|
|
||||||
return true;
|
|
||||||
++str;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string valueToString(LargestInt value) {
|
std::string valueToString(LargestInt value) {
|
||||||
UIntToStringBuffer buffer;
|
UIntToStringBuffer buffer;
|
||||||
char* current = buffer + sizeof(buffer);
|
char* current = buffer + sizeof(buffer);
|
||||||
@@ -198,84 +184,6 @@ std::string valueToQuotedString(const char* value) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
|
|
||||||
static char const* strnpbrk(char const* s, char const* accept, size_t n) {
|
|
||||||
assert((s || !n) && accept);
|
|
||||||
|
|
||||||
char const* const end = s + n;
|
|
||||||
for (char const* cur = s; cur < end; ++cur) {
|
|
||||||
int const c = *cur;
|
|
||||||
for (char const* a = accept; *a; ++a) {
|
|
||||||
if (*a == c) {
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
static std::string valueToQuotedStringN(const char* value, unsigned length) {
|
|
||||||
if (value == NULL)
|
|
||||||
return "";
|
|
||||||
// Not sure how to handle unicode...
|
|
||||||
if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
|
|
||||||
!containsControlCharacter0(value, length))
|
|
||||||
return std::string("\"") + value + "\"";
|
|
||||||
// We have to walk value and escape any special characters.
|
|
||||||
// Appending to std::string is not efficient, but this should be rare.
|
|
||||||
// (Note: forward slashes are *not* rare, but I am not escaping them.)
|
|
||||||
std::string::size_type maxsize =
|
|
||||||
length * 2 + 3; // allescaped+quotes+NULL
|
|
||||||
std::string result;
|
|
||||||
result.reserve(maxsize); // to avoid lots of mallocs
|
|
||||||
result += "\"";
|
|
||||||
char const* end = value + length;
|
|
||||||
for (const char* c = value; c != end; ++c) {
|
|
||||||
switch (*c) {
|
|
||||||
case '\"':
|
|
||||||
result += "\\\"";
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
result += "\\\\";
|
|
||||||
break;
|
|
||||||
case '\b':
|
|
||||||
result += "\\b";
|
|
||||||
break;
|
|
||||||
case '\f':
|
|
||||||
result += "\\f";
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
result += "\\n";
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
result += "\\r";
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
result += "\\t";
|
|
||||||
break;
|
|
||||||
// case '/':
|
|
||||||
// Even though \/ is considered a legal escape in JSON, a bare
|
|
||||||
// slash is also legal, so I see no reason to escape it.
|
|
||||||
// (I hope I am not misunderstanding something.)
|
|
||||||
// blep notes: actually escaping \/ may be useful in javascript to avoid </
|
|
||||||
// sequence.
|
|
||||||
// Should add a flag to allow this compatibility mode and prevent this
|
|
||||||
// sequence from occurring.
|
|
||||||
default:
|
|
||||||
if ((isControlCharacter(*c)) || (*c == 0)) {
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
|
|
||||||
<< std::setw(4) << static_cast<int>(*c);
|
|
||||||
result += oss.str();
|
|
||||||
} else {
|
|
||||||
result += *c;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result += "\"";
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class Writer
|
// Class Writer
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
Writer::~Writer() {}
|
Writer::~Writer() {}
|
||||||
@@ -333,7 +241,7 @@ void FastWriter::writeValue(const Value& value) {
|
|||||||
const std::string& name = *it;
|
const std::string& name = *it;
|
||||||
if (it != members.begin())
|
if (it != members.begin())
|
||||||
document_ += ',';
|
document_ += ',';
|
||||||
document_ += valueToQuotedStringN(name.data(), name.length());
|
document_ += valueToQuotedString(name.c_str());
|
||||||
document_ += yamlCompatiblityEnabled_ ? ": " : ":";
|
document_ += yamlCompatiblityEnabled_ ? ": " : ":";
|
||||||
writeValue(value[name]);
|
writeValue(value[name]);
|
||||||
}
|
}
|
||||||
@@ -374,15 +282,8 @@ void StyledWriter::writeValue(const Value& value) {
|
|||||||
pushValue(valueToString(value.asDouble()));
|
pushValue(valueToString(value.asDouble()));
|
||||||
break;
|
break;
|
||||||
case stringValue:
|
case stringValue:
|
||||||
{
|
pushValue(valueToQuotedString(value.asCString()));
|
||||||
// Is NULL is possible for value.string_?
|
|
||||||
char const* str;
|
|
||||||
char const* end;
|
|
||||||
bool ok = value.getString(&str, &end);
|
|
||||||
if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
|
|
||||||
else pushValue("");
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case booleanValue:
|
case booleanValue:
|
||||||
pushValue(valueToString(value.asBool()));
|
pushValue(valueToString(value.asBool()));
|
||||||
break;
|
break;
|
||||||
@@ -859,15 +760,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
|||||||
pushValue(valueToString(value.asDouble()));
|
pushValue(valueToString(value.asDouble()));
|
||||||
break;
|
break;
|
||||||
case stringValue:
|
case stringValue:
|
||||||
{
|
pushValue(valueToQuotedString(value.asCString()));
|
||||||
// Is NULL is possible for value.string_?
|
|
||||||
char const* str;
|
|
||||||
char const* end;
|
|
||||||
bool ok = value.getString(&str, &end);
|
|
||||||
if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
|
|
||||||
else pushValue("");
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case booleanValue:
|
case booleanValue:
|
||||||
pushValue(valueToString(value.asBool()));
|
pushValue(valueToString(value.asBool()));
|
||||||
break;
|
break;
|
||||||
@@ -886,7 +780,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
|||||||
std::string const& name = *it;
|
std::string const& name = *it;
|
||||||
Value const& childValue = value[name];
|
Value const& childValue = value[name];
|
||||||
writeCommentBeforeValue(childValue);
|
writeCommentBeforeValue(childValue);
|
||||||
writeWithIndent(valueToQuotedStringN(name.data(), name.length()));
|
writeWithIndent(valueToQuotedString(name.c_str()));
|
||||||
*sout_ << colonSymbol_;
|
*sout_ << colonSymbol_;
|
||||||
writeValue(childValue);
|
writeValue(childValue);
|
||||||
if (++it == members.end()) {
|
if (++it == members.end()) {
|
||||||
@@ -1077,7 +971,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
|||||||
} else if (cs_str == "None") {
|
} else if (cs_str == "None") {
|
||||||
cs = CommentStyle::None;
|
cs = CommentStyle::None;
|
||||||
} else {
|
} else {
|
||||||
throwRuntimeError("commentStyle must be 'All' or 'None'");
|
throw std::runtime_error("commentStyle must be 'All' or 'None'");
|
||||||
}
|
}
|
||||||
std::string colonSymbol = " : ";
|
std::string colonSymbol = " : ";
|
||||||
if (eyc) {
|
if (eyc) {
|
||||||
@@ -1107,6 +1001,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const
|
|||||||
Json::Value my_invalid;
|
Json::Value my_invalid;
|
||||||
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
|
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
|
||||||
Json::Value& inv = *invalid;
|
Json::Value& inv = *invalid;
|
||||||
|
bool valid = true;
|
||||||
std::set<std::string> valid_keys;
|
std::set<std::string> valid_keys;
|
||||||
getValidWriterKeys(&valid_keys);
|
getValidWriterKeys(&valid_keys);
|
||||||
Value::Members keys = settings_.getMemberNames();
|
Value::Members keys = settings_.getMemberNames();
|
||||||
@@ -1117,11 +1012,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const
|
|||||||
inv[key] = settings_[key];
|
inv[key] = settings_[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0u == inv.size();
|
return valid;
|
||||||
}
|
|
||||||
Value& StreamWriterBuilder::operator[](std::string key)
|
|
||||||
{
|
|
||||||
return settings_[key];
|
|
||||||
}
|
}
|
||||||
// static
|
// static
|
||||||
void StreamWriterBuilder::setDefaults(Json::Value* settings)
|
void StreamWriterBuilder::setDefaults(Json::Value* settings)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
# vim: et ts=4 sts=4 sw=4 tw=0
|
|
||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
IF(JSONCPP_LIB_BUILD_SHARED)
|
||||||
ADD_DEFINITIONS( -DJSON_DLL )
|
ADD_DEFINITIONS( -DJSON_DLL )
|
||||||
@@ -23,19 +22,9 @@ ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
|||||||
# Run unit tests in post-build
|
# Run unit tests in post-build
|
||||||
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)
|
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)
|
||||||
IF(JSONCPP_WITH_POST_BUILD_UNITTEST)
|
IF(JSONCPP_WITH_POST_BUILD_UNITTEST)
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
ADD_CUSTOM_COMMAND( TARGET jsoncpp_test
|
||||||
# First, copy the shared lib, for Microsoft.
|
POST_BUILD
|
||||||
# Then, run the test executable.
|
COMMAND $<TARGET_FILE:jsoncpp_test>)
|
||||||
ADD_CUSTOM_COMMAND( TARGET jsoncpp_test
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:jsoncpp_lib> $<TARGET_FILE_DIR:jsoncpp_test>
|
|
||||||
COMMAND $<TARGET_FILE:jsoncpp_test>)
|
|
||||||
ELSE(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
# Just run the test executable.
|
|
||||||
ADD_CUSTOM_COMMAND( TARGET jsoncpp_test
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND $<TARGET_FILE:jsoncpp_test>)
|
|
||||||
ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
ENDIF(JSONCPP_WITH_POST_BUILD_UNITTEST)
|
ENDIF(JSONCPP_WITH_POST_BUILD_UNITTEST)
|
||||||
|
|
||||||
SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)
|
SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "jsontest.h"
|
#include "jsontest.h"
|
||||||
#include <json/config.h>
|
#include <json/config.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
#include <stdexcept>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
// Make numeric limits more convenient to talk about.
|
// Make numeric limits more convenient to talk about.
|
||||||
@@ -281,8 +282,6 @@ JSONTEST_FIXTURE(ValueTest, null) {
|
|||||||
JSONTEST_ASSERT_EQUAL(0.0, null_.asDouble());
|
JSONTEST_ASSERT_EQUAL(0.0, null_.asDouble());
|
||||||
JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat());
|
JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", null_.asString());
|
JSONTEST_ASSERT_STRING_EQUAL("", null_.asString());
|
||||||
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::Value::null, null_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, strings) {
|
JSONTEST_FIXTURE(ValueTest, strings) {
|
||||||
@@ -1498,126 +1497,6 @@ JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, StaticString) {
|
|
||||||
char mutant[] = "hello";
|
|
||||||
Json::StaticString ss(mutant);
|
|
||||||
std::string regular(mutant);
|
|
||||||
mutant[1] = 'a';
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("hallo", ss.c_str());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("hello", regular.c_str());
|
|
||||||
{
|
|
||||||
Json::Value root;
|
|
||||||
root["top"] = ss;
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("hallo", root["top"].asString());
|
|
||||||
mutant[1] = 'u';
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("hullo", root["top"].asString());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Json::Value root;
|
|
||||||
root["top"] = regular;
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("hello", root["top"].asString());
|
|
||||||
mutant[1] = 'u';
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("hello", root["top"].asString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, CommentBefore) {
|
|
||||||
Json::Value val; // fill val
|
|
||||||
val.setComment(std::string("// this comment should appear before"), Json::commentBefore);
|
|
||||||
Json::StreamWriterBuilder wbuilder;
|
|
||||||
wbuilder.settings_["commentStyle"] = "All";
|
|
||||||
{
|
|
||||||
char const expected[] = "// this comment should appear before\nnull";
|
|
||||||
std::string result = Json::writeString(wbuilder, val);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
|
|
||||||
std::string res2 = val.toStyledString();
|
|
||||||
std::string exp2 = "\n";
|
|
||||||
exp2 += expected;
|
|
||||||
exp2 += "\n";
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(exp2, res2);
|
|
||||||
}
|
|
||||||
Json::Value other = "hello";
|
|
||||||
val.swapPayload(other);
|
|
||||||
{
|
|
||||||
char const expected[] = "// this comment should appear before\n\"hello\"";
|
|
||||||
std::string result = Json::writeString(wbuilder, val);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
|
|
||||||
std::string res2 = val.toStyledString();
|
|
||||||
std::string exp2 = "\n";
|
|
||||||
exp2 += expected;
|
|
||||||
exp2 += "\n";
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(exp2, res2);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("null\n", other.toStyledString());
|
|
||||||
}
|
|
||||||
val = "hello";
|
|
||||||
// val.setComment("// this comment should appear before", Json::CommentPlacement::commentBefore);
|
|
||||||
// Assignment over-writes comments.
|
|
||||||
{
|
|
||||||
char const expected[] = "\"hello\"";
|
|
||||||
std::string result = Json::writeString(wbuilder, val);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
|
|
||||||
std::string res2 = val.toStyledString();
|
|
||||||
std::string exp2 = "";
|
|
||||||
exp2 += expected;
|
|
||||||
exp2 += "\n";
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(exp2, res2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, zeroes) {
|
|
||||||
char const cstr[] = "h\0i";
|
|
||||||
std::string binary(cstr, sizeof(cstr)); // include trailing 0
|
|
||||||
JSONTEST_ASSERT_EQUAL(4U, binary.length());
|
|
||||||
Json::StreamWriterBuilder b;
|
|
||||||
{
|
|
||||||
Json::Value root;
|
|
||||||
root = binary;
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(binary, root.asString());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const top[] = "top";
|
|
||||||
Json::Value root;
|
|
||||||
root[top] = binary;
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(binary, root[top].asString());
|
|
||||||
Json::Value removed;
|
|
||||||
bool did;
|
|
||||||
did = root.removeMember(top, top + sizeof(top) - 1U,
|
|
||||||
&removed);
|
|
||||||
JSONTEST_ASSERT(did);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(binary, removed.asString());
|
|
||||||
did = root.removeMember(top, top + sizeof(top) - 1U,
|
|
||||||
&removed);
|
|
||||||
JSONTEST_ASSERT(!did);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(binary, removed.asString()); // still
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, zeroesInKeys) {
|
|
||||||
char const cstr[] = "h\0i";
|
|
||||||
std::string binary(cstr, sizeof(cstr)); // include trailing 0
|
|
||||||
JSONTEST_ASSERT_EQUAL(4U, binary.length());
|
|
||||||
{
|
|
||||||
Json::Value root;
|
|
||||||
root[binary] = "there";
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("there", root[binary].asString());
|
|
||||||
JSONTEST_ASSERT(!root.isMember("h"));
|
|
||||||
JSONTEST_ASSERT(root.isMember(binary));
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("there", root.get(binary, Json::Value::nullRef).asString());
|
|
||||||
Json::Value removed;
|
|
||||||
bool did;
|
|
||||||
did = root.removeMember(binary.data(), binary.data() + binary.length(),
|
|
||||||
&removed);
|
|
||||||
JSONTEST_ASSERT(did);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("there", removed.asString());
|
|
||||||
did = root.removeMember(binary.data(), binary.data() + binary.length(),
|
|
||||||
&removed);
|
|
||||||
JSONTEST_ASSERT(!did);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("there", removed.asString()); // still
|
|
||||||
JSONTEST_ASSERT(!root.isMember(binary));
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", root.get(binary, Json::Value::nullRef).asString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct StreamWriterTest : JsonTest::TestCase {};
|
struct StreamWriterTest : JsonTest::TestCase {};
|
||||||
|
|
||||||
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
||||||
@@ -1629,28 +1508,6 @@ JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
|||||||
JSONTEST_ASSERT(Json::writeString(b, nullValue) == "");
|
JSONTEST_ASSERT(Json::writeString(b, nullValue) == "");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(StreamWriterTest, writeZeroes) {
|
|
||||||
std::string binary("hi", 3); // include trailing 0
|
|
||||||
JSONTEST_ASSERT_EQUAL(3, binary.length());
|
|
||||||
std::string expected("\"hi\\u0000\""); // unicoded zero
|
|
||||||
Json::StreamWriterBuilder b;
|
|
||||||
{
|
|
||||||
Json::Value root;
|
|
||||||
root = binary;
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(binary, root.asString());
|
|
||||||
std::string out = Json::writeString(b, root);
|
|
||||||
JSONTEST_ASSERT_EQUAL(expected.size(), out.size());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(expected, out);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Json::Value root;
|
|
||||||
root["top"] = binary;
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(binary, root["top"].asString());
|
|
||||||
std::string out = Json::writeString(b, root["top"]);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(expected, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ReaderTest : JsonTest::TestCase {};
|
struct ReaderTest : JsonTest::TestCase {};
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
|
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
|
||||||
@@ -1814,440 +1671,6 @@ JSONTEST_FIXTURE(CharReaderTest, parseWithStackLimit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CharReaderStrictModeTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderStrictModeTest, dupKeys) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
"{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }";
|
|
||||||
{
|
|
||||||
b.strictMode(&b.settings_);
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(!ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(
|
|
||||||
"* Line 1, Column 41\n"
|
|
||||||
" Duplicate key: 'key'\n",
|
|
||||||
errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) {
|
|
||||||
// This is interpretted as a string value followed by a colon.
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
" \"property\" : \"value\" }";
|
|
||||||
{
|
|
||||||
b.settings_["failIfExtra"] = false;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs == "");
|
|
||||||
JSONTEST_ASSERT_EQUAL("property", root);
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
b.settings_["failIfExtra"] = true;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(!ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(errs,
|
|
||||||
"* Line 1, Column 13\n"
|
|
||||||
" Extra non-whitespace after JSON value.\n");
|
|
||||||
JSONTEST_ASSERT_EQUAL("property", root);
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
b.settings_["failIfExtra"] = false;
|
|
||||||
b.strictMode(&b.settings_);
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(!ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(errs,
|
|
||||||
"* Line 1, Column 13\n"
|
|
||||||
" Extra non-whitespace after JSON value.\n");
|
|
||||||
JSONTEST_ASSERT_EQUAL("property", root);
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue107) {
|
|
||||||
// This is interpretted as an int value followed by a colon.
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
"1:2:3";
|
|
||||||
b.settings_["failIfExtra"] = true;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(!ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(
|
|
||||||
"* Line 1, Column 2\n"
|
|
||||||
" Extra non-whitespace after JSON value.\n",
|
|
||||||
errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(1, root.asInt());
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterObject) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::Value root;
|
|
||||||
{
|
|
||||||
char const doc[] =
|
|
||||||
"{ \"property\" : \"value\" } //trailing\n//comment\n";
|
|
||||||
b.settings_["failIfExtra"] = true;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL("value", root["property"]);
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterArray) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
"[ \"property\" , \"value\" ] //trailing\n//comment\n";
|
|
||||||
b.settings_["failIfExtra"] = true;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL("value", root[1u]);
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterBool) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
" true /*trailing\ncomment*/";
|
|
||||||
b.settings_["failIfExtra"] = true;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, root.asBool());
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
struct CharReaderAllowDropNullTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderAllowDropNullTest, issue178) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
b.settings_["allowDroppedNullPlaceholders"] = true;
|
|
||||||
Json::Value root;
|
|
||||||
std::string errs;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
{
|
|
||||||
char const doc[] = "{\"a\":,\"b\":true}";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(2u, root.size());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::nullValue, root.get("a", true));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "{\"a\":}";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(1u, root.size());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::nullValue, root.get("a", true));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs == "");
|
|
||||||
JSONTEST_ASSERT_EQUAL(0u, root.size());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::arrayValue, root);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[null]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs == "");
|
|
||||||
JSONTEST_ASSERT_EQUAL(1u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[,]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(2u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[,,,]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(4u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[null,]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(2u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[,null]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs == "");
|
|
||||||
JSONTEST_ASSERT_EQUAL(2u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[,,]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(3u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[null,,]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(3u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[,null,]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(3u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[,,null]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs == "");
|
|
||||||
JSONTEST_ASSERT_EQUAL(3u, root.size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[[],,,]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(4u, root.size());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[0u]);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[,[],,]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(4u, root.size());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[1u]);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "[,,,[]]";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs == "");
|
|
||||||
JSONTEST_ASSERT_EQUAL(4u, root.size());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[3u]);
|
|
||||||
}
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderAllowSingleQuotesTest, issue182) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
b.settings_["allowSingleQuotes"] = true;
|
|
||||||
Json::Value root;
|
|
||||||
std::string errs;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
{
|
|
||||||
char const doc[] = "{'a':true,\"b\":true}";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(2u, root.size());
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, root.get("a", false));
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, root.get("b", false));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "{'a': 'x', \"b\":'y'}";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(2u, root.size());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CharReaderAllowZeroesTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderAllowZeroesTest, issue176) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
b.settings_["allowSingleQuotes"] = true;
|
|
||||||
Json::Value root;
|
|
||||||
std::string errs;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
{
|
|
||||||
char const doc[] = "{'a':true,\"b\":true}";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(2u, root.size());
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, root.get("a", false));
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, root.get("b", false));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const doc[] = "{'a': 'x', \"b\":'y'}";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
|
||||||
JSONTEST_ASSERT_EQUAL(2u, root.size());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BuilderTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(BuilderTest, settings) {
|
|
||||||
{
|
|
||||||
Json::Value errs;
|
|
||||||
Json::CharReaderBuilder rb;
|
|
||||||
JSONTEST_ASSERT_EQUAL(false, rb.settings_.isMember("foo"));
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, rb.validate(&errs));
|
|
||||||
rb["foo"] = "bar";
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, rb.settings_.isMember("foo"));
|
|
||||||
JSONTEST_ASSERT_EQUAL(false, rb.validate(&errs));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Json::Value errs;
|
|
||||||
Json::StreamWriterBuilder wb;
|
|
||||||
JSONTEST_ASSERT_EQUAL(false, wb.settings_.isMember("foo"));
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, wb.validate(&errs));
|
|
||||||
wb["foo"] = "bar";
|
|
||||||
JSONTEST_ASSERT_EQUAL(true, wb.settings_.isMember("foo"));
|
|
||||||
JSONTEST_ASSERT_EQUAL(false, wb.validate(&errs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct IteratorTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(IteratorTest, distance) {
|
|
||||||
Json::Value json;
|
|
||||||
json["k1"] = "a";
|
|
||||||
json["k2"] = "b";
|
|
||||||
int dist = 0;
|
|
||||||
std::string str;
|
|
||||||
for (Json::ValueIterator it = json.begin(); it != json.end(); ++it) {
|
|
||||||
dist = it - json.begin();
|
|
||||||
str = it->asString().c_str();
|
|
||||||
}
|
|
||||||
JSONTEST_ASSERT_EQUAL(1, dist);
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("b", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(IteratorTest, names) {
|
|
||||||
Json::Value json;
|
|
||||||
json["k1"] = "a";
|
|
||||||
json["k2"] = "b";
|
|
||||||
Json::ValueIterator it = json.begin();
|
|
||||||
JSONTEST_ASSERT(it != json.end());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::Value("k1"), it.key());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("k1", it.name());
|
|
||||||
JSONTEST_ASSERT_EQUAL(-1, it.index());
|
|
||||||
++it;
|
|
||||||
JSONTEST_ASSERT(it != json.end());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::Value("k2"), it.key());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("k2", it.name());
|
|
||||||
JSONTEST_ASSERT_EQUAL(-1, it.index());
|
|
||||||
++it;
|
|
||||||
JSONTEST_ASSERT(it == json.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(IteratorTest, indexes) {
|
|
||||||
Json::Value json;
|
|
||||||
json[0] = "a";
|
|
||||||
json[1] = "b";
|
|
||||||
Json::ValueIterator it = json.begin();
|
|
||||||
JSONTEST_ASSERT(it != json.end());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::Value(Json::ArrayIndex(0)), it.key());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", it.name());
|
|
||||||
JSONTEST_ASSERT_EQUAL(0, it.index());
|
|
||||||
++it;
|
|
||||||
JSONTEST_ASSERT(it != json.end());
|
|
||||||
JSONTEST_ASSERT_EQUAL(Json::Value(Json::ArrayIndex(1)), it.key());
|
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", it.name());
|
|
||||||
JSONTEST_ASSERT_EQUAL(1, it.index());
|
|
||||||
++it;
|
|
||||||
JSONTEST_ASSERT(it == json.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
JsonTest::Runner runner;
|
JsonTest::Runner runner;
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
|
||||||
@@ -2269,14 +1692,6 @@ int main(int argc, const char* argv[]) {
|
|||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, StaticString);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, CommentBefore);
|
|
||||||
//JSONTEST_REGISTER_FIXTURE(runner, ValueTest, nulls);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys);
|
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, writeZeroes);
|
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors);
|
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors);
|
||||||
JSONTEST_REGISTER_FIXTURE(
|
JSONTEST_REGISTER_FIXTURE(
|
||||||
@@ -2293,25 +1708,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
|
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit);
|
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit);
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderStrictModeTest, dupKeys);
|
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue164);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue107);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterObject);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterArray);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterBool);
|
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowDropNullTest, issue178);
|
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowSingleQuotesTest, issue182);
|
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowZeroesTest, issue176);
|
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, BuilderTest, settings);
|
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, distance);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, names);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, indexes);
|
|
||||||
|
|
||||||
return runner.runCommandLine(argc, argv);
|
return runner.runCommandLine(argc, argv);
|
||||||
}
|
}
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@JSONCPP_VERSION@
|
|
Reference in New Issue
Block a user