mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-14 15:05:34 +02:00
Compare commits
126 Commits
svn-import
...
0.7.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
15949af098 | ||
![]() |
8dc52b3cca | ||
![]() |
add941c1a9 | ||
![]() |
9c80798038 | ||
![]() |
72e5223658 | ||
![]() |
dc84d96a49 | ||
![]() |
1c3a20de50 | ||
![]() |
533dbe0898 | ||
![]() |
6cb2f7bd65 | ||
![]() |
b84a39cae5 | ||
![]() |
7bd75b0fb4 | ||
![]() |
f74a4ff17a | ||
![]() |
b7eccbb110 | ||
![]() |
ebe2d6e6ee | ||
![]() |
4cd31f01bb | ||
![]() |
ab19fa1d6f | ||
![]() |
bc8b5d871f | ||
![]() |
fd06bfca79 | ||
![]() |
4d23492d11 | ||
![]() |
aa650c5b9d | ||
![]() |
ae5a56f9ff | ||
![]() |
8aec8d88f2 | ||
![]() |
9dc9026e0b | ||
![]() |
4002f8a4be | ||
![]() |
0375af2eb5 | ||
![]() |
ba330893d7 | ||
![]() |
57dde78308 | ||
![]() |
69c324ead5 | ||
![]() |
263a4706fa | ||
![]() |
4bceabf2f9 | ||
![]() |
877dd17206 | ||
![]() |
16709c6ee8 | ||
![]() |
b2a1ca5b54 | ||
![]() |
9aa4681052 | ||
![]() |
af77b5b594 | ||
![]() |
11086dd6a7 | ||
![]() |
30b07c0275 | ||
![]() |
32009b17e4 | ||
![]() |
b4357fa224 | ||
![]() |
540db3b052 | ||
![]() |
f4b06cd607 | ||
![]() |
dd5b57a3d9 | ||
![]() |
6270858c43 | ||
![]() |
d9ced92d40 | ||
![]() |
8f730b8a60 | ||
![]() |
b061ff4a1e | ||
![]() |
8ececfa538 | ||
![]() |
d2fa664a12 | ||
![]() |
b7894977e7 | ||
![]() |
53262c66d9 | ||
![]() |
09228968ea | ||
![]() |
83b43caf8e | ||
![]() |
0dc03d0848 | ||
![]() |
45cd9490cd | ||
![]() |
236db83742 | ||
![]() |
a70b00750d | ||
![]() |
033677cc1a | ||
![]() |
9d694516a0 | ||
![]() |
d94caac1ea | ||
![]() |
8eb6f88a87 | ||
![]() |
64d591b720 | ||
![]() |
fe2cd01e80 | ||
![]() |
b02ff20bd3 | ||
![]() |
5bf16105b5 | ||
![]() |
3515db184a | ||
![]() |
48d9a92a1b | ||
![]() |
f97723dbb7 | ||
![]() |
1a6426ac19 | ||
![]() |
bc5dbc6d41 | ||
![]() |
1ac2295c21 | ||
![]() |
81d16dfda1 | ||
![]() |
c138933784 | ||
![]() |
b3deb61f87 | ||
![]() |
740e0207b1 | ||
![]() |
97c77b4a86 | ||
![]() |
7ebdabc059 | ||
![]() |
c6d9424f71 | ||
![]() |
19d0ece5f9 | ||
![]() |
35e4f2abd6 | ||
![]() |
b548cdf49c | ||
![]() |
3b9b7402fd | ||
![]() |
3585477f33 | ||
![]() |
27e3263894 | ||
![]() |
8582876c5c | ||
![]() |
496c655523 | ||
![]() |
49c732607b | ||
![]() |
655a9db0cc | ||
![]() |
f3989977c0 | ||
![]() |
60f778b9fc | ||
![]() |
50f6779578 | ||
![]() |
5a65132e72 | ||
![]() |
bef834edca | ||
![]() |
0973f2e6bc | ||
![]() |
5031a59518 | ||
![]() |
5850b83a5b | ||
![]() |
9dd7eea945 | ||
![]() |
35bea41bc9 | ||
![]() |
542cd1d3f5 | ||
![]() |
ba50403414 | ||
![]() |
0db9d6ea01 | ||
![]() |
b8aaa03367 | ||
![]() |
06dcb1fc89 | ||
![]() |
973de3988b | ||
![]() |
41b79398a3 | ||
![]() |
66b77384d8 | ||
![]() |
17c244e644 | ||
![]() |
8050d8b677 | ||
![]() |
28836b8acc | ||
![]() |
47f1577fd3 | ||
![]() |
9cc184146f | ||
![]() |
c151549937 | ||
![]() |
d61fa29da8 | ||
![]() |
b2a086adeb | ||
![]() |
8d0f8d0dcd | ||
![]() |
49ed6c9774 | ||
![]() |
38c9826423 | ||
![]() |
969921748b | ||
![]() |
ff22ca7973 | ||
![]() |
4b687640cb | ||
![]() |
3a0c4fcc82 | ||
![]() |
445328ace6 | ||
![]() |
9fa4e849a1 | ||
![]() |
1b137a3802 | ||
![]() |
fd6ada015e | ||
![]() |
8540868347 | ||
![]() |
2de98d9bd1 |
47
.clang-format
Normal file
47
.clang-format
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BinPackParameters: false
|
||||
ColumnLimit: 80
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
DerivePointerBinding: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
IndentCaseLabels: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 60
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerBindsToType: true
|
||||
SpacesBeforeTrailingComments: 1
|
||||
Cpp11BracedListStyle: false
|
||||
Standard: Cpp03
|
||||
IndentWidth: 2
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
BreakBeforeBraces: Attach
|
||||
IndentFunctionDeclarationAfterType: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpaceAfterControlStatementKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
ContinuationIndentWidth: 4
|
||||
...
|
||||
|
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,10 +1,13 @@
|
||||
/build/
|
||||
*.pyc
|
||||
*.swp
|
||||
|
||||
*.actual
|
||||
*.actual-rewrite
|
||||
*.process-output
|
||||
*.rewrite
|
||||
bin/
|
||||
buildscons/
|
||||
libs/
|
||||
/bin/
|
||||
/buildscons/
|
||||
/libs/
|
||||
/doc/doxyfile
|
||||
/dist/
|
||||
/include/json/version.h
|
||||
|
@@ -9,15 +9,10 @@ compiler:
|
||||
- clang
|
||||
script: cmake -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIBRARY -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make
|
||||
env:
|
||||
global:
|
||||
- JSONCPP_CONTINUOUS_INTERATION=1
|
||||
matrix:
|
||||
- SHARED_LIBRARY=ON BUILD_TYPE=release VERBOSE_MAKE=false
|
||||
- SHARED_LIBRARY=OFF BUILD_TYPE=release VERBOSE_MAKE=false
|
||||
- SHARED_LIBRARY=OFF BUILD_TYPE=debug VERBOSE VERBOSE_MAKE=true
|
||||
notifications:
|
||||
recipients:
|
||||
- baptiste.lepilleur@gmail.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
- aaronjjacobs@gmail.com
|
||||
|
@@ -1,10 +1,12 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5)
|
||||
PROJECT(jsoncpp)
|
||||
ENABLE_TESTING()
|
||||
|
||||
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_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_CMAKE_PACKAGE "Generate and install cmake package files" OFF)
|
||||
|
||||
# Ensures that CMAKE_BUILD_TYPE is visible in cmake-gui on Unix
|
||||
IF(NOT WIN32)
|
||||
@@ -13,7 +15,19 @@ IF(NOT WIN32)
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage."
|
||||
FORCE)
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
ENDIF(NOT WIN32)
|
||||
ENDIF(NOT WIN32)
|
||||
|
||||
SET(RUNTIME_INSTALL_DIR bin
|
||||
CACHE PATH "Install dir for executables and dlls")
|
||||
SET(ARCHIVE_INSTALL_DIR lib
|
||||
CACHE PATH "Install dir for static libraries")
|
||||
SET(LIBRARY_INSTALL_DIR lib
|
||||
CACHE PATH "Install dir for shared libraries")
|
||||
SET(INCLUDE_INSTALL_DIR include
|
||||
CACHE PATH "Install dir for headers")
|
||||
SET(PACKAGE_INSTALL_DIR lib/cmake
|
||||
CACHE PATH "Install dir for cmake package config files")
|
||||
MARK_AS_ADVANCED( RUNTIME_INSTALL_DIR ARCHIVE_INSTALL_DIR INCLUDE_INSTALL_DIR PACKAGE_INSTALL_DIR )
|
||||
|
||||
# This ensures shared DLL are in the same dir as executable on Windows.
|
||||
# Put all executables / libraries are in a project global directory.
|
||||
@@ -28,24 +42,22 @@ MARK_AS_ADVANCED( CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY
|
||||
# Set variable named ${VAR_NAME} to value ${VALUE}
|
||||
FUNCTION(set_using_dynamic_name VAR_NAME VALUE)
|
||||
SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE)
|
||||
ENDFUNCTION(set_using_dynamic_name)
|
||||
ENDFUNCTION(set_using_dynamic_name)
|
||||
|
||||
# Extract major, minor, patch and qualifier from version text
|
||||
# Parse a version string "X.Y.Z[-qualifier]" and outputs
|
||||
# version parts in ${OUPUT_PREFIX}_MAJOR, _MINOR, _PATCH, _QUALIFIER.
|
||||
# If parse succed then ${OUPUT_PREFIX}_FOUND is TRUE.
|
||||
# Extract major, minor, patch from version text
|
||||
# Parse a version string "X.Y.Z" and outputs
|
||||
# version parts in ${OUPUT_PREFIX}_MAJOR, _MINOR, _PATCH.
|
||||
# If parse succeeds then ${OUPUT_PREFIX}_FOUND is TRUE.
|
||||
MACRO(jsoncpp_parse_version VERSION_TEXT OUPUT_PREFIX)
|
||||
SET(VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z0-9_]+)?")
|
||||
IF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
|
||||
STRING(REGEX MATCHALL "[0-9]+|-([A-Za-z0-9_]+)" VERSION_PARTS ${VERSION_TEXT})
|
||||
list(APPEND VERSION_PARTS "") # empty qualifier to handle no qualifier case
|
||||
LIST(GET VERSION_PARTS 0 ${OUPUT_PREFIX}_MAJOR)
|
||||
LIST(GET VERSION_PARTS 1 ${OUPUT_PREFIX}_MINOR)
|
||||
LIST(GET VERSION_PARTS 2 ${OUPUT_PREFIX}_PATCH)
|
||||
LIST(GET VERSION_PARTS 3 ${OUPUT_PREFIX}_QUALIFIER)
|
||||
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE )
|
||||
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE )
|
||||
ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
|
||||
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE )
|
||||
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE )
|
||||
ENDIF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
|
||||
ENDMACRO(jsoncpp_parse_version)
|
||||
|
||||
@@ -54,10 +66,10 @@ FILE(STRINGS "version" JSONCPP_VERSION)
|
||||
|
||||
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
|
||||
IF(NOT JSONCPP_VERSION_FOUND)
|
||||
MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z[-qualifier]")
|
||||
MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
|
||||
ENDIF(NOT JSONCPP_VERSION_FOUND)
|
||||
|
||||
MESSAGE(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}${JSONCPP_VERSION_QUALIFIER}")
|
||||
MESSAGE(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}")
|
||||
# File version.h is only regenerated on CMake configure step
|
||||
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/src/lib_json/version.h.in"
|
||||
"${PROJECT_SOURCE_DIR}/include/json/version.h" )
|
||||
@@ -68,10 +80,10 @@ macro(UseCompilationWarningAsError)
|
||||
# warnings when compiled in release configuration.
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ")
|
||||
endif( MSVC )
|
||||
endmacro()
|
||||
endmacro()
|
||||
|
||||
# Include our configuration header
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include )
|
||||
INCLUDE_DIRECTORIES( ${jsoncpp_SOURCE_DIR}/include )
|
||||
|
||||
if ( MSVC )
|
||||
# Only enabled in debug because some old versions of VS STL generate
|
||||
@@ -83,6 +95,21 @@ IF(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||
UseCompilationWarningAsError()
|
||||
ENDIF(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||
|
||||
IF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
|
||||
CONFIGURE_FILE(
|
||||
"pkg-config/jsoncpp.pc.in"
|
||||
"pkg-config/jsoncpp.pc"
|
||||
@ONLY)
|
||||
INSTALL(FILES "${CMAKE_BINARY_DIR}/pkg-config/jsoncpp.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
|
||||
ENDIF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
|
||||
|
||||
IF(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||
INSTALL(EXPORT jsoncpp
|
||||
DESTINATION ${PACKAGE_INSTALL_DIR}/jsoncpp
|
||||
FILE jsoncppConfig.cmake)
|
||||
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||
|
||||
# Build the different applications
|
||||
ADD_SUBDIRECTORY( src )
|
||||
|
||||
|
224
README.md
Normal file
224
README.md
Normal file
@@ -0,0 +1,224 @@
|
||||
Introduction
|
||||
------------
|
||||
|
||||
[JSON][json-org] is a lightweight data-interchange format. It can represent
|
||||
numbers, strings, ordered sequences of values, and collections of name/value
|
||||
pairs.
|
||||
|
||||
[json-org]: http://json.org/
|
||||
|
||||
JsonCpp is a C++ library that allows manipulating JSON values, including
|
||||
serialization and deserialization to and from strings. It can also preserve
|
||||
existing comment in unserialization/serialization steps, making it a convenient
|
||||
format to store user input files.
|
||||
|
||||
## A note on backward-compatibility
|
||||
Very soon, we are switching to C++11 only. For older compilers, try the `pre-C++11` branch.
|
||||
|
||||
Using JsonCpp in your project
|
||||
-----------------------------
|
||||
|
||||
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
|
||||
ensures consistency of compilation flags and ABI compatibility. See the section
|
||||
"Generating amalgamated source and header" for instructions.
|
||||
|
||||
The `include/` should be added to your compiler include path. Jsoncpp headers
|
||||
should be included as follow:
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
If JsonCpp was build as a dynamic library on Windows, then your project needs to
|
||||
define the macro `JSON_DLL`.
|
||||
|
||||
|
||||
Building and testing with new CMake
|
||||
-----------------------------------
|
||||
|
||||
[CMake][] is a C++ Makefiles/Solution generator. It is usually available on most
|
||||
Linux system as package. On Ubuntu:
|
||||
|
||||
sudo apt-get install cmake
|
||||
|
||||
[CMake]: http://www.cmake.org
|
||||
|
||||
Note that Python is also required to run the JSON reader/writer tests. If
|
||||
missing, the build will skip running those tests.
|
||||
|
||||
When running CMake, a few parameters are required:
|
||||
|
||||
* a build directory where the makefiles/solution are generated. It is also used
|
||||
to store objects, libraries and executables files.
|
||||
* the generator to use: makefiles or Visual Studio solution? What version or
|
||||
Visual Studio, 32 or 64 bits solution?
|
||||
|
||||
Steps for generating solution/makefiles using `cmake-gui`:
|
||||
|
||||
* Make "source code" point to the source directory.
|
||||
* Make "where to build the binary" point to the directory to use for the build.
|
||||
* Click on the "Grouped" check box.
|
||||
* Review JsonCpp build options (tick `JSONCPP_LIB_BUILD_SHARED` to build as a
|
||||
dynamic library).
|
||||
* Click the configure button at the bottom, then the generate button.
|
||||
* The generated solution/makefiles can be found in the binary directory.
|
||||
|
||||
Alternatively, from the command-line on Unix in the source directory:
|
||||
|
||||
mkdir -p build/debug
|
||||
cd build/debug
|
||||
cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../..
|
||||
make
|
||||
|
||||
Running `cmake -`" will display the list of available generators (passed using
|
||||
the `-G` option).
|
||||
|
||||
By default CMake hides compilation commands. This can be modified by specifying
|
||||
`-DCMAKE_VERBOSE_MAKEFILE=true` when generating makefiles.
|
||||
|
||||
|
||||
Building and testing with SCons
|
||||
-------------------------------
|
||||
|
||||
**Note:** The SCons-based build system is deprecated. Please use CMake; see the
|
||||
section above.
|
||||
|
||||
JsonCpp can use [Scons][] as a build system. Note that SCons requires Python to
|
||||
be installed.
|
||||
|
||||
[SCons]: http://www.scons.org/
|
||||
|
||||
Invoke SCons as follows:
|
||||
|
||||
scons platform=$PLATFORM [TARGET]
|
||||
|
||||
where `$PLATFORM` may be one of:
|
||||
|
||||
* `suncc`: Sun C++ (Solaris)
|
||||
* `vacpp`: Visual Age C++ (AIX)
|
||||
* `mingw`
|
||||
* `msvc6`: Microsoft Visual Studio 6 service pack 5-6
|
||||
* `msvc70`: Microsoft Visual Studio 2002
|
||||
* `msvc71`: Microsoft Visual Studio 2003
|
||||
* `msvc80`: Microsoft Visual Studio 2005
|
||||
* `msvc90`: Microsoft Visual Studio 2008
|
||||
* `linux-gcc`: Gnu C++ (linux, also reported to work for Mac OS X)
|
||||
|
||||
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
|
||||
running SCons.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
In the instructions below, replace `path/to/jsontest` with the path of the
|
||||
`jsontest` executable that was compiled on your platform.
|
||||
|
||||
cd test
|
||||
# This will run the Reader/Writer tests
|
||||
python runjsontests.py path/to/jsontest
|
||||
|
||||
# This will run the Reader/Writer tests, using JSONChecker test suite
|
||||
# (http://www.json.org/JSON_checker/).
|
||||
# Notes: not all tests pass: JsonCpp is too lenient (for example,
|
||||
# it allows an integer to start with '0'). The goal is to improve
|
||||
# strict mode parsing to get all tests to pass.
|
||||
python runjsontests.py --with-json-checker path/to/jsontest
|
||||
|
||||
# This will run the unit tests (mostly Value)
|
||||
python rununittests.py path/to/test_lib_json
|
||||
|
||||
# You can run the tests using valgrind:
|
||||
python rununittests.py --valgrind path/to/test_lib_json
|
||||
|
||||
|
||||
Building the documentation
|
||||
--------------------------
|
||||
|
||||
Run the Python script `doxybuild.py` from the top directory:
|
||||
|
||||
python doxybuild.py --doxygen=$(which doxygen) --open --with-dot
|
||||
|
||||
See `doxybuild.py --help` for options.
|
||||
|
||||
|
||||
Generating amalgamated source and header
|
||||
----------------------------------------
|
||||
|
||||
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
|
||||
can be generated at any time by running the following command from the
|
||||
top-directory (this requires Python 2.6):
|
||||
|
||||
python amalgamate.py
|
||||
|
||||
It is possible to specify header name. See the `-h` option for detail.
|
||||
|
||||
By default, the following files are generated:
|
||||
* `dist/jsoncpp.cpp`: source file that needs to be added to your project.
|
||||
* `dist/json/json.h`: corresponding header file for use in your project. It is
|
||||
equivalent to including `json/json.h` in non-amalgamated source. This header
|
||||
only depends on standard headers.
|
||||
* `dist/json/json-forwards.h`: header that provides forward declaration of all
|
||||
JsonCpp types.
|
||||
|
||||
The amalgamated sources are generated by concatenating JsonCpp source in the
|
||||
correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion
|
||||
of other headers.
|
||||
|
||||
|
||||
Adding a reader/writer test
|
||||
---------------------------
|
||||
|
||||
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.expected` file, that contains a flatened representation of the
|
||||
input document.
|
||||
|
||||
The `TESTNAME.expected` file format is as follows:
|
||||
|
||||
* each line represents a JSON element of the element tree represented by the
|
||||
input document.
|
||||
* each line has two parts: the path to access the element separated from the
|
||||
element value by `=`. Array and object values are always empty (i.e.
|
||||
represented by either `[]` or `{}`).
|
||||
* element path: `.` represents the root element, and is used to separate object
|
||||
members. `[N]` is used to specify the value of an array element at index `N`.
|
||||
|
||||
See the examples `test_complex_01.json` and `test_complex_01.expected` to better
|
||||
understand element paths.
|
||||
|
||||
|
||||
Understanding reader/writer test output
|
||||
---------------------------------------
|
||||
|
||||
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:
|
||||
|
||||
* `test_complex_01.json`: input JSON document.
|
||||
* `test_complex_01.expected`: flattened JSON element tree used to check if
|
||||
parsing was corrected.
|
||||
* `test_complex_01.actual`: flattened JSON element tree produced by `jsontest`
|
||||
from reading `test_complex_01.json`.
|
||||
* `test_complex_01.rewrite`: JSON document written by `jsontest` using the
|
||||
`Json::Value` parsed from `test_complex_01.json` and serialized using
|
||||
`Json::StyledWritter`.
|
||||
* `test_complex_01.actual-rewrite`: flattened JSON element tree produced by
|
||||
`jsontest` from reading `test_complex_01.rewrite`.
|
||||
* `test_complex_01.process-output`: `jsontest` output, typically useful for
|
||||
understanding parsing errors.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
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.
|
||||
|
220
README.txt
220
README.txt
@@ -1,220 +0,0 @@
|
||||
* Introduction:
|
||||
=============
|
||||
|
||||
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
|
||||
It can represent integer, real number, string, an ordered sequence of
|
||||
value, and a collection of name/value pairs.
|
||||
|
||||
JsonCpp (http://jsoncpp.sourceforge.net/) is a simple API to manipulate
|
||||
JSON value, handle serialization and unserialization to string.
|
||||
|
||||
It can also preserve existing comment in unserialization/serialization steps,
|
||||
making it a convenient format to store user input files.
|
||||
|
||||
Unserialization parsing is user friendly and provides precise error reports.
|
||||
|
||||
* Using json-cpp in your project:
|
||||
===============================
|
||||
|
||||
The recommended approach to integrate json-cpp in your project is to
|
||||
build the the amalgamated source (a single .cpp) with your own build
|
||||
system. This ensures compilation flags consistency and ABI compatibility.
|
||||
|
||||
See section "Generating amalgamated source and header" to generate them
|
||||
from the source distribution.
|
||||
|
||||
Directory include/ should be added to your compiler include path.
|
||||
json-cpp headers should be included as follow:
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
If json-cpp was build as a dynamic library on Windows, then your project
|
||||
need to define macro "JSON_DLL" to JSON_API should import exported symbols.
|
||||
|
||||
* Building/Testing with new CMake build system:
|
||||
=============================================
|
||||
|
||||
CMake is a C++ Makefiles/Solution generator that can be downloaded from:
|
||||
http://www.cmake.org
|
||||
|
||||
It is usually available on most Linux system as package. On Ubuntu:
|
||||
sudo apt-get install cmake
|
||||
|
||||
Notes that python is also required to run JSON reader/writer tests. If
|
||||
missing, the build will skip running those tests.
|
||||
|
||||
When running CMake, a few parameters are required:
|
||||
- a build directory where the makefiles/solution are generated. It is
|
||||
also used to store objects, libraries and executables files.
|
||||
- the generator to use: makefiles or Visual Studio solution? What version
|
||||
or Visual Studio, 32 or 64 bits solution?
|
||||
|
||||
Generating solution/makefiles using cmake-gui:
|
||||
- Makes "source code" points the source directory
|
||||
- Makes "where to build the binary" points to the directory to use for
|
||||
the build.
|
||||
- Click on the "Grouped" check box
|
||||
- Review JsonCpp build option (tick JSONCPP_LIB_BUILD_SHARED to build as
|
||||
a dynamic library)
|
||||
- Click configure button at the bottom, then the generate button.
|
||||
- The generated solution/makefiles can be found in the binary directory.
|
||||
|
||||
Alternatively, from the command-line on Unix in the source directory:
|
||||
|
||||
mkdir -p ../build/debug
|
||||
cd ../build/debug
|
||||
cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../../jsoncpp-src
|
||||
make
|
||||
|
||||
Running "cmake -h" will display the list of available generators (passed as -G option).
|
||||
|
||||
By default CMake hides compilation command-line. This can be modified by specifying:
|
||||
-DCMAKE_VERBOSE_MAKEFILE=true when generating makefiles.
|
||||
|
||||
* Building/Testing with the legacy build system based on SCons:
|
||||
=============================================================
|
||||
|
||||
JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires
|
||||
python to be installed (http://www.python.org).
|
||||
|
||||
You download scons-local distribution from the following url:
|
||||
http://sourceforge.net/projects/scons/files/scons-local/1.2.0/
|
||||
|
||||
Unzip it in the directory where you found this README file. scons.py Should be
|
||||
at the same level as README.
|
||||
|
||||
python scons.py platform=PLTFRM [TARGET]
|
||||
where PLTFRM may be one of:
|
||||
suncc Sun C++ (Solaris)
|
||||
vacpp Visual Age C++ (AIX)
|
||||
mingw
|
||||
msvc6 Microsoft Visual Studio 6 service pack 5-6
|
||||
msvc70 Microsoft Visual Studio 2002
|
||||
msvc71 Microsoft Visual Studio 2003
|
||||
msvc80 Microsoft Visual Studio 2005
|
||||
msvc90 Microsoft Visual Studio 2008
|
||||
linux-gcc Gnu C++ (linux, also reported to work for Mac OS X)
|
||||
|
||||
Notes: if you are building with Microsoft Visual Studio 2008, you need to
|
||||
setup the environment by running vcvars32.bat (e.g. MSVC 2008 command prompt)
|
||||
before running scons.
|
||||
|
||||
Adding platform is fairly simple. You need to change the Sconstruct file
|
||||
to do so.
|
||||
|
||||
and TARGET may be:
|
||||
check: build library and run unit tests.
|
||||
|
||||
* Running the test manually:
|
||||
==========================
|
||||
|
||||
Notes that test can be run by scons using the 'check' target (see above).
|
||||
|
||||
You need to run test manually only if you are troubleshooting an issue.
|
||||
|
||||
In the instruction below, replace "path to jsontest.exe" with the path
|
||||
of the 'jsontest' executable that was compiled on your platform.
|
||||
|
||||
cd test
|
||||
# This will run the Reader/Writer tests
|
||||
python runjsontests.py "path to jsontest.exe"
|
||||
|
||||
# This will run the Reader/Writer tests, using JSONChecker test suite
|
||||
# (http://www.json.org/JSON_checker/).
|
||||
# Notes: not all tests pass: JsonCpp is too lenient (for example,
|
||||
# it allows an integer to start with '0'). The goal is to improve
|
||||
# strict mode parsing to get all tests to pass.
|
||||
python runjsontests.py --with-json-checker "path to jsontest.exe"
|
||||
|
||||
# This will run the unit tests (mostly Value)
|
||||
python rununittests.py "path to test_lib_json.exe"
|
||||
|
||||
You can run the tests using valgrind:
|
||||
python rununittests.py --valgrind "path to test_lib_json.exe"
|
||||
|
||||
|
||||
* Building the documentation:
|
||||
===========================
|
||||
|
||||
Run the python script doxybuild.py from the top directory:
|
||||
|
||||
python doxybuild.py --open --with-dot
|
||||
|
||||
See doxybuild.py --help for options.
|
||||
|
||||
Notes that the documentation is also available for download as a tarball.
|
||||
The documentation of the latest release is available online at:
|
||||
http://jsoncpp.sourceforge.net/
|
||||
|
||||
* Generating amalgamated source and header
|
||||
========================================
|
||||
|
||||
JsonCpp is provided with a script to generate a single header and a single
|
||||
source file to ease inclusion in an existing project.
|
||||
|
||||
The amalgamated source can be generated at any time by running the following
|
||||
command from the top-directory (requires python 2.6):
|
||||
|
||||
python amalgamate.py
|
||||
|
||||
It is possible to specify header name. See -h options for detail. By default,
|
||||
the following files are generated:
|
||||
- dist/jsoncpp.cpp: source file that need to be added to your project
|
||||
- dist/json/json.h: header file corresponding to use in your project. It is
|
||||
equivalent to including json/json.h in non-amalgamated source. This header
|
||||
only depends on standard headers.
|
||||
- dist/json/json-forwards.h: header the provides forward declaration
|
||||
of all JsonCpp types. This typically what should be included in headers to
|
||||
speed-up compilation.
|
||||
|
||||
The amalgamated sources are generated by concatenating JsonCpp source in the
|
||||
correct order and defining macro JSON_IS_AMALGAMATION to prevent inclusion
|
||||
of other headers.
|
||||
|
||||
* Adding a reader/writer test:
|
||||
============================
|
||||
|
||||
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.expected file, that contains a flatened representation of
|
||||
the input document.
|
||||
|
||||
TESTNAME.expected file format:
|
||||
- each line represents a JSON element of the element tree represented
|
||||
by the input document.
|
||||
- each line has two parts: the path to access the element separated from
|
||||
the element value by '='. Array and object values are always empty
|
||||
(e.g. represented by either [] or {}).
|
||||
- element path: '.' represented the root element, and is used to separate
|
||||
object members. [N] is used to specify the value of an array element
|
||||
at index N.
|
||||
See test_complex_01.json and test_complex_01.expected to better understand
|
||||
element path.
|
||||
|
||||
|
||||
* Understanding reader/writer test output:
|
||||
========================================
|
||||
|
||||
When a test is run, output files are generated aside the input test files.
|
||||
Below is a short description of the content of each file:
|
||||
|
||||
- test_complex_01.json: input JSON document
|
||||
- test_complex_01.expected: flattened JSON element tree used to check if
|
||||
parsing was corrected.
|
||||
|
||||
- test_complex_01.actual: flattened JSON element tree produced by
|
||||
jsontest.exe from reading test_complex_01.json
|
||||
- test_complex_01.rewrite: JSON document written by jsontest.exe using the
|
||||
Json::Value parsed from test_complex_01.json and serialized using
|
||||
Json::StyledWritter.
|
||||
- test_complex_01.actual-rewrite: flattened JSON element tree produced by
|
||||
jsontest.exe from reading test_complex_01.rewrite.
|
||||
test_complex_01.process-output: jsontest.exe output, typically useful to
|
||||
understand parsing error.
|
||||
|
||||
* License
|
||||
=======
|
||||
|
||||
See file LICENSE for details. Basically JsonCpp is licensed under
|
||||
MIT license, or public domain if desired and recognized in your jurisdiction.
|
||||
|
@@ -119,7 +119,7 @@ elif platform == 'mingw':
|
||||
env.Append( CPPDEFINES=[ "WIN32", "NDEBUG", "_MT" ] )
|
||||
elif platform.startswith('linux-gcc'):
|
||||
env.Tool( 'default' )
|
||||
env.Append( LIBS = ['pthread'], CCFLAGS = "-Wall" )
|
||||
env.Append( LIBS = ['pthread'], CCFLAGS = os.environ.get("CXXFLAGS", "-Wall"), LINKFLAGS=os.environ.get("LDFLAGS", "") )
|
||||
env['SHARED_LIB_ENABLED'] = True
|
||||
else:
|
||||
print "UNSUPPORTED PLATFORM."
|
||||
|
142
amalgamate.py
142
amalgamate.py
@@ -15,36 +15,36 @@ class AmalgamationFile:
|
||||
self.blocks = []
|
||||
|
||||
def add_text( self, text ):
|
||||
if not text.endswith( '\n' ):
|
||||
text += '\n'
|
||||
if not text.endswith( "\n" ):
|
||||
text += "\n"
|
||||
self.blocks.append( text )
|
||||
|
||||
def add_file( self, relative_input_path, wrap_in_comment=False ):
|
||||
def add_marker( prefix ):
|
||||
self.add_text( '' )
|
||||
self.add_text( '// ' + '/'*70 )
|
||||
self.add_text( '// %s of content of file: %s' % (prefix, relative_input_path.replace('\\','/')) )
|
||||
self.add_text( '// ' + '/'*70 )
|
||||
self.add_text( '' )
|
||||
add_marker( 'Beginning' )
|
||||
f = open( os.path.join( self.top_dir, relative_input_path ), 'rt' )
|
||||
self.add_text( "" )
|
||||
self.add_text( "// " + "/"*70 )
|
||||
self.add_text( "// %s of content of file: %s" % (prefix, relative_input_path.replace("\\","/")) )
|
||||
self.add_text( "// " + "/"*70 )
|
||||
self.add_text( "" )
|
||||
add_marker( "Beginning" )
|
||||
f = open( os.path.join( self.top_dir, relative_input_path ), "rt" )
|
||||
content = f.read()
|
||||
if wrap_in_comment:
|
||||
content = '/*\n' + content + '\n*/'
|
||||
content = "/*\n" + content + "\n*/"
|
||||
self.add_text( content )
|
||||
f.close()
|
||||
add_marker( 'End' )
|
||||
self.add_text( '\n\n\n\n' )
|
||||
add_marker( "End" )
|
||||
self.add_text( "\n\n\n\n" )
|
||||
|
||||
def get_value( self ):
|
||||
return ''.join( self.blocks ).replace('\r\n','\n')
|
||||
return "".join( self.blocks ).replace("\r\n","\n")
|
||||
|
||||
def write_to( self, output_path ):
|
||||
output_dir = os.path.dirname( output_path )
|
||||
if output_dir and not os.path.isdir( output_dir ):
|
||||
os.makedirs( output_dir )
|
||||
f = open( output_path, 'wb' )
|
||||
f.write( self.get_value() )
|
||||
f = open( output_path, "wb" )
|
||||
f.write( str.encode(self.get_value(), 'UTF-8') )
|
||||
f.close()
|
||||
|
||||
def amalgamate_source( source_top_dir=None,
|
||||
@@ -56,69 +56,69 @@ def amalgamate_source( source_top_dir=None,
|
||||
target_source_path: output .cpp path
|
||||
header_include_path: generated header path relative to target_source_path.
|
||||
"""
|
||||
print 'Amalgating header...'
|
||||
print ("Amalgating header...")
|
||||
header = AmalgamationFile( source_top_dir )
|
||||
header.add_text( '/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).' )
|
||||
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_text( '#ifndef JSON_AMALGATED_H_INCLUDED' )
|
||||
header.add_text( '# define JSON_AMALGATED_H_INCLUDED' )
|
||||
header.add_text( '/// If defined, indicates that the source file is amalgated' )
|
||||
header.add_text( '/// to prevent private header inclusion.' )
|
||||
header.add_text( '#define JSON_IS_AMALGAMATION' )
|
||||
header.add_file( 'include/json/version.h' )
|
||||
header.add_file( 'include/json/config.h' )
|
||||
header.add_file( 'include/json/forwards.h' )
|
||||
header.add_file( 'include/json/features.h' )
|
||||
header.add_file( 'include/json/value.h' )
|
||||
header.add_file( 'include/json/reader.h' )
|
||||
header.add_file( 'include/json/writer.h' )
|
||||
header.add_file( 'include/json/assertions.h' )
|
||||
header.add_text( '#endif //ifndef JSON_AMALGATED_H_INCLUDED' )
|
||||
header.add_text( "/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/)." )
|
||||
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_text( "#ifndef JSON_AMALGATED_H_INCLUDED" )
|
||||
header.add_text( "# define JSON_AMALGATED_H_INCLUDED" )
|
||||
header.add_text( "/// If defined, indicates that the source file is amalgated" )
|
||||
header.add_text( "/// to prevent private header inclusion." )
|
||||
header.add_text( "#define JSON_IS_AMALGAMATION" )
|
||||
header.add_file( "include/json/version.h" )
|
||||
header.add_file( "include/json/config.h" )
|
||||
header.add_file( "include/json/forwards.h" )
|
||||
header.add_file( "include/json/features.h" )
|
||||
header.add_file( "include/json/value.h" )
|
||||
header.add_file( "include/json/reader.h" )
|
||||
header.add_file( "include/json/writer.h" )
|
||||
header.add_file( "include/json/assertions.h" )
|
||||
header.add_text( "#endif //ifndef JSON_AMALGATED_H_INCLUDED" )
|
||||
|
||||
target_header_path = os.path.join( os.path.dirname(target_source_path), header_include_path )
|
||||
print 'Writing amalgated header to %r' % target_header_path
|
||||
print ("Writing amalgated header to %r" % target_header_path)
|
||||
header.write_to( target_header_path )
|
||||
|
||||
base, ext = os.path.splitext( header_include_path )
|
||||
forward_header_include_path = base + '-forwards' + ext
|
||||
print 'Amalgating forward header...'
|
||||
forward_header_include_path = base + "-forwards" + ext
|
||||
print ("Amalgating forward header...")
|
||||
header = AmalgamationFile( source_top_dir )
|
||||
header.add_text( '/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).' )
|
||||
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_file( 'LICENSE', wrap_in_comment=True )
|
||||
header.add_text( '#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED' )
|
||||
header.add_text( '# define JSON_FORWARD_AMALGATED_H_INCLUDED' )
|
||||
header.add_text( '/// If defined, indicates that the source file is amalgated' )
|
||||
header.add_text( '/// to prevent private header inclusion.' )
|
||||
header.add_text( '#define JSON_IS_AMALGAMATION' )
|
||||
header.add_file( 'include/json/config.h' )
|
||||
header.add_file( 'include/json/forwards.h' )
|
||||
header.add_text( '#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED' )
|
||||
header.add_text( "/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/)." )
|
||||
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_file( "LICENSE", wrap_in_comment=True )
|
||||
header.add_text( "#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED" )
|
||||
header.add_text( "# define JSON_FORWARD_AMALGATED_H_INCLUDED" )
|
||||
header.add_text( "/// If defined, indicates that the source file is amalgated" )
|
||||
header.add_text( "/// to prevent private header inclusion." )
|
||||
header.add_text( "#define JSON_IS_AMALGAMATION" )
|
||||
header.add_file( "include/json/config.h" )
|
||||
header.add_file( "include/json/forwards.h" )
|
||||
header.add_text( "#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED" )
|
||||
|
||||
target_forward_header_path = os.path.join( os.path.dirname(target_source_path),
|
||||
forward_header_include_path )
|
||||
print 'Writing amalgated forward header to %r' % target_forward_header_path
|
||||
print ("Writing amalgated forward header to %r" % target_forward_header_path)
|
||||
header.write_to( target_forward_header_path )
|
||||
|
||||
print 'Amalgating source...'
|
||||
print ("Amalgating source...")
|
||||
source = AmalgamationFile( source_top_dir )
|
||||
source.add_text( '/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).' )
|
||||
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_text( '' )
|
||||
source.add_text( '#include <%s>' % header_include_path )
|
||||
source.add_text( '' )
|
||||
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_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_value.cpp') )
|
||||
source.add_file( os.path.join(lib_json, 'json_writer.cpp') )
|
||||
source.add_text( "/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/)." )
|
||||
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_text( "" )
|
||||
source.add_text( "#include <%s>" % header_include_path )
|
||||
source.add_text( "" )
|
||||
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_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_value.cpp") )
|
||||
source.add_file( os.path.join(lib_json, "json_writer.cpp") )
|
||||
|
||||
print 'Writing amalgated source to %r' % target_source_path
|
||||
print ("Writing amalgated source to %r" % target_source_path)
|
||||
source.write_to( target_source_path )
|
||||
|
||||
def main():
|
||||
@@ -128,11 +128,11 @@ Generate a single amalgated source and header file from the sources.
|
||||
from optparse import OptionParser
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.allow_interspersed_args = False
|
||||
parser.add_option('-s', '--source', dest="target_source_path", action='store', default='dist/jsoncpp.cpp',
|
||||
parser.add_option("-s", "--source", dest="target_source_path", action="store", default="dist/jsoncpp.cpp",
|
||||
help="""Output .cpp source path. [Default: %default]""")
|
||||
parser.add_option('-i', '--include', dest="header_include_path", action='store', default='json/json.h',
|
||||
parser.add_option("-i", "--include", dest="header_include_path", action="store", default="json/json.h",
|
||||
help="""Header include path. Used to include the header from the amalgated source file. [Default: %default]""")
|
||||
parser.add_option('-t', '--top-dir', dest="top_dir", action='store', default=os.getcwd(),
|
||||
parser.add_option("-t", "--top-dir", dest="top_dir", action="store", default=os.getcwd(),
|
||||
help="""Source top-directory. [Default: %default]""")
|
||||
parser.enable_interspersed_args()
|
||||
options, args = parser.parse_args()
|
||||
@@ -141,10 +141,10 @@ Generate a single amalgated source and header file from the sources.
|
||||
target_source_path=options.target_source_path,
|
||||
header_include_path=options.header_include_path )
|
||||
if msg:
|
||||
sys.stderr.write( msg + '\n' )
|
||||
sys.stderr.write( msg + "\n" )
|
||||
sys.exit( 1 )
|
||||
else:
|
||||
print 'Source succesfully amalagated'
|
||||
|
||||
if __name__ == '__main__':
|
||||
print ("Source succesfully amalagated")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
14
dev.makefile
Normal file
14
dev.makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
all: build test-amalgamate
|
||||
|
||||
build:
|
||||
mkdir -p build/debug
|
||||
cd build/debug; cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=ON -G "Unix Makefiles" ../..
|
||||
make -C build/debug
|
||||
|
||||
# Currently, this depends on include/json/version.h generated
|
||||
# by cmake.
|
||||
test-amalgamate: build
|
||||
python2.7 amalgamate.py
|
||||
python3.4 amalgamate.py
|
||||
|
||||
.PHONY: build
|
2510
doc/doxyfile.in
2510
doc/doxyfile.in
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,3 @@
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="10%" align="left" valign="center">
|
||||
<a href="http://sourceforge.net">
|
||||
<img
|
||||
src="http://sourceforge.net/sflogo.php?group_id=144446"
|
||||
width="88" height="31" border="0" alt="SourceForge Logo"></a>
|
||||
</td>
|
||||
<td width="20%" align="left" valign="center">
|
||||
hosts this site.
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td align="right" valign="center">
|
||||
Send comments to:<br>
|
||||
<a href="mailto:jsoncpp-devel@lists.sourceforge.net">Json-cpp Developers</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -11,12 +11,12 @@ JsonCpp - JSON data format manipulation library
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="center">
|
||||
<a href="http://sourceforge.net/projects/jsoncpp/">
|
||||
<a href="https://github.com/open-source-parsers/jsoncpp">
|
||||
JsonCpp project page
|
||||
</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="center">
|
||||
<a href="http://jsoncpp.sourceforge.net">JsonCpp home page</a>
|
||||
<a href="https://github.com/open-source-parsers/jsoncpp">JsonCpp home page</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@@ -25,10 +25,11 @@ Here is an example of JSON data:
|
||||
"indent" : { "length" : 3, "use_space": true }
|
||||
}
|
||||
\endverbatim
|
||||
<code>jsoncpp</code> supports comments as <i>meta-data</i>.
|
||||
|
||||
\section _features Features
|
||||
- read and write JSON document
|
||||
- attach C and C++ style comments to element during parsing
|
||||
- attach C++ style comments to element during parsing
|
||||
- rewrite JSON document preserving original comments
|
||||
|
||||
Notes: Comments used to be supported in JSON but where removed for
|
||||
@@ -84,43 +85,35 @@ std::cout << root;
|
||||
|
||||
\section _pbuild Build instructions
|
||||
The build instructions are located in the file
|
||||
<a HREF="README.txt">README.txt</a> in the top-directory of the project.
|
||||
<a HREF="https://github.com/open-source-parsers/jsoncpp/blob/master/README.md">README.md</a> in the top-directory of the project.
|
||||
|
||||
Permanent link to the latest revision of the file in subversion:
|
||||
<a HREF="http://jsoncpp.svn.sourceforge.net/viewvc/jsoncpp/trunk/jsoncpp/README.txt?view=markup">latest README.txt</a>
|
||||
|
||||
\section _pdownload Download
|
||||
The sources can be downloaded from
|
||||
<a HREF="http://sourceforge.net/projects/jsoncpp/files/">SourceForge download page</a>.
|
||||
|
||||
The latest version of the source is available in the project's subversion repository:
|
||||
<a HREF="http://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/">
|
||||
http://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/</a>
|
||||
|
||||
To checkout the source, see the following
|
||||
<a HREF="http://sourceforge.net/scm/?type=svn&group_id=144446">instructions</a>.
|
||||
The latest version of the source is available in the project's GitHub repository:
|
||||
<a HREF="https://github.com/open-source-parsers/jsoncpp/">
|
||||
jsoncpp</a>
|
||||
|
||||
\section _news What's New?
|
||||
The description of latest changes can be found in
|
||||
<a HREF="NEWS.txt">NEWS.txt</a> in the top-directory of the project.
|
||||
|
||||
Permanent link to the latest revision of the file in subversion:
|
||||
<a HREF="http://svn.sourceforge.net/viewcvs.cgi/jsoncpp/README.txt?view=markup">latest NEWS.txt</a>
|
||||
|
||||
\section _plinks Project links
|
||||
- <a HREF="http://jsoncpp.sourceforge.net">json-cpp home</a>
|
||||
- <a HREF="http://www.sourceforge.net/projects/jsoncpp/">json-cpp sourceforge project</a>
|
||||
<a HREF="https://github.com/open-source-parsers/jsoncpp/wiki/NEWS">
|
||||
the NEWS wiki
|
||||
</a>.
|
||||
|
||||
\section _rlinks Related links
|
||||
- <a HREF="http://www.json.org/">JSON</a> Specification and alternate language implementations.
|
||||
- <a HREF="http://www.yaml.org/">YAML</a> A data format designed for human readability.
|
||||
- <a HREF="http://www.cl.cam.ac.uk/~mgk25/unicode.html">UTF-8 and Unicode FAQ</a>.
|
||||
|
||||
\section _plinks Old project links
|
||||
- <a href="https://sourceforge.net/projects/jsoncpp/">https://sourceforge.net/projects/jsoncpp/</a>
|
||||
- <a href="http://jsoncpp.sourceforge.net">http://jsoncpp.sourceforge.net</a>
|
||||
- <a href="http://sourceforge.net/projects/jsoncpp/files/">http://sourceforge.net/projects/jsoncpp/files/</a>
|
||||
- <a href="http://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/">http://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/</a>
|
||||
- <a href="http://jsoncpp.sourceforge.net/old.html">http://jsoncpp.sourceforge.net/old.html</a>
|
||||
|
||||
\section _license License
|
||||
See file <a HREF="LICENSE">LICENSE</a> in the top-directory of the project.
|
||||
See file <a href="https://github.com/open-source-parsers/jsoncpp/blob/master/LICENSE"><code>LICENSE</code></a> in the top-directory of the project.
|
||||
|
||||
Basically JsonCpp is licensed under MIT license, or public domain if desired
|
||||
and recognized in your jurisdiction.
|
||||
|
||||
\author Baptiste Lepilleur <blep@users.sourceforge.net>
|
||||
\author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
|
||||
*/
|
||||
|
@@ -1,38 +1,3 @@
|
||||
/*! \page roadmap JsonCpp roadmap
|
||||
\section ms_release Makes JsonCpp ready for release
|
||||
- Build system clean-up:
|
||||
- Fix build on Windows (shared-library build is broken)
|
||||
- Compile and run tests using shared library on Windows to ensure no JSON_API macro is missing.
|
||||
- Add enable/disable flag for static and shared library build
|
||||
- Enhance help
|
||||
- Platform portability check: (Notes: was ok on last check)
|
||||
- linux/gcc,
|
||||
- solaris/cc,
|
||||
- windows/msvc678,
|
||||
- aix/vacpp
|
||||
- Add JsonCpp version to header as numeric for use in preprocessor test
|
||||
- Remove buggy experimental hash stuff
|
||||
\section ms_strict Adds a strict mode to reader/parser
|
||||
Strict JSON support as specific in RFC 4627 (http://www.ietf.org/rfc/rfc4627.txt?number=4627).
|
||||
- Enforce only object or array as root element
|
||||
- Disable comment support
|
||||
- Get jsonchecker failing tests to pass in strict mode
|
||||
\section ms_writer Writter control
|
||||
Provides more control to determine how specific items are serialized when JSON allow choice:
|
||||
- Optionally allow escaping of non-ASCII characters using unicode escape sequence "\\u".
|
||||
- Optionally allow escaping of "/" using "\/".
|
||||
\section ms_separation Expose json reader/writer API that do not impose using Json::Value.
|
||||
Some typical use-case involve an application specific structure to/from a JSON document.
|
||||
- Event base parser to allow unserializing a Json document directly in datastructure instead of
|
||||
using the intermediate Json::Value.
|
||||
- Stream based parser to serialized a Json document without using Json::Value as input.
|
||||
- Performance oriented parser/writer:
|
||||
- Provides an event based parser. Should allow pulling & skipping events for ease of use.
|
||||
- Provides a JSON document builder: fast only.
|
||||
\section ms_perfo Performance tuning
|
||||
- Provides support for static property name definition avoiding allocation
|
||||
- Static property dictionnary can be provided to JSON reader
|
||||
- Performance scenario & benchmarking
|
||||
\section testing Testing
|
||||
- Adds more tests for unicode parsing (e.g. including surrogate and error detection).
|
||||
Moved to: https://github.com/open-source-parsers/jsoncpp/wiki/Roadmap
|
||||
*/
|
||||
|
@@ -116,7 +116,7 @@ def build_doc( options, make_release=False ):
|
||||
ok = run_doxygen( options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent )
|
||||
if not options.silent:
|
||||
print open(warning_log_path, 'rb').read()
|
||||
index_path = os.path.abspath(os.path.join(subst_keys['%HTML_OUTPUT%'], 'index.html'))
|
||||
index_path = os.path.abspath(os.path.join('doc', subst_keys['%HTML_OUTPUT%'], 'index.html'))
|
||||
print 'Generated documentation can be found in:'
|
||||
print index_path
|
||||
if options.open:
|
||||
|
@@ -1,2 +1,2 @@
|
||||
FILE(GLOB INCLUDE_FILES "json/*.h")
|
||||
INSTALL(FILES ${INCLUDE_FILES} DESTINATION include/json)
|
||||
INSTALL(FILES ${INCLUDE_FILES} DESTINATION ${INCLUDE_INSTALL_DIR}/json)
|
||||
|
@@ -4,29 +4,38 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||
# define CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include <json/config.h>
|
||||
#include "config.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
#if JSON_USE_EXCEPTION
|
||||
# include <stdexcept>
|
||||
#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw
|
||||
#define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message );
|
||||
#else // JSON_USE_EXCEPTION
|
||||
#define JSON_ASSERT( condition ) assert( condition );
|
||||
#include <stdexcept>
|
||||
#define JSON_ASSERT(condition) \
|
||||
assert(condition); // @todo <= change this into an exception throw
|
||||
#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message);
|
||||
#else // JSON_USE_EXCEPTION
|
||||
#define JSON_ASSERT(condition) assert(condition);
|
||||
|
||||
// The call to assert() will show the failure message in debug builds. In
|
||||
// release bugs we write to invalid memory in order to crash hard, so that a
|
||||
// debugger or crash reporter gets the chance to take over. We still call exit()
|
||||
// afterward in order to tell the compiler that this macro doesn't return.
|
||||
#define JSON_FAIL_MESSAGE( message ) { assert(false && message); strcpy(reinterpret_cast<char*>(666), message); exit(123); }
|
||||
#define JSON_FAIL_MESSAGE(message) \
|
||||
{ \
|
||||
assert(false&& message); \
|
||||
strcpy(reinterpret_cast<char*>(666), message); \
|
||||
exit(123); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) { JSON_FAIL_MESSAGE( message ) }
|
||||
#define JSON_ASSERT_MESSAGE(condition, message) \
|
||||
if (!(condition)) { \
|
||||
JSON_FAIL_MESSAGE(message) \
|
||||
}
|
||||
|
||||
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||
|
@@ -4,21 +4,22 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_AUTOLINK_H_INCLUDED
|
||||
# define JSON_AUTOLINK_H_INCLUDED
|
||||
#define JSON_AUTOLINK_H_INCLUDED
|
||||
|
||||
# include "config.h"
|
||||
#include "config.h"
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# include <cpptl/cpptl_autolink.h>
|
||||
# endif
|
||||
#ifdef JSON_IN_CPPTL
|
||||
#include <cpptl/cpptl_autolink.h>
|
||||
#endif
|
||||
|
||||
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
|
||||
# define CPPTL_AUTOLINK_NAME "json"
|
||||
# undef CPPTL_AUTOLINK_DLL
|
||||
# ifdef JSON_DLL
|
||||
# define CPPTL_AUTOLINK_DLL
|
||||
# endif
|
||||
# include "autolink.h"
|
||||
# endif
|
||||
#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \
|
||||
!defined(JSON_IN_CPPTL)
|
||||
#define CPPTL_AUTOLINK_NAME "json"
|
||||
#undef CPPTL_AUTOLINK_DLL
|
||||
#ifdef JSON_DLL
|
||||
#define CPPTL_AUTOLINK_DLL
|
||||
#endif
|
||||
#include "autolink.h"
|
||||
#endif
|
||||
|
||||
#endif // JSON_AUTOLINK_H_INCLUDED
|
||||
|
@@ -4,105 +4,109 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_CONFIG_H_INCLUDED
|
||||
# define JSON_CONFIG_H_INCLUDED
|
||||
#define JSON_CONFIG_H_INCLUDED
|
||||
|
||||
/// If defined, indicates that json library is embedded in CppTL library.
|
||||
//# define JSON_IN_CPPTL 1
|
||||
|
||||
/// If defined, indicates that json may leverage CppTL library
|
||||
//# define JSON_USE_CPPTL 1
|
||||
/// If defined, indicates that cpptl vector based map should be used instead of std::map
|
||||
/// If defined, indicates that cpptl vector based map should be used instead of
|
||||
/// std::map
|
||||
/// as Value container.
|
||||
//# 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
|
||||
/// 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
|
||||
// assertion macros. The default is to use exceptions.
|
||||
# ifndef JSON_USE_EXCEPTION
|
||||
# define JSON_USE_EXCEPTION 1
|
||||
# endif
|
||||
#ifndef JSON_USE_EXCEPTION
|
||||
#define JSON_USE_EXCEPTION 1
|
||||
#endif
|
||||
|
||||
/// If defined, indicates that the source file is amalgated
|
||||
/// to prevent private header inclusion.
|
||||
/// Remarks: it is automatically defined in the generated amalgated header.
|
||||
// #define JSON_IS_AMALGAMATION
|
||||
|
||||
#ifdef JSON_IN_CPPTL
|
||||
#include <cpptl/config.h>
|
||||
#ifndef JSON_USE_CPPTL
|
||||
#define JSON_USE_CPPTL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# include <cpptl/config.h>
|
||||
# ifndef JSON_USE_CPPTL
|
||||
# define JSON_USE_CPPTL 1
|
||||
# endif
|
||||
# endif
|
||||
#ifdef JSON_IN_CPPTL
|
||||
#define JSON_API CPPTL_API
|
||||
#elif defined(JSON_DLL_BUILD)
|
||||
#if defined(_MSC_VER)
|
||||
#define JSON_API __declspec(dllexport)
|
||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
#endif // if defined(_MSC_VER)
|
||||
#elif defined(JSON_DLL)
|
||||
#if defined(_MSC_VER)
|
||||
#define JSON_API __declspec(dllimport)
|
||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
#endif // if defined(_MSC_VER)
|
||||
#endif // ifdef JSON_IN_CPPTL
|
||||
#if !defined(JSON_API)
|
||||
#define JSON_API
|
||||
#endif
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# define JSON_API CPPTL_API
|
||||
# elif defined(JSON_DLL_BUILD)
|
||||
# if defined(_MSC_VER)
|
||||
# define JSON_API __declspec(dllexport)
|
||||
# define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
# endif // if defined(_MSC_VER)
|
||||
# elif defined(JSON_DLL)
|
||||
# if defined(_MSC_VER)
|
||||
# define JSON_API __declspec(dllimport)
|
||||
# define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
# endif // if defined(_MSC_VER)
|
||||
# endif // ifdef JSON_IN_CPPTL
|
||||
# if !defined(JSON_API)
|
||||
# define JSON_API
|
||||
# endif
|
||||
|
||||
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
|
||||
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
|
||||
// integer
|
||||
// Storages, and 64 bits integer support is disabled.
|
||||
// #define JSON_NO_INT64 1
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
|
||||
// Microsoft Visual Studio 6 only support conversion from __int64 to double
|
||||
// (no conversion from unsigned __int64).
|
||||
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
||||
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' characters in the debug information)
|
||||
// All projects I've ever seen with VS6 were using this globally (not bothering with pragma push/pop).
|
||||
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
|
||||
// characters in the debug information)
|
||||
// All projects I've ever seen with VS6 were using this globally (not bothering
|
||||
// with pragma push/pop).
|
||||
#pragma warning(disable : 4786)
|
||||
#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 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.
|
||||
# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||
#endif
|
||||
|
||||
#if !defined(JSONCPP_DEPRECATED)
|
||||
# define JSONCPP_DEPRECATED(message)
|
||||
#define JSONCPP_DEPRECATED(message)
|
||||
#endif // if !defined(JSONCPP_DEPRECATED)
|
||||
|
||||
namespace Json {
|
||||
typedef int Int;
|
||||
typedef unsigned int UInt;
|
||||
# if defined(JSON_NO_INT64)
|
||||
typedef int LargestInt;
|
||||
typedef unsigned int LargestUInt;
|
||||
# undef JSON_HAS_INT64
|
||||
# else // if defined(JSON_NO_INT64)
|
||||
// For Microsoft Visual use specific types as long long is not supported
|
||||
# if defined(_MSC_VER) // Microsoft Visual Studio
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
# else // if defined(_MSC_VER) // Other platforms, use long long
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
# endif // if defined(_MSC_VER)
|
||||
typedef Int64 LargestInt;
|
||||
typedef UInt64 LargestUInt;
|
||||
# define JSON_HAS_INT64
|
||||
# endif // if defined(JSON_NO_INT64)
|
||||
typedef int Int;
|
||||
typedef unsigned int UInt;
|
||||
#if defined(JSON_NO_INT64)
|
||||
typedef int LargestInt;
|
||||
typedef unsigned int LargestUInt;
|
||||
#undef JSON_HAS_INT64
|
||||
#else // if defined(JSON_NO_INT64)
|
||||
// For Microsoft Visual use specific types as long long is not supported
|
||||
#if defined(_MSC_VER) // Microsoft Visual Studio
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#else // if defined(_MSC_VER) // Other platforms, use long long
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
#endif // if defined(_MSC_VER)
|
||||
typedef Int64 LargestInt;
|
||||
typedef UInt64 LargestUInt;
|
||||
#define JSON_HAS_INT64
|
||||
#endif // if defined(JSON_NO_INT64)
|
||||
} // end namespace Json
|
||||
|
||||
|
||||
#endif // JSON_CONFIG_H_INCLUDED
|
||||
|
@@ -4,51 +4,53 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
|
||||
# define CPPTL_JSON_FEATURES_H_INCLUDED
|
||||
#define CPPTL_JSON_FEATURES_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include "forwards.h"
|
||||
#include "forwards.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Configuration passed to reader and writer.
|
||||
* This configuration object can be used to force the Reader or Writer
|
||||
* to behave in a standard conforming way.
|
||||
*/
|
||||
class JSON_API Features
|
||||
{
|
||||
public:
|
||||
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
|
||||
* - C & C++ comments are allowed
|
||||
* - Root object can be any JSON value
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features all();
|
||||
/** \brief Configuration passed to reader and writer.
|
||||
* This configuration object can be used to force the Reader or Writer
|
||||
* to behave in a standard conforming way.
|
||||
*/
|
||||
class JSON_API Features {
|
||||
public:
|
||||
/** \brief A configuration that allows all features and assumes all strings
|
||||
* are UTF-8.
|
||||
* - C & C++ comments are allowed
|
||||
* - Root object can be any JSON value
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features all();
|
||||
|
||||
/** \brief A configuration that is strictly compatible with the JSON specification.
|
||||
* - Comments are forbidden.
|
||||
* - Root object must be either an array or an object value.
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features strictMode();
|
||||
/** \brief A configuration that is strictly compatible with the JSON
|
||||
* specification.
|
||||
* - Comments are forbidden.
|
||||
* - Root object must be either an array or an object value.
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features strictMode();
|
||||
|
||||
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
||||
*/
|
||||
Features();
|
||||
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
||||
*/
|
||||
Features();
|
||||
|
||||
/// \c true if comments are allowed. Default: \c true.
|
||||
bool allowComments_;
|
||||
/// \c true if comments are allowed. Default: \c true.
|
||||
bool allowComments_;
|
||||
|
||||
/// \c true if root must be either an array or an object value. Default: \c false.
|
||||
bool strictRoot_;
|
||||
/// \c true if root must be either an array or an object value. Default: \c
|
||||
/// false.
|
||||
bool strictRoot_;
|
||||
|
||||
/// \c true if dropped null placeholders are allowed. Default: \c false.
|
||||
bool allowDroppedNullPlaceholders_;
|
||||
/// \c true if dropped null placeholders are allowed. Default: \c false.
|
||||
bool allowDroppedNullPlaceholders_;
|
||||
|
||||
/// \c true if numeric object key are allowed. Default: \c false.
|
||||
bool allowNumericKeys_;
|
||||
};
|
||||
/// \c true if numeric object key are allowed. Default: \c false.
|
||||
bool allowNumericKeys_;
|
||||
};
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
@@ -4,41 +4,40 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||
# define JSON_FORWARDS_H_INCLUDED
|
||||
#define JSON_FORWARDS_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include "config.h"
|
||||
#include "config.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
|
||||
// writer.h
|
||||
class FastWriter;
|
||||
class StyledWriter;
|
||||
// writer.h
|
||||
class FastWriter;
|
||||
class StyledWriter;
|
||||
|
||||
// reader.h
|
||||
class Reader;
|
||||
// reader.h
|
||||
class Reader;
|
||||
|
||||
// features.h
|
||||
class Features;
|
||||
// features.h
|
||||
class Features;
|
||||
|
||||
// value.h
|
||||
typedef unsigned int ArrayIndex;
|
||||
class StaticString;
|
||||
class Path;
|
||||
class PathArgument;
|
||||
class Value;
|
||||
class ValueIteratorBase;
|
||||
class ValueIterator;
|
||||
class ValueConstIterator;
|
||||
// value.h
|
||||
typedef unsigned int ArrayIndex;
|
||||
class StaticString;
|
||||
class Path;
|
||||
class PathArgument;
|
||||
class Value;
|
||||
class ValueIteratorBase;
|
||||
class ValueIterator;
|
||||
class ValueConstIterator;
|
||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
class ValueMapAllocator;
|
||||
class ValueInternalLink;
|
||||
class ValueInternalArray;
|
||||
class ValueInternalMap;
|
||||
class ValueMapAllocator;
|
||||
class ValueInternalLink;
|
||||
class ValueInternalArray;
|
||||
class ValueInternalMap;
|
||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
#endif // JSON_FORWARDS_H_INCLUDED
|
||||
|
@@ -4,12 +4,12 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_JSON_H_INCLUDED
|
||||
# define JSON_JSON_H_INCLUDED
|
||||
#define JSON_JSON_H_INCLUDED
|
||||
|
||||
# include "autolink.h"
|
||||
# include "value.h"
|
||||
# include "reader.h"
|
||||
# include "writer.h"
|
||||
# include "features.h"
|
||||
#include "autolink.h"
|
||||
#include "value.h"
|
||||
#include "reader.h"
|
||||
#include "writer.h"
|
||||
#include "features.h"
|
||||
|
||||
#endif // JSON_JSON_H_INCLUDED
|
||||
|
@@ -4,246 +4,273 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
||||
# define CPPTL_JSON_READER_H_INCLUDED
|
||||
#define CPPTL_JSON_READER_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include "features.h"
|
||||
# include "value.h"
|
||||
#include "features.h"
|
||||
#include "value.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
# include <deque>
|
||||
# include <iosfwd>
|
||||
# include <stack>
|
||||
# include <string>
|
||||
#include <deque>
|
||||
#include <iosfwd>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to be used by...
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4251)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
||||
*
|
||||
*/
|
||||
class JSON_API Reader
|
||||
{
|
||||
public:
|
||||
typedef char Char;
|
||||
typedef const Char *Location;
|
||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
|
||||
*Value.
|
||||
*
|
||||
*/
|
||||
class JSON_API Reader {
|
||||
public:
|
||||
typedef char Char;
|
||||
typedef const Char* Location;
|
||||
|
||||
/** \brief An error tagged with where in the JSON text it was encountered.
|
||||
*
|
||||
* The offsets give the [start, limit) range of bytes within the text. Note
|
||||
* that this is bytes, not codepoints.
|
||||
*
|
||||
*/
|
||||
struct StructuredError
|
||||
{
|
||||
size_t offset_start;
|
||||
size_t offset_limit;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
/** \brief Constructs a Reader allowing all features
|
||||
* for parsing.
|
||||
*/
|
||||
Reader();
|
||||
|
||||
/** \brief Constructs a Reader allowing the specified feature set
|
||||
* for parsing.
|
||||
*/
|
||||
Reader( const Features &features );
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||
* \param document UTF-8 encoded string containing the document to read.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
*/
|
||||
bool parse( const std::string &document,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read.
|
||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read.
|
||||
\ Must be >= beginDoc.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
*/
|
||||
bool parse( const char *beginDoc, const char *endDoc,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/// \brief Parse from input stream.
|
||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||
bool parse( std::istream &is,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||
* \return Formatted error message with the list of errors with their location in
|
||||
* the parsed document. An empty string is returned if no error occurred
|
||||
* during parsing.
|
||||
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
|
||||
std::string getFormatedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||
* \return Formatted error message with the list of errors with their location in
|
||||
* the parsed document. An empty string is returned if no error occurred
|
||||
* during parsing.
|
||||
*/
|
||||
std::string getFormattedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a vector of structured erros encounted while parsing.
|
||||
* \return A (possibly empty) vector of StructuredError objects. Currently
|
||||
* only one error can be returned, but the caller should tolerate multiple
|
||||
* errors. This can occur if the parser recovers from a non-fatal
|
||||
* parse error and then encounters additional errors.
|
||||
*/
|
||||
std::vector<StructuredError> getStructuredErrors() const;
|
||||
|
||||
private:
|
||||
enum TokenType
|
||||
{
|
||||
tokenEndOfStream = 0,
|
||||
tokenObjectBegin,
|
||||
tokenObjectEnd,
|
||||
tokenArrayBegin,
|
||||
tokenArrayEnd,
|
||||
tokenString,
|
||||
tokenNumber,
|
||||
tokenTrue,
|
||||
tokenFalse,
|
||||
tokenNull,
|
||||
tokenArraySeparator,
|
||||
tokenMemberSeparator,
|
||||
tokenComment,
|
||||
tokenError
|
||||
};
|
||||
|
||||
class Token
|
||||
{
|
||||
public:
|
||||
TokenType type_;
|
||||
Location start_;
|
||||
Location end_;
|
||||
};
|
||||
|
||||
class ErrorInfo
|
||||
{
|
||||
public:
|
||||
Token token_;
|
||||
std::string message_;
|
||||
Location extra_;
|
||||
};
|
||||
|
||||
typedef std::deque<ErrorInfo> Errors;
|
||||
|
||||
bool expectToken( TokenType type, Token &token, const char *message );
|
||||
bool readToken( Token &token );
|
||||
void skipSpaces();
|
||||
bool match( Location pattern,
|
||||
int patternLength );
|
||||
bool readComment();
|
||||
bool readCStyleComment();
|
||||
bool readCppStyleComment();
|
||||
bool readString();
|
||||
void readNumber();
|
||||
bool readValue();
|
||||
bool readObject( Token &token );
|
||||
bool readArray( Token &token );
|
||||
bool decodeNumber( Token &token );
|
||||
bool decodeNumber( Token &token, Value &decoded );
|
||||
bool decodeString( Token &token );
|
||||
bool decodeString( Token &token, std::string &decoded );
|
||||
bool decodeDouble( Token &token );
|
||||
bool decodeDouble( Token &token, Value &decoded );
|
||||
bool decodeUnicodeCodePoint( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode );
|
||||
bool decodeUnicodeEscapeSequence( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode );
|
||||
bool addError( const std::string &message,
|
||||
Token &token,
|
||||
Location extra = 0 );
|
||||
bool recoverFromError( TokenType skipUntilToken );
|
||||
bool addErrorAndRecover( const std::string &message,
|
||||
Token &token,
|
||||
TokenType skipUntilToken );
|
||||
void skipUntilSpace();
|
||||
Value ¤tValue();
|
||||
Char getNextChar();
|
||||
void getLocationLineAndColumn( Location location,
|
||||
int &line,
|
||||
int &column ) const;
|
||||
std::string getLocationLineAndColumn( Location location ) const;
|
||||
void addComment( Location begin,
|
||||
Location end,
|
||||
CommentPlacement placement );
|
||||
void skipCommentTokens( Token &token );
|
||||
|
||||
typedef std::stack<Value *> Nodes;
|
||||
Nodes nodes_;
|
||||
Errors errors_;
|
||||
std::string document_;
|
||||
Location begin_;
|
||||
Location end_;
|
||||
Location current_;
|
||||
Location lastValueEnd_;
|
||||
Value *lastValue_;
|
||||
std::string commentsBefore_;
|
||||
Features features_;
|
||||
bool collectComments_;
|
||||
};
|
||||
|
||||
/** \brief Read from 'sin' into 'root'.
|
||||
|
||||
Always keep comments from the input JSON.
|
||||
|
||||
This can be used to read a file into a particular sub-object.
|
||||
For example:
|
||||
\code
|
||||
Json::Value root;
|
||||
cin >> root["dir"]["file"];
|
||||
cout << root;
|
||||
\endcode
|
||||
Result:
|
||||
\verbatim
|
||||
{
|
||||
"dir": {
|
||||
"file": {
|
||||
// The input stream JSON would be nested here.
|
||||
}
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
\throw std::exception on parse error.
|
||||
\see Json::operator<<()
|
||||
/** \brief An error tagged with where in the JSON text it was encountered.
|
||||
*
|
||||
* The offsets give the [start, limit) range of bytes within the text. Note
|
||||
* that this is bytes, not codepoints.
|
||||
*
|
||||
*/
|
||||
JSON_API std::istream& operator>>( std::istream&, Value& );
|
||||
struct StructuredError {
|
||||
size_t offset_start;
|
||||
size_t offset_limit;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
/** \brief Constructs a Reader allowing all features
|
||||
* for parsing.
|
||||
*/
|
||||
Reader();
|
||||
|
||||
/** \brief Constructs a Reader allowing the specified feature set
|
||||
* for parsing.
|
||||
*/
|
||||
Reader(const Features& features);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
* document.
|
||||
* \param document UTF-8 encoded string containing the document to read.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them
|
||||
* back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if
|
||||
* Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an
|
||||
* error occurred.
|
||||
*/
|
||||
bool
|
||||
parse(const std::string& document, Value& root, bool collectComments = true);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
document.
|
||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
|
||||
document to read.
|
||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
||||
document to read.
|
||||
\ Must be >= beginDoc.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them
|
||||
back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if
|
||||
Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an
|
||||
error occurred.
|
||||
*/
|
||||
bool parse(const char* beginDoc,
|
||||
const char* endDoc,
|
||||
Value& root,
|
||||
bool collectComments = true);
|
||||
|
||||
/// \brief Parse from input stream.
|
||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||
bool parse(std::istream& is, Value& root, bool collectComments = true);
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed
|
||||
* document.
|
||||
* \return Formatted error message with the list of errors with their location
|
||||
* in
|
||||
* the parsed document. An empty string is returned if no error
|
||||
* occurred
|
||||
* during parsing.
|
||||
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
|
||||
std::string getFormatedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed
|
||||
* document.
|
||||
* \return Formatted error message with the list of errors with their location
|
||||
* in
|
||||
* the parsed document. An empty string is returned if no error
|
||||
* occurred
|
||||
* during parsing.
|
||||
*/
|
||||
std::string getFormattedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a vector of structured erros encounted while parsing.
|
||||
* \return A (possibly empty) vector of StructuredError objects. Currently
|
||||
* only one error can be returned, but the caller should tolerate
|
||||
* multiple
|
||||
* errors. This can occur if the parser recovers from a non-fatal
|
||||
* parse error and then encounters additional errors.
|
||||
*/
|
||||
std::vector<StructuredError> getStructuredErrors() const;
|
||||
|
||||
/** \brief Add a semantic error message.
|
||||
* \param value JSON Value location associated with the error
|
||||
* \param message The error message.
|
||||
* \return \c true if the error was successfully added, \c false if the
|
||||
* Value offset exceeds the document size.
|
||||
*/
|
||||
bool pushError(const Value& value, const std::string& message);
|
||||
|
||||
/** \brief Add a semantic error message with extra context.
|
||||
* \param value JSON Value location associated with the error
|
||||
* \param message The error message.
|
||||
* \param extra Additional JSON Value location to contextualize the error
|
||||
* \return \c true if the error was successfully added, \c false if either
|
||||
* Value offset exceeds the document size.
|
||||
*/
|
||||
bool pushError(const Value& value, const std::string& message, const Value& extra);
|
||||
|
||||
/** \brief Return whether there are any errors.
|
||||
* \return \c true if there are no errors to report \c false if
|
||||
* errors have occurred.
|
||||
*/
|
||||
bool good() const;
|
||||
|
||||
private:
|
||||
enum TokenType {
|
||||
tokenEndOfStream = 0,
|
||||
tokenObjectBegin,
|
||||
tokenObjectEnd,
|
||||
tokenArrayBegin,
|
||||
tokenArrayEnd,
|
||||
tokenString,
|
||||
tokenNumber,
|
||||
tokenTrue,
|
||||
tokenFalse,
|
||||
tokenNull,
|
||||
tokenArraySeparator,
|
||||
tokenMemberSeparator,
|
||||
tokenComment,
|
||||
tokenError
|
||||
};
|
||||
|
||||
class Token {
|
||||
public:
|
||||
TokenType type_;
|
||||
Location start_;
|
||||
Location end_;
|
||||
};
|
||||
|
||||
class ErrorInfo {
|
||||
public:
|
||||
Token token_;
|
||||
std::string message_;
|
||||
Location extra_;
|
||||
};
|
||||
|
||||
typedef std::deque<ErrorInfo> Errors;
|
||||
|
||||
bool expectToken(TokenType type, Token& token, const char* message);
|
||||
bool readToken(Token& token);
|
||||
void skipSpaces();
|
||||
bool match(Location pattern, int patternLength);
|
||||
bool readComment();
|
||||
bool readCStyleComment();
|
||||
bool readCppStyleComment();
|
||||
bool readString();
|
||||
void readNumber();
|
||||
bool readValue();
|
||||
bool readObject(Token& token);
|
||||
bool readArray(Token& token);
|
||||
bool decodeNumber(Token& token);
|
||||
bool decodeNumber(Token& token, Value& decoded);
|
||||
bool decodeString(Token& token);
|
||||
bool decodeString(Token& token, std::string& decoded);
|
||||
bool decodeDouble(Token& token);
|
||||
bool decodeDouble(Token& token, Value& decoded);
|
||||
bool decodeUnicodeCodePoint(Token& token,
|
||||
Location& current,
|
||||
Location end,
|
||||
unsigned int& unicode);
|
||||
bool decodeUnicodeEscapeSequence(Token& token,
|
||||
Location& current,
|
||||
Location end,
|
||||
unsigned int& unicode);
|
||||
bool addError(const std::string& message, Token& token, Location extra = 0);
|
||||
bool recoverFromError(TokenType skipUntilToken);
|
||||
bool addErrorAndRecover(const std::string& message,
|
||||
Token& token,
|
||||
TokenType skipUntilToken);
|
||||
void skipUntilSpace();
|
||||
Value& currentValue();
|
||||
Char getNextChar();
|
||||
void
|
||||
getLocationLineAndColumn(Location location, int& line, int& column) const;
|
||||
std::string getLocationLineAndColumn(Location location) const;
|
||||
void addComment(Location begin, Location end, CommentPlacement placement);
|
||||
void skipCommentTokens(Token& token);
|
||||
|
||||
typedef std::stack<Value*> Nodes;
|
||||
Nodes nodes_;
|
||||
Errors errors_;
|
||||
std::string document_;
|
||||
Location begin_;
|
||||
Location end_;
|
||||
Location current_;
|
||||
Location lastValueEnd_;
|
||||
Value* lastValue_;
|
||||
std::string commentsBefore_;
|
||||
Features features_;
|
||||
bool collectComments_;
|
||||
};
|
||||
|
||||
/** \brief Read from 'sin' into 'root'.
|
||||
|
||||
Always keep comments from the input JSON.
|
||||
|
||||
This can be used to read a file into a particular sub-object.
|
||||
For example:
|
||||
\code
|
||||
Json::Value root;
|
||||
cin >> root["dir"]["file"];
|
||||
cout << root;
|
||||
\endcode
|
||||
Result:
|
||||
\verbatim
|
||||
{
|
||||
"dir": {
|
||||
"file": {
|
||||
// The input stream JSON would be nested here.
|
||||
}
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
\throw std::exception on parse error.
|
||||
\see Json::operator<<()
|
||||
*/
|
||||
JSON_API std::istream& operator>>(std::istream&, Value&);
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
# pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
#endif // CPPTL_JSON_READER_H_INCLUDED
|
||||
|
1924
include/json/value.h
1924
include/json/value.h
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
||||
// DO NOT EDIT. This file is generated by CMake from "version"
|
||||
// DO NOT EDIT. This file is generated by CMake from "version"
|
||||
// and "version.h.in" files.
|
||||
// Run CMake configure step to update it.
|
||||
#ifndef JSON_VERSION_H_INCLUDED
|
||||
# define JSON_VERSION_H_INCLUDED
|
||||
|
||||
# define JSONCPP_VERSION_STRING "0.6.0-dev"
|
||||
# define JSONCPP_VERSION_STRING "0.7.0"
|
||||
# define JSONCPP_VERSION_MAJOR 0
|
||||
# define JSONCPP_VERSION_MINOR 6
|
||||
# define JSONCPP_VERSION_MINOR 7
|
||||
# define JSONCPP_VERSION_PATCH 0
|
||||
# define JSONCPP_VERSION_QUALIFIER -dev
|
||||
# define JSONCPP_VERSION_QUALIFIER
|
||||
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
||||
|
||||
#endif // JSON_VERSION_H_INCLUDED
|
||||
|
@@ -4,200 +4,210 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_WRITER_H_INCLUDED
|
||||
# define JSON_WRITER_H_INCLUDED
|
||||
#define JSON_WRITER_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include "value.h"
|
||||
#include "value.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
# include <vector>
|
||||
# include <string>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to be used by...
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4251)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
namespace Json {
|
||||
|
||||
class Value;
|
||||
class Value;
|
||||
|
||||
/** \brief Abstract class for writers.
|
||||
*/
|
||||
class JSON_API Writer
|
||||
{
|
||||
public:
|
||||
virtual ~Writer();
|
||||
/** \brief Abstract class for writers.
|
||||
*/
|
||||
class JSON_API Writer {
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
virtual std::string write( const Value &root ) = 0;
|
||||
};
|
||||
virtual std::string write(const Value& root) = 0;
|
||||
};
|
||||
|
||||
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
|
||||
*
|
||||
* The JSON document is written in a single line. It is not intended for 'human' consumption,
|
||||
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||
* \sa Reader, Value
|
||||
*/
|
||||
class JSON_API FastWriter : public Writer
|
||||
{
|
||||
public:
|
||||
FastWriter();
|
||||
virtual ~FastWriter(){}
|
||||
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
|
||||
*without formatting (not human friendly).
|
||||
*
|
||||
* The JSON document is written in a single line. It is not intended for 'human'
|
||||
*consumption,
|
||||
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||
* \sa Reader, Value
|
||||
*/
|
||||
class JSON_API FastWriter : public Writer {
|
||||
public:
|
||||
FastWriter();
|
||||
virtual ~FastWriter() {}
|
||||
|
||||
void enableYAMLCompatibility();
|
||||
void enableYAMLCompatibility();
|
||||
|
||||
/** \brief Drop the "null" string from the writer's output for nullValues.
|
||||
* Strictly speaking, this is not valid JSON. But when the output is being
|
||||
* fed to a browser's Javascript, it makes for smaller output and the
|
||||
* browser can handle the output just fine.
|
||||
*/
|
||||
void dropNullPlaceholders();
|
||||
/** \brief Drop the "null" string from the writer's output for nullValues.
|
||||
* Strictly speaking, this is not valid JSON. But when the output is being
|
||||
* fed to a browser's Javascript, it makes for smaller output and the
|
||||
* browser can handle the output just fine.
|
||||
*/
|
||||
void dropNullPlaceholders();
|
||||
|
||||
public: // overridden from Writer
|
||||
virtual std::string write( const Value &root );
|
||||
void omitEndingLineFeed();
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
public: // overridden from Writer
|
||||
virtual std::string write(const Value& root);
|
||||
|
||||
std::string document_;
|
||||
bool yamlCompatiblityEnabled_;
|
||||
bool dropNullPlaceholders_;
|
||||
};
|
||||
private:
|
||||
void writeValue(const Value& value);
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value types,
|
||||
* and all the values fit on one lines, then print the array on a single line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledWriter: public Writer
|
||||
{
|
||||
public:
|
||||
StyledWriter();
|
||||
virtual ~StyledWriter(){}
|
||||
std::string document_;
|
||||
bool yamlCompatiblityEnabled_;
|
||||
bool dropNullPlaceholders_;
|
||||
bool omitEndingLineFeed_;
|
||||
};
|
||||
|
||||
public: // overridden from Writer
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param root Value to serialize.
|
||||
* \return String containing the JSON document that represents the root value.
|
||||
*/
|
||||
virtual std::string write( const Value &root );
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||
*human friendly way.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per
|
||||
*line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value
|
||||
*types,
|
||||
* and all the values fit on one lines, then print the array on a single
|
||||
*line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their
|
||||
*#CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledWriter : public Writer {
|
||||
public:
|
||||
StyledWriter();
|
||||
virtual ~StyledWriter() {}
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
void writeArrayValue( const Value &value );
|
||||
bool isMultineArray( const Value &value );
|
||||
void pushValue( const std::string &value );
|
||||
void writeIndent();
|
||||
void writeWithIndent( const std::string &value );
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue( const Value &root );
|
||||
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||
bool hasCommentForValue( const Value &value );
|
||||
static std::string normalizeEOL( const std::string &text );
|
||||
public: // overridden from Writer
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param root Value to serialize.
|
||||
* \return String containing the JSON document that represents the root value.
|
||||
*/
|
||||
virtual std::string write(const Value& root);
|
||||
|
||||
typedef std::vector<std::string> ChildValues;
|
||||
private:
|
||||
void writeValue(const Value& value);
|
||||
void writeArrayValue(const Value& value);
|
||||
bool isMultineArray(const Value& value);
|
||||
void pushValue(const std::string& value);
|
||||
void writeIndent();
|
||||
void writeWithIndent(const std::string& value);
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue(const Value& root);
|
||||
void writeCommentAfterValueOnSameLine(const Value& root);
|
||||
bool hasCommentForValue(const Value& value);
|
||||
static std::string normalizeEOL(const std::string& text);
|
||||
|
||||
ChildValues childValues_;
|
||||
std::string document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
int indentSize_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
typedef std::vector<std::string> ChildValues;
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
|
||||
to a stream rather than to a string.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value types,
|
||||
* and all the values fit on one lines, then print the array on a single line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||
*
|
||||
* \param indentation Each level will be indented by this amount extra.
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledStreamWriter
|
||||
{
|
||||
public:
|
||||
StyledStreamWriter( std::string indentation="\t" );
|
||||
~StyledStreamWriter(){}
|
||||
ChildValues childValues_;
|
||||
std::string document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
int indentSize_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
|
||||
public:
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param out Stream to write to. (Can be ostringstream, e.g.)
|
||||
* \param root Value to serialize.
|
||||
* \note There is no point in deriving from Writer, since write() should not return a value.
|
||||
*/
|
||||
void write( std::ostream &out, const Value &root );
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||
human friendly way,
|
||||
to a stream rather than to a string.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per
|
||||
line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value
|
||||
types,
|
||||
* and all the values fit on one lines, then print the array on a single
|
||||
line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their
|
||||
#CommentPlacement.
|
||||
*
|
||||
* \param indentation Each level will be indented by this amount extra.
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledStreamWriter {
|
||||
public:
|
||||
StyledStreamWriter(std::string indentation = "\t");
|
||||
~StyledStreamWriter() {}
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
void writeArrayValue( const Value &value );
|
||||
bool isMultineArray( const Value &value );
|
||||
void pushValue( const std::string &value );
|
||||
void writeIndent();
|
||||
void writeWithIndent( const std::string &value );
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue( const Value &root );
|
||||
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||
bool hasCommentForValue( const Value &value );
|
||||
static std::string normalizeEOL( const std::string &text );
|
||||
public:
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param out Stream to write to. (Can be ostringstream, e.g.)
|
||||
* \param root Value to serialize.
|
||||
* \note There is no point in deriving from Writer, since write() should not
|
||||
* return a value.
|
||||
*/
|
||||
void write(std::ostream& out, const Value& root);
|
||||
|
||||
typedef std::vector<std::string> ChildValues;
|
||||
private:
|
||||
void writeValue(const Value& value);
|
||||
void writeArrayValue(const Value& value);
|
||||
bool isMultineArray(const Value& value);
|
||||
void pushValue(const std::string& value);
|
||||
void writeIndent();
|
||||
void writeWithIndent(const std::string& value);
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue(const Value& root);
|
||||
void writeCommentAfterValueOnSameLine(const Value& root);
|
||||
bool hasCommentForValue(const Value& value);
|
||||
static std::string normalizeEOL(const std::string& text);
|
||||
|
||||
ChildValues childValues_;
|
||||
std::ostream* document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
std::string indentation_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
typedef std::vector<std::string> ChildValues;
|
||||
|
||||
# if defined(JSON_HAS_INT64)
|
||||
std::string JSON_API valueToString( Int value );
|
||||
std::string JSON_API valueToString( UInt value );
|
||||
# endif // if defined(JSON_HAS_INT64)
|
||||
std::string JSON_API valueToString( LargestInt value );
|
||||
std::string JSON_API valueToString( LargestUInt value );
|
||||
std::string JSON_API valueToString( double value );
|
||||
std::string JSON_API valueToString( bool value );
|
||||
std::string JSON_API valueToQuotedString( const char *value );
|
||||
ChildValues childValues_;
|
||||
std::ostream* document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
std::string indentation_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
|
||||
/// \brief Output using the StyledStreamWriter.
|
||||
/// \see Json::operator>>()
|
||||
JSON_API std::ostream& operator<<( std::ostream&, const Value &root );
|
||||
#if defined(JSON_HAS_INT64)
|
||||
std::string JSON_API valueToString(Int value);
|
||||
std::string JSON_API valueToString(UInt value);
|
||||
#endif // if defined(JSON_HAS_INT64)
|
||||
std::string JSON_API valueToString(LargestInt value);
|
||||
std::string JSON_API valueToString(LargestUInt value);
|
||||
std::string JSON_API valueToString(double value);
|
||||
std::string JSON_API valueToString(bool value);
|
||||
std::string JSON_API valueToQuotedString(const char* value);
|
||||
|
||||
/// \brief Output using the StyledStreamWriter.
|
||||
/// \see Json::operator>>()
|
||||
JSON_API std::ostream& operator<<(std::ostream&, const Value& root);
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
# pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
#endif // JSON_WRITER_H_INCLUDED
|
||||
|
42
makefiles/msvc2010/jsoncpp.sln
Normal file
42
makefiles/msvc2010/jsoncpp.sln
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_json", "lib_json.vcxproj", "{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsontest", "jsontest.vcxproj", "{25AF2DD2-D396-4668-B188-488C33B8E620}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_lib_json", "test_lib_json.vcxproj", "{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Debug|x64.Build.0 = Debug|x64
|
||||
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Release|Win32.Build.0 = Release|Win32
|
||||
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Release|x64.ActiveCfg = Release|x64
|
||||
{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}.Release|x64.Build.0 = Release|x64
|
||||
{25AF2DD2-D396-4668-B188-488C33B8E620}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{25AF2DD2-D396-4668-B188-488C33B8E620}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{25AF2DD2-D396-4668-B188-488C33B8E620}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{25AF2DD2-D396-4668-B188-488C33B8E620}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{25AF2DD2-D396-4668-B188-488C33B8E620}.Release|Win32.Build.0 = Release|Win32
|
||||
{25AF2DD2-D396-4668-B188-488C33B8E620}.Release|x64.ActiveCfg = Release|Win32
|
||||
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release|Win32.Build.0 = Release|Win32
|
||||
{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release|x64.ActiveCfg = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
96
makefiles/msvc2010/jsontest.vcxproj
Normal file
96
makefiles/msvc2010/jsontest.vcxproj
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{25AF2DD2-D396-4668-B188-488C33B8E620}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../build/vs71/debug/jsontest\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../build/vs71/debug/jsontest\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../build/vs71/release/jsontest\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../build/vs71/release/jsontest\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OutputFile>$(OutDir)jsontest.exe</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)jsontest.pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OutputFile>$(OutDir)jsontest.exe</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\jsontestrunner\main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="lib_json.vcxproj">
|
||||
<Project>{1e6c2c1c-6453-4129-ae3f-0ee8e6599c89}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
13
makefiles/msvc2010/jsontest.vcxproj.filters
Normal file
13
makefiles/msvc2010/jsontest.vcxproj.filters
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{903591b3-ade3-4ce4-b1f9-1e175e62b014}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\jsontestrunner\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
143
makefiles/msvc2010/lib_json.vcxproj
Normal file
143
makefiles/msvc2010/lib_json.vcxproj
Normal file
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\lib_json\json_reader.cpp" />
|
||||
<ClCompile Include="..\..\src\lib_json\json_value.cpp" />
|
||||
<ClCompile Include="..\..\src\lib_json\json_writer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\json\reader.h" />
|
||||
<ClInclude Include="..\..\include\json\value.h" />
|
||||
<ClInclude Include="..\..\include\json\writer.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{1E6C2C1C-6453-4129-AE3F-0EE8E6599C89}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>jsoncpp</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
33
makefiles/msvc2010/lib_json.vcxproj.filters
Normal file
33
makefiles/msvc2010/lib_json.vcxproj.filters
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{c110bc57-c46e-476c-97ea-84d8014f431c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{ed718592-5acf-47b5-8f2b-b8224590da6a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\lib_json\json_reader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\lib_json\json_value.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\lib_json\json_writer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\json\reader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\json\value.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\json\writer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
109
makefiles/msvc2010/test_lib_json.vcxproj
Normal file
109
makefiles/msvc2010/test_lib_json.vcxproj
Normal file
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}</ProjectGuid>
|
||||
<RootNamespace>test_lib_json</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../build/vs71/debug/test_lib_json\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../build/vs71/debug/test_lib_json\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../build/vs71/release/test_lib_json\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../build/vs71/release/test_lib_json\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OutputFile>$(OutDir)test_lib_json.exe</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)test_lib_json.pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Message>Running all unit tests</Message>
|
||||
<Command>$(TargetPath)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OutputFile>$(OutDir)test_lib_json.exe</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Message>Running all unit tests</Message>
|
||||
<Command>$(TargetPath)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\test_lib_json\jsontest.cpp" />
|
||||
<ClCompile Include="..\..\src\test_lib_json\main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\test_lib_json\jsontest.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="lib_json.vcxproj">
|
||||
<Project>{1e6c2c1c-6453-4129-ae3f-0ee8e6599c89}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
24
makefiles/msvc2010/test_lib_json.vcxproj.filters
Normal file
24
makefiles/msvc2010/test_lib_json.vcxproj.filters
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\test_lib_json\jsontest.cpp">
|
||||
<Filter>Source Filter</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\test_lib_json\main.cpp">
|
||||
<Filter>Source Filter</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Filter">
|
||||
<UniqueIdentifier>{bf40cbfc-8e98-40b4-b9f3-7e8d579cbae2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{5fd39074-89e6-4939-aa3f-694fefd296b1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\test_lib_json\jsontest.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -10,6 +10,9 @@ python makerelease.py --force --retag --platform=msvc6,msvc71,msvc80,mingw -uble
|
||||
|
||||
Example of invocation when doing a release:
|
||||
python makerelease.py 0.5.0 0.6.0-dev
|
||||
|
||||
Note: This was for Subversion. Now that we are in GitHub, we do not
|
||||
need to build versioned tarballs anymore, so makerelease.py is defunct.
|
||||
"""
|
||||
import os.path
|
||||
import subprocess
|
||||
|
11
pkg-config/jsoncpp.pc.in
Normal file
11
pkg-config/jsoncpp.pc.in
Normal file
@@ -0,0 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: jsoncpp
|
||||
Description: A C++ library for interacting with JSON
|
||||
Version: @JSONCPP_VERSION@
|
||||
URL: https://github.com/open-source-parsers/jsoncpp
|
||||
Libs: -L${libdir} -ljsoncpp
|
||||
Cflags: -I${includedir}
|
@@ -12,11 +12,10 @@ SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_e
|
||||
|
||||
IF(PYTHONINTERP_FOUND)
|
||||
# Run end to end parser/writer tests
|
||||
GET_PROPERTY(JSONTESTRUNNER_EXE_PATH TARGET jsontestrunner_exe PROPERTY LOCATION)
|
||||
SET(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../test)
|
||||
SET(RUNJSONTESTS_PATH ${TEST_DIR}/runjsontests.py)
|
||||
ADD_CUSTOM_TARGET(jsoncpp_readerwriter_tests ALL
|
||||
"${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" "${JSONTESTRUNNER_EXE_PATH}" "${TEST_DIR}/data"
|
||||
"${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
|
||||
DEPENDS jsontestrunner_exe jsoncpp_test
|
||||
)
|
||||
ADD_CUSTOM_TARGET(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests)
|
||||
|
@@ -6,296 +6,272 @@
|
||||
/* This executable is used for testing parser/writer using real JSON files.
|
||||
*/
|
||||
|
||||
|
||||
#include <json/json.h>
|
||||
#include <algorithm> // sort
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
||||
# pragma warning( disable: 4996 ) // disable fopen deprecation warning
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
||||
#pragma warning(disable : 4996) // disable fopen deprecation warning
|
||||
#endif
|
||||
|
||||
static std::string
|
||||
normalizeFloatingPointStr( double value )
|
||||
{
|
||||
char buffer[32];
|
||||
static std::string normalizeFloatingPointStr(double value) {
|
||||
char buffer[32];
|
||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
||||
sprintf_s( buffer, sizeof(buffer), "%.16g", value );
|
||||
sprintf_s(buffer, sizeof(buffer), "%.16g", value);
|
||||
#else
|
||||
snprintf( buffer, sizeof(buffer), "%.16g", value );
|
||||
snprintf(buffer, sizeof(buffer), "%.16g", value);
|
||||
#endif
|
||||
buffer[sizeof(buffer)-1] = 0;
|
||||
std::string s( buffer );
|
||||
std::string::size_type index = s.find_last_of( "eE" );
|
||||
if ( index != std::string::npos )
|
||||
buffer[sizeof(buffer) - 1] = 0;
|
||||
std::string s(buffer);
|
||||
std::string::size_type index = s.find_last_of("eE");
|
||||
if (index != std::string::npos) {
|
||||
std::string::size_type hasSign =
|
||||
(s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
|
||||
std::string::size_type exponentStartIndex = index + 1 + hasSign;
|
||||
std::string normalized = s.substr(0, exponentStartIndex);
|
||||
std::string::size_type indexDigit =
|
||||
s.find_first_not_of('0', exponentStartIndex);
|
||||
std::string exponent = "0";
|
||||
if (indexDigit !=
|
||||
std::string::npos) // There is an exponent different from 0
|
||||
{
|
||||
std::string::size_type hasSign = (s[index+1] == '+' || s[index+1] == '-') ? 1 : 0;
|
||||
std::string::size_type exponentStartIndex = index + 1 + hasSign;
|
||||
std::string normalized = s.substr( 0, exponentStartIndex );
|
||||
std::string::size_type indexDigit = s.find_first_not_of( '0', exponentStartIndex );
|
||||
std::string exponent = "0";
|
||||
if ( indexDigit != std::string::npos ) // There is an exponent different from 0
|
||||
{
|
||||
exponent = s.substr( indexDigit );
|
||||
}
|
||||
return normalized + exponent;
|
||||
exponent = s.substr(indexDigit);
|
||||
}
|
||||
return s;
|
||||
return normalized + exponent;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static std::string
|
||||
readInputTestFile( const char *path )
|
||||
{
|
||||
FILE *file = fopen( path, "rb" );
|
||||
if ( !file )
|
||||
return std::string("");
|
||||
fseek( file, 0, SEEK_END );
|
||||
long size = ftell( file );
|
||||
fseek( file, 0, SEEK_SET );
|
||||
std::string text;
|
||||
char *buffer = new char[size+1];
|
||||
buffer[size] = 0;
|
||||
if ( fread( buffer, 1, size, file ) == (unsigned long)size )
|
||||
text = buffer;
|
||||
fclose( file );
|
||||
delete[] buffer;
|
||||
return text;
|
||||
static std::string readInputTestFile(const char* path) {
|
||||
FILE* file = fopen(path, "rb");
|
||||
if (!file)
|
||||
return std::string("");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
std::string text;
|
||||
char* buffer = new char[size + 1];
|
||||
buffer[size] = 0;
|
||||
if (fread(buffer, 1, size, file) == (unsigned long)size)
|
||||
text = buffer;
|
||||
fclose(file);
|
||||
delete[] buffer;
|
||||
return text;
|
||||
}
|
||||
|
||||
static void
|
||||
printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
case Json::nullValue:
|
||||
fprintf( fout, "%s=null\n", path.c_str() );
|
||||
break;
|
||||
case Json::intValue:
|
||||
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestInt() ).c_str() );
|
||||
break;
|
||||
case Json::uintValue:
|
||||
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestUInt() ).c_str() );
|
||||
break;
|
||||
case Json::realValue:
|
||||
fprintf( fout, "%s=%s\n", path.c_str(), normalizeFloatingPointStr(value.asDouble()).c_str() );
|
||||
break;
|
||||
case Json::stringValue:
|
||||
fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() );
|
||||
break;
|
||||
case Json::booleanValue:
|
||||
fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" );
|
||||
break;
|
||||
case Json::arrayValue:
|
||||
{
|
||||
fprintf( fout, "%s=[]\n", path.c_str() );
|
||||
int size = value.size();
|
||||
for ( int index =0; index < size; ++index )
|
||||
{
|
||||
static char buffer[16];
|
||||
printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
|
||||
if (value.hasComment(Json::commentBefore)) {
|
||||
fprintf(fout, "%s\n", value.getComment(Json::commentBefore).c_str());
|
||||
}
|
||||
switch (value.type()) {
|
||||
case Json::nullValue:
|
||||
fprintf(fout, "%s=null\n", path.c_str());
|
||||
break;
|
||||
case Json::intValue:
|
||||
fprintf(fout,
|
||||
"%s=%s\n",
|
||||
path.c_str(),
|
||||
Json::valueToString(value.asLargestInt()).c_str());
|
||||
break;
|
||||
case Json::uintValue:
|
||||
fprintf(fout,
|
||||
"%s=%s\n",
|
||||
path.c_str(),
|
||||
Json::valueToString(value.asLargestUInt()).c_str());
|
||||
break;
|
||||
case Json::realValue:
|
||||
fprintf(fout,
|
||||
"%s=%s\n",
|
||||
path.c_str(),
|
||||
normalizeFloatingPointStr(value.asDouble()).c_str());
|
||||
break;
|
||||
case Json::stringValue:
|
||||
fprintf(fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str());
|
||||
break;
|
||||
case Json::booleanValue:
|
||||
fprintf(fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false");
|
||||
break;
|
||||
case Json::arrayValue: {
|
||||
fprintf(fout, "%s=[]\n", path.c_str());
|
||||
int size = value.size();
|
||||
for (int index = 0; index < size; ++index) {
|
||||
static char buffer[16];
|
||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
||||
sprintf_s( buffer, sizeof(buffer), "[%d]", index );
|
||||
sprintf_s(buffer, sizeof(buffer), "[%d]", index);
|
||||
#else
|
||||
snprintf( buffer, sizeof(buffer), "[%d]", index );
|
||||
snprintf(buffer, sizeof(buffer), "[%d]", index);
|
||||
#endif
|
||||
printValueTree( fout, value[index], path + buffer );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Json::objectValue:
|
||||
{
|
||||
fprintf( fout, "%s={}\n", path.c_str() );
|
||||
Json::Value::Members members( value.getMemberNames() );
|
||||
std::sort( members.begin(), members.end() );
|
||||
std::string suffix = *(path.end()-1) == '.' ? "" : ".";
|
||||
for ( Json::Value::Members::iterator it = members.begin();
|
||||
it != members.end();
|
||||
++it )
|
||||
{
|
||||
const std::string &name = *it;
|
||||
printValueTree( fout, value[name], path + suffix + name );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printValueTree(fout, value[index], path + buffer);
|
||||
}
|
||||
} break;
|
||||
case Json::objectValue: {
|
||||
fprintf(fout, "%s={}\n", path.c_str());
|
||||
Json::Value::Members members(value.getMemberNames());
|
||||
std::sort(members.begin(), members.end());
|
||||
std::string suffix = *(path.end() - 1) == '.' ? "" : ".";
|
||||
for (Json::Value::Members::iterator it = members.begin();
|
||||
it != members.end();
|
||||
++it) {
|
||||
const std::string& name = *it;
|
||||
printValueTree(fout, value[name], path + suffix + name);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (value.hasComment(Json::commentAfter)) {
|
||||
fprintf(fout, "%s\n", value.getComment(Json::commentAfter).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static int parseAndSaveValueTree(const std::string& input,
|
||||
const std::string& actual,
|
||||
const std::string& kind,
|
||||
Json::Value& root,
|
||||
const Json::Features& features,
|
||||
bool parseOnly) {
|
||||
Json::Reader reader(features);
|
||||
bool parsingSuccessful = reader.parse(input, root);
|
||||
if (!parsingSuccessful) {
|
||||
printf("Failed to parse %s file: \n%s\n",
|
||||
kind.c_str(),
|
||||
reader.getFormattedErrorMessages().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
parseAndSaveValueTree( const std::string &input,
|
||||
const std::string &actual,
|
||||
const std::string &kind,
|
||||
Json::Value &root,
|
||||
const Json::Features &features,
|
||||
bool parseOnly )
|
||||
{
|
||||
Json::Reader reader( features );
|
||||
bool parsingSuccessful = reader.parse( input, root );
|
||||
if ( !parsingSuccessful )
|
||||
{
|
||||
printf( "Failed to parse %s file: \n%s\n",
|
||||
kind.c_str(),
|
||||
reader.getFormattedErrorMessages().c_str() );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( !parseOnly )
|
||||
{
|
||||
FILE *factual = fopen( actual.c_str(), "wt" );
|
||||
if ( !factual )
|
||||
{
|
||||
printf( "Failed to create %s actual file.\n", kind.c_str() );
|
||||
return 2;
|
||||
}
|
||||
printValueTree( factual, root );
|
||||
fclose( factual );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rewriteValueTree( const std::string &rewritePath,
|
||||
const Json::Value &root,
|
||||
std::string &rewrite )
|
||||
{
|
||||
//Json::FastWriter writer;
|
||||
//writer.enableYAMLCompatibility();
|
||||
Json::StyledWriter writer;
|
||||
rewrite = writer.write( root );
|
||||
FILE *fout = fopen( rewritePath.c_str(), "wt" );
|
||||
if ( !fout )
|
||||
{
|
||||
printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() );
|
||||
if (!parseOnly) {
|
||||
FILE* factual = fopen(actual.c_str(), "wt");
|
||||
if (!factual) {
|
||||
printf("Failed to create %s actual file.\n", kind.c_str());
|
||||
return 2;
|
||||
}
|
||||
fprintf( fout, "%s\n", rewrite.c_str() );
|
||||
fclose( fout );
|
||||
return 0;
|
||||
}
|
||||
printValueTree(factual, root);
|
||||
fclose(factual);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static std::string
|
||||
removeSuffix( const std::string &path,
|
||||
const std::string &extension )
|
||||
{
|
||||
if ( extension.length() >= path.length() )
|
||||
return std::string("");
|
||||
std::string suffix = path.substr( path.length() - extension.length() );
|
||||
if ( suffix != extension )
|
||||
return std::string("");
|
||||
return path.substr( 0, path.length() - extension.length() );
|
||||
static int rewriteValueTree(const std::string& rewritePath,
|
||||
const Json::Value& root,
|
||||
std::string& rewrite) {
|
||||
// Json::FastWriter writer;
|
||||
// writer.enableYAMLCompatibility();
|
||||
Json::StyledWriter writer;
|
||||
rewrite = writer.write(root);
|
||||
FILE* fout = fopen(rewritePath.c_str(), "wt");
|
||||
if (!fout) {
|
||||
printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
|
||||
return 2;
|
||||
}
|
||||
fprintf(fout, "%s\n", rewrite.c_str());
|
||||
fclose(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::string removeSuffix(const std::string& path,
|
||||
const std::string& extension) {
|
||||
if (extension.length() >= path.length())
|
||||
return std::string("");
|
||||
std::string suffix = path.substr(path.length() - extension.length());
|
||||
if (suffix != extension)
|
||||
return std::string("");
|
||||
return path.substr(0, path.length() - extension.length());
|
||||
}
|
||||
|
||||
static void
|
||||
printConfig()
|
||||
{
|
||||
// Print the configuration used to compile JsonCpp
|
||||
static void printConfig() {
|
||||
// Print the configuration used to compile JsonCpp
|
||||
#if defined(JSON_NO_INT64)
|
||||
printf( "JSON_NO_INT64=1\n" );
|
||||
printf("JSON_NO_INT64=1\n");
|
||||
#else
|
||||
printf( "JSON_NO_INT64=0\n" );
|
||||
printf("JSON_NO_INT64=0\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
printUsage( const char *argv[] )
|
||||
{
|
||||
printf( "Usage: %s [--strict] input-json-file", argv[0] );
|
||||
return 3;
|
||||
static int printUsage(const char* argv[]) {
|
||||
printf("Usage: %s [--strict] input-json-file", argv[0]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
int parseCommandLine(int argc,
|
||||
const char* argv[],
|
||||
Json::Features& features,
|
||||
std::string& path,
|
||||
bool& parseOnly) {
|
||||
parseOnly = false;
|
||||
if (argc < 2) {
|
||||
return printUsage(argv);
|
||||
}
|
||||
|
||||
int
|
||||
parseCommandLine( int argc, const char *argv[],
|
||||
Json::Features &features, std::string &path,
|
||||
bool &parseOnly )
|
||||
{
|
||||
parseOnly = false;
|
||||
if ( argc < 2 )
|
||||
{
|
||||
return printUsage( argv );
|
||||
}
|
||||
int index = 1;
|
||||
if (std::string(argv[1]) == "--json-checker") {
|
||||
features = Json::Features::strictMode();
|
||||
parseOnly = true;
|
||||
++index;
|
||||
}
|
||||
|
||||
int index = 1;
|
||||
if ( std::string(argv[1]) == "--json-checker" )
|
||||
{
|
||||
features = Json::Features::strictMode();
|
||||
parseOnly = true;
|
||||
++index;
|
||||
}
|
||||
if (std::string(argv[1]) == "--json-config") {
|
||||
printConfig();
|
||||
return 3;
|
||||
}
|
||||
|
||||
if ( std::string(argv[1]) == "--json-config" )
|
||||
{
|
||||
printConfig();
|
||||
if (index == argc || index + 1 < argc) {
|
||||
return printUsage(argv);
|
||||
}
|
||||
|
||||
path = argv[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
std::string path;
|
||||
Json::Features features;
|
||||
bool parseOnly;
|
||||
int exitCode = parseCommandLine(argc, argv, features, path, parseOnly);
|
||||
if (exitCode != 0) {
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
try {
|
||||
std::string input = readInputTestFile(path.c_str());
|
||||
if (input.empty()) {
|
||||
printf("Failed to read input or empty input: %s\n", path.c_str());
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
if ( index == argc || index + 1 < argc )
|
||||
{
|
||||
return printUsage( argv );
|
||||
}
|
||||
std::string basePath = removeSuffix(argv[1], ".json");
|
||||
if (!parseOnly && basePath.empty()) {
|
||||
printf("Bad input path. Path does not end with '.expected':\n%s\n",
|
||||
path.c_str());
|
||||
return 3;
|
||||
}
|
||||
|
||||
path = argv[index];
|
||||
return 0;
|
||||
std::string actualPath = basePath + ".actual";
|
||||
std::string rewritePath = basePath + ".rewrite";
|
||||
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
||||
|
||||
Json::Value root;
|
||||
exitCode = parseAndSaveValueTree(
|
||||
input, actualPath, "input", root, features, parseOnly);
|
||||
if (exitCode == 0 && !parseOnly) {
|
||||
std::string rewrite;
|
||||
exitCode = rewriteValueTree(rewritePath, root, rewrite);
|
||||
if (exitCode == 0) {
|
||||
Json::Value rewriteRoot;
|
||||
exitCode = parseAndSaveValueTree(rewrite,
|
||||
rewriteActualPath,
|
||||
"rewrite",
|
||||
rewriteRoot,
|
||||
features,
|
||||
parseOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
printf("Unhandled exception:\n%s\n", e.what());
|
||||
exitCode = 1;
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, const char *argv[] )
|
||||
{
|
||||
std::string path;
|
||||
Json::Features features;
|
||||
bool parseOnly;
|
||||
int exitCode = parseCommandLine( argc, argv, features, path, parseOnly );
|
||||
if ( exitCode != 0 )
|
||||
{
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::string input = readInputTestFile( path.c_str() );
|
||||
if ( input.empty() )
|
||||
{
|
||||
printf( "Failed to read input or empty input: %s\n", path.c_str() );
|
||||
return 3;
|
||||
}
|
||||
|
||||
std::string basePath = removeSuffix( argv[1], ".json" );
|
||||
if ( !parseOnly && basePath.empty() )
|
||||
{
|
||||
printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
|
||||
return 3;
|
||||
}
|
||||
|
||||
std::string actualPath = basePath + ".actual";
|
||||
std::string rewritePath = basePath + ".rewrite";
|
||||
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
||||
|
||||
Json::Value root;
|
||||
exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
|
||||
if ( exitCode == 0 && !parseOnly )
|
||||
{
|
||||
std::string rewrite;
|
||||
exitCode = rewriteValueTree( rewritePath, root, rewrite );
|
||||
if ( exitCode == 0 )
|
||||
{
|
||||
Json::Value rewriteRoot;
|
||||
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
|
||||
"rewrite", rewriteRoot, features, parseOnly );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
printf( "Unhandled exception:\n%s\n", e.what() );
|
||||
exitCode = 1;
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
// vim: et ts=4 sts=4 sw=4 tw=0
|
||||
|
@@ -7,6 +7,10 @@ ELSE(JSONCPP_LIB_BUILD_SHARED)
|
||||
ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
||||
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
SET( JSONCPP_INCLUDE_DIR ../../include )
|
||||
|
||||
SET( PUBLIC_HEADERS
|
||||
@@ -33,11 +37,21 @@ ADD_LIBRARY( jsoncpp_lib ${JSONCPP_LIB_TYPE}
|
||||
version.h.in
|
||||
)
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp )
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSON_CPP_VERSION} SOVERSION ${JSON_CPP_VERSION} )
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR} )
|
||||
|
||||
# Install instructions for this target
|
||||
INSTALL( TARGETS jsoncpp_lib
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
IF(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib
|
||||
PUBLIC $<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSON_INCLUDE_DIR}>
|
||||
)
|
||||
SET(INSTALL_EXPORT EXPORT jsoncpp)
|
||||
ELSE(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||
SET(INSTALL_EXPORT)
|
||||
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||
|
||||
INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT}
|
||||
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR}
|
||||
)
|
||||
|
@@ -4,12 +4,12 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
#define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
|
||||
namespace Json {
|
||||
|
||||
@@ -18,111 +18,104 @@ namespace Json {
|
||||
* 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.
|
||||
* 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
|
||||
{
|
||||
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(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; )
|
||||
~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
|
||||
{
|
||||
BatchInfo *nextBatch = batch->next_;
|
||||
free( batch );
|
||||
batch = nextBatch;
|
||||
currentBatch_ = allocateBatch(objectsPerPage_);
|
||||
currentBatch_->next_ = batches_; // insert at the head of the list
|
||||
batches_ = currentBatch_;
|
||||
}
|
||||
}
|
||||
}
|
||||
AllocatedType* allocated = currentBatch_->used_;
|
||||
currentBatch_->used_ += objectPerAllocation;
|
||||
return allocated;
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
/// 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];
|
||||
};
|
||||
struct BatchInfo {
|
||||
BatchInfo* next_;
|
||||
AllocatedType* used_;
|
||||
AllocatedType* end_;
|
||||
AllocatedType buffer_[objectPerAllocation];
|
||||
};
|
||||
|
||||
// disabled copy constructor and assignement operator.
|
||||
BatchAllocator( const BatchAllocator & );
|
||||
void operator =( const BatchAllocator &);
|
||||
// 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;
|
||||
}
|
||||
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_;
|
||||
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 // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
||||
|
||||
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
// vim: et ts=3 sts=3 sw=3 tw=0
|
||||
|
@@ -15,441 +15,346 @@ namespace Json {
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueArrayAllocator::~ValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
ValueArrayAllocator::~ValueArrayAllocator() {}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class DefaultValueArrayAllocator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||
{
|
||||
class DefaultValueArrayAllocator : public ValueArrayAllocator {
|
||||
public: // overridden from ValueArrayAllocator
|
||||
virtual ~DefaultValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
virtual ~DefaultValueArrayAllocator() {}
|
||||
|
||||
virtual ValueInternalArray *newArray()
|
||||
{
|
||||
return new ValueInternalArray();
|
||||
}
|
||||
virtual ValueInternalArray* newArray() { return new ValueInternalArray(); }
|
||||
|
||||
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||
{
|
||||
return new ValueInternalArray( other );
|
||||
}
|
||||
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
|
||||
return new ValueInternalArray(other);
|
||||
}
|
||||
|
||||
virtual void destructArray( ValueInternalArray *array )
|
||||
{
|
||||
delete array;
|
||||
}
|
||||
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 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 Value* allocateArrayPage() {
|
||||
return static_cast<Value*>(
|
||||
malloc(sizeof(Value) * ValueInternalArray::itemsPerPage));
|
||||
}
|
||||
|
||||
virtual void releaseArrayPage( Value *value )
|
||||
{
|
||||
if ( value )
|
||||
free( value );
|
||||
}
|
||||
virtual void releaseArrayPage(Value* value) {
|
||||
if (value)
|
||||
free(value);
|
||||
}
|
||||
};
|
||||
|
||||
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||
{
|
||||
class DefaultValueArrayAllocator : public ValueArrayAllocator {
|
||||
public: // overridden from ValueArrayAllocator
|
||||
virtual ~DefaultValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
virtual ~DefaultValueArrayAllocator() {}
|
||||
|
||||
virtual ValueInternalArray *newArray()
|
||||
{
|
||||
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||
new (array) ValueInternalArray(); // placement new
|
||||
return array;
|
||||
}
|
||||
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 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 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 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 Value* allocateArrayPage() {
|
||||
return static_cast<Value*>(pagesAllocator_.allocate());
|
||||
}
|
||||
|
||||
virtual void releaseArrayPage(Value* value) {
|
||||
if (value)
|
||||
pagesAllocator_.release(value);
|
||||
}
|
||||
|
||||
virtual void releaseArrayPage( Value *value )
|
||||
{
|
||||
if ( value )
|
||||
pagesAllocator_.release( value );
|
||||
}
|
||||
private:
|
||||
BatchAllocator<ValueInternalArray,1> arraysAllocator_;
|
||||
BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
|
||||
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 ValueArrayAllocator*& arrayAllocator() {
|
||||
static DefaultValueArrayAllocator defaultAllocator;
|
||||
static ValueArrayAllocator* arrayAllocator = &defaultAllocator;
|
||||
return arrayAllocator;
|
||||
}
|
||||
|
||||
static struct DummyArrayAllocatorInitializer {
|
||||
DummyArrayAllocatorInitializer()
|
||||
{
|
||||
arrayAllocator(); // ensure arrayAllocator() statics are initialized before main().
|
||||
}
|
||||
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_;
|
||||
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::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_);
|
||||
}
|
||||
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::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 );
|
||||
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::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::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_ );
|
||||
void ValueInternalArray::makeEndIterator(IteratorState& it) const {
|
||||
makeIterator(it, size_);
|
||||
}
|
||||
|
||||
ValueInternalArray::ValueInternalArray() : pages_(0), size_(0), pageCount_(0) {}
|
||||
|
||||
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( 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::operator =( const ValueInternalArray &other )
|
||||
{
|
||||
ValueInternalArray temp( other );
|
||||
swap( temp );
|
||||
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;
|
||||
}
|
||||
|
||||
ValueInternalArray::~ValueInternalArray()
|
||||
{
|
||||
// destroy all constructed items
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeBeginIterator( it);
|
||||
makeEndIterator( itEnd );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
Value *value = &dereference(it);
|
||||
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();
|
||||
}
|
||||
// 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_ );
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ValueInternalArray::clear()
|
||||
{
|
||||
ValueInternalArray dummy;
|
||||
swap( dummy );
|
||||
Value& ValueInternalArray::resolveReference(ArrayIndex index) {
|
||||
if (index >= size_)
|
||||
makeIndexValid(index);
|
||||
return pages_[index / itemsPerPage][index % itemsPerPage];
|
||||
}
|
||||
|
||||
|
||||
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 );
|
||||
Value* ValueInternalArray::find(ArrayIndex index) const {
|
||||
if (index >= size_)
|
||||
return 0;
|
||||
return &(pages_[index / itemsPerPage][index % itemsPerPage]);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
ValueInternalArray::ArrayIndex ValueInternalArray::size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
Value &
|
||||
ValueInternalArray::resolveReference( ArrayIndex index )
|
||||
{
|
||||
if ( index >= size_ )
|
||||
makeIndexValid( index );
|
||||
return pages_[index/itemsPerPage][index%itemsPerPage];
|
||||
int ValueInternalArray::distance(const IteratorState& x,
|
||||
const IteratorState& y) {
|
||||
return indexOf(y) - indexOf(x);
|
||||
}
|
||||
|
||||
Value *
|
||||
ValueInternalArray::find( ArrayIndex index ) const
|
||||
{
|
||||
if ( index >= size_ )
|
||||
return 0;
|
||||
return &(pages_[index/itemsPerPage][index%itemsPerPage]);
|
||||
ValueInternalArray::ArrayIndex
|
||||
ValueInternalArray::indexOf(const IteratorState& iterator) {
|
||||
if (!iterator.array_)
|
||||
return ArrayIndex(-1);
|
||||
return ArrayIndex((iterator.currentPageIndex_ - iterator.array_->pages_) *
|
||||
itemsPerPage +
|
||||
iterator.currentItemIndex_);
|
||||
}
|
||||
|
||||
ValueInternalArray::ArrayIndex
|
||||
ValueInternalArray::size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
int ValueInternalArray::compare(const ValueInternalArray& other) const {
|
||||
int sizeDiff(size_ - other.size_);
|
||||
if (sizeDiff != 0)
|
||||
return sizeDiff;
|
||||
|
||||
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;
|
||||
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
|
||||
// vim: et ts=3 sts=3 sw=3 tw=0
|
||||
|
@@ -15,602 +15,459 @@ namespace Json {
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
|
||||
/** \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() : 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;
|
||||
}
|
||||
}
|
||||
|
||||
ValueInternalLink::~ValueInternalLink()
|
||||
{
|
||||
for ( int index =0; index < itemPerLink; ++index )
|
||||
{
|
||||
if ( !items_[index].isItemAvailable() )
|
||||
{
|
||||
if ( !items_[index].isMemberNameStatic() )
|
||||
free( keys_[index] );
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ValueMapAllocator::~ValueMapAllocator()
|
||||
{
|
||||
}
|
||||
ValueMapAllocator::~ValueMapAllocator() {}
|
||||
|
||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||
{
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator {
|
||||
public: // overridden from ValueMapAllocator
|
||||
virtual ValueInternalMap *newMap()
|
||||
{
|
||||
return new ValueInternalMap();
|
||||
}
|
||||
virtual ValueInternalMap* newMap() { return new ValueInternalMap(); }
|
||||
|
||||
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||
{
|
||||
return new ValueInternalMap( other );
|
||||
}
|
||||
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
|
||||
return new ValueInternalMap(other);
|
||||
}
|
||||
|
||||
virtual void destructMap( ValueInternalMap *map )
|
||||
{
|
||||
delete map;
|
||||
}
|
||||
virtual void destructMap(ValueInternalMap* map) { delete map; }
|
||||
|
||||
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||
{
|
||||
return new ValueInternalLink[size];
|
||||
}
|
||||
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
|
||||
return new ValueInternalLink[size];
|
||||
}
|
||||
|
||||
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||
{
|
||||
delete [] links;
|
||||
}
|
||||
virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
|
||||
|
||||
virtual ValueInternalLink *allocateMapLink()
|
||||
{
|
||||
return new ValueInternalLink();
|
||||
}
|
||||
virtual ValueInternalLink* allocateMapLink() {
|
||||
return new ValueInternalLink();
|
||||
}
|
||||
|
||||
virtual void releaseMapLink( ValueInternalLink *link )
|
||||
{
|
||||
delete link;
|
||||
}
|
||||
virtual void releaseMapLink(ValueInternalLink* link) { delete link; }
|
||||
};
|
||||
#else
|
||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||
{
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator {
|
||||
public: // overridden from ValueMapAllocator
|
||||
virtual ValueInternalMap *newMap()
|
||||
{
|
||||
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||
new (map) ValueInternalMap(); // placement new
|
||||
return map;
|
||||
}
|
||||
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 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 void destructMap(ValueInternalMap* map) {
|
||||
if (map) {
|
||||
map->~ValueInternalMap();
|
||||
mapsAllocator_.release(map);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||
{
|
||||
return new ValueInternalLink[size];
|
||||
}
|
||||
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
|
||||
return new ValueInternalLink[size];
|
||||
}
|
||||
|
||||
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||
{
|
||||
delete [] links;
|
||||
}
|
||||
virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
|
||||
|
||||
virtual ValueInternalLink *allocateMapLink()
|
||||
{
|
||||
ValueInternalLink *link = linksAllocator_.allocate();
|
||||
memset( link, 0, sizeof(ValueInternalLink) );
|
||||
return link;
|
||||
}
|
||||
virtual ValueInternalLink* allocateMapLink() {
|
||||
ValueInternalLink* link = linksAllocator_.allocate();
|
||||
memset(link, 0, sizeof(ValueInternalLink));
|
||||
return link;
|
||||
}
|
||||
|
||||
virtual void releaseMapLink(ValueInternalLink* link) {
|
||||
link->~ValueInternalLink();
|
||||
linksAllocator_.release(link);
|
||||
}
|
||||
|
||||
virtual void releaseMapLink( ValueInternalLink *link )
|
||||
{
|
||||
link->~ValueInternalLink();
|
||||
linksAllocator_.release( link );
|
||||
}
|
||||
private:
|
||||
BatchAllocator<ValueInternalMap,1> mapsAllocator_;
|
||||
BatchAllocator<ValueInternalLink,1> linksAllocator_;
|
||||
BatchAllocator<ValueInternalMap, 1> mapsAllocator_;
|
||||
BatchAllocator<ValueInternalLink, 1> linksAllocator_;
|
||||
};
|
||||
#endif
|
||||
|
||||
static ValueMapAllocator *&mapAllocator()
|
||||
{
|
||||
static DefaultValueMapAllocator defaultAllocator;
|
||||
static ValueMapAllocator *mapAllocator = &defaultAllocator;
|
||||
return mapAllocator;
|
||||
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() {
|
||||
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.
|
||||
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 )
|
||||
{
|
||||
: 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( 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::operator =( const ValueInternalMap &other )
|
||||
{
|
||||
ValueInternalMap dummy( other );
|
||||
swap( dummy );
|
||||
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 );
|
||||
}
|
||||
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_ );
|
||||
}
|
||||
}
|
||||
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::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 );
|
||||
void ValueInternalMap::clear() {
|
||||
ValueInternalMap dummy;
|
||||
swap(dummy);
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::BucketIndex
|
||||
ValueInternalMap::size() const
|
||||
{
|
||||
return itemCount_;
|
||||
ValueInternalMap::BucketIndex ValueInternalMap::size() const {
|
||||
return itemCount_;
|
||||
}
|
||||
|
||||
bool
|
||||
ValueInternalMap::reserveDelta( BucketIndex growth )
|
||||
{
|
||||
return reserve( itemCount_ + growth );
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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];
|
||||
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];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
reserveDelta(1);
|
||||
return unsafeAdd(key, isStatic, hashedKey);
|
||||
}
|
||||
|
||||
|
||||
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];
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
reserveDelta( 1 );
|
||||
return unsafeAdd( key, isStatic, hashedKey );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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_;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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::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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ValueInternalMap::HashKey
|
||||
ValueInternalMap::hash( const char *key ) const
|
||||
{
|
||||
HashKey hash = 0;
|
||||
while ( *key )
|
||||
hash += *key++ * 37;
|
||||
return hash;
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
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::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;
|
||||
}
|
||||
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
|
||||
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::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::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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
{
|
||||
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_];
|
||||
}
|
||||
|
||||
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_];
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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
|
||||
// vim: et ts=3 sts=3 sw=3 tw=0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||
# define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||
#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||
|
||||
/* This header provides common string manipulation support, such as UTF-8,
|
||||
* portable conversion from/to string...
|
||||
@@ -15,77 +15,71 @@
|
||||
namespace Json {
|
||||
|
||||
/// Converts a unicode code-point to UTF-8.
|
||||
static inline std::string
|
||||
codePointToUTF8(unsigned int cp)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||
static inline std::string codePointToUTF8(unsigned int cp) {
|
||||
std::string result;
|
||||
|
||||
if (cp <= 0x7f)
|
||||
{
|
||||
result.resize(1);
|
||||
result[0] = static_cast<char>(cp);
|
||||
}
|
||||
else if (cp <= 0x7FF)
|
||||
{
|
||||
result.resize(2);
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||
}
|
||||
else if (cp <= 0xFFFF)
|
||||
{
|
||||
result.resize(3);
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
||||
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
||||
}
|
||||
else if (cp <= 0x10FFFF)
|
||||
{
|
||||
result.resize(4);
|
||||
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
||||
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
||||
}
|
||||
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||
|
||||
return result;
|
||||
if (cp <= 0x7f) {
|
||||
result.resize(1);
|
||||
result[0] = static_cast<char>(cp);
|
||||
} else if (cp <= 0x7FF) {
|
||||
result.resize(2);
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||
} else if (cp <= 0xFFFF) {
|
||||
result.resize(3);
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
||||
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
||||
} else if (cp <= 0x10FFFF) {
|
||||
result.resize(4);
|
||||
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
||||
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// Returns true if ch is a control character (in range [0,32[).
|
||||
static inline bool
|
||||
isControlCharacter(char ch)
|
||||
{
|
||||
return ch > 0 && ch <= 0x1F;
|
||||
}
|
||||
static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
|
||||
|
||||
|
||||
enum {
|
||||
/// Constant that specify the size of the buffer that must be passed to uintToString.
|
||||
uintToStringBufferSize = 3*sizeof(LargestUInt)+1
|
||||
enum {
|
||||
/// Constant that specify the size of the buffer that must be passed to
|
||||
/// uintToString.
|
||||
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
|
||||
};
|
||||
|
||||
// Defines a char buffer for use with uintToString().
|
||||
typedef char UIntToStringBuffer[uintToStringBufferSize];
|
||||
|
||||
|
||||
/** Converts an unsigned integer to string.
|
||||
* @param value Unsigned interger to convert to string
|
||||
* @param current Input/Output string buffer.
|
||||
* @param current Input/Output string buffer.
|
||||
* Must have at least uintToStringBufferSize chars free.
|
||||
*/
|
||||
static inline void
|
||||
uintToString( LargestUInt value,
|
||||
char *¤t )
|
||||
{
|
||||
*--current = 0;
|
||||
do
|
||||
{
|
||||
*--current = char(value % 10) + '0';
|
||||
value /= 10;
|
||||
}
|
||||
while ( value != 0 );
|
||||
static inline void uintToString(LargestUInt value, char*& current) {
|
||||
*--current = 0;
|
||||
do {
|
||||
*--current = char(value % 10) + '0';
|
||||
value /= 10;
|
||||
} while (value != 0);
|
||||
}
|
||||
|
||||
/** Change ',' to '.' everywhere in buffer.
|
||||
*
|
||||
* We had a sophisticated way, but it did not work in WinCE.
|
||||
* @see https://github.com/open-source-parsers/jsoncpp/pull/9
|
||||
*/
|
||||
static inline void fixNumericLocale(char* begin, char* end) {
|
||||
while (begin < end) {
|
||||
if (*begin == ',') {
|
||||
*begin = '.';
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Json {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -17,201 +17,165 @@ namespace Json {
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase()
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
: current_()
|
||||
, isNull_( true )
|
||||
{
|
||||
: current_(), isNull_(true) {
|
||||
}
|
||||
#else
|
||||
: isArray_( true )
|
||||
, isNull_( true )
|
||||
{
|
||||
iterator_.array_ = ValueInternalArray::IteratorState();
|
||||
: isArray_(true), isNull_(true) {
|
||||
iterator_.array_ = ValueInternalArray::IteratorState();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t )
|
||||
: current_( current )
|
||||
, isNull_( false )
|
||||
{
|
||||
}
|
||||
ValueIteratorBase::ValueIteratorBase(
|
||||
const Value::ObjectValues::iterator& current)
|
||||
: current_(current), isNull_(false) {}
|
||||
#else
|
||||
ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
|
||||
: isArray_( true )
|
||||
{
|
||||
iterator_.array_ = state;
|
||||
ValueIteratorBase::ValueIteratorBase(
|
||||
const ValueInternalArray::IteratorState& state)
|
||||
: isArray_(true) {
|
||||
iterator_.array_ = state;
|
||||
}
|
||||
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
|
||||
: isArray_( false )
|
||||
{
|
||||
iterator_.map_ = 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_ );
|
||||
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_ );
|
||||
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_ );
|
||||
if (isArray_)
|
||||
ValueInternalArray::decrement(iterator_.array_);
|
||||
ValueInternalMap::decrement(iterator_.map_);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ValueIteratorBase::difference_type
|
||||
ValueIteratorBase::computeDistance( const SelfType &other ) const
|
||||
{
|
||||
ValueIteratorBase::difference_type
|
||||
ValueIteratorBase::computeDistance(const SelfType& other) const {
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
# ifdef JSON_USE_CPPTL_SMALLMAP
|
||||
return current_ - other.current_;
|
||||
# else
|
||||
// Iterator for null value are initialized using the default
|
||||
// constructor, which initialize current_ to the default
|
||||
// std::map::iterator. As begin() and end() are two instance
|
||||
// of the default std::map::iterator, they can not be compared.
|
||||
// To allow this, we handle this comparison specifically.
|
||||
if ( isNull_ && other.isNull_ )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
|
||||
// which is the one used by default).
|
||||
// Using a portable hand-made version for non random iterator instead:
|
||||
// return difference_type( std::distance( current_, other.current_ ) );
|
||||
difference_type myDistance = 0;
|
||||
for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
|
||||
{
|
||||
++myDistance;
|
||||
}
|
||||
return myDistance;
|
||||
# endif
|
||||
#ifdef JSON_USE_CPPTL_SMALLMAP
|
||||
return current_ - other.current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
|
||||
return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
|
||||
// Iterator for null value are initialized using the default
|
||||
// constructor, which initialize current_ to the default
|
||||
// std::map::iterator. As begin() and end() are two instance
|
||||
// of the default std::map::iterator, they can not be compared.
|
||||
// To allow this, we handle this comparison specifically.
|
||||
if (isNull_ && other.isNull_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Usage of std::distance is not portable (does not compile with Sun Studio 12
|
||||
// RogueWave STL,
|
||||
// which is the one used by default).
|
||||
// Using a portable hand-made version for non random iterator instead:
|
||||
// return difference_type( std::distance( current_, other.current_ ) );
|
||||
difference_type myDistance = 0;
|
||||
for (Value::ObjectValues::iterator it = current_; it != other.current_;
|
||||
++it) {
|
||||
++myDistance;
|
||||
}
|
||||
return myDistance;
|
||||
#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_ )
|
||||
{
|
||||
return other.isNull_;
|
||||
}
|
||||
return current_ == other.current_;
|
||||
if (isNull_) {
|
||||
return other.isNull_;
|
||||
}
|
||||
return current_ == other.current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
|
||||
return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
|
||||
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_;
|
||||
isNull_ = other.isNull_;
|
||||
current_ = other.current_;
|
||||
isNull_ = other.isNull_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
iterator_.array_ = other.iterator_.array_;
|
||||
iterator_.map_ = other.iterator_.map_;
|
||||
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;
|
||||
if ( czstring.c_str() )
|
||||
{
|
||||
if ( czstring.isStaticString() )
|
||||
return Value( StaticString( czstring.c_str() ) );
|
||||
return Value( czstring.c_str() );
|
||||
}
|
||||
return Value( czstring.index() );
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
if (czstring.c_str()) {
|
||||
if (czstring.isStaticString())
|
||||
return Value(StaticString(czstring.c_str()));
|
||||
return Value(czstring.c_str());
|
||||
}
|
||||
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 );
|
||||
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;
|
||||
if ( !czstring.c_str() )
|
||||
return czstring.index();
|
||||
return Value::UInt( -1 );
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
if (!czstring.c_str())
|
||||
return czstring.index();
|
||||
return Value::UInt(-1);
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||
return Value::UInt( -1 );
|
||||
if (isArray_)
|
||||
return Value::UInt(ValueInternalArray::indexOf(iterator_.array_));
|
||||
return Value::UInt(-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ValueIteratorBase::memberName() const
|
||||
{
|
||||
const char* ValueIteratorBase::memberName() const {
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
const char *name = (*current_).first.c_str();
|
||||
return name ? name : "";
|
||||
const char* name = (*current_).first.c_str();
|
||||
return name ? name : "";
|
||||
#else
|
||||
if ( !isArray_ )
|
||||
return ValueInternalMap::key( iterator_.map_ );
|
||||
return "";
|
||||
if (!isArray_)
|
||||
return ValueInternalMap::key(iterator_.map_);
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
@@ -220,36 +184,28 @@ ValueIteratorBase::memberName() const
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueConstIterator::ValueConstIterator()
|
||||
{
|
||||
}
|
||||
|
||||
ValueConstIterator::ValueConstIterator() {}
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t )
|
||||
: ValueIteratorBase( current )
|
||||
{
|
||||
}
|
||||
ValueConstIterator::ValueConstIterator(
|
||||
const Value::ObjectValues::iterator& current)
|
||||
: ValueIteratorBase(current) {}
|
||||
#else
|
||||
ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
ValueConstIterator::ValueConstIterator(
|
||||
const ValueInternalArray::IteratorState& state)
|
||||
: ValueIteratorBase(state) {}
|
||||
|
||||
ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
ValueConstIterator::ValueConstIterator(
|
||||
const ValueInternalMap::IteratorState& state)
|
||||
: ValueIteratorBase(state) {}
|
||||
#endif
|
||||
|
||||
ValueConstIterator &
|
||||
ValueConstIterator::operator =( const ValueIteratorBase &other )
|
||||
{
|
||||
copy( other );
|
||||
return *this;
|
||||
ValueConstIterator& ValueConstIterator::
|
||||
operator=(const ValueIteratorBase& other) {
|
||||
copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
@@ -258,44 +214,28 @@ ValueConstIterator::operator =( const ValueIteratorBase &other )
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIterator::ValueIterator()
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator() {}
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t )
|
||||
: ValueIteratorBase( current )
|
||||
{
|
||||
}
|
||||
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
||||
: ValueIteratorBase(current) {}
|
||||
#else
|
||||
ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
ValueIterator::ValueIterator(const ValueInternalArray::IteratorState& state)
|
||||
: ValueIteratorBase(state) {}
|
||||
|
||||
ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
ValueIterator::ValueIterator(const ValueInternalMap::IteratorState& state)
|
||||
: ValueIteratorBase(state) {}
|
||||
#endif
|
||||
|
||||
ValueIterator::ValueIterator( const ValueConstIterator &other )
|
||||
: ValueIteratorBase( other )
|
||||
{
|
||||
}
|
||||
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
||||
: ValueIteratorBase(other) {}
|
||||
|
||||
ValueIterator::ValueIterator( const ValueIterator &other )
|
||||
: ValueIteratorBase( other )
|
||||
{
|
||||
}
|
||||
ValueIterator::ValueIterator(const ValueIterator& other)
|
||||
: ValueIteratorBase(other) {}
|
||||
|
||||
ValueIterator &
|
||||
ValueIterator::operator =( const SelfType &other )
|
||||
{
|
||||
copy( other );
|
||||
return *this;
|
||||
ValueIterator& ValueIterator::operator=(const SelfType& other) {
|
||||
copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
// vim: et ts=3 sts=3 sw=3 tw=0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
// DO NOT EDIT. This file is generated by CMake from "version"
|
||||
// DO NOT EDIT. This file is generated by CMake from "version"
|
||||
// and "version.h.in" files.
|
||||
// Run CMake configure step to update it.
|
||||
#ifndef JSON_VERSION_H_INCLUDED
|
||||
@@ -8,7 +8,7 @@
|
||||
# define JSONCPP_VERSION_MAJOR @JSONCPP_VERSION_MAJOR@
|
||||
# define JSONCPP_VERSION_MINOR @JSONCPP_VERSION_MINOR@
|
||||
# define JSONCPP_VERSION_PATCH @JSONCPP_VERSION_PATCH@
|
||||
# define JSONCPP_VERSION_QUALIFIER @JSONCPP_VERSION_QUALIFIER@
|
||||
# define JSONCPP_VERSION_QUALIFIER
|
||||
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
||||
|
||||
#endif // JSON_VERSION_H_INCLUDED
|
||||
|
@@ -15,8 +15,8 @@ TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib)
|
||||
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)
|
||||
IF(JSONCPP_WITH_POST_BUILD_UNITTEST)
|
||||
ADD_CUSTOM_COMMAND( TARGET jsoncpp_test
|
||||
POST_BUILD
|
||||
COMMAND jsoncpp_test)
|
||||
POST_BUILD
|
||||
COMMAND $<TARGET_FILE:jsoncpp_test>)
|
||||
ENDIF(JSONCPP_WITH_POST_BUILD_UNITTEST)
|
||||
|
||||
SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)
|
||||
|
@@ -10,569 +10,434 @@
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Used to install a report hook that prevent dialog on assertion and error.
|
||||
# include <crtdbg.h>
|
||||
#include <crtdbg.h>
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Used to prevent dialog on memory fault.
|
||||
// Limits headers included by Windows.h
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define NOSERVICE
|
||||
# define NOMCX
|
||||
# define NOIME
|
||||
# define NOSOUND
|
||||
# define NOCOMM
|
||||
# define NORPC
|
||||
# define NOGDI
|
||||
# define NOUSER
|
||||
# define NODRIVERS
|
||||
# define NOLOGERROR
|
||||
# define NOPROFILER
|
||||
# define NOMEMMGR
|
||||
# define NOLFILEIO
|
||||
# define NOOPENFILE
|
||||
# define NORESOURCE
|
||||
# define NOATOM
|
||||
# define NOLANGUAGE
|
||||
# define NOLSTRING
|
||||
# define NODBCS
|
||||
# define NOKEYBOARDINFO
|
||||
# define NOGDICAPMASKS
|
||||
# define NOCOLOR
|
||||
# define NOGDIOBJ
|
||||
# define NODRAWTEXT
|
||||
# define NOTEXTMETRIC
|
||||
# define NOSCALABLEFONT
|
||||
# define NOBITMAP
|
||||
# define NORASTEROPS
|
||||
# define NOMETAFILE
|
||||
# define NOSYSMETRICS
|
||||
# define NOSYSTEMPARAMSINFO
|
||||
# define NOMSG
|
||||
# define NOWINSTYLES
|
||||
# define NOWINOFFSETS
|
||||
# define NOSHOWWINDOW
|
||||
# define NODEFERWINDOWPOS
|
||||
# define NOVIRTUALKEYCODES
|
||||
# define NOKEYSTATES
|
||||
# define NOWH
|
||||
# define NOMENUS
|
||||
# define NOSCROLL
|
||||
# define NOCLIPBOARD
|
||||
# define NOICONS
|
||||
# define NOMB
|
||||
# define NOSYSCOMMANDS
|
||||
# define NOMDI
|
||||
# define NOCTLMGR
|
||||
# define NOWINMESSAGES
|
||||
# include <windows.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOSERVICE
|
||||
#define NOMCX
|
||||
#define NOIME
|
||||
#define NOSOUND
|
||||
#define NOCOMM
|
||||
#define NORPC
|
||||
#define NOGDI
|
||||
#define NOUSER
|
||||
#define NODRIVERS
|
||||
#define NOLOGERROR
|
||||
#define NOPROFILER
|
||||
#define NOMEMMGR
|
||||
#define NOLFILEIO
|
||||
#define NOOPENFILE
|
||||
#define NORESOURCE
|
||||
#define NOATOM
|
||||
#define NOLANGUAGE
|
||||
#define NOLSTRING
|
||||
#define NODBCS
|
||||
#define NOKEYBOARDINFO
|
||||
#define NOGDICAPMASKS
|
||||
#define NOCOLOR
|
||||
#define NOGDIOBJ
|
||||
#define NODRAWTEXT
|
||||
#define NOTEXTMETRIC
|
||||
#define NOSCALABLEFONT
|
||||
#define NOBITMAP
|
||||
#define NORASTEROPS
|
||||
#define NOMETAFILE
|
||||
#define NOSYSMETRICS
|
||||
#define NOSYSTEMPARAMSINFO
|
||||
#define NOMSG
|
||||
#define NOWINSTYLES
|
||||
#define NOWINOFFSETS
|
||||
#define NOSHOWWINDOW
|
||||
#define NODEFERWINDOWPOS
|
||||
#define NOVIRTUALKEYCODES
|
||||
#define NOKEYSTATES
|
||||
#define NOWH
|
||||
#define NOMENUS
|
||||
#define NOSCROLL
|
||||
#define NOCLIPBOARD
|
||||
#define NOICONS
|
||||
#define NOMB
|
||||
#define NOSYSCOMMANDS
|
||||
#define NOMDI
|
||||
#define NOCTLMGR
|
||||
#define NOWINMESSAGES
|
||||
#include <windows.h>
|
||||
#endif // if defined(_WIN32)
|
||||
|
||||
namespace JsonTest {
|
||||
|
||||
|
||||
// class TestResult
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestResult::TestResult()
|
||||
: predicateId_( 1 )
|
||||
, lastUsedPredicateId_( 0 )
|
||||
, messageTarget_( 0 )
|
||||
{
|
||||
// The root predicate has id 0
|
||||
rootPredicateNode_.id_ = 0;
|
||||
rootPredicateNode_.next_ = 0;
|
||||
predicateStackTail_ = &rootPredicateNode_;
|
||||
: predicateId_(1), lastUsedPredicateId_(0), messageTarget_(0) {
|
||||
// The root predicate has id 0
|
||||
rootPredicateNode_.id_ = 0;
|
||||
rootPredicateNode_.next_ = 0;
|
||||
predicateStackTail_ = &rootPredicateNode_;
|
||||
}
|
||||
|
||||
void TestResult::setTestName(const std::string& name) { name_ = name; }
|
||||
|
||||
void
|
||||
TestResult::setTestName( const std::string &name )
|
||||
{
|
||||
name_ = name;
|
||||
TestResult&
|
||||
TestResult::addFailure(const char* file, unsigned int line, const char* expr) {
|
||||
/// Walks the PredicateContext stack adding them to failures_ if not already
|
||||
/// added.
|
||||
unsigned int nestingLevel = 0;
|
||||
PredicateContext* lastNode = rootPredicateNode_.next_;
|
||||
for (; lastNode != 0; lastNode = lastNode->next_) {
|
||||
if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
|
||||
{
|
||||
lastUsedPredicateId_ = lastNode->id_;
|
||||
addFailureInfo(
|
||||
lastNode->file_, lastNode->line_, lastNode->expr_, nestingLevel);
|
||||
// Link the PredicateContext to the failure for message target when
|
||||
// popping the PredicateContext.
|
||||
lastNode->failure_ = &(failures_.back());
|
||||
}
|
||||
++nestingLevel;
|
||||
}
|
||||
|
||||
// Adds the failed assertion
|
||||
addFailureInfo(file, line, expr, nestingLevel);
|
||||
messageTarget_ = &(failures_.back());
|
||||
return *this;
|
||||
}
|
||||
|
||||
TestResult &
|
||||
TestResult::addFailure( const char *file, unsigned int line,
|
||||
const char *expr )
|
||||
{
|
||||
/// Walks the PredicateContext stack adding them to failures_ if not already added.
|
||||
unsigned int nestingLevel = 0;
|
||||
PredicateContext *lastNode = rootPredicateNode_.next_;
|
||||
for ( ; lastNode != 0; lastNode = lastNode->next_ )
|
||||
{
|
||||
if ( lastNode->id_ > lastUsedPredicateId_ ) // new PredicateContext
|
||||
{
|
||||
lastUsedPredicateId_ = lastNode->id_;
|
||||
addFailureInfo( lastNode->file_, lastNode->line_, lastNode->expr_,
|
||||
nestingLevel );
|
||||
// Link the PredicateContext to the failure for message target when
|
||||
// popping the PredicateContext.
|
||||
lastNode->failure_ = &( failures_.back() );
|
||||
}
|
||||
++nestingLevel;
|
||||
}
|
||||
|
||||
// Adds the failed assertion
|
||||
addFailureInfo( file, line, expr, nestingLevel );
|
||||
messageTarget_ = &( failures_.back() );
|
||||
return *this;
|
||||
void TestResult::addFailureInfo(const char* file,
|
||||
unsigned int line,
|
||||
const char* expr,
|
||||
unsigned int nestingLevel) {
|
||||
Failure failure;
|
||||
failure.file_ = file;
|
||||
failure.line_ = line;
|
||||
if (expr) {
|
||||
failure.expr_ = expr;
|
||||
}
|
||||
failure.nestingLevel_ = nestingLevel;
|
||||
failures_.push_back(failure);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::addFailureInfo( const char *file, unsigned int line,
|
||||
const char *expr, unsigned int nestingLevel )
|
||||
{
|
||||
Failure failure;
|
||||
failure.file_ = file;
|
||||
failure.line_ = line;
|
||||
if ( expr )
|
||||
{
|
||||
failure.expr_ = expr;
|
||||
}
|
||||
failure.nestingLevel_ = nestingLevel;
|
||||
failures_.push_back( failure );
|
||||
TestResult& TestResult::popPredicateContext() {
|
||||
PredicateContext* lastNode = &rootPredicateNode_;
|
||||
while (lastNode->next_ != 0 && lastNode->next_->next_ != 0) {
|
||||
lastNode = lastNode->next_;
|
||||
}
|
||||
// Set message target to popped failure
|
||||
PredicateContext* tail = lastNode->next_;
|
||||
if (tail != 0 && tail->failure_ != 0) {
|
||||
messageTarget_ = tail->failure_;
|
||||
}
|
||||
// Remove tail from list
|
||||
predicateStackTail_ = lastNode;
|
||||
lastNode->next_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool TestResult::failed() const { return !failures_.empty(); }
|
||||
|
||||
TestResult &
|
||||
TestResult::popPredicateContext()
|
||||
{
|
||||
PredicateContext *lastNode = &rootPredicateNode_;
|
||||
while ( lastNode->next_ != 0 && lastNode->next_->next_ != 0 )
|
||||
{
|
||||
lastNode = lastNode->next_;
|
||||
}
|
||||
// Set message target to popped failure
|
||||
PredicateContext *tail = lastNode->next_;
|
||||
if ( tail != 0 && tail->failure_ != 0 )
|
||||
{
|
||||
messageTarget_ = tail->failure_;
|
||||
}
|
||||
// Remove tail from list
|
||||
predicateStackTail_ = lastNode;
|
||||
lastNode->next_ = 0;
|
||||
return *this;
|
||||
unsigned int TestResult::getAssertionNestingLevel() const {
|
||||
unsigned int level = 0;
|
||||
const PredicateContext* lastNode = &rootPredicateNode_;
|
||||
while (lastNode->next_ != 0) {
|
||||
lastNode = lastNode->next_;
|
||||
++level;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
void TestResult::printFailure(bool printTestName) const {
|
||||
if (failures_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool
|
||||
TestResult::failed() const
|
||||
{
|
||||
return !failures_.empty();
|
||||
if (printTestName) {
|
||||
printf("* Detail of %s test failure:\n", name_.c_str());
|
||||
}
|
||||
|
||||
// Print in reverse to display the callstack in the right order
|
||||
Failures::const_iterator itEnd = failures_.end();
|
||||
for (Failures::const_iterator it = failures_.begin(); it != itEnd; ++it) {
|
||||
const Failure& failure = *it;
|
||||
std::string indent(failure.nestingLevel_ * 2, ' ');
|
||||
if (failure.file_) {
|
||||
printf("%s%s(%d): ", indent.c_str(), failure.file_, failure.line_);
|
||||
}
|
||||
if (!failure.expr_.empty()) {
|
||||
printf("%s\n", failure.expr_.c_str());
|
||||
} else if (failure.file_) {
|
||||
printf("\n");
|
||||
}
|
||||
if (!failure.message_.empty()) {
|
||||
std::string reindented = indentText(failure.message_, indent + " ");
|
||||
printf("%s\n", reindented.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
TestResult::getAssertionNestingLevel() const
|
||||
{
|
||||
unsigned int level = 0;
|
||||
const PredicateContext *lastNode = &rootPredicateNode_;
|
||||
while ( lastNode->next_ != 0 )
|
||||
{
|
||||
lastNode = lastNode->next_;
|
||||
++level;
|
||||
}
|
||||
return level;
|
||||
std::string TestResult::indentText(const std::string& text,
|
||||
const std::string& indent) {
|
||||
std::string reindented;
|
||||
std::string::size_type lastIndex = 0;
|
||||
while (lastIndex < text.size()) {
|
||||
std::string::size_type nextIndex = text.find('\n', lastIndex);
|
||||
if (nextIndex == std::string::npos) {
|
||||
nextIndex = text.size() - 1;
|
||||
}
|
||||
reindented += indent;
|
||||
reindented += text.substr(lastIndex, nextIndex - lastIndex + 1);
|
||||
lastIndex = nextIndex + 1;
|
||||
}
|
||||
return reindented;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::printFailure( bool printTestName ) const
|
||||
{
|
||||
if ( failures_.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( printTestName )
|
||||
{
|
||||
printf( "* Detail of %s test failure:\n", name_.c_str() );
|
||||
}
|
||||
|
||||
// Print in reverse to display the callstack in the right order
|
||||
Failures::const_iterator itEnd = failures_.end();
|
||||
for ( Failures::const_iterator it = failures_.begin(); it != itEnd; ++it )
|
||||
{
|
||||
const Failure &failure = *it;
|
||||
std::string indent( failure.nestingLevel_ * 2, ' ' );
|
||||
if ( failure.file_ )
|
||||
{
|
||||
printf( "%s%s(%d): ", indent.c_str(), failure.file_, failure.line_ );
|
||||
}
|
||||
if ( !failure.expr_.empty() )
|
||||
{
|
||||
printf( "%s\n", failure.expr_.c_str() );
|
||||
}
|
||||
else if ( failure.file_ )
|
||||
{
|
||||
printf( "\n" );
|
||||
}
|
||||
if ( !failure.message_.empty() )
|
||||
{
|
||||
std::string reindented = indentText( failure.message_, indent + " " );
|
||||
printf( "%s\n", reindented.c_str() );
|
||||
}
|
||||
}
|
||||
TestResult& TestResult::addToLastFailure(const std::string& message) {
|
||||
if (messageTarget_ != 0) {
|
||||
messageTarget_->message_ += message;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
TestResult::indentText( const std::string &text,
|
||||
const std::string &indent )
|
||||
{
|
||||
std::string reindented;
|
||||
std::string::size_type lastIndex = 0;
|
||||
while ( lastIndex < text.size() )
|
||||
{
|
||||
std::string::size_type nextIndex = text.find( '\n', lastIndex );
|
||||
if ( nextIndex == std::string::npos )
|
||||
{
|
||||
nextIndex = text.size() - 1;
|
||||
}
|
||||
reindented += indent;
|
||||
reindented += text.substr( lastIndex, nextIndex - lastIndex + 1 );
|
||||
lastIndex = nextIndex + 1;
|
||||
}
|
||||
return reindented;
|
||||
TestResult& TestResult::operator<<(Json::Int64 value) {
|
||||
return addToLastFailure(Json::valueToString(value));
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::addToLastFailure( const std::string &message )
|
||||
{
|
||||
if ( messageTarget_ != 0 )
|
||||
{
|
||||
messageTarget_->message_ += message;
|
||||
}
|
||||
return *this;
|
||||
TestResult& TestResult::operator<<(Json::UInt64 value) {
|
||||
return addToLastFailure(Json::valueToString(value));
|
||||
}
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( Json::Int64 value ) {
|
||||
return addToLastFailure( Json::valueToString(value) );
|
||||
TestResult& TestResult::operator<<(bool value) {
|
||||
return addToLastFailure(value ? "true" : "false");
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( Json::UInt64 value ) {
|
||||
return addToLastFailure( Json::valueToString(value) );
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( bool value ) {
|
||||
return addToLastFailure(value ? "true" : "false");
|
||||
}
|
||||
|
||||
|
||||
// class TestCase
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestCase::TestCase()
|
||||
: result_( 0 )
|
||||
{
|
||||
TestCase::TestCase() : result_(0) {}
|
||||
|
||||
TestCase::~TestCase() {}
|
||||
|
||||
void TestCase::run(TestResult& result) {
|
||||
result_ = &result;
|
||||
runTestCase();
|
||||
}
|
||||
|
||||
|
||||
TestCase::~TestCase()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestCase::run( TestResult &result )
|
||||
{
|
||||
result_ = &result;
|
||||
runTestCase();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// class Runner
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Runner::Runner()
|
||||
{
|
||||
Runner::Runner() {}
|
||||
|
||||
Runner& Runner::add(TestCaseFactory factory) {
|
||||
tests_.push_back(factory);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Runner &
|
||||
Runner::add( TestCaseFactory factory )
|
||||
{
|
||||
tests_.push_back( factory );
|
||||
return *this;
|
||||
unsigned int Runner::testCount() const {
|
||||
return static_cast<unsigned int>(tests_.size());
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
Runner::testCount() const
|
||||
{
|
||||
return static_cast<unsigned int>( tests_.size() );
|
||||
std::string Runner::testNameAt(unsigned int index) const {
|
||||
TestCase* test = tests_[index]();
|
||||
std::string name = test->testName();
|
||||
delete test;
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Runner::testNameAt( unsigned int index ) const
|
||||
{
|
||||
TestCase *test = tests_[index]();
|
||||
std::string name = test->testName();
|
||||
delete test;
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Runner::runTestAt( unsigned int index, TestResult &result ) const
|
||||
{
|
||||
TestCase *test = tests_[index]();
|
||||
result.setTestName( test->testName() );
|
||||
printf( "Testing %s: ", test->testName() );
|
||||
fflush( stdout );
|
||||
void Runner::runTestAt(unsigned int index, TestResult& result) const {
|
||||
TestCase* test = tests_[index]();
|
||||
result.setTestName(test->testName());
|
||||
printf("Testing %s: ", test->testName());
|
||||
fflush(stdout);
|
||||
#if JSON_USE_EXCEPTION
|
||||
try
|
||||
{
|
||||
try {
|
||||
#endif // if JSON_USE_EXCEPTION
|
||||
test->run( result );
|
||||
test->run(result);
|
||||
#if JSON_USE_EXCEPTION
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
result.addFailure( __FILE__, __LINE__,
|
||||
"Unexpected exception caught:" ) << e.what();
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
result.addFailure(__FILE__, __LINE__, "Unexpected exception caught:")
|
||||
<< e.what();
|
||||
}
|
||||
#endif // if JSON_USE_EXCEPTION
|
||||
delete test;
|
||||
const char *status = result.failed() ? "FAILED"
|
||||
: "OK";
|
||||
printf( "%s\n", status );
|
||||
fflush( stdout );
|
||||
delete test;
|
||||
const char* status = result.failed() ? "FAILED" : "OK";
|
||||
printf("%s\n", status);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
bool Runner::runAllTest(bool printSummary) const {
|
||||
unsigned int count = testCount();
|
||||
std::deque<TestResult> failures;
|
||||
for (unsigned int index = 0; index < count; ++index) {
|
||||
TestResult result;
|
||||
runTestAt(index, result);
|
||||
if (result.failed()) {
|
||||
failures.push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Runner::runAllTest( bool printSummary ) const
|
||||
{
|
||||
unsigned int count = testCount();
|
||||
std::deque<TestResult> failures;
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
TestResult result;
|
||||
runTestAt( index, result );
|
||||
if ( result.failed() )
|
||||
{
|
||||
failures.push_back( result );
|
||||
}
|
||||
}
|
||||
if (failures.empty()) {
|
||||
if (printSummary) {
|
||||
printf("All %d tests passed\n", count);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
for (unsigned int index = 0; index < failures.size(); ++index) {
|
||||
TestResult& result = failures[index];
|
||||
result.printFailure(count > 1);
|
||||
}
|
||||
|
||||
if ( failures.empty() )
|
||||
{
|
||||
if ( printSummary )
|
||||
{
|
||||
printf( "All %d tests passed\n", count );
|
||||
}
|
||||
if (printSummary) {
|
||||
unsigned int failedCount = static_cast<unsigned int>(failures.size());
|
||||
unsigned int passedCount = count - failedCount;
|
||||
printf("%d/%d tests passed (%d failure(s))\n",
|
||||
passedCount,
|
||||
count,
|
||||
failedCount);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Runner::testIndex(const std::string& testName,
|
||||
unsigned int& indexOut) const {
|
||||
unsigned int count = testCount();
|
||||
for (unsigned int index = 0; index < count; ++index) {
|
||||
if (testNameAt(index) == testName) {
|
||||
indexOut = index;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( unsigned int index = 0; index < failures.size(); ++index )
|
||||
{
|
||||
TestResult &result = failures[index];
|
||||
result.printFailure( count > 1 );
|
||||
}
|
||||
|
||||
if ( printSummary )
|
||||
{
|
||||
unsigned int failedCount = static_cast<unsigned int>( failures.size() );
|
||||
unsigned int passedCount = count - failedCount;
|
||||
printf( "%d/%d tests passed (%d failure(s))\n", passedCount, count, failedCount );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Runner::testIndex( const std::string &testName,
|
||||
unsigned int &indexOut ) const
|
||||
{
|
||||
unsigned int count = testCount();
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
if ( testNameAt(index) == testName )
|
||||
{
|
||||
indexOut = index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
void Runner::listTests() const {
|
||||
unsigned int count = testCount();
|
||||
for (unsigned int index = 0; index < count; ++index) {
|
||||
printf("%s\n", testNameAt(index).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Runner::listTests() const
|
||||
{
|
||||
unsigned int count = testCount();
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
printf( "%s\n", testNameAt( index ).c_str() );
|
||||
}
|
||||
int Runner::runCommandLine(int argc, const char* argv[]) const {
|
||||
typedef std::deque<std::string> TestNames;
|
||||
Runner subrunner;
|
||||
for (int index = 1; index < argc; ++index) {
|
||||
std::string opt = argv[index];
|
||||
if (opt == "--list-tests") {
|
||||
listTests();
|
||||
return 0;
|
||||
} else if (opt == "--test-auto") {
|
||||
preventDialogOnCrash();
|
||||
} else if (opt == "--test") {
|
||||
++index;
|
||||
if (index < argc) {
|
||||
unsigned int testNameIndex;
|
||||
if (testIndex(argv[index], testNameIndex)) {
|
||||
subrunner.add(tests_[testNameIndex]);
|
||||
} else {
|
||||
fprintf(stderr, "Test '%s' does not exist!\n", argv[index]);
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
printUsage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
printUsage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
bool succeeded;
|
||||
if (subrunner.testCount() > 0) {
|
||||
succeeded = subrunner.runAllTest(subrunner.testCount() > 1);
|
||||
} else {
|
||||
succeeded = runAllTest(true);
|
||||
}
|
||||
return succeeded ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Runner::runCommandLine( int argc, const char *argv[] ) const
|
||||
{
|
||||
typedef std::deque<std::string> TestNames;
|
||||
Runner subrunner;
|
||||
for ( int index = 1; index < argc; ++index )
|
||||
{
|
||||
std::string opt = argv[index];
|
||||
if ( opt == "--list-tests" )
|
||||
{
|
||||
listTests();
|
||||
return 0;
|
||||
}
|
||||
else if ( opt == "--test-auto" )
|
||||
{
|
||||
preventDialogOnCrash();
|
||||
}
|
||||
else if ( opt == "--test" )
|
||||
{
|
||||
++index;
|
||||
if ( index < argc )
|
||||
{
|
||||
unsigned int testNameIndex;
|
||||
if ( testIndex( argv[index], testNameIndex ) )
|
||||
{
|
||||
subrunner.add( tests_[testNameIndex] );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( stderr, "Test '%s' does not exist!\n", argv[index] );
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printUsage( argv[0] );
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printUsage( argv[0] );
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
bool succeeded;
|
||||
if ( subrunner.testCount() > 0 )
|
||||
{
|
||||
succeeded = subrunner.runAllTest( subrunner.testCount() > 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
succeeded = runAllTest( true );
|
||||
}
|
||||
return succeeded ? 0
|
||||
: 1;
|
||||
}
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
// Hook MSVCRT assertions to prevent dialog from appearing
|
||||
static int
|
||||
msvcrtSilentReportHook( int reportType, char *message, int * /*returnValue*/ )
|
||||
{
|
||||
// The default CRT handling of error and assertion is to display
|
||||
// an error dialog to the user.
|
||||
// Instead, when an error or an assertion occurs, we force the
|
||||
// application to terminate using abort() after display
|
||||
// the message on stderr.
|
||||
if ( reportType == _CRT_ERROR ||
|
||||
reportType == _CRT_ASSERT )
|
||||
{
|
||||
// calling abort() cause the ReportHook to be called
|
||||
// The following is used to detect this case and let's the
|
||||
// error handler fallback on its default behaviour (
|
||||
// display a warning message)
|
||||
static volatile bool isAborting = false;
|
||||
if ( isAborting )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
isAborting = true;
|
||||
static int
|
||||
msvcrtSilentReportHook(int reportType, char* message, int* /*returnValue*/) {
|
||||
// The default CRT handling of error and assertion is to display
|
||||
// an error dialog to the user.
|
||||
// Instead, when an error or an assertion occurs, we force the
|
||||
// application to terminate using abort() after display
|
||||
// the message on stderr.
|
||||
if (reportType == _CRT_ERROR || reportType == _CRT_ASSERT) {
|
||||
// calling abort() cause the ReportHook to be called
|
||||
// The following is used to detect this case and let's the
|
||||
// error handler fallback on its default behaviour (
|
||||
// display a warning message)
|
||||
static volatile bool isAborting = false;
|
||||
if (isAborting) {
|
||||
return TRUE;
|
||||
}
|
||||
isAborting = true;
|
||||
|
||||
fprintf( stderr, "CRT Error/Assert:\n%s\n", message );
|
||||
fflush( stderr );
|
||||
abort();
|
||||
}
|
||||
// Let's other reportType (_CRT_WARNING) be handled as they would by default
|
||||
return FALSE;
|
||||
fprintf(stderr, "CRT Error/Assert:\n%s\n", message);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
// Let's other reportType (_CRT_WARNING) be handled as they would by default
|
||||
return FALSE;
|
||||
}
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
|
||||
void
|
||||
Runner::preventDialogOnCrash()
|
||||
{
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
// Install a hook to prevent MSVCRT error and assertion from
|
||||
// popping a dialog
|
||||
// This function a NO-OP in release configuration
|
||||
// (which cause warning since msvcrtSilentReportHook is not referenced)
|
||||
_CrtSetReportHook( &msvcrtSilentReportHook );
|
||||
void Runner::preventDialogOnCrash() {
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
// Install a hook to prevent MSVCRT error and assertion from
|
||||
// popping a dialog
|
||||
// This function a NO-OP in release configuration
|
||||
// (which cause warning since msvcrtSilentReportHook is not referenced)
|
||||
_CrtSetReportHook(&msvcrtSilentReportHook);
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
// @todo investiguate this handler (for buffer overflow)
|
||||
// _set_security_error_handler
|
||||
// @todo investiguate this handler (for buffer overflow)
|
||||
// _set_security_error_handler
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Prevents the system from popping a dialog for debugging if the
|
||||
// application fails due to invalid memory access.
|
||||
SetErrorMode( SEM_FAILCRITICALERRORS
|
||||
| SEM_NOGPFAULTERRORBOX
|
||||
| SEM_NOOPENFILEERRORBOX );
|
||||
// Prevents the system from popping a dialog for debugging if the
|
||||
// application fails due to invalid memory access.
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||
SEM_NOOPENFILEERRORBOX);
|
||||
#endif // if defined(_WIN32)
|
||||
}
|
||||
|
||||
void
|
||||
Runner::printUsage( const char *appName )
|
||||
{
|
||||
printf(
|
||||
"Usage: %s [options]\n"
|
||||
"\n"
|
||||
"If --test is not specified, then all the test cases be run.\n"
|
||||
"\n"
|
||||
"Valid options:\n"
|
||||
"--list-tests: print the name of all test cases on the standard\n"
|
||||
" output and exit.\n"
|
||||
"--test TESTNAME: executes the test case with the specified name.\n"
|
||||
" May be repeated.\n"
|
||||
"--test-auto: prevent dialog prompting for debugging on crash.\n"
|
||||
, appName );
|
||||
void Runner::printUsage(const char* appName) {
|
||||
printf("Usage: %s [options]\n"
|
||||
"\n"
|
||||
"If --test is not specified, then all the test cases be run.\n"
|
||||
"\n"
|
||||
"Valid options:\n"
|
||||
"--list-tests: print the name of all test cases on the standard\n"
|
||||
" output and exit.\n"
|
||||
"--test TESTNAME: executes the test case with the specified name.\n"
|
||||
" May be repeated.\n"
|
||||
"--test-auto: prevent dialog prompting for debugging on crash.\n",
|
||||
appName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Assertion functions
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestResult &
|
||||
checkStringEqual( TestResult &result,
|
||||
const std::string &expected, const std::string &actual,
|
||||
const char *file, unsigned int line, const char *expr )
|
||||
{
|
||||
if ( expected != actual )
|
||||
{
|
||||
result.addFailure( file, line, expr );
|
||||
result << "Expected: '" << expected << "'\n";
|
||||
result << "Actual : '" << actual << "'";
|
||||
}
|
||||
return result;
|
||||
TestResult& checkStringEqual(TestResult& result,
|
||||
const std::string& expected,
|
||||
const std::string& actual,
|
||||
const char* file,
|
||||
unsigned int line,
|
||||
const char* expr) {
|
||||
if (expected != actual) {
|
||||
result.addFailure(file, line, expr);
|
||||
result << "Expected: '" << expected << "'\n";
|
||||
result << "Actual : '" << actual << "'";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace JsonTest
|
||||
// vim: et ts=4 sts=4 sw=4 tw=0
|
||||
|
@@ -4,15 +4,15 @@
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSONTEST_H_INCLUDED
|
||||
# define JSONTEST_H_INCLUDED
|
||||
#define JSONTEST_H_INCLUDED
|
||||
|
||||
# include <json/config.h>
|
||||
# include <json/value.h>
|
||||
# include <json/writer.h>
|
||||
# include <stdio.h>
|
||||
# include <deque>
|
||||
# include <sstream>
|
||||
# include <string>
|
||||
#include <json/config.h>
|
||||
#include <json/value.h>
|
||||
#include <json/writer.h>
|
||||
#include <stdio.h>
|
||||
#include <deque>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
@@ -20,8 +20,6 @@
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
/** \brief Unit testing framework.
|
||||
* \warning: all assertions are non-aborting, test case execution will continue
|
||||
* even if an assertion namespace.
|
||||
@@ -30,244 +28,253 @@
|
||||
*/
|
||||
namespace JsonTest {
|
||||
|
||||
class Failure {
|
||||
public:
|
||||
const char* file_;
|
||||
unsigned int line_;
|
||||
std::string expr_;
|
||||
std::string message_;
|
||||
unsigned int nestingLevel_;
|
||||
};
|
||||
|
||||
class Failure
|
||||
{
|
||||
public:
|
||||
const char *file_;
|
||||
unsigned int line_;
|
||||
std::string expr_;
|
||||
std::string message_;
|
||||
unsigned int nestingLevel_;
|
||||
};
|
||||
/// Context used to create the assertion callstack on failure.
|
||||
/// Must be a POD to allow inline initialisation without stepping
|
||||
/// into the debugger.
|
||||
struct PredicateContext {
|
||||
typedef unsigned int Id;
|
||||
Id id_;
|
||||
const char* file_;
|
||||
unsigned int line_;
|
||||
const char* expr_;
|
||||
PredicateContext* next_;
|
||||
/// Related Failure, set when the PredicateContext is converted
|
||||
/// into a Failure.
|
||||
Failure* failure_;
|
||||
};
|
||||
|
||||
class TestResult {
|
||||
public:
|
||||
TestResult();
|
||||
|
||||
/// Context used to create the assertion callstack on failure.
|
||||
/// Must be a POD to allow inline initialisation without stepping
|
||||
/// into the debugger.
|
||||
struct PredicateContext
|
||||
{
|
||||
typedef unsigned int Id;
|
||||
Id id_;
|
||||
const char *file_;
|
||||
unsigned int line_;
|
||||
const char *expr_;
|
||||
PredicateContext *next_;
|
||||
/// Related Failure, set when the PredicateContext is converted
|
||||
/// into a Failure.
|
||||
Failure *failure_;
|
||||
};
|
||||
/// \internal Implementation detail for assertion macros
|
||||
/// Not encapsulated to prevent step into when debugging failed assertions
|
||||
/// Incremented by one on assertion predicate entry, decreased by one
|
||||
/// by addPredicateContext().
|
||||
PredicateContext::Id predicateId_;
|
||||
|
||||
class TestResult
|
||||
{
|
||||
public:
|
||||
TestResult();
|
||||
/// \internal Implementation detail for predicate macros
|
||||
PredicateContext* predicateStackTail_;
|
||||
|
||||
/// \internal Implementation detail for assertion macros
|
||||
/// Not encapsulated to prevent step into when debugging failed assertions
|
||||
/// Incremented by one on assertion predicate entry, decreased by one
|
||||
/// by addPredicateContext().
|
||||
PredicateContext::Id predicateId_;
|
||||
void setTestName(const std::string& name);
|
||||
|
||||
/// \internal Implementation detail for predicate macros
|
||||
PredicateContext *predicateStackTail_;
|
||||
/// Adds an assertion failure.
|
||||
TestResult&
|
||||
addFailure(const char* file, unsigned int line, const char* expr = 0);
|
||||
|
||||
void setTestName( const std::string &name );
|
||||
/// Removes the last PredicateContext added to the predicate stack
|
||||
/// chained list.
|
||||
/// Next messages will be targed at the PredicateContext that was removed.
|
||||
TestResult& popPredicateContext();
|
||||
|
||||
/// Adds an assertion failure.
|
||||
TestResult &addFailure( const char *file, unsigned int line,
|
||||
const char *expr = 0 );
|
||||
bool failed() const;
|
||||
|
||||
/// Removes the last PredicateContext added to the predicate stack
|
||||
/// chained list.
|
||||
/// Next messages will be targed at the PredicateContext that was removed.
|
||||
TestResult &popPredicateContext();
|
||||
void printFailure(bool printTestName) const;
|
||||
|
||||
bool failed() const;
|
||||
// Generic operator that will work with anything ostream can deal with.
|
||||
template <typename T> TestResult& operator<<(const T& value) {
|
||||
std::ostringstream oss;
|
||||
oss.precision(16);
|
||||
oss.setf(std::ios_base::floatfield);
|
||||
oss << value;
|
||||
return addToLastFailure(oss.str());
|
||||
}
|
||||
|
||||
void printFailure( bool printTestName ) const;
|
||||
// Specialized versions.
|
||||
TestResult& operator<<(bool value);
|
||||
// std:ostream does not support 64bits integers on all STL implementation
|
||||
TestResult& operator<<(Json::Int64 value);
|
||||
TestResult& operator<<(Json::UInt64 value);
|
||||
|
||||
// Generic operator that will work with anything ostream can deal with.
|
||||
template <typename T>
|
||||
TestResult &operator << ( const T& value ) {
|
||||
std::ostringstream oss;
|
||||
oss.precision( 16 );
|
||||
oss.setf( std::ios_base::floatfield );
|
||||
oss << value;
|
||||
return addToLastFailure(oss.str());
|
||||
}
|
||||
private:
|
||||
TestResult& addToLastFailure(const std::string& message);
|
||||
unsigned int getAssertionNestingLevel() const;
|
||||
/// Adds a failure or a predicate context
|
||||
void addFailureInfo(const char* file,
|
||||
unsigned int line,
|
||||
const char* expr,
|
||||
unsigned int nestingLevel);
|
||||
static std::string indentText(const std::string& text,
|
||||
const std::string& indent);
|
||||
|
||||
// Specialized versions.
|
||||
TestResult &operator << ( bool value );
|
||||
// std:ostream does not support 64bits integers on all STL implementation
|
||||
TestResult &operator << ( Json::Int64 value );
|
||||
TestResult &operator << ( Json::UInt64 value );
|
||||
typedef std::deque<Failure> Failures;
|
||||
Failures failures_;
|
||||
std::string name_;
|
||||
PredicateContext rootPredicateNode_;
|
||||
PredicateContext::Id lastUsedPredicateId_;
|
||||
/// Failure which is the target of the messages added using operator <<
|
||||
Failure* messageTarget_;
|
||||
};
|
||||
|
||||
private:
|
||||
TestResult &addToLastFailure( const std::string &message );
|
||||
unsigned int getAssertionNestingLevel() const;
|
||||
/// Adds a failure or a predicate context
|
||||
void addFailureInfo( const char *file, unsigned int line,
|
||||
const char *expr, unsigned int nestingLevel );
|
||||
static std::string indentText( const std::string &text,
|
||||
const std::string &indent );
|
||||
class TestCase {
|
||||
public:
|
||||
TestCase();
|
||||
|
||||
typedef std::deque<Failure> Failures;
|
||||
Failures failures_;
|
||||
std::string name_;
|
||||
PredicateContext rootPredicateNode_;
|
||||
PredicateContext::Id lastUsedPredicateId_;
|
||||
/// Failure which is the target of the messages added using operator <<
|
||||
Failure *messageTarget_;
|
||||
};
|
||||
virtual ~TestCase();
|
||||
|
||||
void run(TestResult& result);
|
||||
|
||||
class TestCase
|
||||
{
|
||||
public:
|
||||
TestCase();
|
||||
virtual const char* testName() const = 0;
|
||||
|
||||
virtual ~TestCase();
|
||||
protected:
|
||||
TestResult* result_;
|
||||
|
||||
void run( TestResult &result );
|
||||
private:
|
||||
virtual void runTestCase() = 0;
|
||||
};
|
||||
|
||||
virtual const char *testName() const = 0;
|
||||
/// Function pointer type for TestCase factory
|
||||
typedef TestCase* (*TestCaseFactory)();
|
||||
|
||||
protected:
|
||||
TestResult *result_;
|
||||
class Runner {
|
||||
public:
|
||||
Runner();
|
||||
|
||||
private:
|
||||
virtual void runTestCase() = 0;
|
||||
};
|
||||
/// Adds a test to the suite
|
||||
Runner& add(TestCaseFactory factory);
|
||||
|
||||
/// Function pointer type for TestCase factory
|
||||
typedef TestCase *(*TestCaseFactory)();
|
||||
/// Runs test as specified on the command-line
|
||||
/// If no command-line arguments are provided, run all tests.
|
||||
/// If --list-tests is provided, then print the list of all test cases
|
||||
/// If --test <testname> is provided, then run test testname.
|
||||
int runCommandLine(int argc, const char* argv[]) const;
|
||||
|
||||
class Runner
|
||||
{
|
||||
public:
|
||||
Runner();
|
||||
/// Runs all the test cases
|
||||
bool runAllTest(bool printSummary) const;
|
||||
|
||||
/// Adds a test to the suite
|
||||
Runner &add( TestCaseFactory factory );
|
||||
/// Returns the number of test case in the suite
|
||||
unsigned int testCount() const;
|
||||
|
||||
/// Runs test as specified on the command-line
|
||||
/// If no command-line arguments are provided, run all tests.
|
||||
/// If --list-tests is provided, then print the list of all test cases
|
||||
/// If --test <testname> is provided, then run test testname.
|
||||
int runCommandLine( int argc, const char *argv[] ) const;
|
||||
/// Returns the name of the test case at the specified index
|
||||
std::string testNameAt(unsigned int index) const;
|
||||
|
||||
/// Runs all the test cases
|
||||
bool runAllTest( bool printSummary ) const;
|
||||
/// Runs the test case at the specified index using the specified TestResult
|
||||
void runTestAt(unsigned int index, TestResult& result) const;
|
||||
|
||||
/// Returns the number of test case in the suite
|
||||
unsigned int testCount() const;
|
||||
static void printUsage(const char* appName);
|
||||
|
||||
/// Returns the name of the test case at the specified index
|
||||
std::string testNameAt( unsigned int index ) const;
|
||||
private: // prevents copy construction and assignment
|
||||
Runner(const Runner& other);
|
||||
Runner& operator=(const Runner& other);
|
||||
|
||||
/// Runs the test case at the specified index using the specified TestResult
|
||||
void runTestAt( unsigned int index, TestResult &result ) const;
|
||||
private:
|
||||
void listTests() const;
|
||||
bool testIndex(const std::string& testName, unsigned int& index) const;
|
||||
static void preventDialogOnCrash();
|
||||
|
||||
static void printUsage( const char *appName );
|
||||
private:
|
||||
typedef std::deque<TestCaseFactory> Factories;
|
||||
Factories tests_;
|
||||
};
|
||||
|
||||
private: // prevents copy construction and assignment
|
||||
Runner( const Runner &other );
|
||||
Runner &operator =( const Runner &other );
|
||||
template <typename T, typename U>
|
||||
TestResult& checkEqual(TestResult& result,
|
||||
const T& expected,
|
||||
const U& actual,
|
||||
const char* file,
|
||||
unsigned int line,
|
||||
const char* expr) {
|
||||
if (static_cast<U>(expected) != actual) {
|
||||
result.addFailure(file, line, expr);
|
||||
result << "Expected: " << static_cast<U>(expected) << "\n";
|
||||
result << "Actual : " << actual;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
void listTests() const;
|
||||
bool testIndex( const std::string &testName, unsigned int &index ) const;
|
||||
static void preventDialogOnCrash();
|
||||
|
||||
private:
|
||||
typedef std::deque<TestCaseFactory> Factories;
|
||||
Factories tests_;
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
TestResult &
|
||||
checkEqual( TestResult &result, const T &expected, const U &actual,
|
||||
const char *file, unsigned int line, const char *expr )
|
||||
{
|
||||
if ( static_cast< U >( expected ) != actual )
|
||||
{
|
||||
result.addFailure( file, line, expr );
|
||||
result << "Expected: " << static_cast< U >( expected ) << "\n";
|
||||
result << "Actual : " << actual;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
checkStringEqual( TestResult &result,
|
||||
const std::string &expected, const std::string &actual,
|
||||
const char *file, unsigned int line, const char *expr );
|
||||
TestResult& checkStringEqual(TestResult& result,
|
||||
const std::string& expected,
|
||||
const std::string& actual,
|
||||
const char* file,
|
||||
unsigned int line,
|
||||
const char* expr);
|
||||
|
||||
} // namespace JsonTest
|
||||
|
||||
|
||||
/// \brief Asserts that the given expression is true.
|
||||
/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
|
||||
/// JSONTEST_ASSERT( x == y );
|
||||
#define JSONTEST_ASSERT( expr ) \
|
||||
if ( expr ) \
|
||||
{ \
|
||||
} \
|
||||
else \
|
||||
result_->addFailure( __FILE__, __LINE__, #expr )
|
||||
#define JSONTEST_ASSERT(expr) \
|
||||
if (expr) { \
|
||||
} else \
|
||||
result_->addFailure(__FILE__, __LINE__, #expr)
|
||||
|
||||
/// \brief Asserts that the given predicate is true.
|
||||
/// The predicate may do other assertions and be a member function of the fixture.
|
||||
#define JSONTEST_ASSERT_PRED( expr ) \
|
||||
{ \
|
||||
JsonTest::PredicateContext _minitest_Context = { \
|
||||
result_->predicateId_, __FILE__, __LINE__, #expr }; \
|
||||
result_->predicateStackTail_->next_ = &_minitest_Context; \
|
||||
result_->predicateId_ += 1; \
|
||||
result_->predicateStackTail_ = &_minitest_Context; \
|
||||
(expr); \
|
||||
result_->popPredicateContext(); \
|
||||
}
|
||||
/// The predicate may do other assertions and be a member function of the
|
||||
/// fixture.
|
||||
#define JSONTEST_ASSERT_PRED(expr) \
|
||||
{ \
|
||||
JsonTest::PredicateContext _minitest_Context = { \
|
||||
result_->predicateId_, __FILE__, __LINE__, #expr \
|
||||
}; \
|
||||
result_->predicateStackTail_->next_ = &_minitest_Context; \
|
||||
result_->predicateId_ += 1; \
|
||||
result_->predicateStackTail_ = &_minitest_Context; \
|
||||
(expr); \
|
||||
result_->popPredicateContext(); \
|
||||
}
|
||||
|
||||
/// \brief Asserts that two values are equals.
|
||||
#define JSONTEST_ASSERT_EQUAL( expected, actual ) \
|
||||
JsonTest::checkEqual( *result_, expected, actual, \
|
||||
__FILE__, __LINE__, \
|
||||
#expected " == " #actual )
|
||||
#define JSONTEST_ASSERT_EQUAL(expected, actual) \
|
||||
JsonTest::checkEqual(*result_, \
|
||||
expected, \
|
||||
actual, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
#expected " == " #actual)
|
||||
|
||||
/// \brief Asserts that two values are equals.
|
||||
#define JSONTEST_ASSERT_STRING_EQUAL( expected, actual ) \
|
||||
JsonTest::checkStringEqual( *result_, \
|
||||
std::string(expected), std::string(actual), \
|
||||
__FILE__, __LINE__, \
|
||||
#expected " == " #actual )
|
||||
#define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \
|
||||
JsonTest::checkStringEqual(*result_, \
|
||||
std::string(expected), \
|
||||
std::string(actual), \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
#expected " == " #actual)
|
||||
|
||||
/// \brief Asserts that a given expression throws an exception
|
||||
#define JSONTEST_ASSERT_THROWS(expr) \
|
||||
{ \
|
||||
bool _threw = false; \
|
||||
try { \
|
||||
expr; \
|
||||
} \
|
||||
catch (...) { \
|
||||
_threw = true; \
|
||||
} \
|
||||
if (!_threw) \
|
||||
result_->addFailure( \
|
||||
__FILE__, __LINE__, "expected exception thrown: " #expr); \
|
||||
}
|
||||
|
||||
/// \brief Begin a fixture test case.
|
||||
#define JSONTEST_FIXTURE( FixtureType, name ) \
|
||||
class Test##FixtureType##name : public FixtureType \
|
||||
{ \
|
||||
public: \
|
||||
static JsonTest::TestCase *factory() \
|
||||
{ \
|
||||
return new Test##FixtureType##name(); \
|
||||
} \
|
||||
public: /* overidden from TestCase */ \
|
||||
virtual const char *testName() const \
|
||||
{ \
|
||||
return #FixtureType "/" #name; \
|
||||
} \
|
||||
virtual void runTestCase(); \
|
||||
}; \
|
||||
\
|
||||
void Test##FixtureType##name::runTestCase()
|
||||
#define JSONTEST_FIXTURE(FixtureType, name) \
|
||||
class Test##FixtureType##name : public FixtureType { \
|
||||
public: \
|
||||
static JsonTest::TestCase* factory() { \
|
||||
return new Test##FixtureType##name(); \
|
||||
} \
|
||||
\
|
||||
public: /* overidden from TestCase */ \
|
||||
virtual const char* testName() const { return #FixtureType "/" #name; } \
|
||||
virtual void runTestCase(); \
|
||||
}; \
|
||||
\
|
||||
void Test##FixtureType##name::runTestCase()
|
||||
|
||||
#define JSONTEST_FIXTURE_FACTORY( FixtureType, name ) \
|
||||
&Test##FixtureType##name::factory
|
||||
#define JSONTEST_FIXTURE_FACTORY(FixtureType, name) \
|
||||
&Test##FixtureType##name::factory
|
||||
|
||||
#define JSONTEST_REGISTER_FIXTURE( runner, FixtureType, name ) \
|
||||
(runner).add( JSONTEST_FIXTURE_FACTORY( FixtureType, name ) )
|
||||
#define JSONTEST_REGISTER_FIXTURE(runner, FixtureType, name) \
|
||||
(runner).add(JSONTEST_FIXTURE_FACTORY(FixtureType, name))
|
||||
|
||||
#endif // ifndef JSONTEST_H_INCLUDED
|
||||
// vim: et ts=4 sts=4 sw=4 tw=0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,3 @@
|
||||
// C++ style comment
|
||||
.=null
|
||||
|
||||
|
@@ -1,2 +1,4 @@
|
||||
/* C style comment
|
||||
*/
|
||||
.=null
|
||||
|
||||
|
@@ -1,7 +1,14 @@
|
||||
.={}
|
||||
/* C-style comment
|
||||
|
||||
C-style-2 comment */
|
||||
.c-test={}
|
||||
.c-test.a=1
|
||||
/* Internal comment c-style */
|
||||
.c-test.b=2
|
||||
// C++-style comment
|
||||
.cpp-test={}
|
||||
// Multiline comment cpp-style
|
||||
// Second line
|
||||
.cpp-test.c=3
|
||||
.cpp-test.d=4
|
||||
|
@@ -9,7 +9,8 @@
|
||||
},
|
||||
// C++-style comment
|
||||
"cpp-test" : {
|
||||
// Internal comment cpp-style
|
||||
// Multiline comment cpp-style
|
||||
// Second line
|
||||
"c" : 3,
|
||||
"d" : 4
|
||||
}
|
||||
|
@@ -1 +1,2 @@
|
||||
// Max signed integer
|
||||
.=2147483647
|
||||
|
@@ -1 +1,2 @@
|
||||
// Min signed integer
|
||||
.=-2147483648
|
||||
|
@@ -1 +1,2 @@
|
||||
// Max unsigned integer
|
||||
.=4294967295
|
||||
|
@@ -1,2 +1,3 @@
|
||||
// Min unsigned integer
|
||||
.=0
|
||||
|
||||
|
@@ -1,3 +1,11 @@
|
||||
/* A comment
|
||||
at the beginning of the file.
|
||||
*/
|
||||
.={}
|
||||
.first=1
|
||||
/* Comment before 'second'
|
||||
*/
|
||||
.second=2
|
||||
/* A comment at
|
||||
the end of the file.
|
||||
*/
|
||||
|
@@ -1,2 +1,3 @@
|
||||
// 2^33 => out of integer range, switch to double
|
||||
.=8589934592
|
||||
|
||||
|
@@ -1,2 +1,3 @@
|
||||
// -2^32 => out of signed integer range, switch to double
|
||||
.=-4294967295
|
||||
|
||||
|
@@ -1,2 +1,3 @@
|
||||
// -2^32 => out of signed integer range, switch to double
|
||||
.=-4294967295
|
||||
|
||||
|
@@ -1,2 +1,3 @@
|
||||
// 1.2345678
|
||||
.=1.2345678
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// 1234567.8
|
||||
.=1234567.8
|
||||
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// -1.2345678
|
||||
.=-1.2345678
|
||||
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// -1234567.8
|
||||
.=-1234567.8
|
||||
|
||||
|
||||
|
@@ -1 +1,4 @@
|
||||
// Out of 32-bit integer range, switch to double in 32-bit mode. Length the
|
||||
// same as UINT_MAX in base 10 and digit less than UINT_MAX's last digit in
|
||||
// order to catch a bug in the parsing code.
|
||||
.=4300000001
|
||||
|
@@ -1 +1,4 @@
|
||||
// Out of 64-bit integer range, switch to double in all modes. Length the same
|
||||
// as ULONG_MAX in base 10 and digit less than ULONG_MAX's last digit in order
|
||||
// to catch a bug in the parsing code.
|
||||
.=1.9e+19
|
||||
|
@@ -1 +1,4 @@
|
||||
// Out of 32-bit signed integer range, switch to double in all modes. Length
|
||||
// the same as INT_MIN in base 10 and digit less than INT_MIN's last digit in
|
||||
// order to catch a bug in the parsing code.
|
||||
.=-2200000001
|
||||
|
@@ -1 +1,4 @@
|
||||
// Out of 64-bit signed integer range, switch to double in all modes. Length
|
||||
// the same as LONG_MIN in base 10 and digit less than LONG_MIN's last digit in
|
||||
// order to catch a bug in the parsing code.
|
||||
.=-9.3e+18
|
||||
|
@@ -1 +1,2 @@
|
||||
// 2^64 -> switch to double.
|
||||
.=1.844674407370955e+19
|
||||
|
Reference in New Issue
Block a user