mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-15 07:14:45 +02:00
Compare commits
3 Commits
1.2.0
...
svn-releas
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1e9892addb | ||
![]() |
c2eabf0cf8 | ||
![]() |
3269eefd84 |
@@ -1,47 +0,0 @@
|
|||||||
---
|
|
||||||
# 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
|
|
||||||
...
|
|
||||||
|
|
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,13 +0,0 @@
|
|||||||
/build/
|
|
||||||
*.pyc
|
|
||||||
*.swp
|
|
||||||
*.actual
|
|
||||||
*.actual-rewrite
|
|
||||||
*.process-output
|
|
||||||
*.rewrite
|
|
||||||
/bin/
|
|
||||||
/buildscons/
|
|
||||||
/libs/
|
|
||||||
/doc/doxyfile
|
|
||||||
/dist/
|
|
||||||
#/include/json/version.h
|
|
18
.travis.yml
18
.travis.yml
@@ -1,18 +0,0 @@
|
|||||||
# Build matrix / environment variable are explained on:
|
|
||||||
# http://about.travis-ci.org/docs/user/build-configuration/
|
|
||||||
# This file can be validated on:
|
|
||||||
# http://lint.travis-ci.org/
|
|
||||||
before_install: sudo apt-get install cmake
|
|
||||||
language: cpp
|
|
||||||
compiler:
|
|
||||||
- gcc
|
|
||||||
- clang
|
|
||||||
script: cmake -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIBRARY -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make
|
|
||||||
env:
|
|
||||||
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:
|
|
||||||
email:
|
|
||||||
- aaronjjacobs@gmail.com
|
|
109
CMakeLists.txt
109
CMakeLists.txt
@@ -1,109 +0,0 @@
|
|||||||
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)
|
|
||||||
IF(NOT CMAKE_BUILD_TYPE)
|
|
||||||
SET(CMAKE_BUILD_TYPE Release CACHE STRING
|
|
||||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage."
|
|
||||||
FORCE)
|
|
||||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
|
||||||
ENDIF(NOT WIN32)
|
|
||||||
|
|
||||||
SET(LIB_SUFFIX "" CACHE STRING "Optional arch-dependent suffix for the library installation directory")
|
|
||||||
|
|
||||||
SET(RUNTIME_INSTALL_DIR bin
|
|
||||||
CACHE PATH "Install dir for executables and dlls")
|
|
||||||
SET(ARCHIVE_INSTALL_DIR lib${LIB_SUFFIX}
|
|
||||||
CACHE PATH "Install dir for static libraries")
|
|
||||||
SET(LIBRARY_INSTALL_DIR lib${LIB_SUFFIX}
|
|
||||||
CACHE PATH "Install dir for shared libraries")
|
|
||||||
SET(INCLUDE_INSTALL_DIR include
|
|
||||||
CACHE PATH "Install dir for headers")
|
|
||||||
SET(PACKAGE_INSTALL_DIR lib${LIB_SUFFIX}/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 )
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
# 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(GET VERSION_PARTS 0 ${OUPUT_PREFIX}_MAJOR)
|
|
||||||
LIST(GET VERSION_PARTS 1 ${OUPUT_PREFIX}_MINOR)
|
|
||||||
LIST(GET VERSION_PARTS 2 ${OUPUT_PREFIX}_PATCH)
|
|
||||||
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE )
|
|
||||||
ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
|
|
||||||
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE )
|
|
||||||
ENDIF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
|
|
||||||
ENDMACRO(jsoncpp_parse_version)
|
|
||||||
|
|
||||||
# Read out version from "version" file
|
|
||||||
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")
|
|
||||||
ENDIF(NOT JSONCPP_VERSION_FOUND)
|
|
||||||
|
|
||||||
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" )
|
|
||||||
|
|
||||||
macro(UseCompilationWarningAsError)
|
|
||||||
if ( MSVC )
|
|
||||||
# Only enabled in debug because some old versions of VS STL generate
|
|
||||||
# warnings when compiled in release configuration.
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ")
|
|
||||||
endif( MSVC )
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Include our configuration header
|
|
||||||
INCLUDE_DIRECTORIES( ${jsoncpp_SOURCE_DIR}/include )
|
|
||||||
|
|
||||||
if ( MSVC )
|
|
||||||
# Only enabled in debug because some old versions of VS STL generate
|
|
||||||
# unreachable code warning when compiled in release configuration.
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ")
|
|
||||||
endif( MSVC )
|
|
||||||
|
|
||||||
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${LIB_SUFFIX}/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 )
|
|
||||||
|
|
||||||
#install the includes
|
|
||||||
ADD_SUBDIRECTORY( include )
|
|
84
NEWS.txt
84
NEWS.txt
@@ -1,69 +1,3 @@
|
|||||||
New in SVN
|
|
||||||
----------
|
|
||||||
|
|
||||||
* Updated the type system's behavior, in order to better support backwards
|
|
||||||
compatibility with code that was written before 64-bit integer support was
|
|
||||||
introduced. Here's how it works now:
|
|
||||||
|
|
||||||
* isInt, isInt64, isUInt, and isUInt64 return true if and only if the
|
|
||||||
value can be exactly represented as that type. In particular, a value
|
|
||||||
constructed with a double like 17.0 will now return true for all of
|
|
||||||
these methods.
|
|
||||||
|
|
||||||
* isDouble and isFloat now return true for all numeric values, since all
|
|
||||||
numeric values can be converted to a double or float without
|
|
||||||
truncation. Note however that the conversion may not be exact -- for
|
|
||||||
example, doubles cannot exactly represent all integers above 2^53 + 1.
|
|
||||||
|
|
||||||
* isBool, isNull, isString, isArray, and isObject now return true if and
|
|
||||||
only if the value is of that type.
|
|
||||||
|
|
||||||
* isConvertibleTo(fooValue) indicates that it is safe to call asFoo.
|
|
||||||
(For each type foo, isFoo always implies isConvertibleTo(fooValue).)
|
|
||||||
asFoo returns an approximate or exact representation as appropriate.
|
|
||||||
For example, a double value may be truncated when asInt is called.
|
|
||||||
|
|
||||||
* For backwards compatibility with old code, isConvertibleTo(intValue)
|
|
||||||
may return false even if type() == intValue. This is because the value
|
|
||||||
may have been constructed with a 64-bit integer larger than maxInt,
|
|
||||||
and calling asInt() would cause an exception. If you're writing new
|
|
||||||
code, use isInt64 to find out whether the value is exactly
|
|
||||||
representable using an Int64, or asDouble() combined with minInt64 and
|
|
||||||
maxInt64 to figure out whether it is approximately representable.
|
|
||||||
|
|
||||||
* Value
|
|
||||||
- Patch #10: BOOST_FOREACH compatibility. Made Json::iterator more
|
|
||||||
standard compliant, added missing iterator_category and value_type
|
|
||||||
typedefs (contribued by Robert A. Iannucci).
|
|
||||||
|
|
||||||
* Compilation
|
|
||||||
|
|
||||||
- New CMake based build system. Based in part on contribution from
|
|
||||||
Igor Okulist and Damien Buhl (Patch #14).
|
|
||||||
|
|
||||||
- New header json/version.h now contains version number macros
|
|
||||||
(JSONCPP_VERSION_MAJOR, JSONCPP_VERSION_MINOR, JSONCPP_VERSION_PATCH
|
|
||||||
and JSONCPP_VERSION_HEXA).
|
|
||||||
|
|
||||||
- Patch #11: added missing JSON_API on some classes causing link issues
|
|
||||||
when building as a dynamic library on Windows
|
|
||||||
(contributed by Francis Bolduc).
|
|
||||||
|
|
||||||
- Visual Studio DLL: suppressed warning "C4251: <data member>: <type>
|
|
||||||
needs to have dll-interface to be used by..." via pragma push/pop
|
|
||||||
in json-cpp headers.
|
|
||||||
|
|
||||||
- Added Travis CI intregration: https://travis-ci.org/blep/jsoncpp-mirror
|
|
||||||
|
|
||||||
* Bug fixes
|
|
||||||
- Patch #15: Copy constructor does not initialize allocated_ for stringValue
|
|
||||||
(contributed by rmongia).
|
|
||||||
|
|
||||||
- Patch #16: Missing field copy in Json::Value::iterator causing infinite
|
|
||||||
loop when using experimental internal map (#define JSON_VALUE_USE_INTERNAL_MAP)
|
|
||||||
(contributed by Ming-Lin Kao).
|
|
||||||
|
|
||||||
|
|
||||||
New in JsonCpp 0.6.0:
|
New in JsonCpp 0.6.0:
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
@@ -79,8 +13,8 @@ New in SVN
|
|||||||
Notes: you need to setup the environment by running vcvars32.bat
|
Notes: you need to setup the environment by running vcvars32.bat
|
||||||
(e.g. MSVC 2008 command prompt in start menu) before running scons.
|
(e.g. MSVC 2008 command prompt in start menu) before running scons.
|
||||||
|
|
||||||
- Added support for amalgamated source and header generation (a la sqlite).
|
- Added support for amalgated source and header generation (a la sqlite).
|
||||||
Refer to README.txt section "Generating amalgamated source and header"
|
Refer to README.txt section "Generating amalgated source and header"
|
||||||
for detail.
|
for detail.
|
||||||
|
|
||||||
* Value
|
* Value
|
||||||
@@ -153,20 +87,6 @@ New in SVN
|
|||||||
- Bug #3139678: stack buffer overflow when parsing a double with a
|
- Bug #3139678: stack buffer overflow when parsing a double with a
|
||||||
length of 32 characters.
|
length of 32 characters.
|
||||||
|
|
||||||
- Fixed Value::operator <= implementation (had the semantic of operator >=).
|
|
||||||
Found when adding unit tests for comparison operators.
|
|
||||||
|
|
||||||
- Value::compare() is now const and has an actual implementation with
|
|
||||||
unit tests.
|
|
||||||
|
|
||||||
- Bug #2407932: strpbrk() can fail for NULL pointer.
|
|
||||||
|
|
||||||
- Bug #3306345: Fixed minor typo in Path::resolve().
|
|
||||||
|
|
||||||
- Bug #3314841/#3306896: errors in amalgamate.py
|
|
||||||
|
|
||||||
- Fixed some Coverity warnings and line-endings.
|
|
||||||
|
|
||||||
* License
|
* License
|
||||||
|
|
||||||
- See file LICENSE for details. Basically JsonCpp is now licensed under
|
- See file LICENSE for details. Basically JsonCpp is now licensed under
|
||||||
|
224
README.md
224
README.md
@@ -1,224 +0,0 @@
|
|||||||
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.
|
|
||||||
|
|
172
README.txt
Normal file
172
README.txt
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
* 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.
|
||||||
|
|
||||||
|
|
||||||
|
* Building/Testing:
|
||||||
|
=================
|
||||||
|
|
||||||
|
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 amalgated 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 amalgated source can be generated at any time by running the following
|
||||||
|
command from the top-directory (requires python 2.6):
|
||||||
|
|
||||||
|
python amalgate.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-amalgated 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 amalgated sources are generated by concatenating JsonCpp source in the
|
||||||
|
correct order and defining macro JSON_IS_AMALGATED to prevent inclusion of
|
||||||
|
other headers.
|
||||||
|
|
||||||
|
* Using json-cpp in your project:
|
||||||
|
===============================
|
||||||
|
|
||||||
|
include/ should be added to your compiler include path. jsoncpp headers
|
||||||
|
should be included as follow:
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
|
||||||
|
* 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" ] )
|
env.Append( CPPDEFINES=[ "WIN32", "NDEBUG", "_MT" ] )
|
||||||
elif platform.startswith('linux-gcc'):
|
elif platform.startswith('linux-gcc'):
|
||||||
env.Tool( 'default' )
|
env.Tool( 'default' )
|
||||||
env.Append( LIBS = ['pthread'], CCFLAGS = os.environ.get("CXXFLAGS", "-Wall"), LINKFLAGS=os.environ.get("LDFLAGS", "") )
|
env.Append( LIBS = ['pthread'], CCFLAGS = "-Wall" )
|
||||||
env['SHARED_LIB_ENABLED'] = True
|
env['SHARED_LIB_ENABLED'] = True
|
||||||
else:
|
else:
|
||||||
print "UNSUPPORTED PLATFORM."
|
print "UNSUPPORTED PLATFORM."
|
||||||
|
150
amalgamate.py
150
amalgamate.py
@@ -1,150 +0,0 @@
|
|||||||
"""Amalgate json-cpp library sources into a single source and header file.
|
|
||||||
|
|
||||||
Requires Python 2.6
|
|
||||||
|
|
||||||
Example of invocation (must be invoked from json-cpp top directory):
|
|
||||||
python amalgate.py
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
class AmalgamationFile:
|
|
||||||
def __init__( self, top_dir ):
|
|
||||||
self.top_dir = top_dir
|
|
||||||
self.blocks = []
|
|
||||||
|
|
||||||
def add_text( self, text ):
|
|
||||||
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" )
|
|
||||||
content = f.read()
|
|
||||||
if wrap_in_comment:
|
|
||||||
content = "/*\n" + content + "\n*/"
|
|
||||||
self.add_text( content )
|
|
||||||
f.close()
|
|
||||||
add_marker( "End" )
|
|
||||||
self.add_text( "\n\n\n\n" )
|
|
||||||
|
|
||||||
def get_value( self ):
|
|
||||||
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( str.encode(self.get_value(), 'UTF-8') )
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
def amalgamate_source( source_top_dir=None,
|
|
||||||
target_source_path=None,
|
|
||||||
header_include_path=None ):
|
|
||||||
"""Produces amalgated source.
|
|
||||||
Parameters:
|
|
||||||
source_top_dir: top-directory
|
|
||||||
target_source_path: output .cpp path
|
|
||||||
header_include_path: generated header path relative to target_source_path.
|
|
||||||
"""
|
|
||||||
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" )
|
|
||||||
|
|
||||||
target_header_path = os.path.join( os.path.dirname(target_source_path), header_include_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...")
|
|
||||||
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" )
|
|
||||||
|
|
||||||
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)
|
|
||||||
header.write_to( target_forward_header_path )
|
|
||||||
|
|
||||||
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") )
|
|
||||||
|
|
||||||
print("Writing amalgated source to %r" % target_source_path)
|
|
||||||
source.write_to( target_source_path )
|
|
||||||
|
|
||||||
def main():
|
|
||||||
usage = """%prog [options]
|
|
||||||
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",
|
|
||||||
help="""Output .cpp source path. [Default: %default]""")
|
|
||||||
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(),
|
|
||||||
help="""Source top-directory. [Default: %default]""")
|
|
||||||
parser.enable_interspersed_args()
|
|
||||||
options, args = parser.parse_args()
|
|
||||||
|
|
||||||
msg = amalgamate_source( source_top_dir=options.top_dir,
|
|
||||||
target_source_path=options.target_source_path,
|
|
||||||
header_include_path=options.header_include_path )
|
|
||||||
if msg:
|
|
||||||
sys.stderr.write( msg + "\n" )
|
|
||||||
sys.exit( 1 )
|
|
||||||
else:
|
|
||||||
print("Source succesfully amalagated")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
147
amalgate.py
Normal file
147
amalgate.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
"""Amalgate json-cpp library sources into a single source and header file.
|
||||||
|
|
||||||
|
Requires Python 2.6
|
||||||
|
|
||||||
|
Example of invocation (must be invoked from json-cpp top directory):
|
||||||
|
python amalgate.py
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class AmalagatedFile:
|
||||||
|
def __init__( self, top_dir ):
|
||||||
|
self.top_dir = top_dir
|
||||||
|
self.blocks = []
|
||||||
|
|
||||||
|
def add_text( self, text ):
|
||||||
|
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' )
|
||||||
|
content = f.read()
|
||||||
|
if wrap_in_comment:
|
||||||
|
content = '/*\n' + content + '\n*/'
|
||||||
|
self.add_text( content )
|
||||||
|
f.close()
|
||||||
|
add_marker( 'End' )
|
||||||
|
self.add_text( '\n\n\n\n' )
|
||||||
|
|
||||||
|
def get_value( self ):
|
||||||
|
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.close()
|
||||||
|
|
||||||
|
def amalgate_source( source_top_dir=None,
|
||||||
|
target_source_path=None,
|
||||||
|
header_include_path=None ):
|
||||||
|
"""Produces amalgated source.
|
||||||
|
Parameters:
|
||||||
|
source_top_dir: top-directory
|
||||||
|
target_source_path: output .cpp path
|
||||||
|
header_include_path: generated header path relative to target_source_path.
|
||||||
|
"""
|
||||||
|
print 'Amalgating header...'
|
||||||
|
header = AmalagatedFile( 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_AMALGATED' )
|
||||||
|
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_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
|
||||||
|
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...'
|
||||||
|
header = AmalagatedFile( 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_AMALGATED' )
|
||||||
|
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
|
||||||
|
header.write_to( target_forward_header_path )
|
||||||
|
|
||||||
|
print 'Amalgating source...'
|
||||||
|
source = AmalagatedFile( 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( '' )
|
||||||
|
source.add_file( 'src/lib_json\json_tool.h' )
|
||||||
|
source.add_file( 'src/lib_json\json_reader.cpp' )
|
||||||
|
source.add_file( 'src/lib_json\json_batchallocator.h' )
|
||||||
|
source.add_file( 'src/lib_json\json_valueiterator.inl' )
|
||||||
|
source.add_file( 'src/lib_json\json_value.cpp' )
|
||||||
|
source.add_file( 'src/lib_json\json_writer.cpp' )
|
||||||
|
|
||||||
|
print 'Writing amalgated source to %r' % target_source_path
|
||||||
|
source.write_to( target_source_path )
|
||||||
|
|
||||||
|
def main():
|
||||||
|
usage = """%prog [options]
|
||||||
|
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',
|
||||||
|
help="""Output .cpp source path. [Default: %default]""")
|
||||||
|
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(),
|
||||||
|
help="""Source top-directory. [Default: %default]""")
|
||||||
|
parser.enable_interspersed_args()
|
||||||
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
|
msg = amalgate_source( source_top_dir=options.top_dir,
|
||||||
|
target_source_path=options.target_source_path,
|
||||||
|
header_include_path=options.header_include_path )
|
||||||
|
if msg:
|
||||||
|
sys.stderr.write( msg + '\n' )
|
||||||
|
sys.exit( 1 )
|
||||||
|
else:
|
||||||
|
print 'Source succesfully amalagated'
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
14
dev.makefile
14
dev.makefile
@@ -1,14 +0,0 @@
|
|||||||
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
|
|
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"cmake_variants" : [
|
|
||||||
{"name": "generator",
|
|
||||||
"generators": [
|
|
||||||
{"generator": [
|
|
||||||
"Visual Studio 7 .NET 2003",
|
|
||||||
"Visual Studio 9 2008",
|
|
||||||
"Visual Studio 9 2008 Win64",
|
|
||||||
"Visual Studio 10",
|
|
||||||
"Visual Studio 10 Win64",
|
|
||||||
"Visual Studio 11",
|
|
||||||
"Visual Studio 11 Win64"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{"generator": ["MinGW Makefiles"],
|
|
||||||
"env_prepend": [{"path": "c:/wut/prg/MinGW/bin"}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{"name": "shared_dll",
|
|
||||||
"variables": [
|
|
||||||
["JSONCPP_LIB_BUILD_SHARED=true"],
|
|
||||||
["JSONCPP_LIB_BUILD_SHARED=false"]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{"name": "build_type",
|
|
||||||
"build_types": [
|
|
||||||
"debug",
|
|
||||||
"release"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"cmake_variants" : [
|
|
||||||
{"name": "generator",
|
|
||||||
"generators": [
|
|
||||||
{"generator": [
|
|
||||||
"Visual Studio 6",
|
|
||||||
"Visual Studio 7",
|
|
||||||
"Visual Studio 8 2005"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{"name": "shared_dll",
|
|
||||||
"variables": [
|
|
||||||
["JSONCPP_LIB_BUILD_SHARED=true"],
|
|
||||||
["JSONCPP_LIB_BUILD_SHARED=false"]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{"name": "build_type",
|
|
||||||
"build_types": [
|
|
||||||
"debug",
|
|
||||||
"release"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@@ -2,7 +2,6 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
# Baptiste Lepilleur, 2009
|
# Baptiste Lepilleur, 2009
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from dircache import listdir
|
from dircache import listdir
|
||||||
import re
|
import re
|
||||||
import fnmatch
|
import fnmatch
|
||||||
@@ -191,12 +190,12 @@ if __name__ == "__main__":
|
|||||||
test_cases.append( (ant_pattern, local_path(accepted_matches), local_path( rejected_matches )) )
|
test_cases.append( (ant_pattern, local_path(accepted_matches), local_path( rejected_matches )) )
|
||||||
for ant_pattern, accepted_matches, rejected_matches in test_cases:
|
for ant_pattern, accepted_matches, rejected_matches in test_cases:
|
||||||
rex = ant_pattern_to_re( ant_pattern )
|
rex = ant_pattern_to_re( ant_pattern )
|
||||||
print('ant_pattern:', ant_pattern, ' => ', rex.pattern)
|
print 'ant_pattern:', ant_pattern, ' => ', rex.pattern
|
||||||
for accepted_match in accepted_matches:
|
for accepted_match in accepted_matches:
|
||||||
print('Accepted?:', accepted_match)
|
print 'Accepted?:', accepted_match
|
||||||
self.assertTrue( rex.match( accepted_match ) is not None )
|
self.assert_( rex.match( accepted_match ) is not None )
|
||||||
for rejected_match in rejected_matches:
|
for rejected_match in rejected_matches:
|
||||||
print('Rejected?:', rejected_match)
|
print 'Rejected?:', rejected_match
|
||||||
self.assertTrue( rex.match( rejected_match ) is None )
|
self.assert_( rex.match( rejected_match ) is None )
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@@ -1,281 +0,0 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import collections
|
|
||||||
import itertools
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import string
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import cgi
|
|
||||||
|
|
||||||
class BuildDesc:
|
|
||||||
def __init__(self, prepend_envs=None, variables=None, build_type=None, generator=None):
|
|
||||||
self.prepend_envs = prepend_envs or [] # [ { "var": "value" } ]
|
|
||||||
self.variables = variables or []
|
|
||||||
self.build_type = build_type
|
|
||||||
self.generator = generator
|
|
||||||
|
|
||||||
def merged_with( self, build_desc ):
|
|
||||||
"""Returns a new BuildDesc by merging field content.
|
|
||||||
Prefer build_desc fields to self fields for single valued field.
|
|
||||||
"""
|
|
||||||
return BuildDesc( self.prepend_envs + build_desc.prepend_envs,
|
|
||||||
self.variables + build_desc.variables,
|
|
||||||
build_desc.build_type or self.build_type,
|
|
||||||
build_desc.generator or self.generator )
|
|
||||||
|
|
||||||
def env( self ):
|
|
||||||
environ = os.environ.copy()
|
|
||||||
for values_by_name in self.prepend_envs:
|
|
||||||
for var, value in list(values_by_name.items()):
|
|
||||||
var = var.upper()
|
|
||||||
if type(value) is unicode:
|
|
||||||
value = value.encode( sys.getdefaultencoding() )
|
|
||||||
if var in environ:
|
|
||||||
environ[var] = value + os.pathsep + environ[var]
|
|
||||||
else:
|
|
||||||
environ[var] = value
|
|
||||||
return environ
|
|
||||||
|
|
||||||
def cmake_args( self ):
|
|
||||||
args = ["-D%s" % var for var in self.variables]
|
|
||||||
# skip build type for Visual Studio solution as it cause warning
|
|
||||||
if self.build_type and 'Visual' not in self.generator:
|
|
||||||
args.append( "-DCMAKE_BUILD_TYPE=%s" % self.build_type )
|
|
||||||
if self.generator:
|
|
||||||
args.extend( ['-G', self.generator] )
|
|
||||||
return args
|
|
||||||
|
|
||||||
def __repr__( self ):
|
|
||||||
return "BuildDesc( %s, build_type=%s )" % (" ".join( self.cmake_args()), self.build_type)
|
|
||||||
|
|
||||||
class BuildData:
|
|
||||||
def __init__( self, desc, work_dir, source_dir ):
|
|
||||||
self.desc = desc
|
|
||||||
self.work_dir = work_dir
|
|
||||||
self.source_dir = source_dir
|
|
||||||
self.cmake_log_path = os.path.join( work_dir, 'batchbuild_cmake.log' )
|
|
||||||
self.build_log_path = os.path.join( work_dir, 'batchbuild_build.log' )
|
|
||||||
self.cmake_succeeded = False
|
|
||||||
self.build_succeeded = False
|
|
||||||
|
|
||||||
def execute_build(self):
|
|
||||||
print('Build %s' % self.desc)
|
|
||||||
self._make_new_work_dir( )
|
|
||||||
self.cmake_succeeded = self._generate_makefiles( )
|
|
||||||
if self.cmake_succeeded:
|
|
||||||
self.build_succeeded = self._build_using_makefiles( )
|
|
||||||
return self.build_succeeded
|
|
||||||
|
|
||||||
def _generate_makefiles(self):
|
|
||||||
print(' Generating makefiles: ', end=' ')
|
|
||||||
cmd = ['cmake'] + self.desc.cmake_args( ) + [os.path.abspath( self.source_dir )]
|
|
||||||
succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.cmake_log_path )
|
|
||||||
print('done' if succeeded else 'FAILED')
|
|
||||||
return succeeded
|
|
||||||
|
|
||||||
def _build_using_makefiles(self):
|
|
||||||
print(' Building:', end=' ')
|
|
||||||
cmd = ['cmake', '--build', self.work_dir]
|
|
||||||
if self.desc.build_type:
|
|
||||||
cmd += ['--config', self.desc.build_type]
|
|
||||||
succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.build_log_path )
|
|
||||||
print('done' if succeeded else 'FAILED')
|
|
||||||
return succeeded
|
|
||||||
|
|
||||||
def _execute_build_subprocess(self, cmd, env, log_path):
|
|
||||||
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.work_dir,
|
|
||||||
env=env )
|
|
||||||
stdout, _ = process.communicate( )
|
|
||||||
succeeded = (process.returncode == 0)
|
|
||||||
with open( log_path, 'wb' ) as flog:
|
|
||||||
log = ' '.join( cmd ) + '\n' + stdout + '\nExit code: %r\n' % process.returncode
|
|
||||||
flog.write( fix_eol( log ) )
|
|
||||||
return succeeded
|
|
||||||
|
|
||||||
def _make_new_work_dir(self):
|
|
||||||
if os.path.isdir( self.work_dir ):
|
|
||||||
print(' Removing work directory', self.work_dir)
|
|
||||||
shutil.rmtree( self.work_dir, ignore_errors=True )
|
|
||||||
if not os.path.isdir( self.work_dir ):
|
|
||||||
os.makedirs( self.work_dir )
|
|
||||||
|
|
||||||
def fix_eol( stdout ):
|
|
||||||
"""Fixes wrong EOL produced by cmake --build on Windows (\r\r\n instead of \r\n).
|
|
||||||
"""
|
|
||||||
return re.sub( '\r*\n', os.linesep, stdout )
|
|
||||||
|
|
||||||
def load_build_variants_from_config( config_path ):
|
|
||||||
with open( config_path, 'rb' ) as fconfig:
|
|
||||||
data = json.load( fconfig )
|
|
||||||
variants = data[ 'cmake_variants' ]
|
|
||||||
build_descs_by_axis = collections.defaultdict( list )
|
|
||||||
for axis in variants:
|
|
||||||
axis_name = axis["name"]
|
|
||||||
build_descs = []
|
|
||||||
if "generators" in axis:
|
|
||||||
for generator_data in axis["generators"]:
|
|
||||||
for generator in generator_data["generator"]:
|
|
||||||
build_desc = BuildDesc( generator=generator,
|
|
||||||
prepend_envs=generator_data.get("env_prepend") )
|
|
||||||
build_descs.append( build_desc )
|
|
||||||
elif "variables" in axis:
|
|
||||||
for variables in axis["variables"]:
|
|
||||||
build_desc = BuildDesc( variables=variables )
|
|
||||||
build_descs.append( build_desc )
|
|
||||||
elif "build_types" in axis:
|
|
||||||
for build_type in axis["build_types"]:
|
|
||||||
build_desc = BuildDesc( build_type=build_type )
|
|
||||||
build_descs.append( build_desc )
|
|
||||||
build_descs_by_axis[axis_name].extend( build_descs )
|
|
||||||
return build_descs_by_axis
|
|
||||||
|
|
||||||
def generate_build_variants( build_descs_by_axis ):
|
|
||||||
"""Returns a list of BuildDesc generated for the partial BuildDesc for each axis."""
|
|
||||||
axis_names = list(build_descs_by_axis.keys())
|
|
||||||
build_descs = []
|
|
||||||
for axis_name, axis_build_descs in list(build_descs_by_axis.items()):
|
|
||||||
if len(build_descs):
|
|
||||||
# for each existing build_desc and each axis build desc, create a new build_desc
|
|
||||||
new_build_descs = []
|
|
||||||
for prototype_build_desc, axis_build_desc in itertools.product( build_descs, axis_build_descs):
|
|
||||||
new_build_descs.append( prototype_build_desc.merged_with( axis_build_desc ) )
|
|
||||||
build_descs = new_build_descs
|
|
||||||
else:
|
|
||||||
build_descs = axis_build_descs
|
|
||||||
return build_descs
|
|
||||||
|
|
||||||
HTML_TEMPLATE = string.Template('''<html>
|
|
||||||
<head>
|
|
||||||
<title>$title</title>
|
|
||||||
<style type="text/css">
|
|
||||||
td.failed {background-color:#f08080;}
|
|
||||||
td.ok {background-color:#c0eec0;}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table border="1">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Variables</th>
|
|
||||||
$th_vars
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Build type</th>
|
|
||||||
$th_build_types
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
$tr_builds
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body></html>''')
|
|
||||||
|
|
||||||
def generate_html_report( html_report_path, builds ):
|
|
||||||
report_dir = os.path.dirname( html_report_path )
|
|
||||||
# Vertical axis: generator
|
|
||||||
# Horizontal: variables, then build_type
|
|
||||||
builds_by_generator = collections.defaultdict( list )
|
|
||||||
variables = set()
|
|
||||||
build_types_by_variable = collections.defaultdict( set )
|
|
||||||
build_by_pos_key = {} # { (generator, var_key, build_type): build }
|
|
||||||
for build in builds:
|
|
||||||
builds_by_generator[build.desc.generator].append( build )
|
|
||||||
var_key = tuple(sorted(build.desc.variables))
|
|
||||||
variables.add( var_key )
|
|
||||||
build_types_by_variable[var_key].add( build.desc.build_type )
|
|
||||||
pos_key = (build.desc.generator, var_key, build.desc.build_type)
|
|
||||||
build_by_pos_key[pos_key] = build
|
|
||||||
variables = sorted( variables )
|
|
||||||
th_vars = []
|
|
||||||
th_build_types = []
|
|
||||||
for variable in variables:
|
|
||||||
build_types = sorted( build_types_by_variable[variable] )
|
|
||||||
nb_build_type = len(build_types_by_variable[variable])
|
|
||||||
th_vars.append( '<th colspan="%d">%s</th>' % (nb_build_type, cgi.escape( ' '.join( variable ) ) ) )
|
|
||||||
for build_type in build_types:
|
|
||||||
th_build_types.append( '<th>%s</th>' % cgi.escape(build_type) )
|
|
||||||
tr_builds = []
|
|
||||||
for generator in sorted( builds_by_generator ):
|
|
||||||
tds = [ '<td>%s</td>\n' % cgi.escape( generator ) ]
|
|
||||||
for variable in variables:
|
|
||||||
build_types = sorted( build_types_by_variable[variable] )
|
|
||||||
for build_type in build_types:
|
|
||||||
pos_key = (generator, variable, build_type)
|
|
||||||
build = build_by_pos_key.get(pos_key)
|
|
||||||
if build:
|
|
||||||
cmake_status = 'ok' if build.cmake_succeeded else 'FAILED'
|
|
||||||
build_status = 'ok' if build.build_succeeded else 'FAILED'
|
|
||||||
cmake_log_url = os.path.relpath( build.cmake_log_path, report_dir )
|
|
||||||
build_log_url = os.path.relpath( build.build_log_path, report_dir )
|
|
||||||
td = '<td class="%s"><a href="%s" class="%s">CMake: %s</a>' % (
|
|
||||||
build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status)
|
|
||||||
if build.cmake_succeeded:
|
|
||||||
td += '<br><a href="%s" class="%s">Build: %s</a>' % (
|
|
||||||
build_log_url, build_status.lower(), build_status)
|
|
||||||
td += '</td>'
|
|
||||||
else:
|
|
||||||
td = '<td></td>'
|
|
||||||
tds.append( td )
|
|
||||||
tr_builds.append( '<tr>%s</tr>' % '\n'.join( tds ) )
|
|
||||||
html = HTML_TEMPLATE.substitute(
|
|
||||||
title='Batch build report',
|
|
||||||
th_vars=' '.join(th_vars),
|
|
||||||
th_build_types=' '.join( th_build_types),
|
|
||||||
tr_builds='\n'.join( tr_builds ) )
|
|
||||||
with open( html_report_path, 'wt' ) as fhtml:
|
|
||||||
fhtml.write( html )
|
|
||||||
print('HTML report generated in:', html_report_path)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
usage = r"""%prog WORK_DIR SOURCE_DIR CONFIG_JSON_PATH [CONFIG2_JSON_PATH...]
|
|
||||||
Build a given CMake based project located in SOURCE_DIR with multiple generators/options.dry_run
|
|
||||||
as described in CONFIG_JSON_PATH building in WORK_DIR.
|
|
||||||
|
|
||||||
Example of call:
|
|
||||||
python devtools\batchbuild.py e:\buildbots\jsoncpp\build . devtools\agent_vmw7.json
|
|
||||||
"""
|
|
||||||
from optparse import OptionParser
|
|
||||||
parser = OptionParser(usage=usage)
|
|
||||||
parser.allow_interspersed_args = True
|
|
||||||
# parser.add_option('-v', '--verbose', dest="verbose", action='store_true',
|
|
||||||
# help="""Be verbose.""")
|
|
||||||
parser.enable_interspersed_args()
|
|
||||||
options, args = parser.parse_args()
|
|
||||||
if len(args) < 3:
|
|
||||||
parser.error( "Missing one of WORK_DIR SOURCE_DIR CONFIG_JSON_PATH." )
|
|
||||||
work_dir = args[0]
|
|
||||||
source_dir = args[1].rstrip('/\\')
|
|
||||||
config_paths = args[2:]
|
|
||||||
for config_path in config_paths:
|
|
||||||
if not os.path.isfile( config_path ):
|
|
||||||
parser.error( "Can not read: %r" % config_path )
|
|
||||||
|
|
||||||
# generate build variants
|
|
||||||
build_descs = []
|
|
||||||
for config_path in config_paths:
|
|
||||||
build_descs_by_axis = load_build_variants_from_config( config_path )
|
|
||||||
build_descs.extend( generate_build_variants( build_descs_by_axis ) )
|
|
||||||
print('Build variants (%d):' % len(build_descs))
|
|
||||||
# assign build directory for each variant
|
|
||||||
if not os.path.isdir( work_dir ):
|
|
||||||
os.makedirs( work_dir )
|
|
||||||
builds = []
|
|
||||||
with open( os.path.join( work_dir, 'matrix-dir-map.txt' ), 'wt' ) as fmatrixmap:
|
|
||||||
for index, build_desc in enumerate( build_descs ):
|
|
||||||
build_desc_work_dir = os.path.join( work_dir, '%03d' % (index+1) )
|
|
||||||
builds.append( BuildData( build_desc, build_desc_work_dir, source_dir ) )
|
|
||||||
fmatrixmap.write( '%s: %s\n' % (build_desc_work_dir, build_desc) )
|
|
||||||
for build in builds:
|
|
||||||
build.execute_build()
|
|
||||||
html_report_path = os.path.join( work_dir, 'batchbuild-report.html' )
|
|
||||||
generate_html_report( html_report_path, builds )
|
|
||||||
print('Done')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
|
@@ -1,4 +1,3 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
|
def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
|
||||||
@@ -7,8 +6,8 @@ def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
|
|||||||
raise ValueError( 'Path "%s" is not a file' % path )
|
raise ValueError( 'Path "%s" is not a file' % path )
|
||||||
try:
|
try:
|
||||||
f = open(path, 'rb')
|
f = open(path, 'rb')
|
||||||
except IOError as msg:
|
except IOError, msg:
|
||||||
print("%s: I/O Error: %s" % (file, str(msg)), file=sys.stderr)
|
print >> sys.stderr, "%s: I/O Error: %s" % (file, str(msg))
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
raw_lines = f.readlines()
|
raw_lines = f.readlines()
|
||||||
@@ -16,7 +15,7 @@ def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
|
|||||||
f.close()
|
f.close()
|
||||||
fixed_lines = [line.rstrip('\r\n') + eol for line in raw_lines]
|
fixed_lines = [line.rstrip('\r\n') + eol for line in raw_lines]
|
||||||
if raw_lines != fixed_lines:
|
if raw_lines != fixed_lines:
|
||||||
print('%s =>' % path, end=' ')
|
print '%s =>' % path,
|
||||||
if not is_dry_run:
|
if not is_dry_run:
|
||||||
f = open(path, "wb")
|
f = open(path, "wb")
|
||||||
try:
|
try:
|
||||||
@@ -24,7 +23,7 @@ def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
|
|||||||
finally:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
if verbose:
|
if verbose:
|
||||||
print(is_dry_run and ' NEED FIX' or ' FIXED')
|
print is_dry_run and ' NEED FIX' or ' FIXED'
|
||||||
return True
|
return True
|
||||||
##
|
##
|
||||||
##
|
##
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
"""Updates the license text in source file.
|
"""Updates the license text in source file.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
# An existing license is found if the file starts with the string below,
|
# An existing license is found if the file starts with the string below,
|
||||||
# and ends with the first blank line.
|
# and ends with the first blank line.
|
||||||
@@ -35,11 +34,11 @@ def update_license( path, dry_run, show_diff ):
|
|||||||
if not dry_run:
|
if not dry_run:
|
||||||
with open( path, 'wb' ) as fout:
|
with open( path, 'wb' ) as fout:
|
||||||
fout.write( new_text.replace('\n', newline ) )
|
fout.write( new_text.replace('\n', newline ) )
|
||||||
print('Updated', path)
|
print 'Updated', path
|
||||||
if show_diff:
|
if show_diff:
|
||||||
import difflib
|
import difflib
|
||||||
print('\n'.join( difflib.unified_diff( original_text.split('\n'),
|
print '\n'.join( difflib.unified_diff( original_text.split('\n'),
|
||||||
new_text.split('\n') ) ))
|
new_text.split('\n') ) )
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -84,7 +83,7 @@ python devtools\licenseupdater.py include src
|
|||||||
parser.enable_interspersed_args()
|
parser.enable_interspersed_args()
|
||||||
options, args = parser.parse_args()
|
options, args = parser.parse_args()
|
||||||
update_license_in_source_directories( args, options.dry_run, options.show_diff )
|
update_license_in_source_directories( args, options.dry_run, options.show_diff )
|
||||||
print('Done')
|
print 'Done'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
|
2310
doc/doxyfile.in
2310
doc/doxyfile.in
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,23 @@
|
|||||||
<hr>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -11,12 +11,12 @@ JsonCpp - JSON data format manipulation library
|
|||||||
<table width="100%">
|
<table width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td width="40%" align="left" valign="center">
|
<td width="40%" align="left" valign="center">
|
||||||
<a href="https://github.com/open-source-parsers/jsoncpp">
|
<a href="http://sourceforge.net/projects/jsoncpp/">
|
||||||
JsonCpp project page
|
JsonCpp project page
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td width="40%" align="right" valign="center">
|
<td width="40%" align="right" valign="center">
|
||||||
<a href="https://github.com/open-source-parsers/jsoncpp">JsonCpp home page</a>
|
<a href="http://jsoncpp.sourceforge.net">JsonCpp home page</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@@ -25,11 +25,10 @@ Here is an example of JSON data:
|
|||||||
"indent" : { "length" : 3, "use_space": true }
|
"indent" : { "length" : 3, "use_space": true }
|
||||||
}
|
}
|
||||||
\endverbatim
|
\endverbatim
|
||||||
<code>jsoncpp</code> supports comments as <i>meta-data</i>.
|
|
||||||
|
|
||||||
\section _features Features
|
\section _features Features
|
||||||
- read and write JSON document
|
- read and write JSON document
|
||||||
- attach C++ style comments to element during parsing
|
- attach C and C++ style comments to element during parsing
|
||||||
- rewrite JSON document preserving original comments
|
- rewrite JSON document preserving original comments
|
||||||
|
|
||||||
Notes: Comments used to be supported in JSON but where removed for
|
Notes: Comments used to be supported in JSON but where removed for
|
||||||
@@ -85,35 +84,43 @@ std::cout << root;
|
|||||||
|
|
||||||
\section _pbuild Build instructions
|
\section _pbuild Build instructions
|
||||||
The build instructions are located in the file
|
The build instructions are located in the file
|
||||||
<a HREF="https://github.com/open-source-parsers/jsoncpp/blob/master/README.md">README.md</a> in the top-directory of the project.
|
<a HREF="README.txt">README.txt</a> in the top-directory of the project.
|
||||||
|
|
||||||
The latest version of the source is available in the project's GitHub repository:
|
Permanent link to the latest revision of the file in subversion:
|
||||||
<a HREF="https://github.com/open-source-parsers/jsoncpp/">
|
<a HREF="http://jsoncpp.svn.sourceforge.net/viewvc/jsoncpp/trunk/jsoncpp/README.txt?view=markup">latest README.txt</a>
|
||||||
jsoncpp</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>.
|
||||||
|
|
||||||
\section _news What's New?
|
\section _news What's New?
|
||||||
The description of latest changes can be found in
|
The description of latest changes can be found in
|
||||||
<a HREF="https://github.com/open-source-parsers/jsoncpp/wiki/NEWS">
|
<a HREF="NEWS.txt">NEWS.txt</a> in the top-directory of the project.
|
||||||
the NEWS wiki
|
|
||||||
</a>.
|
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>
|
||||||
|
|
||||||
\section _rlinks Related links
|
\section _rlinks Related links
|
||||||
- <a HREF="http://www.json.org/">JSON</a> Specification and alternate language implementations.
|
- <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.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>.
|
- <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
|
\section _license License
|
||||||
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.
|
See file <a HREF="LICENSE">LICENSE</a> in the top-directory of the project.
|
||||||
|
|
||||||
Basically JsonCpp is licensed under MIT license, or public domain if desired
|
Basically JsonCpp is licensed under MIT license, or public domain if desired
|
||||||
and recognized in your jurisdiction.
|
and recognized in your jurisdiction.
|
||||||
|
|
||||||
\author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
|
\author Baptiste Lepilleur <blep@users.sourceforge.net>
|
||||||
*/
|
*/
|
||||||
|
@@ -1,3 +1,37 @@
|
|||||||
/*! \page roadmap JsonCpp roadmap
|
/*! \page roadmap JsonCpp roadmap
|
||||||
Moved to: https://github.com/open-source-parsers/jsoncpp/wiki/Roadmap
|
\section ms_release Makes JsonCpp ready for release
|
||||||
|
- Build system clean-up:
|
||||||
|
- Fix build on Windows (shared-library build is broken)
|
||||||
|
- 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).
|
||||||
*/
|
*/
|
||||||
|
30
doxybuild.py
30
doxybuild.py
@@ -1,12 +1,12 @@
|
|||||||
"""Script to generate doxygen documentation.
|
"""Script to generate doxygen documentation.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
from devtools import tarball
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
|
from devtools import tarball
|
||||||
|
|
||||||
def find_program(*filenames):
|
def find_program(*filenames):
|
||||||
"""find a program in folders path_lst, and sets env[var]
|
"""find a program in folders path_lst, and sets env[var]
|
||||||
@@ -33,9 +33,9 @@ def do_subst_in_file(targetfile, sourcefile, dict):
|
|||||||
contents = f.read()
|
contents = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
except:
|
except:
|
||||||
print("Can't read source file %s"%sourcefile)
|
print "Can't read source file %s"%sourcefile
|
||||||
raise
|
raise
|
||||||
for (k,v) in list(dict.items()):
|
for (k,v) in dict.items():
|
||||||
v = v.replace('\\','\\\\')
|
v = v.replace('\\','\\\\')
|
||||||
contents = re.sub(k, v, contents)
|
contents = re.sub(k, v, contents)
|
||||||
try:
|
try:
|
||||||
@@ -43,7 +43,7 @@ def do_subst_in_file(targetfile, sourcefile, dict):
|
|||||||
f.write(contents)
|
f.write(contents)
|
||||||
f.close()
|
f.close()
|
||||||
except:
|
except:
|
||||||
print("Can't write target file %s"%targetfile)
|
print "Can't write target file %s"%targetfile
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
|
def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
|
||||||
@@ -53,12 +53,12 @@ def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
|
|||||||
try:
|
try:
|
||||||
os.chdir( working_dir )
|
os.chdir( working_dir )
|
||||||
cmd = [doxygen_path, config_file]
|
cmd = [doxygen_path, config_file]
|
||||||
print('Running:', ' '.join( cmd ))
|
print 'Running:', ' '.join( cmd )
|
||||||
try:
|
try:
|
||||||
import subprocess
|
import subprocess
|
||||||
except:
|
except:
|
||||||
if os.system( ' '.join( cmd ) ) != 0:
|
if os.system( ' '.join( cmd ) ) != 0:
|
||||||
print('Documentation generation failed')
|
print 'Documentation generation failed'
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
if is_silent:
|
if is_silent:
|
||||||
@@ -67,8 +67,8 @@ def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
|
|||||||
process = subprocess.Popen( cmd )
|
process = subprocess.Popen( cmd )
|
||||||
stdout, _ = process.communicate()
|
stdout, _ = process.communicate()
|
||||||
if process.returncode:
|
if process.returncode:
|
||||||
print('Documentation generation failed:')
|
print 'Documentation generation failed:'
|
||||||
print(stdout)
|
print stdout
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
finally:
|
finally:
|
||||||
@@ -107,7 +107,7 @@ def build_doc( options, make_release=False ):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if os.path.isdir( output_dir ):
|
if os.path.isdir( output_dir ):
|
||||||
print('Deleting directory:', output_dir)
|
print 'Deleting directory:', output_dir
|
||||||
shutil.rmtree( output_dir )
|
shutil.rmtree( output_dir )
|
||||||
if not os.path.isdir( output_dir ):
|
if not os.path.isdir( output_dir ):
|
||||||
os.makedirs( output_dir )
|
os.makedirs( output_dir )
|
||||||
@@ -115,15 +115,15 @@ def build_doc( options, make_release=False ):
|
|||||||
do_subst_in_file( 'doc/doxyfile', 'doc/doxyfile.in', subst_keys )
|
do_subst_in_file( 'doc/doxyfile', 'doc/doxyfile.in', subst_keys )
|
||||||
ok = run_doxygen( options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent )
|
ok = run_doxygen( options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent )
|
||||||
if not options.silent:
|
if not options.silent:
|
||||||
print(open(warning_log_path, 'rb').read())
|
print open(warning_log_path, 'rb').read()
|
||||||
index_path = os.path.abspath(os.path.join('doc', subst_keys['%HTML_OUTPUT%'], 'index.html'))
|
index_path = os.path.abspath(os.path.join(subst_keys['%HTML_OUTPUT%'], 'index.html'))
|
||||||
print('Generated documentation can be found in:')
|
print 'Generated documentation can be found in:'
|
||||||
print(index_path)
|
print index_path
|
||||||
if options.open:
|
if options.open:
|
||||||
import webbrowser
|
import webbrowser
|
||||||
webbrowser.open( 'file://' + index_path )
|
webbrowser.open( 'file://' + index_path )
|
||||||
if options.make_tarball:
|
if options.make_tarball:
|
||||||
print('Generating doc tarball to', tarball_path)
|
print 'Generating doc tarball to', tarball_path
|
||||||
tarball_sources = [
|
tarball_sources = [
|
||||||
output_dir,
|
output_dir,
|
||||||
'README.txt',
|
'README.txt',
|
||||||
|
@@ -1,2 +0,0 @@
|
|||||||
FILE(GLOB INCLUDE_FILES "json/*.h")
|
|
||||||
INSTALL(FILES ${INCLUDE_FILES} DESTINATION ${INCLUDE_INSTALL_DIR}/json)
|
|
@@ -1,41 +0,0 @@
|
|||||||
// Copyright 2007-2010 Baptiste Lepilleur
|
|
||||||
// Distributed under MIT license, or public domain if desired and
|
|
||||||
// recognized in your jurisdiction.
|
|
||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
||||||
|
|
||||||
#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
|
||||||
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
|
||||||
#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);
|
|
||||||
|
|
||||||
// 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); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define JSON_ASSERT_MESSAGE(condition, message) \
|
|
||||||
if (!(condition)) { \
|
|
||||||
JSON_FAIL_MESSAGE(message) \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
|
@@ -4,22 +4,21 @@
|
|||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef JSON_AUTOLINK_H_INCLUDED
|
#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
|
# ifdef JSON_IN_CPPTL
|
||||||
#include <cpptl/cpptl_autolink.h>
|
# include <cpptl/cpptl_autolink.h>
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \
|
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
|
||||||
!defined(JSON_IN_CPPTL)
|
# define CPPTL_AUTOLINK_NAME "json"
|
||||||
#define CPPTL_AUTOLINK_NAME "json"
|
# undef CPPTL_AUTOLINK_DLL
|
||||||
#undef CPPTL_AUTOLINK_DLL
|
# ifdef JSON_DLL
|
||||||
#ifdef JSON_DLL
|
# define CPPTL_AUTOLINK_DLL
|
||||||
#define CPPTL_AUTOLINK_DLL
|
# endif
|
||||||
#endif
|
# include "autolink.h"
|
||||||
#include "autolink.h"
|
# endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // JSON_AUTOLINK_H_INCLUDED
|
#endif // JSON_AUTOLINK_H_INCLUDED
|
||||||
|
@@ -4,66 +4,54 @@
|
|||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef JSON_CONFIG_H_INCLUDED
|
#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.
|
/// If defined, indicates that json library is embedded in CppTL library.
|
||||||
//# define JSON_IN_CPPTL 1
|
//# define JSON_IN_CPPTL 1
|
||||||
|
|
||||||
/// If defined, indicates that json may leverage CppTL library
|
/// If defined, indicates that json may leverage CppTL library
|
||||||
//# define JSON_USE_CPPTL 1
|
//# define JSON_USE_CPPTL 1
|
||||||
/// If defined, indicates that cpptl vector based map should be used instead of
|
/// If defined, indicates that cpptl vector based map should be used instead of std::map
|
||||||
/// std::map
|
|
||||||
/// as Value container.
|
/// as Value container.
|
||||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||||
/// If defined, indicates that Json specific container should be used
|
/// If defined, indicates that Json specific container should be used
|
||||||
/// (hash table & simple deque container with customizable allocator).
|
/// (hash table & simple deque container with customizable allocator).
|
||||||
/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
|
/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
|
||||||
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
||||||
/// Force usage of standard new/malloc based allocator instead of memory pool
|
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
|
||||||
/// based allocator.
|
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
|
||||||
/// 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.
|
/// 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.
|
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
|
||||||
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
||||||
|
|
||||||
// If non-zero, the library uses exceptions to report bad input instead of C
|
/// If defined, indicates that Json use exception to report invalid type manipulation
|
||||||
// assertion macros. The default is to use exceptions.
|
/// instead of C assert macro.
|
||||||
#ifndef JSON_USE_EXCEPTION
|
# define JSON_USE_EXCEPTION 1
|
||||||
#define JSON_USE_EXCEPTION 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// If defined, indicates that the source file is amalgated
|
/// If defined, indicates that the source file is amalgated
|
||||||
/// to prevent private header inclusion.
|
/// to prevent private header inclusion.
|
||||||
/// Remarks: it is automatically defined in the generated amalgated header.
|
/// Remarks: it is automatically defined in the generated amalgated header.
|
||||||
// #define JSON_IS_AMALGAMATION
|
// #define JSON_IS_AMALGATED
|
||||||
|
|
||||||
#ifdef JSON_IN_CPPTL
|
|
||||||
#include <cpptl/config.h>
|
|
||||||
#ifndef JSON_USE_CPPTL
|
|
||||||
#define JSON_USE_CPPTL 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JSON_IN_CPPTL
|
# ifdef JSON_IN_CPPTL
|
||||||
#define JSON_API CPPTL_API
|
# include <cpptl/config.h>
|
||||||
#elif defined(JSON_DLL_BUILD)
|
# ifndef JSON_USE_CPPTL
|
||||||
#if defined(_MSC_VER)
|
# define JSON_USE_CPPTL 1
|
||||||
#define JSON_API __declspec(dllexport)
|
# endif
|
||||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
# endif
|
||||||
#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
|
# ifdef JSON_IN_CPPTL
|
||||||
// integer
|
# define JSON_API CPPTL_API
|
||||||
|
# elif defined(JSON_DLL_BUILD)
|
||||||
|
# define JSON_API __declspec(dllexport)
|
||||||
|
# elif defined(JSON_DLL)
|
||||||
|
# define JSON_API __declspec(dllimport)
|
||||||
|
# else
|
||||||
|
# define JSON_API
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
|
||||||
// Storages, and 64 bits integer support is disabled.
|
// Storages, and 64 bits integer support is disabled.
|
||||||
// #define JSON_NO_INT64 1
|
// #define JSON_NO_INT64 1
|
||||||
|
|
||||||
@@ -71,42 +59,38 @@
|
|||||||
// Microsoft Visual Studio 6 only support conversion from __int64 to double
|
// Microsoft Visual Studio 6 only support conversion from __int64 to double
|
||||||
// (no conversion from unsigned __int64).
|
// (no conversion from unsigned __int64).
|
||||||
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
#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).
|
|
||||||
#pragma warning(disable : 4786)
|
|
||||||
#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
|
#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.
|
/// Indicates that the following function is deprecated.
|
||||||
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(JSONCPP_DEPRECATED)
|
#if !defined(JSONCPP_DEPRECATED)
|
||||||
#define JSONCPP_DEPRECATED(message)
|
# define JSONCPP_DEPRECATED(message)
|
||||||
#endif // if !defined(JSONCPP_DEPRECATED)
|
#endif // if !defined(JSONCPP_DEPRECATED)
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
typedef int Int;
|
typedef int Int;
|
||||||
typedef unsigned int UInt;
|
typedef unsigned int UInt;
|
||||||
#if defined(JSON_NO_INT64)
|
# if defined(JSON_NO_INT64)
|
||||||
typedef int LargestInt;
|
typedef int LargestInt;
|
||||||
typedef unsigned int LargestUInt;
|
typedef unsigned int LargestUInt;
|
||||||
#undef JSON_HAS_INT64
|
# undef JSON_HAS_INT64
|
||||||
#else // if defined(JSON_NO_INT64)
|
# else // if defined(JSON_NO_INT64)
|
||||||
// For Microsoft Visual use specific types as long long is not supported
|
// For Microsoft Visual use specific types as long long is not supported
|
||||||
#if defined(_MSC_VER) // Microsoft Visual Studio
|
# if defined(_MSC_VER) // Microsoft Visual Studio
|
||||||
typedef __int64 Int64;
|
typedef __int64 Int64;
|
||||||
typedef unsigned __int64 UInt64;
|
typedef unsigned __int64 UInt64;
|
||||||
#else // if defined(_MSC_VER) // Other platforms, use long long
|
# else // if defined(_MSC_VER) // Other platforms, use long long
|
||||||
typedef long long int Int64;
|
typedef long long int Int64;
|
||||||
typedef unsigned long long int UInt64;
|
typedef unsigned long long int UInt64;
|
||||||
#endif // if defined(_MSC_VER)
|
# endif // if defined(_MSC_VER)
|
||||||
typedef Int64 LargestInt;
|
typedef Int64 LargestInt;
|
||||||
typedef UInt64 LargestUInt;
|
typedef UInt64 LargestUInt;
|
||||||
#define JSON_HAS_INT64
|
# define JSON_HAS_INT64
|
||||||
#endif // if defined(JSON_NO_INT64)
|
# endif // if defined(JSON_NO_INT64)
|
||||||
} // end namespace Json
|
} // end namespace Json
|
||||||
|
|
||||||
|
|
||||||
#endif // JSON_CONFIG_H_INCLUDED
|
#endif // JSON_CONFIG_H_INCLUDED
|
||||||
|
@@ -4,30 +4,29 @@
|
|||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
|
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
#define CPPTL_JSON_FEATURES_H_INCLUDED
|
# define CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
|
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
#if !defined(JSON_IS_AMALGATED)
|
||||||
#include "forwards.h"
|
# include "forwards.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGATED)
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
/** \brief Configuration passed to reader and writer.
|
/** \brief Configuration passed to reader and writer.
|
||||||
* This configuration object can be used to force the Reader or Writer
|
* This configuration object can be used to force the Reader or Writer
|
||||||
* to behave in a standard conforming way.
|
* to behave in a standard conforming way.
|
||||||
*/
|
*/
|
||||||
class JSON_API Features {
|
class JSON_API Features
|
||||||
public:
|
{
|
||||||
/** \brief A configuration that allows all features and assumes all strings
|
public:
|
||||||
* are UTF-8.
|
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
|
||||||
* - C & C++ comments are allowed
|
* - C & C++ comments are allowed
|
||||||
* - Root object can be any JSON value
|
* - Root object can be any JSON value
|
||||||
* - Assumes Value strings are encoded in UTF-8
|
* - Assumes Value strings are encoded in UTF-8
|
||||||
*/
|
*/
|
||||||
static Features all();
|
static Features all();
|
||||||
|
|
||||||
/** \brief A configuration that is strictly compatible with the JSON
|
/** \brief A configuration that is strictly compatible with the JSON specification.
|
||||||
* specification.
|
|
||||||
* - Comments are forbidden.
|
* - Comments are forbidden.
|
||||||
* - Root object must be either an array or an object value.
|
* - Root object must be either an array or an object value.
|
||||||
* - Assumes Value strings are encoded in UTF-8
|
* - Assumes Value strings are encoded in UTF-8
|
||||||
@@ -41,16 +40,9 @@ public:
|
|||||||
/// \c true if comments are allowed. Default: \c true.
|
/// \c true if comments are allowed. Default: \c true.
|
||||||
bool allowComments_;
|
bool allowComments_;
|
||||||
|
|
||||||
/// \c true if root must be either an array or an object value. Default: \c
|
/// \c true if root must be either an array or an object value. Default: \c false.
|
||||||
/// false.
|
|
||||||
bool strictRoot_;
|
bool strictRoot_;
|
||||||
|
};
|
||||||
/// \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_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
|
@@ -4,40 +4,41 @@
|
|||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef JSON_FORWARDS_H_INCLUDED
|
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||||
#define JSON_FORWARDS_H_INCLUDED
|
# define JSON_FORWARDS_H_INCLUDED
|
||||||
|
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
#if !defined(JSON_IS_AMALGATED)
|
||||||
#include "config.h"
|
# include "config.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGATED)
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
// writer.h
|
// writer.h
|
||||||
class FastWriter;
|
class FastWriter;
|
||||||
class StyledWriter;
|
class StyledWriter;
|
||||||
|
|
||||||
// reader.h
|
// reader.h
|
||||||
class Reader;
|
class Reader;
|
||||||
|
|
||||||
// features.h
|
// features.h
|
||||||
class Features;
|
class Features;
|
||||||
|
|
||||||
// value.h
|
// value.h
|
||||||
typedef unsigned int ArrayIndex;
|
typedef unsigned int ArrayIndex;
|
||||||
class StaticString;
|
class StaticString;
|
||||||
class Path;
|
class Path;
|
||||||
class PathArgument;
|
class PathArgument;
|
||||||
class Value;
|
class Value;
|
||||||
class ValueIteratorBase;
|
class ValueIteratorBase;
|
||||||
class ValueIterator;
|
class ValueIterator;
|
||||||
class ValueConstIterator;
|
class ValueConstIterator;
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
class ValueMapAllocator;
|
class ValueMapAllocator;
|
||||||
class ValueInternalLink;
|
class ValueInternalLink;
|
||||||
class ValueInternalArray;
|
class ValueInternalArray;
|
||||||
class ValueInternalMap;
|
class ValueInternalMap;
|
||||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
|
|
||||||
#endif // JSON_FORWARDS_H_INCLUDED
|
#endif // JSON_FORWARDS_H_INCLUDED
|
||||||
|
@@ -4,12 +4,12 @@
|
|||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef JSON_JSON_H_INCLUDED
|
#ifndef JSON_JSON_H_INCLUDED
|
||||||
#define JSON_JSON_H_INCLUDED
|
# define JSON_JSON_H_INCLUDED
|
||||||
|
|
||||||
#include "autolink.h"
|
# include "autolink.h"
|
||||||
#include "value.h"
|
# include "value.h"
|
||||||
#include "reader.h"
|
# include "reader.h"
|
||||||
#include "writer.h"
|
# include "writer.h"
|
||||||
#include "features.h"
|
# include "features.h"
|
||||||
|
|
||||||
#endif // JSON_JSON_H_INCLUDED
|
#endif // JSON_JSON_H_INCLUDED
|
||||||
|
@@ -4,46 +4,27 @@
|
|||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
||||||
#define CPPTL_JSON_READER_H_INCLUDED
|
# define CPPTL_JSON_READER_H_INCLUDED
|
||||||
|
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
#if !defined(JSON_IS_AMALGATED)
|
||||||
#include "features.h"
|
# include "features.h"
|
||||||
#include "value.h"
|
# include "value.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGATED)
|
||||||
#include <deque>
|
# include <deque>
|
||||||
#include <iosfwd>
|
# include <stack>
|
||||||
#include <stack>
|
# include <string>
|
||||||
#include <string>
|
# include <iostream>
|
||||||
|
|
||||||
// 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)
|
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
|
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
||||||
*Value.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class JSON_API Reader {
|
class JSON_API Reader
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
typedef char Char;
|
typedef char Char;
|
||||||
typedef const Char* Location;
|
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
|
/** \brief Constructs a Reader allowing all features
|
||||||
* for parsing.
|
* for parsing.
|
||||||
@@ -53,108 +34,63 @@ public:
|
|||||||
/** \brief Constructs a Reader allowing the specified feature set
|
/** \brief Constructs a Reader allowing the specified feature set
|
||||||
* for parsing.
|
* for parsing.
|
||||||
*/
|
*/
|
||||||
Reader(const Features& features);
|
Reader( const Features &features );
|
||||||
|
|
||||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||||
* document.
|
|
||||||
* \param document UTF-8 encoded string containing the document to read.
|
* \param document UTF-8 encoded string containing the document to read.
|
||||||
* \param root [out] Contains the root value of the document if it was
|
* \param root [out] Contains the root value of the document if it was
|
||||||
* successfully parsed.
|
* successfully parsed.
|
||||||
* \param collectComments \c true to collect comment and allow writing them
|
* \param collectComments \c true to collect comment and allow writing them back during
|
||||||
* back during
|
|
||||||
* serialization, \c false to discard comments.
|
* serialization, \c false to discard comments.
|
||||||
* This parameter is ignored if
|
* This parameter is ignored if Features::allowComments_
|
||||||
* Features::allowComments_
|
|
||||||
* is \c false.
|
* is \c false.
|
||||||
* \return \c true if the document was successfully parsed, \c false if an
|
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||||
* error occurred.
|
|
||||||
*/
|
*/
|
||||||
bool
|
bool parse( const std::string &document,
|
||||||
parse(const std::string& document, Value& root, bool collectComments = true);
|
Value &root,
|
||||||
|
bool collectComments = true );
|
||||||
|
|
||||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||||
document.
|
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read.
|
||||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
|
* \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read.
|
||||||
document to read.
|
|
||||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
|
||||||
document to read.
|
|
||||||
\ Must be >= beginDoc.
|
\ Must be >= beginDoc.
|
||||||
* \param root [out] Contains the root value of the document if it was
|
* \param root [out] Contains the root value of the document if it was
|
||||||
* successfully parsed.
|
* successfully parsed.
|
||||||
* \param collectComments \c true to collect comment and allow writing them
|
* \param collectComments \c true to collect comment and allow writing them back during
|
||||||
back during
|
|
||||||
* serialization, \c false to discard comments.
|
* serialization, \c false to discard comments.
|
||||||
* This parameter is ignored if
|
* This parameter is ignored if Features::allowComments_
|
||||||
Features::allowComments_
|
|
||||||
* is \c false.
|
* is \c false.
|
||||||
* \return \c true if the document was successfully parsed, \c false if an
|
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||||
error occurred.
|
|
||||||
*/
|
*/
|
||||||
bool parse(const char* beginDoc,
|
bool parse( const char *beginDoc, const char *endDoc,
|
||||||
const char* endDoc,
|
Value &root,
|
||||||
Value& root,
|
bool collectComments = true );
|
||||||
bool collectComments = true);
|
|
||||||
|
|
||||||
/// \brief Parse from input stream.
|
/// \brief Parse from input stream.
|
||||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||||
bool parse(std::istream& is, Value& root, bool collectComments = true);
|
bool parse( std::istream &is,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments = true );
|
||||||
|
|
||||||
/** \brief Returns a user friendly string that list errors in the parsed
|
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||||
* document.
|
* \return Formatted error message with the list of errors with their location in
|
||||||
* \return Formatted error message with the list of errors with their location
|
* the parsed document. An empty string is returned if no error occurred
|
||||||
* in
|
|
||||||
* the parsed document. An empty string is returned if no error
|
|
||||||
* occurred
|
|
||||||
* during parsing.
|
* during parsing.
|
||||||
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||||
*/
|
*/
|
||||||
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
|
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
|
||||||
std::string getFormatedErrorMessages() const;
|
std::string getFormatedErrorMessages() const;
|
||||||
|
|
||||||
/** \brief Returns a user friendly string that list errors in the parsed
|
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||||
* document.
|
* \return Formatted error message with the list of errors with their location in
|
||||||
* \return Formatted error message with the list of errors with their location
|
* the parsed document. An empty string is returned if no error occurred
|
||||||
* in
|
|
||||||
* the parsed document. An empty string is returned if no error
|
|
||||||
* occurred
|
|
||||||
* during parsing.
|
* during parsing.
|
||||||
*/
|
*/
|
||||||
std::string getFormattedErrorMessages() const;
|
std::string getFormattedErrorMessages() const;
|
||||||
|
|
||||||
/** \brief Returns a vector of structured erros encounted while parsing.
|
private:
|
||||||
* \return A (possibly empty) vector of StructuredError objects. Currently
|
enum TokenType
|
||||||
* 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,
|
tokenEndOfStream = 0,
|
||||||
tokenObjectBegin,
|
tokenObjectBegin,
|
||||||
tokenObjectEnd,
|
tokenObjectEnd,
|
||||||
@@ -171,14 +107,16 @@ private:
|
|||||||
tokenError
|
tokenError
|
||||||
};
|
};
|
||||||
|
|
||||||
class Token {
|
class Token
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
TokenType type_;
|
TokenType type_;
|
||||||
Location start_;
|
Location start_;
|
||||||
Location end_;
|
Location end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ErrorInfo {
|
class ErrorInfo
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Token token_;
|
Token token_;
|
||||||
std::string message_;
|
std::string message_;
|
||||||
@@ -187,46 +125,51 @@ private:
|
|||||||
|
|
||||||
typedef std::deque<ErrorInfo> Errors;
|
typedef std::deque<ErrorInfo> Errors;
|
||||||
|
|
||||||
bool readToken(Token& token);
|
bool expectToken( TokenType type, Token &token, const char *message );
|
||||||
|
bool readToken( Token &token );
|
||||||
void skipSpaces();
|
void skipSpaces();
|
||||||
bool match(Location pattern, int patternLength);
|
bool match( Location pattern,
|
||||||
|
int patternLength );
|
||||||
bool readComment();
|
bool readComment();
|
||||||
bool readCStyleComment();
|
bool readCStyleComment();
|
||||||
bool readCppStyleComment();
|
bool readCppStyleComment();
|
||||||
bool readString();
|
bool readString();
|
||||||
void readNumber();
|
void readNumber();
|
||||||
bool readValue();
|
bool readValue();
|
||||||
bool readObject(Token& token);
|
bool readObject( Token &token );
|
||||||
bool readArray(Token& token);
|
bool readArray( Token &token );
|
||||||
bool decodeNumber(Token& token);
|
bool decodeNumber( Token &token );
|
||||||
bool decodeNumber(Token& token, Value& decoded);
|
bool decodeString( Token &token );
|
||||||
bool decodeString(Token& token);
|
bool decodeString( Token &token, std::string &decoded );
|
||||||
bool decodeString(Token& token, std::string& decoded);
|
bool decodeDouble( Token &token );
|
||||||
bool decodeDouble(Token& token);
|
bool decodeUnicodeCodePoint( Token &token,
|
||||||
bool decodeDouble(Token& token, Value& decoded);
|
Location ¤t,
|
||||||
bool decodeUnicodeCodePoint(Token& token,
|
|
||||||
Location& current,
|
|
||||||
Location end,
|
Location end,
|
||||||
unsigned int& unicode);
|
unsigned int &unicode );
|
||||||
bool decodeUnicodeEscapeSequence(Token& token,
|
bool decodeUnicodeEscapeSequence( Token &token,
|
||||||
Location& current,
|
Location ¤t,
|
||||||
Location end,
|
Location end,
|
||||||
unsigned int& unicode);
|
unsigned int &unicode );
|
||||||
bool addError(const std::string& message, Token& token, Location extra = 0);
|
bool addError( const std::string &message,
|
||||||
bool recoverFromError(TokenType skipUntilToken);
|
Token &token,
|
||||||
bool addErrorAndRecover(const std::string& message,
|
Location extra = 0 );
|
||||||
Token& token,
|
bool recoverFromError( TokenType skipUntilToken );
|
||||||
TokenType skipUntilToken);
|
bool addErrorAndRecover( const std::string &message,
|
||||||
|
Token &token,
|
||||||
|
TokenType skipUntilToken );
|
||||||
void skipUntilSpace();
|
void skipUntilSpace();
|
||||||
Value& currentValue();
|
Value ¤tValue();
|
||||||
Char getNextChar();
|
Char getNextChar();
|
||||||
void
|
void getLocationLineAndColumn( Location location,
|
||||||
getLocationLineAndColumn(Location location, int& line, int& column) const;
|
int &line,
|
||||||
std::string getLocationLineAndColumn(Location location) const;
|
int &column ) const;
|
||||||
void addComment(Location begin, Location end, CommentPlacement placement);
|
std::string getLocationLineAndColumn( Location location ) const;
|
||||||
void skipCommentTokens(Token& token);
|
void addComment( Location begin,
|
||||||
|
Location end,
|
||||||
|
CommentPlacement placement );
|
||||||
|
void skipCommentTokens( Token &token );
|
||||||
|
|
||||||
typedef std::stack<Value*> Nodes;
|
typedef std::stack<Value *> Nodes;
|
||||||
Nodes nodes_;
|
Nodes nodes_;
|
||||||
Errors errors_;
|
Errors errors_;
|
||||||
std::string document_;
|
std::string document_;
|
||||||
@@ -234,13 +177,13 @@ private:
|
|||||||
Location end_;
|
Location end_;
|
||||||
Location current_;
|
Location current_;
|
||||||
Location lastValueEnd_;
|
Location lastValueEnd_;
|
||||||
Value* lastValue_;
|
Value *lastValue_;
|
||||||
std::string commentsBefore_;
|
std::string commentsBefore_;
|
||||||
Features features_;
|
Features features_;
|
||||||
bool collectComments_;
|
bool collectComments_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Read from 'sin' into 'root'.
|
/** \brief Read from 'sin' into 'root'.
|
||||||
|
|
||||||
Always keep comments from the input JSON.
|
Always keep comments from the input JSON.
|
||||||
|
|
||||||
@@ -263,13 +206,9 @@ private:
|
|||||||
\endverbatim
|
\endverbatim
|
||||||
\throw std::exception on parse error.
|
\throw std::exception on parse error.
|
||||||
\see Json::operator<<()
|
\see Json::operator<<()
|
||||||
*/
|
*/
|
||||||
JSON_API std::istream& operator>>(std::istream&, Value&);
|
std::istream& operator>>( std::istream&, Value& );
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
|
||||||
|
|
||||||
#endif // CPPTL_JSON_READER_H_INCLUDED
|
#endif // CPPTL_JSON_READER_H_INCLUDED
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,14 +0,0 @@
|
|||||||
// 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 "1.2.0"
|
|
||||||
# define JSONCPP_VERSION_MAJOR 1
|
|
||||||
# define JSONCPP_VERSION_MINOR 2
|
|
||||||
# define JSONCPP_VERSION_PATCH 0
|
|
||||||
# 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,118 +4,97 @@
|
|||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef JSON_WRITER_H_INCLUDED
|
#ifndef JSON_WRITER_H_INCLUDED
|
||||||
#define JSON_WRITER_H_INCLUDED
|
# define JSON_WRITER_H_INCLUDED
|
||||||
|
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
#if !defined(JSON_IS_AMALGATED)
|
||||||
#include "value.h"
|
# include "value.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGATED)
|
||||||
#include <vector>
|
# include <vector>
|
||||||
#include <string>
|
# include <string>
|
||||||
|
# include <iostream>
|
||||||
// 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)
|
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
class Value;
|
class Value;
|
||||||
|
|
||||||
/** \brief Abstract class for writers.
|
/** \brief Abstract class for writers.
|
||||||
*/
|
*/
|
||||||
class JSON_API Writer {
|
class JSON_API Writer
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
virtual ~Writer();
|
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
|
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
|
||||||
*without formatting (not human friendly).
|
|
||||||
*
|
*
|
||||||
* The JSON document is written in a single line. It is not intended for 'human'
|
* The JSON document is written in a single line. It is not intended for 'human' consumption,
|
||||||
*consumption,
|
|
||||||
* but may be usefull to support feature such as RPC where bandwith is limited.
|
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||||
* \sa Reader, Value
|
* \sa Reader, Value
|
||||||
*/
|
*/
|
||||||
class JSON_API FastWriter : public Writer {
|
class JSON_API FastWriter : public Writer
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
FastWriter();
|
FastWriter();
|
||||||
virtual ~FastWriter() {}
|
virtual ~FastWriter(){}
|
||||||
|
|
||||||
void enableYAMLCompatibility();
|
void enableYAMLCompatibility();
|
||||||
|
|
||||||
/** \brief Drop the "null" string from the writer's output for nullValues.
|
public: // overridden from Writer
|
||||||
* Strictly speaking, this is not valid JSON. But when the output is being
|
virtual std::string write( const Value &root );
|
||||||
* fed to a browser's Javascript, it makes for smaller output and the
|
|
||||||
* browser can handle the output just fine.
|
|
||||||
*/
|
|
||||||
void dropNullPlaceholders();
|
|
||||||
|
|
||||||
void omitEndingLineFeed();
|
private:
|
||||||
|
void writeValue( const Value &value );
|
||||||
public: // overridden from Writer
|
|
||||||
virtual std::string write(const Value& root);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void writeValue(const Value& value);
|
|
||||||
|
|
||||||
std::string document_;
|
std::string document_;
|
||||||
bool yamlCompatiblityEnabled_;
|
bool yamlCompatiblityEnabled_;
|
||||||
bool dropNullPlaceholders_;
|
};
|
||||||
bool omitEndingLineFeed_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
|
||||||
*human friendly way.
|
|
||||||
*
|
*
|
||||||
* The rules for line break and indent are as follow:
|
* The rules for line break and indent are as follow:
|
||||||
* - Object value:
|
* - Object value:
|
||||||
* - if empty then print {} without indent and line break
|
* - if empty then print {} without indent and line break
|
||||||
* - if not empty the print '{', line break & indent, print one value per
|
* - if not empty the print '{', line break & indent, print one value per line
|
||||||
*line
|
|
||||||
* and then unindent and line break and print '}'.
|
* and then unindent and line break and print '}'.
|
||||||
* - Array value:
|
* - Array value:
|
||||||
* - if empty then print [] without indent and line break
|
* - if empty then print [] without indent and line break
|
||||||
* - if the array contains no object value, empty array or some other value
|
* - if the array contains no object value, empty array or some other value types,
|
||||||
*types,
|
* and all the values fit on one lines, then print the array on a single line.
|
||||||
* 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
|
* - 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.
|
* object or non empty array, then print one value per line.
|
||||||
*
|
*
|
||||||
* If the Value have comments then they are outputed according to their
|
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||||
*#CommentPlacement.
|
|
||||||
*
|
*
|
||||||
* \sa Reader, Value, Value::setComment()
|
* \sa Reader, Value, Value::setComment()
|
||||||
*/
|
*/
|
||||||
class JSON_API StyledWriter : public Writer {
|
class JSON_API StyledWriter: public Writer
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
StyledWriter();
|
StyledWriter();
|
||||||
virtual ~StyledWriter() {}
|
virtual ~StyledWriter(){}
|
||||||
|
|
||||||
public: // overridden from Writer
|
public: // overridden from Writer
|
||||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||||
* \param root Value to serialize.
|
* \param root Value to serialize.
|
||||||
* \return String containing the JSON document that represents the root value.
|
* \return String containing the JSON document that represents the root value.
|
||||||
*/
|
*/
|
||||||
virtual std::string write(const Value& root);
|
virtual std::string write( const Value &root );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void writeValue(const Value& value);
|
void writeValue( const Value &value );
|
||||||
void writeArrayValue(const Value& value);
|
void writeArrayValue( const Value &value );
|
||||||
bool isMultineArray(const Value& value);
|
bool isMultineArray( const Value &value );
|
||||||
void pushValue(const std::string& value);
|
void pushValue( const std::string &value );
|
||||||
void writeIndent();
|
void writeIndent();
|
||||||
void writeWithIndent(const std::string& value);
|
void writeWithIndent( const std::string &value );
|
||||||
void indent();
|
void indent();
|
||||||
void unindent();
|
void unindent();
|
||||||
void writeCommentBeforeValue(const Value& root);
|
void writeCommentBeforeValue( const Value &root );
|
||||||
void writeCommentAfterValueOnSameLine(const Value& root);
|
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||||
bool hasCommentForValue(const Value& value);
|
bool hasCommentForValue( const Value &value );
|
||||||
static std::string normalizeEOL(const std::string& text);
|
static std::string normalizeEOL( const std::string &text );
|
||||||
|
|
||||||
typedef std::vector<std::string> ChildValues;
|
typedef std::vector<std::string> ChildValues;
|
||||||
|
|
||||||
@@ -125,60 +104,55 @@ private:
|
|||||||
int rightMargin_;
|
int rightMargin_;
|
||||||
int indentSize_;
|
int indentSize_;
|
||||||
bool addChildValues_;
|
bool addChildValues_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
|
||||||
human friendly way,
|
|
||||||
to a stream rather than to a string.
|
to a stream rather than to a string.
|
||||||
*
|
*
|
||||||
* The rules for line break and indent are as follow:
|
* The rules for line break and indent are as follow:
|
||||||
* - Object value:
|
* - Object value:
|
||||||
* - if empty then print {} without indent and line break
|
* - if empty then print {} without indent and line break
|
||||||
* - if not empty the print '{', line break & indent, print one value per
|
* - if not empty the print '{', line break & indent, print one value per line
|
||||||
line
|
|
||||||
* and then unindent and line break and print '}'.
|
* and then unindent and line break and print '}'.
|
||||||
* - Array value:
|
* - Array value:
|
||||||
* - if empty then print [] without indent and line break
|
* - if empty then print [] without indent and line break
|
||||||
* - if the array contains no object value, empty array or some other value
|
* - if the array contains no object value, empty array or some other value types,
|
||||||
types,
|
* and all the values fit on one lines, then print the array on a single line.
|
||||||
* 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
|
* - 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.
|
* object or non empty array, then print one value per line.
|
||||||
*
|
*
|
||||||
* If the Value have comments then they are outputed according to their
|
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||||
#CommentPlacement.
|
|
||||||
*
|
*
|
||||||
* \param indentation Each level will be indented by this amount extra.
|
* \param indentation Each level will be indented by this amount extra.
|
||||||
* \sa Reader, Value, Value::setComment()
|
* \sa Reader, Value, Value::setComment()
|
||||||
*/
|
*/
|
||||||
class JSON_API StyledStreamWriter {
|
class JSON_API StyledStreamWriter
|
||||||
public:
|
{
|
||||||
StyledStreamWriter(std::string indentation = "\t");
|
public:
|
||||||
~StyledStreamWriter() {}
|
StyledStreamWriter( std::string indentation="\t" );
|
||||||
|
~StyledStreamWriter(){}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
/** \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 out Stream to write to. (Can be ostringstream, e.g.)
|
||||||
* \param root Value to serialize.
|
* \param root Value to serialize.
|
||||||
* \note There is no point in deriving from Writer, since write() should not
|
* \note There is no point in deriving from Writer, since write() should not return a value.
|
||||||
* return a value.
|
|
||||||
*/
|
*/
|
||||||
void write(std::ostream& out, const Value& root);
|
void write( std::ostream &out, const Value &root );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void writeValue(const Value& value);
|
void writeValue( const Value &value );
|
||||||
void writeArrayValue(const Value& value);
|
void writeArrayValue( const Value &value );
|
||||||
bool isMultineArray(const Value& value);
|
bool isMultineArray( const Value &value );
|
||||||
void pushValue(const std::string& value);
|
void pushValue( const std::string &value );
|
||||||
void writeIndent();
|
void writeIndent();
|
||||||
void writeWithIndent(const std::string& value);
|
void writeWithIndent( const std::string &value );
|
||||||
void indent();
|
void indent();
|
||||||
void unindent();
|
void unindent();
|
||||||
void writeCommentBeforeValue(const Value& root);
|
void writeCommentBeforeValue( const Value &root );
|
||||||
void writeCommentAfterValueOnSameLine(const Value& root);
|
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||||
bool hasCommentForValue(const Value& value);
|
bool hasCommentForValue( const Value &value );
|
||||||
static std::string normalizeEOL(const std::string& text);
|
static std::string normalizeEOL( const std::string &text );
|
||||||
|
|
||||||
typedef std::vector<std::string> ChildValues;
|
typedef std::vector<std::string> ChildValues;
|
||||||
|
|
||||||
@@ -188,26 +162,24 @@ private:
|
|||||||
int rightMargin_;
|
int rightMargin_;
|
||||||
std::string indentation_;
|
std::string indentation_;
|
||||||
bool addChildValues_;
|
bool addChildValues_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(JSON_HAS_INT64)
|
# if defined(JSON_HAS_INT64)
|
||||||
std::string JSON_API valueToString(Int value);
|
std::string JSON_API valueToString( Int value );
|
||||||
std::string JSON_API valueToString(UInt value);
|
std::string JSON_API valueToString( UInt value );
|
||||||
#endif // if defined(JSON_HAS_INT64)
|
# endif // if defined(JSON_HAS_INT64)
|
||||||
std::string JSON_API valueToString(LargestInt value);
|
std::string JSON_API valueToString( LargestInt value );
|
||||||
std::string JSON_API valueToString(LargestUInt value);
|
std::string JSON_API valueToString( LargestUInt value );
|
||||||
std::string JSON_API valueToString(double value);
|
std::string JSON_API valueToString( double value );
|
||||||
std::string JSON_API valueToString(bool value);
|
std::string JSON_API valueToString( bool value );
|
||||||
std::string JSON_API valueToQuotedString(const char* value);
|
std::string JSON_API valueToQuotedString( const char *value );
|
||||||
|
|
||||||
/// \brief Output using the StyledStreamWriter.
|
/// \brief Output using the StyledStreamWriter.
|
||||||
/// \see Json::operator>>()
|
/// \see Json::operator>>()
|
||||||
JSON_API std::ostream& operator<<(std::ostream&, const Value& root);
|
std::ostream& operator<<( std::ostream&, const Value &root );
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
|
||||||
|
|
||||||
#endif // JSON_WRITER_H_INCLUDED
|
#endif // JSON_WRITER_H_INCLUDED
|
||||||
|
@@ -1,42 +0,0 @@
|
|||||||
|
|
||||||
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
|
|
@@ -1,96 +0,0 @@
|
|||||||
<?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>
|
|
@@ -1,13 +0,0 @@
|
|||||||
<?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>
|
|
@@ -1,143 +0,0 @@
|
|||||||
<?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>
|
|
@@ -1,33 +0,0 @@
|
|||||||
<?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>
|
|
@@ -1,109 +0,0 @@
|
|||||||
<?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>
|
|
@@ -1,24 +0,0 @@
|
|||||||
<?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,11 +10,7 @@ python makerelease.py --force --retag --platform=msvc6,msvc71,msvc80,mingw -uble
|
|||||||
|
|
||||||
Example of invocation when doing a release:
|
Example of invocation when doing a release:
|
||||||
python makerelease.py 0.5.0 0.6.0-dev
|
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.
|
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -27,7 +23,7 @@ import tempfile
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from devtools import antglob, fixeol, tarball
|
from devtools import antglob, fixeol, tarball
|
||||||
import amalgamate
|
import amalgate
|
||||||
|
|
||||||
SVN_ROOT = 'https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/'
|
SVN_ROOT = 'https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/'
|
||||||
SVN_TAG_ROOT = SVN_ROOT + 'tags/jsoncpp'
|
SVN_TAG_ROOT = SVN_ROOT + 'tags/jsoncpp'
|
||||||
@@ -47,7 +43,7 @@ class SVNError(Exception):
|
|||||||
|
|
||||||
def svn_command( command, *args ):
|
def svn_command( command, *args ):
|
||||||
cmd = ['svn', '--non-interactive', command] + list(args)
|
cmd = ['svn', '--non-interactive', command] + list(args)
|
||||||
print('Running:', ' '.join( cmd ))
|
print 'Running:', ' '.join( cmd )
|
||||||
process = subprocess.Popen( cmd,
|
process = subprocess.Popen( cmd,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT )
|
stderr=subprocess.STDOUT )
|
||||||
@@ -85,7 +81,7 @@ def svn_check_if_tag_exist( tag_url ):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
list_stdout = svn_command( 'list', tag_url )
|
list_stdout = svn_command( 'list', tag_url )
|
||||||
except SVNError as e:
|
except SVNError, e:
|
||||||
if e.returncode != 1 or not str(e).find('tag_url'):
|
if e.returncode != 1 or not str(e).find('tag_url'):
|
||||||
raise e
|
raise e
|
||||||
# otherwise ignore error, meaning tag does not exist
|
# otherwise ignore error, meaning tag does not exist
|
||||||
@@ -118,7 +114,7 @@ def svn_export( tag_url, export_dir ):
|
|||||||
def fix_sources_eol( dist_dir ):
|
def fix_sources_eol( dist_dir ):
|
||||||
"""Set file EOL for tarball distribution.
|
"""Set file EOL for tarball distribution.
|
||||||
"""
|
"""
|
||||||
print('Preparing exported source file EOL for distribution...')
|
print 'Preparing exported source file EOL for distribution...'
|
||||||
prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
|
prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
|
||||||
win_sources = antglob.glob( dist_dir,
|
win_sources = antglob.glob( dist_dir,
|
||||||
includes = '**/*.sln **/*.vcproj',
|
includes = '**/*.sln **/*.vcproj',
|
||||||
@@ -149,7 +145,7 @@ def download( url, target_path ):
|
|||||||
|
|
||||||
def check_compile( distcheck_top_dir, platform ):
|
def check_compile( distcheck_top_dir, platform ):
|
||||||
cmd = [sys.executable, 'scons.py', 'platform=%s' % platform, 'check']
|
cmd = [sys.executable, 'scons.py', 'platform=%s' % platform, 'check']
|
||||||
print('Running:', ' '.join( cmd ))
|
print 'Running:', ' '.join( cmd )
|
||||||
log_path = os.path.join( distcheck_top_dir, 'build-%s.log' % platform )
|
log_path = os.path.join( distcheck_top_dir, 'build-%s.log' % platform )
|
||||||
flog = open( log_path, 'wb' )
|
flog = open( log_path, 'wb' )
|
||||||
try:
|
try:
|
||||||
@@ -180,9 +176,9 @@ def run_sftp_batch( userhost, sftp, batch, retry=0 ):
|
|||||||
# psftp -agent -C blep,jsoncpp@web.sourceforge.net -batch -b batch.sftp -bc
|
# psftp -agent -C blep,jsoncpp@web.sourceforge.net -batch -b batch.sftp -bc
|
||||||
cmd = [sftp, '-agent', '-C', '-batch', '-b', path, '-bc', userhost]
|
cmd = [sftp, '-agent', '-C', '-batch', '-b', path, '-bc', userhost]
|
||||||
error = None
|
error = None
|
||||||
for retry_index in range(0, max(1,retry)):
|
for retry_index in xrange(0, max(1,retry)):
|
||||||
heading = retry_index == 0 and 'Running:' or 'Retrying:'
|
heading = retry_index == 0 and 'Running:' or 'Retrying:'
|
||||||
print(heading, ' '.join( cmd ))
|
print heading, ' '.join( cmd )
|
||||||
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
||||||
stdout = process.communicate()[0]
|
stdout = process.communicate()[0]
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
@@ -220,21 +216,21 @@ exit
|
|||||||
upload_paths = set( [os.path.basename(p) for p in antglob.glob( doc_dir )] )
|
upload_paths = set( [os.path.basename(p) for p in antglob.glob( doc_dir )] )
|
||||||
paths_to_remove = existing_paths - upload_paths
|
paths_to_remove = existing_paths - upload_paths
|
||||||
if paths_to_remove:
|
if paths_to_remove:
|
||||||
print('Removing the following file from web:')
|
print 'Removing the following file from web:'
|
||||||
print('\n'.join( paths_to_remove ))
|
print '\n'.join( paths_to_remove )
|
||||||
stdout = run_sftp_batch( userhost, sftp, """cd htdocs
|
stdout = run_sftp_batch( userhost, sftp, """cd htdocs
|
||||||
rm %s
|
rm %s
|
||||||
exit""" % ' '.join(paths_to_remove) )
|
exit""" % ' '.join(paths_to_remove) )
|
||||||
print('Uploading %d files:' % len(upload_paths))
|
print 'Uploading %d files:' % len(upload_paths)
|
||||||
batch_size = 10
|
batch_size = 10
|
||||||
upload_paths = list(upload_paths)
|
upload_paths = list(upload_paths)
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
for index in range(0,len(upload_paths),batch_size):
|
for index in xrange(0,len(upload_paths),batch_size):
|
||||||
paths = upload_paths[index:index+batch_size]
|
paths = upload_paths[index:index+batch_size]
|
||||||
file_per_sec = (time.time() - start_time) / (index+1)
|
file_per_sec = (time.time() - start_time) / (index+1)
|
||||||
remaining_files = len(upload_paths) - index
|
remaining_files = len(upload_paths) - index
|
||||||
remaining_sec = file_per_sec * remaining_files
|
remaining_sec = file_per_sec * remaining_files
|
||||||
print('%d/%d, ETA=%.1fs' % (index+1, len(upload_paths), remaining_sec))
|
print '%d/%d, ETA=%.1fs' % (index+1, len(upload_paths), remaining_sec)
|
||||||
run_sftp_batch( userhost, sftp, """cd htdocs
|
run_sftp_batch( userhost, sftp, """cd htdocs
|
||||||
lcd %s
|
lcd %s
|
||||||
mput %s
|
mput %s
|
||||||
@@ -298,7 +294,7 @@ Warning: --force should only be used when developping/testing the release script
|
|||||||
else:
|
else:
|
||||||
msg = check_no_pending_commit()
|
msg = check_no_pending_commit()
|
||||||
if not msg:
|
if not msg:
|
||||||
print('Setting version to', release_version)
|
print 'Setting version to', release_version
|
||||||
set_version( release_version )
|
set_version( release_version )
|
||||||
svn_commit( 'Release ' + release_version )
|
svn_commit( 'Release ' + release_version )
|
||||||
tag_url = svn_join_url( SVN_TAG_ROOT, release_version )
|
tag_url = svn_join_url( SVN_TAG_ROOT, release_version )
|
||||||
@@ -306,11 +302,11 @@ Warning: --force should only be used when developping/testing the release script
|
|||||||
if options.retag_release:
|
if options.retag_release:
|
||||||
svn_remove_tag( tag_url, 'Overwriting previous tag' )
|
svn_remove_tag( tag_url, 'Overwriting previous tag' )
|
||||||
else:
|
else:
|
||||||
print('Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url)
|
print 'Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url
|
||||||
sys.exit( 1 )
|
sys.exit( 1 )
|
||||||
svn_tag_sandbox( tag_url, 'Release ' + release_version )
|
svn_tag_sandbox( tag_url, 'Release ' + release_version )
|
||||||
|
|
||||||
print('Generated doxygen document...')
|
print 'Generated doxygen document...'
|
||||||
## doc_dirname = r'jsoncpp-api-html-0.5.0'
|
## doc_dirname = r'jsoncpp-api-html-0.5.0'
|
||||||
## doc_tarball_path = r'e:\prg\vc\Lib\jsoncpp-trunk\dist\jsoncpp-api-html-0.5.0.tar.gz'
|
## doc_tarball_path = r'e:\prg\vc\Lib\jsoncpp-trunk\dist\jsoncpp-api-html-0.5.0.tar.gz'
|
||||||
doc_tarball_path, doc_dirname = doxybuild.build_doc( options, make_release=True )
|
doc_tarball_path, doc_dirname = doxybuild.build_doc( options, make_release=True )
|
||||||
@@ -324,55 +320,55 @@ Warning: --force should only be used when developping/testing the release script
|
|||||||
|
|
||||||
source_dir = 'jsoncpp-src-' + release_version
|
source_dir = 'jsoncpp-src-' + release_version
|
||||||
source_tarball_path = 'dist/%s.tar.gz' % source_dir
|
source_tarball_path = 'dist/%s.tar.gz' % source_dir
|
||||||
print('Generating source tarball to', source_tarball_path)
|
print 'Generating source tarball to', source_tarball_path
|
||||||
tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir )
|
tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir )
|
||||||
|
|
||||||
amalgamation_tarball_path = 'dist/%s-amalgamation.tar.gz' % source_dir
|
amalgated_tarball_path = 'dist/%s-amalgated.tar.gz' % source_dir
|
||||||
print('Generating amalgamation source tarball to', amalgamation_tarball_path)
|
print 'Generating amalgated source tarball to', amalgated_tarball_path
|
||||||
amalgamation_dir = 'dist/amalgamation'
|
amalgated_dir = 'dist/amalgated'
|
||||||
amalgamate.amalgamate_source( export_dir, '%s/jsoncpp.cpp' % amalgamation_dir, 'json/json.h' )
|
amalgate.amalgate_source( export_dir, '%s/jsoncpp.cpp' % amalgated_dir, 'json/json.h' )
|
||||||
amalgamation_source_dir = 'jsoncpp-src-amalgamation' + release_version
|
amalgated_source_dir = 'jsoncpp-src-amalgated' + release_version
|
||||||
tarball.make_tarball( amalgamation_tarball_path, [amalgamation_dir],
|
tarball.make_tarball( amalgated_tarball_path, [amalgated_dir],
|
||||||
amalgamation_dir, prefix_dir=amalgamation_source_dir )
|
amalgated_dir, prefix_dir=amalgated_source_dir )
|
||||||
|
|
||||||
# Decompress source tarball, download and install scons-local
|
# Decompress source tarball, download and install scons-local
|
||||||
distcheck_dir = 'dist/distcheck'
|
distcheck_dir = 'dist/distcheck'
|
||||||
distcheck_top_dir = distcheck_dir + '/' + source_dir
|
distcheck_top_dir = distcheck_dir + '/' + source_dir
|
||||||
print('Decompressing source tarball to', distcheck_dir)
|
print 'Decompressing source tarball to', distcheck_dir
|
||||||
rmdir_if_exist( distcheck_dir )
|
rmdir_if_exist( distcheck_dir )
|
||||||
tarball.decompress( source_tarball_path, distcheck_dir )
|
tarball.decompress( source_tarball_path, distcheck_dir )
|
||||||
scons_local_path = 'dist/scons-local.tar.gz'
|
scons_local_path = 'dist/scons-local.tar.gz'
|
||||||
print('Downloading scons-local to', scons_local_path)
|
print 'Downloading scons-local to', scons_local_path
|
||||||
download( SCONS_LOCAL_URL, scons_local_path )
|
download( SCONS_LOCAL_URL, scons_local_path )
|
||||||
print('Decompressing scons-local to', distcheck_top_dir)
|
print 'Decompressing scons-local to', distcheck_top_dir
|
||||||
tarball.decompress( scons_local_path, distcheck_top_dir )
|
tarball.decompress( scons_local_path, distcheck_top_dir )
|
||||||
|
|
||||||
# Run compilation
|
# Run compilation
|
||||||
print('Compiling decompressed tarball')
|
print 'Compiling decompressed tarball'
|
||||||
all_build_status = True
|
all_build_status = True
|
||||||
for platform in options.platforms.split(','):
|
for platform in options.platforms.split(','):
|
||||||
print('Testing platform:', platform)
|
print 'Testing platform:', platform
|
||||||
build_status, log_path = check_compile( distcheck_top_dir, platform )
|
build_status, log_path = check_compile( distcheck_top_dir, platform )
|
||||||
print('see build log:', log_path)
|
print 'see build log:', log_path
|
||||||
print(build_status and '=> ok' or '=> FAILED')
|
print build_status and '=> ok' or '=> FAILED'
|
||||||
all_build_status = all_build_status and build_status
|
all_build_status = all_build_status and build_status
|
||||||
if not build_status:
|
if not build_status:
|
||||||
print('Testing failed on at least one platform, aborting...')
|
print 'Testing failed on at least one platform, aborting...'
|
||||||
svn_remove_tag( tag_url, 'Removing tag due to failed testing' )
|
svn_remove_tag( tag_url, 'Removing tag due to failed testing' )
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if options.user:
|
if options.user:
|
||||||
if not options.no_web:
|
if not options.no_web:
|
||||||
print('Uploading documentation using user', options.user)
|
print 'Uploading documentation using user', options.user
|
||||||
sourceforge_web_synchro( SOURCEFORGE_PROJECT, doc_distcheck_top_dir, user=options.user, sftp=options.sftp )
|
sourceforge_web_synchro( SOURCEFORGE_PROJECT, doc_distcheck_top_dir, user=options.user, sftp=options.sftp )
|
||||||
print('Completed documentation upload')
|
print 'Completed documentation upload'
|
||||||
print('Uploading source and documentation tarballs for release using user', options.user)
|
print 'Uploading source and documentation tarballs for release using user', options.user
|
||||||
sourceforge_release_tarball( SOURCEFORGE_PROJECT,
|
sourceforge_release_tarball( SOURCEFORGE_PROJECT,
|
||||||
[source_tarball_path, doc_tarball_path],
|
[source_tarball_path, doc_tarball_path],
|
||||||
user=options.user, sftp=options.sftp )
|
user=options.user, sftp=options.sftp )
|
||||||
print('Source and doc release tarballs uploaded')
|
print 'Source and doc release tarballs uploaded'
|
||||||
else:
|
else:
|
||||||
print('No upload user specified. Web site and download tarbal were not uploaded.')
|
print 'No upload user specified. Web site and download tarbal were not uploaded.'
|
||||||
print('Tarball can be found at:', doc_tarball_path)
|
print 'Tarball can be found at:', doc_tarball_path
|
||||||
|
|
||||||
# Set next version number and commit
|
# Set next version number and commit
|
||||||
set_version( next_version )
|
set_version( next_version )
|
||||||
|
@@ -1,11 +0,0 @@
|
|||||||
prefix=@CMAKE_INSTALL_PREFIX@
|
|
||||||
exec_prefix=${prefix}
|
|
||||||
libdir=${exec_prefix}/@LIBRARY_INSTALL_DIR@
|
|
||||||
includedir=${prefix}/@INCLUDE_INSTALL_DIR@
|
|
||||||
|
|
||||||
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}
|
|
@@ -1,6 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
from SCons.Script import * # the usual scons stuff you get in a SConscript
|
from SCons.Script import * # the usual scons stuff you get in a SConscript
|
||||||
import collections
|
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
||||||
"""
|
"""
|
||||||
@@ -26,28 +25,28 @@ def generate(env):
|
|||||||
contents = f.read()
|
contents = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
except:
|
except:
|
||||||
raise SCons.Errors.UserError("Can't read source file %s"%sourcefile)
|
raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
|
||||||
for (k,v) in list(dict.items()):
|
for (k,v) in dict.items():
|
||||||
contents = re.sub(k, v, contents)
|
contents = re.sub(k, v, contents)
|
||||||
try:
|
try:
|
||||||
f = open(targetfile, 'wb')
|
f = open(targetfile, 'wb')
|
||||||
f.write(contents)
|
f.write(contents)
|
||||||
f.close()
|
f.close()
|
||||||
except:
|
except:
|
||||||
raise SCons.Errors.UserError("Can't write target file %s"%targetfile)
|
raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
|
||||||
return 0 # success
|
return 0 # success
|
||||||
|
|
||||||
def subst_in_file(target, source, env):
|
def subst_in_file(target, source, env):
|
||||||
if 'SUBST_DICT' not in env:
|
if not env.has_key('SUBST_DICT'):
|
||||||
raise SCons.Errors.UserError("SubstInFile requires SUBST_DICT to be set.")
|
raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
|
||||||
d = dict(env['SUBST_DICT']) # copy it
|
d = dict(env['SUBST_DICT']) # copy it
|
||||||
for (k,v) in list(d.items()):
|
for (k,v) in d.items():
|
||||||
if isinstance(v, collections.Callable):
|
if callable(v):
|
||||||
d[k] = env.subst(v()).replace('\\','\\\\')
|
d[k] = env.subst(v()).replace('\\','\\\\')
|
||||||
elif SCons.Util.is_String(v):
|
elif SCons.Util.is_String(v):
|
||||||
d[k] = env.subst(v).replace('\\','\\\\')
|
d[k] = env.subst(v).replace('\\','\\\\')
|
||||||
else:
|
else:
|
||||||
raise SCons.Errors.UserError("SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)))
|
raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
|
||||||
for (t,s) in zip(target, source):
|
for (t,s) in zip(target, source):
|
||||||
return do_subst_in_file(str(t), str(s), d)
|
return do_subst_in_file(str(t), str(s), d)
|
||||||
|
|
||||||
@@ -61,8 +60,8 @@ def generate(env):
|
|||||||
Returns original target, source tuple unchanged.
|
Returns original target, source tuple unchanged.
|
||||||
"""
|
"""
|
||||||
d = env['SUBST_DICT'].copy() # copy it
|
d = env['SUBST_DICT'].copy() # copy it
|
||||||
for (k,v) in list(d.items()):
|
for (k,v) in d.items():
|
||||||
if isinstance(v, collections.Callable):
|
if callable(v):
|
||||||
d[k] = env.subst(v())
|
d[k] = env.subst(v())
|
||||||
elif SCons.Util.is_String(v):
|
elif SCons.Util.is_String(v):
|
||||||
d[k]=env.subst(v)
|
d[k]=env.subst(v)
|
||||||
|
@@ -1,5 +0,0 @@
|
|||||||
ADD_SUBDIRECTORY(lib_json)
|
|
||||||
IF(JSONCPP_WITH_TESTS)
|
|
||||||
ADD_SUBDIRECTORY(jsontestrunner)
|
|
||||||
ADD_SUBDIRECTORY(test_lib_json)
|
|
||||||
ENDIF(JSONCPP_WITH_TESTS)
|
|
@@ -1,22 +0,0 @@
|
|||||||
FIND_PACKAGE(PythonInterp 2.6 REQUIRED)
|
|
||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
ADD_DEFINITIONS( -DJSON_DLL )
|
|
||||||
ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
|
|
||||||
ADD_EXECUTABLE(jsontestrunner_exe
|
|
||||||
main.cpp
|
|
||||||
)
|
|
||||||
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib)
|
|
||||||
SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe)
|
|
||||||
|
|
||||||
IF(PYTHONINTERP_FOUND)
|
|
||||||
# Run end to end parser/writer tests
|
|
||||||
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}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
|
|
||||||
DEPENDS jsontestrunner_exe jsoncpp_test
|
|
||||||
)
|
|
||||||
ADD_CUSTOM_TARGET(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests)
|
|
||||||
ENDIF(PYTHONINTERP_FOUND)
|
|
@@ -6,244 +6,237 @@
|
|||||||
/* This executable is used for testing parser/writer using real JSON files.
|
/* This executable is used for testing parser/writer using real JSON files.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <algorithm> // sort
|
#include <algorithm> // sort
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
||||||
#pragma warning(disable : 4996) // disable fopen deprecation warning
|
# pragma warning( disable: 4996 ) // disable fopen deprecation warning
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static std::string normalizeFloatingPointStr(double value) {
|
static std::string
|
||||||
char buffer[32];
|
readInputTestFile( const char *path )
|
||||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
{
|
||||||
sprintf_s(buffer, sizeof(buffer), "%.16g", value);
|
FILE *file = fopen( path, "rb" );
|
||||||
#else
|
if ( !file )
|
||||||
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) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string readInputTestFile(const char* path) {
|
|
||||||
FILE* file = fopen(path, "rb");
|
|
||||||
if (!file)
|
|
||||||
return std::string("");
|
return std::string("");
|
||||||
fseek(file, 0, SEEK_END);
|
fseek( file, 0, SEEK_END );
|
||||||
long size = ftell(file);
|
long size = ftell( file );
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek( file, 0, SEEK_SET );
|
||||||
std::string text;
|
std::string text;
|
||||||
char* buffer = new char[size + 1];
|
char *buffer = new char[size+1];
|
||||||
buffer[size] = 0;
|
buffer[size] = 0;
|
||||||
if (fread(buffer, 1, size, file) == (unsigned long)size)
|
if ( fread( buffer, 1, size, file ) == (unsigned long)size )
|
||||||
text = buffer;
|
text = buffer;
|
||||||
fclose(file);
|
fclose( file );
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
|
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() )
|
||||||
}
|
{
|
||||||
switch (value.type()) {
|
|
||||||
case Json::nullValue:
|
case Json::nullValue:
|
||||||
fprintf(fout, "%s=null\n", path.c_str());
|
fprintf( fout, "%s=null\n", path.c_str() );
|
||||||
break;
|
break;
|
||||||
case Json::intValue:
|
case Json::intValue:
|
||||||
fprintf(fout,
|
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestInt() ).c_str() );
|
||||||
"%s=%s\n",
|
|
||||||
path.c_str(),
|
|
||||||
Json::valueToString(value.asLargestInt()).c_str());
|
|
||||||
break;
|
break;
|
||||||
case Json::uintValue:
|
case Json::uintValue:
|
||||||
fprintf(fout,
|
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestUInt() ).c_str() );
|
||||||
"%s=%s\n",
|
|
||||||
path.c_str(),
|
|
||||||
Json::valueToString(value.asLargestUInt()).c_str());
|
|
||||||
break;
|
break;
|
||||||
case Json::realValue:
|
case Json::realValue:
|
||||||
fprintf(fout,
|
fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
|
||||||
"%s=%s\n",
|
|
||||||
path.c_str(),
|
|
||||||
normalizeFloatingPointStr(value.asDouble()).c_str());
|
|
||||||
break;
|
break;
|
||||||
case Json::stringValue:
|
case Json::stringValue:
|
||||||
fprintf(fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str());
|
fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() );
|
||||||
break;
|
break;
|
||||||
case Json::booleanValue:
|
case Json::booleanValue:
|
||||||
fprintf(fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false");
|
fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" );
|
||||||
break;
|
break;
|
||||||
case Json::arrayValue: {
|
case Json::arrayValue:
|
||||||
fprintf(fout, "%s=[]\n", path.c_str());
|
{
|
||||||
|
fprintf( fout, "%s=[]\n", path.c_str() );
|
||||||
int size = value.size();
|
int size = value.size();
|
||||||
for (int index = 0; index < size; ++index) {
|
for ( int index =0; index < size; ++index )
|
||||||
|
{
|
||||||
static char buffer[16];
|
static char buffer[16];
|
||||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
sprintf( buffer, "[%d]", index );
|
||||||
sprintf_s(buffer, sizeof(buffer), "[%d]", index);
|
printValueTree( fout, value[index], path + buffer );
|
||||||
#else
|
|
||||||
snprintf(buffer, sizeof(buffer), "[%d]", index);
|
|
||||||
#endif
|
|
||||||
printValueTree(fout, value[index], path + buffer);
|
|
||||||
}
|
}
|
||||||
} break;
|
}
|
||||||
case Json::objectValue: {
|
break;
|
||||||
fprintf(fout, "%s={}\n", path.c_str());
|
case Json::objectValue:
|
||||||
Json::Value::Members members(value.getMemberNames());
|
{
|
||||||
std::sort(members.begin(), members.end());
|
fprintf( fout, "%s={}\n", path.c_str() );
|
||||||
std::string suffix = *(path.end() - 1) == '.' ? "" : ".";
|
Json::Value::Members members( value.getMemberNames() );
|
||||||
for (Json::Value::Members::iterator it = members.begin();
|
std::sort( members.begin(), members.end() );
|
||||||
|
std::string suffix = *(path.end()-1) == '.' ? "" : ".";
|
||||||
|
for ( Json::Value::Members::iterator it = members.begin();
|
||||||
it != members.end();
|
it != members.end();
|
||||||
++it) {
|
++it )
|
||||||
const std::string& name = *it;
|
{
|
||||||
printValueTree(fout, value[name], path + suffix + name);
|
const std::string &name = *it;
|
||||||
|
printValueTree( fout, value[name], path + suffix + name );
|
||||||
}
|
}
|
||||||
} break;
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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,
|
static int
|
||||||
const std::string& kind,
|
parseAndSaveValueTree( const std::string &input,
|
||||||
Json::Value& root,
|
const std::string &actual,
|
||||||
const Json::Features& features,
|
const std::string &kind,
|
||||||
bool parseOnly) {
|
Json::Value &root,
|
||||||
Json::Reader reader(features);
|
const Json::Features &features,
|
||||||
bool parsingSuccessful = reader.parse(input, root);
|
bool parseOnly )
|
||||||
if (!parsingSuccessful) {
|
{
|
||||||
printf("Failed to parse %s file: \n%s\n",
|
Json::Reader reader( features );
|
||||||
|
bool parsingSuccessful = reader.parse( input, root );
|
||||||
|
if ( !parsingSuccessful )
|
||||||
|
{
|
||||||
|
printf( "Failed to parse %s file: \n%s\n",
|
||||||
kind.c_str(),
|
kind.c_str(),
|
||||||
reader.getFormattedErrorMessages().c_str());
|
reader.getFormattedErrorMessages().c_str() );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parseOnly) {
|
if ( !parseOnly )
|
||||||
FILE* factual = fopen(actual.c_str(), "wt");
|
{
|
||||||
if (!factual) {
|
FILE *factual = fopen( actual.c_str(), "wt" );
|
||||||
printf("Failed to create %s actual file.\n", kind.c_str());
|
if ( !factual )
|
||||||
|
{
|
||||||
|
printf( "Failed to create %s actual file.\n", kind.c_str() );
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
printValueTree(factual, root);
|
printValueTree( factual, root );
|
||||||
fclose(factual);
|
fclose( factual );
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rewriteValueTree(const std::string& rewritePath,
|
|
||||||
const Json::Value& root,
|
static int
|
||||||
std::string& rewrite) {
|
rewriteValueTree( const std::string &rewritePath,
|
||||||
// Json::FastWriter writer;
|
const Json::Value &root,
|
||||||
// writer.enableYAMLCompatibility();
|
std::string &rewrite )
|
||||||
|
{
|
||||||
|
//Json::FastWriter writer;
|
||||||
|
//writer.enableYAMLCompatibility();
|
||||||
Json::StyledWriter writer;
|
Json::StyledWriter writer;
|
||||||
rewrite = writer.write(root);
|
rewrite = writer.write( root );
|
||||||
FILE* fout = fopen(rewritePath.c_str(), "wt");
|
FILE *fout = fopen( rewritePath.c_str(), "wt" );
|
||||||
if (!fout) {
|
if ( !fout )
|
||||||
printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
|
{
|
||||||
|
printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() );
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
fprintf(fout, "%s\n", rewrite.c_str());
|
fprintf( fout, "%s\n", rewrite.c_str() );
|
||||||
fclose(fout);
|
fclose( fout );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string removeSuffix(const std::string& path,
|
|
||||||
const std::string& extension) {
|
static std::string
|
||||||
if (extension.length() >= path.length())
|
removeSuffix( const std::string &path,
|
||||||
|
const std::string &extension )
|
||||||
|
{
|
||||||
|
if ( extension.length() >= path.length() )
|
||||||
return std::string("");
|
return std::string("");
|
||||||
std::string suffix = path.substr(path.length() - extension.length());
|
std::string suffix = path.substr( path.length() - extension.length() );
|
||||||
if (suffix != extension)
|
if ( suffix != extension )
|
||||||
return std::string("");
|
return std::string("");
|
||||||
return path.substr(0, path.length() - extension.length());
|
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)
|
#if defined(JSON_NO_INT64)
|
||||||
printf("JSON_NO_INT64=1\n");
|
printf( "JSON_NO_INT64=1\n" );
|
||||||
#else
|
#else
|
||||||
printf("JSON_NO_INT64=0\n");
|
printf( "JSON_NO_INT64=0\n" );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int printUsage(const char* argv[]) {
|
|
||||||
printf("Usage: %s [--strict] input-json-file", argv[0]);
|
static int
|
||||||
|
printUsage( const char *argv[] )
|
||||||
|
{
|
||||||
|
printf( "Usage: %s [--strict] input-json-file", argv[0] );
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parseCommandLine(int argc,
|
|
||||||
const char* argv[],
|
int
|
||||||
Json::Features& features,
|
parseCommandLine( int argc, const char *argv[],
|
||||||
std::string& path,
|
Json::Features &features, std::string &path,
|
||||||
bool& parseOnly) {
|
bool &parseOnly )
|
||||||
|
{
|
||||||
parseOnly = false;
|
parseOnly = false;
|
||||||
if (argc < 2) {
|
if ( argc < 2 )
|
||||||
return printUsage(argv);
|
{
|
||||||
|
return printUsage( argv );
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
if (std::string(argv[1]) == "--json-checker") {
|
if ( std::string(argv[1]) == "--json-checker" )
|
||||||
|
{
|
||||||
features = Json::Features::strictMode();
|
features = Json::Features::strictMode();
|
||||||
parseOnly = true;
|
parseOnly = true;
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::string(argv[1]) == "--json-config") {
|
if ( std::string(argv[1]) == "--json-config" )
|
||||||
|
{
|
||||||
printConfig();
|
printConfig();
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index == argc || index + 1 < argc) {
|
if ( index == argc || index + 1 < argc )
|
||||||
return printUsage(argv);
|
{
|
||||||
|
return printUsage( argv );
|
||||||
}
|
}
|
||||||
|
|
||||||
path = argv[index];
|
path = argv[index];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
|
||||||
|
int main( int argc, const char *argv[] )
|
||||||
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
Json::Features features;
|
Json::Features features;
|
||||||
bool parseOnly;
|
bool parseOnly;
|
||||||
int exitCode = parseCommandLine(argc, argv, features, path, parseOnly);
|
int exitCode = parseCommandLine( argc, argv, features, path, parseOnly );
|
||||||
if (exitCode != 0) {
|
if ( exitCode != 0 )
|
||||||
|
{
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try
|
||||||
std::string input = readInputTestFile(path.c_str());
|
{
|
||||||
if (input.empty()) {
|
std::string input = readInputTestFile( path.c_str() );
|
||||||
printf("Failed to read input or empty input: %s\n", path.c_str());
|
if ( input.empty() )
|
||||||
|
{
|
||||||
|
printf( "Failed to read input or empty input: %s\n", path.c_str() );
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string basePath = removeSuffix(argv[1], ".json");
|
std::string basePath = removeSuffix( argv[1], ".json" );
|
||||||
if (!parseOnly && basePath.empty()) {
|
if ( !parseOnly && basePath.empty() )
|
||||||
printf("Bad input path. Path does not end with '.expected':\n%s\n",
|
{
|
||||||
path.c_str());
|
printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,26 +245,25 @@ int main(int argc, const char* argv[]) {
|
|||||||
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
||||||
|
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
exitCode = parseAndSaveValueTree(
|
exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
|
||||||
input, actualPath, "input", root, features, parseOnly);
|
if ( exitCode == 0 && !parseOnly )
|
||||||
if (exitCode == 0 && !parseOnly) {
|
{
|
||||||
std::string rewrite;
|
std::string rewrite;
|
||||||
exitCode = rewriteValueTree(rewritePath, root, rewrite);
|
exitCode = rewriteValueTree( rewritePath, root, rewrite );
|
||||||
if (exitCode == 0) {
|
if ( exitCode == 0 )
|
||||||
|
{
|
||||||
Json::Value rewriteRoot;
|
Json::Value rewriteRoot;
|
||||||
exitCode = parseAndSaveValueTree(rewrite,
|
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
|
||||||
rewriteActualPath,
|
"rewrite", rewriteRoot, features, parseOnly );
|
||||||
"rewrite",
|
|
||||||
rewriteRoot,
|
|
||||||
features,
|
|
||||||
parseOnly);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch ( const std::exception &e )
|
||||||
printf("Unhandled exception:\n%s\n", e.what());
|
{
|
||||||
|
printf( "Unhandled exception:\n%s\n", e.what() );
|
||||||
exitCode = 1;
|
exitCode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,70 +0,0 @@
|
|||||||
OPTION(JSONCPP_LIB_BUILD_SHARED "Build jsoncpp_lib as a shared library." OFF)
|
|
||||||
IF(BUILD_SHARED_LIBS)
|
|
||||||
SET(JSONCPP_LIB_BUILD_SHARED ON)
|
|
||||||
ENDIF(BUILD_SHARED_LIBS)
|
|
||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
SET(JSONCPP_LIB_TYPE SHARED)
|
|
||||||
ADD_DEFINITIONS( -DJSON_DLL_BUILD )
|
|
||||||
ELSE(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
SET(JSONCPP_LIB_TYPE STATIC)
|
|
||||||
ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
|
|
||||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
|
||||||
#Get compiler version.
|
|
||||||
execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
|
|
||||||
OUTPUT_VARIABLE GNUCXX_VERSION )
|
|
||||||
|
|
||||||
#-Werror=* was introduced -after- GCC 4.1.2
|
|
||||||
if( GNUCXX_VERSION VERSION_GREATER 4.1.2 )
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
|
|
||||||
endif()
|
|
||||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
|
||||||
|
|
||||||
SET( JSONCPP_INCLUDE_DIR ../../include )
|
|
||||||
|
|
||||||
SET( PUBLIC_HEADERS
|
|
||||||
${JSONCPP_INCLUDE_DIR}/json/config.h
|
|
||||||
${JSONCPP_INCLUDE_DIR}/json/forwards.h
|
|
||||||
${JSONCPP_INCLUDE_DIR}/json/features.h
|
|
||||||
${JSONCPP_INCLUDE_DIR}/json/value.h
|
|
||||||
${JSONCPP_INCLUDE_DIR}/json/reader.h
|
|
||||||
${JSONCPP_INCLUDE_DIR}/json/writer.h
|
|
||||||
${JSONCPP_INCLUDE_DIR}/json/assertions.h
|
|
||||||
${JSONCPP_INCLUDE_DIR}/json/version.h
|
|
||||||
)
|
|
||||||
|
|
||||||
SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} )
|
|
||||||
|
|
||||||
ADD_LIBRARY( jsoncpp_lib ${JSONCPP_LIB_TYPE}
|
|
||||||
${PUBLIC_HEADERS}
|
|
||||||
json_tool.h
|
|
||||||
json_reader.cpp
|
|
||||||
json_batchallocator.h
|
|
||||||
json_valueiterator.inl
|
|
||||||
json_value.cpp
|
|
||||||
json_writer.cpp
|
|
||||||
version.h.in
|
|
||||||
)
|
|
||||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp )
|
|
||||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR} )
|
|
||||||
|
|
||||||
IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
|
|
||||||
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib PUBLIC
|
|
||||||
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
|
|
||||||
)
|
|
||||||
ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
|
|
||||||
|
|
||||||
# Install instructions for this target
|
|
||||||
IF(JSONCPP_WITH_CMAKE_PACKAGE)
|
|
||||||
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
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
#define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
#include <stdlib.h>
|
# include <stdlib.h>
|
||||||
#include <assert.h>
|
# include <assert.h>
|
||||||
|
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
@@ -18,104 +18,113 @@ namespace Json {
|
|||||||
* This memory allocator allocates memory for a batch of object (specified by
|
* This memory allocator allocates memory for a batch of object (specified by
|
||||||
* the page size, the number of object in each page).
|
* the page size, the number of object in each page).
|
||||||
*
|
*
|
||||||
* It does not allow the destruction of a single object. All the allocated
|
* It does not allow the destruction of a single object. All the allocated objects
|
||||||
* objects can be destroyed at once. The memory can be either released or reused
|
* can be destroyed at once. The memory can be either released or reused for future
|
||||||
* for future allocation.
|
* allocation.
|
||||||
*
|
*
|
||||||
* The in-place new operator must be used to construct the object using the
|
* The in-place new operator must be used to construct the object using the pointer
|
||||||
* pointer returned by allocate.
|
* returned by allocate.
|
||||||
*/
|
*/
|
||||||
template <typename AllocatedType, const unsigned int objectPerAllocation>
|
template<typename AllocatedType
|
||||||
class BatchAllocator {
|
,const unsigned int objectPerAllocation>
|
||||||
|
class BatchAllocator
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
BatchAllocator(unsigned int objectsPerPage = 255)
|
typedef AllocatedType Type;
|
||||||
: freeHead_(0), objectsPerPage_(objectsPerPage) {
|
|
||||||
// printf( "Size: %d => %s\n", sizeof(AllocatedType),
|
BatchAllocator( unsigned int objectsPerPage = 255 )
|
||||||
// typeid(AllocatedType).name() );
|
: freeHead_( 0 )
|
||||||
assert(sizeof(AllocatedType) * objectPerAllocation >=
|
, objectsPerPage_( objectsPerPage )
|
||||||
sizeof(AllocatedType*)); // We must be able to store a slist in the
|
{
|
||||||
// object free space.
|
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
|
||||||
assert(objectsPerPage >= 16);
|
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
|
||||||
batches_ = allocateBatch(0); // allocated a dummy page
|
assert( objectsPerPage >= 16 );
|
||||||
|
batches_ = allocateBatch( 0 ); // allocated a dummy page
|
||||||
currentBatch_ = batches_;
|
currentBatch_ = batches_;
|
||||||
}
|
}
|
||||||
|
|
||||||
~BatchAllocator() {
|
~BatchAllocator()
|
||||||
for (BatchInfo* batch = batches_; batch;) {
|
{
|
||||||
BatchInfo* nextBatch = batch->next_;
|
for ( BatchInfo *batch = batches_; batch; )
|
||||||
free(batch);
|
{
|
||||||
|
BatchInfo *nextBatch = batch->next_;
|
||||||
|
free( batch );
|
||||||
batch = nextBatch;
|
batch = nextBatch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// allocate space for an array of objectPerAllocation object.
|
/// allocate space for an array of objectPerAllocation object.
|
||||||
/// @warning it is the responsability of the caller to call objects
|
/// @warning it is the responsability of the caller to call objects constructors.
|
||||||
/// constructors.
|
AllocatedType *allocate()
|
||||||
AllocatedType* allocate() {
|
|
||||||
if (freeHead_) // returns node from free list.
|
|
||||||
{
|
{
|
||||||
AllocatedType* object = freeHead_;
|
if ( freeHead_ ) // returns node from free list.
|
||||||
freeHead_ = *(AllocatedType**)object;
|
{
|
||||||
|
AllocatedType *object = freeHead_;
|
||||||
|
freeHead_ = *(AllocatedType **)object;
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
if (currentBatch_->used_ == currentBatch_->end_) {
|
if ( currentBatch_->used_ == currentBatch_->end_ )
|
||||||
|
{
|
||||||
currentBatch_ = currentBatch_->next_;
|
currentBatch_ = currentBatch_->next_;
|
||||||
while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_)
|
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
|
||||||
currentBatch_ = currentBatch_->next_;
|
currentBatch_ = currentBatch_->next_;
|
||||||
|
|
||||||
if (!currentBatch_) // no free batch found, allocate a new one
|
if ( !currentBatch_ ) // no free batch found, allocate a new one
|
||||||
{
|
{
|
||||||
currentBatch_ = allocateBatch(objectsPerPage_);
|
currentBatch_ = allocateBatch( objectsPerPage_ );
|
||||||
currentBatch_->next_ = batches_; // insert at the head of the list
|
currentBatch_->next_ = batches_; // insert at the head of the list
|
||||||
batches_ = currentBatch_;
|
batches_ = currentBatch_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AllocatedType* allocated = currentBatch_->used_;
|
AllocatedType *allocated = currentBatch_->used_;
|
||||||
currentBatch_->used_ += objectPerAllocation;
|
currentBatch_->used_ += objectPerAllocation;
|
||||||
return allocated;
|
return allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release the object.
|
/// Release the object.
|
||||||
/// @warning it is the responsability of the caller to actually destruct the
|
/// @warning it is the responsability of the caller to actually destruct the object.
|
||||||
/// object.
|
void release( AllocatedType *object )
|
||||||
void release(AllocatedType* object) {
|
{
|
||||||
assert(object != 0);
|
assert( object != 0 );
|
||||||
*(AllocatedType**)object = freeHead_;
|
*(AllocatedType **)object = freeHead_;
|
||||||
freeHead_ = object;
|
freeHead_ = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct BatchInfo {
|
struct BatchInfo
|
||||||
BatchInfo* next_;
|
{
|
||||||
AllocatedType* used_;
|
BatchInfo *next_;
|
||||||
AllocatedType* end_;
|
AllocatedType *used_;
|
||||||
|
AllocatedType *end_;
|
||||||
AllocatedType buffer_[objectPerAllocation];
|
AllocatedType buffer_[objectPerAllocation];
|
||||||
};
|
};
|
||||||
|
|
||||||
// disabled copy constructor and assignement operator.
|
// disabled copy constructor and assignement operator.
|
||||||
BatchAllocator(const BatchAllocator&);
|
BatchAllocator( const BatchAllocator & );
|
||||||
void operator=(const BatchAllocator&);
|
void operator =( const BatchAllocator &);
|
||||||
|
|
||||||
static BatchInfo* allocateBatch(unsigned int objectsPerPage) {
|
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
|
||||||
const unsigned int mallocSize =
|
{
|
||||||
sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation +
|
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
|
||||||
sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
||||||
BatchInfo* batch = static_cast<BatchInfo*>(malloc(mallocSize));
|
BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
|
||||||
batch->next_ = 0;
|
batch->next_ = 0;
|
||||||
batch->used_ = batch->buffer_;
|
batch->used_ = batch->buffer_;
|
||||||
batch->end_ = batch->buffer_ + objectsPerPage;
|
batch->end_ = batch->buffer_ + objectsPerPage;
|
||||||
return batch;
|
return batch;
|
||||||
}
|
}
|
||||||
|
|
||||||
BatchInfo* batches_;
|
BatchInfo *batches_;
|
||||||
BatchInfo* currentBatch_;
|
BatchInfo *currentBatch_;
|
||||||
/// Head of a single linked list within the allocated space of freeed object
|
/// Head of a single linked list within the allocated space of freeed object
|
||||||
AllocatedType* freeHead_;
|
AllocatedType *freeHead_;
|
||||||
unsigned int objectsPerPage_;
|
unsigned int objectsPerPage_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
#endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
|
@@ -15,236 +15,306 @@ namespace Json {
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ValueArrayAllocator::~ValueArrayAllocator() {}
|
ValueArrayAllocator::~ValueArrayAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// class DefaultValueArrayAllocator
|
// class DefaultValueArrayAllocator
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
class DefaultValueArrayAllocator : public ValueArrayAllocator {
|
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||||
|
{
|
||||||
public: // overridden from ValueArrayAllocator
|
public: // overridden from ValueArrayAllocator
|
||||||
virtual ~DefaultValueArrayAllocator() {}
|
virtual ~DefaultValueArrayAllocator()
|
||||||
|
{
|
||||||
virtual ValueInternalArray* newArray() { return new ValueInternalArray(); }
|
|
||||||
|
|
||||||
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
|
|
||||||
return new ValueInternalArray(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void destructArray(ValueInternalArray* array) { delete array; }
|
virtual ValueInternalArray *newArray()
|
||||||
|
{
|
||||||
|
return new ValueInternalArray();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void
|
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||||
reallocateArrayPageIndex(Value**& indexes,
|
{
|
||||||
ValueInternalArray::PageIndex& indexCount,
|
return new ValueInternalArray( other );
|
||||||
ValueInternalArray::PageIndex minNewIndexCount) {
|
}
|
||||||
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
|
|
||||||
if (minNewIndexCount > newIndexCount)
|
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;
|
newIndexCount = minNewIndexCount;
|
||||||
void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
|
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||||
JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
|
if ( !newIndexes )
|
||||||
|
throw std::bad_alloc();
|
||||||
indexCount = newIndexCount;
|
indexCount = newIndexCount;
|
||||||
indexes = static_cast<Value**>(newIndexes);
|
indexes = static_cast<Value **>( newIndexes );
|
||||||
}
|
}
|
||||||
virtual void releaseArrayPageIndex(Value** indexes,
|
virtual void releaseArrayPageIndex( Value **indexes,
|
||||||
ValueInternalArray::PageIndex indexCount) {
|
ValueInternalArray::PageIndex indexCount )
|
||||||
if (indexes)
|
{
|
||||||
free(indexes);
|
if ( indexes )
|
||||||
|
free( indexes );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Value* allocateArrayPage() {
|
virtual Value *allocateArrayPage()
|
||||||
return static_cast<Value*>(
|
{
|
||||||
malloc(sizeof(Value) * ValueInternalArray::itemsPerPage));
|
return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void releaseArrayPage(Value* value) {
|
virtual void releaseArrayPage( Value *value )
|
||||||
if (value)
|
{
|
||||||
free(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)
|
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||||
class DefaultValueArrayAllocator : public ValueArrayAllocator {
|
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||||
|
{
|
||||||
public: // overridden from ValueArrayAllocator
|
public: // overridden from ValueArrayAllocator
|
||||||
virtual ~DefaultValueArrayAllocator() {}
|
virtual ~DefaultValueArrayAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual ValueInternalArray* newArray() {
|
virtual ValueInternalArray *newArray()
|
||||||
ValueInternalArray* array = arraysAllocator_.allocate();
|
{
|
||||||
|
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||||
new (array) ValueInternalArray(); // placement new
|
new (array) ValueInternalArray(); // placement new
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
|
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||||
ValueInternalArray* array = arraysAllocator_.allocate();
|
{
|
||||||
new (array) ValueInternalArray(other); // placement new
|
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||||
|
new (array) ValueInternalArray( other ); // placement new
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void destructArray(ValueInternalArray* array) {
|
virtual void destructArray( ValueInternalArray *array )
|
||||||
if (array) {
|
{
|
||||||
|
if ( array )
|
||||||
|
{
|
||||||
array->~ValueInternalArray();
|
array->~ValueInternalArray();
|
||||||
arraysAllocator_.release(array);
|
arraysAllocator_.release( array );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void
|
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||||
reallocateArrayPageIndex(Value**& indexes,
|
ValueInternalArray::PageIndex &indexCount,
|
||||||
ValueInternalArray::PageIndex& indexCount,
|
ValueInternalArray::PageIndex minNewIndexCount )
|
||||||
ValueInternalArray::PageIndex minNewIndexCount) {
|
{
|
||||||
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
|
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||||
if (minNewIndexCount > newIndexCount)
|
if ( minNewIndexCount > newIndexCount )
|
||||||
newIndexCount = minNewIndexCount;
|
newIndexCount = minNewIndexCount;
|
||||||
void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
|
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||||
JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
|
if ( !newIndexes )
|
||||||
|
throw std::bad_alloc();
|
||||||
indexCount = newIndexCount;
|
indexCount = newIndexCount;
|
||||||
indexes = static_cast<Value**>(newIndexes);
|
indexes = static_cast<Value **>( newIndexes );
|
||||||
}
|
}
|
||||||
virtual void releaseArrayPageIndex(Value** indexes,
|
virtual void releaseArrayPageIndex( Value **indexes,
|
||||||
ValueInternalArray::PageIndex indexCount) {
|
ValueInternalArray::PageIndex indexCount )
|
||||||
if (indexes)
|
{
|
||||||
free(indexes);
|
if ( indexes )
|
||||||
|
free( indexes );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Value* allocateArrayPage() {
|
virtual Value *allocateArrayPage()
|
||||||
return static_cast<Value*>(pagesAllocator_.allocate());
|
{
|
||||||
|
return static_cast<Value *>( pagesAllocator_.allocate() );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void releaseArrayPage(Value* value) {
|
virtual void releaseArrayPage( Value *value )
|
||||||
if (value)
|
{
|
||||||
pagesAllocator_.release(value);
|
if ( value )
|
||||||
|
pagesAllocator_.release( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BatchAllocator<ValueInternalArray, 1> arraysAllocator_;
|
BatchAllocator<ValueInternalArray,1> arraysAllocator_;
|
||||||
BatchAllocator<Value, ValueInternalArray::itemsPerPage> pagesAllocator_;
|
BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
|
||||||
};
|
};
|
||||||
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
|
||||||
static ValueArrayAllocator*& arrayAllocator() {
|
static ValueArrayAllocator *&arrayAllocator()
|
||||||
|
{
|
||||||
static DefaultValueArrayAllocator defaultAllocator;
|
static DefaultValueArrayAllocator defaultAllocator;
|
||||||
static ValueArrayAllocator* arrayAllocator = &defaultAllocator;
|
static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
|
||||||
return arrayAllocator;
|
return arrayAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct DummyArrayAllocatorInitializer {
|
static struct DummyArrayAllocatorInitializer {
|
||||||
DummyArrayAllocatorInitializer() {
|
DummyArrayAllocatorInitializer()
|
||||||
arrayAllocator(); // ensure arrayAllocator() statics are initialized before
|
{
|
||||||
// main().
|
arrayAllocator(); // ensure arrayAllocator() statics are initialized before main().
|
||||||
}
|
}
|
||||||
} dummyArrayAllocatorInitializer;
|
} dummyArrayAllocatorInitializer;
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// class ValueInternalArray
|
// class ValueInternalArray
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
bool ValueInternalArray::equals(const IteratorState& x,
|
bool
|
||||||
const IteratorState& other) {
|
ValueInternalArray::equals( const IteratorState &x,
|
||||||
return x.array_ == other.array_ &&
|
const IteratorState &other )
|
||||||
x.currentItemIndex_ == other.currentItemIndex_ &&
|
{
|
||||||
x.currentPageIndex_ == other.currentPageIndex_;
|
return x.array_ == other.array_
|
||||||
|
&& x.currentItemIndex_ == other.currentItemIndex_
|
||||||
|
&& x.currentPageIndex_ == other.currentPageIndex_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalArray::increment(IteratorState& it) {
|
|
||||||
JSON_ASSERT_MESSAGE(
|
void
|
||||||
it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
|
ValueInternalArray::increment( IteratorState &it )
|
||||||
it.currentItemIndex_ !=
|
{
|
||||||
it.array_->size_,
|
JSON_ASSERT_MESSAGE( it.array_ &&
|
||||||
"ValueInternalArray::increment(): moving iterator beyond end");
|
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
|
||||||
|
!= it.array_->size_,
|
||||||
|
"ValueInternalArray::increment(): moving iterator beyond end" );
|
||||||
++(it.currentItemIndex_);
|
++(it.currentItemIndex_);
|
||||||
if (it.currentItemIndex_ == itemsPerPage) {
|
if ( it.currentItemIndex_ == itemsPerPage )
|
||||||
|
{
|
||||||
it.currentItemIndex_ = 0;
|
it.currentItemIndex_ = 0;
|
||||||
++(it.currentPageIndex_);
|
++(it.currentPageIndex_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalArray::decrement(IteratorState& it) {
|
|
||||||
JSON_ASSERT_MESSAGE(
|
void
|
||||||
it.array_ && it.currentPageIndex_ == it.array_->pages_ &&
|
ValueInternalArray::decrement( IteratorState &it )
|
||||||
it.currentItemIndex_ == 0,
|
{
|
||||||
"ValueInternalArray::decrement(): moving iterator beyond end");
|
JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
|
||||||
if (it.currentItemIndex_ == 0) {
|
&& it.currentItemIndex_ == 0,
|
||||||
it.currentItemIndex_ = itemsPerPage - 1;
|
"ValueInternalArray::decrement(): moving iterator beyond end" );
|
||||||
|
if ( it.currentItemIndex_ == 0 )
|
||||||
|
{
|
||||||
|
it.currentItemIndex_ = itemsPerPage-1;
|
||||||
--(it.currentPageIndex_);
|
--(it.currentPageIndex_);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
--(it.currentItemIndex_);
|
--(it.currentItemIndex_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& ValueInternalArray::unsafeDereference(const IteratorState& it) {
|
|
||||||
|
Value &
|
||||||
|
ValueInternalArray::unsafeDereference( const IteratorState &it )
|
||||||
|
{
|
||||||
return (*(it.currentPageIndex_))[it.currentItemIndex_];
|
return (*(it.currentPageIndex_))[it.currentItemIndex_];
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& ValueInternalArray::dereference(const IteratorState& it) {
|
|
||||||
JSON_ASSERT_MESSAGE(
|
Value &
|
||||||
it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
|
ValueInternalArray::dereference( const IteratorState &it )
|
||||||
it.currentItemIndex_ <
|
{
|
||||||
it.array_->size_,
|
JSON_ASSERT_MESSAGE( it.array_ &&
|
||||||
"ValueInternalArray::dereference(): dereferencing invalid iterator");
|
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
|
||||||
return unsafeDereference(it);
|
< it.array_->size_,
|
||||||
|
"ValueInternalArray::dereference(): dereferencing invalid iterator" );
|
||||||
|
return unsafeDereference( it );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalArray::makeBeginIterator(IteratorState& it) const {
|
void
|
||||||
it.array_ = const_cast<ValueInternalArray*>(this);
|
ValueInternalArray::makeBeginIterator( IteratorState &it ) const
|
||||||
|
{
|
||||||
|
it.array_ = const_cast<ValueInternalArray *>( this );
|
||||||
it.currentItemIndex_ = 0;
|
it.currentItemIndex_ = 0;
|
||||||
it.currentPageIndex_ = pages_;
|
it.currentPageIndex_ = pages_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalArray::makeIterator(IteratorState& it,
|
|
||||||
ArrayIndex index) const {
|
void
|
||||||
it.array_ = const_cast<ValueInternalArray*>(this);
|
ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
|
||||||
|
{
|
||||||
|
it.array_ = const_cast<ValueInternalArray *>( this );
|
||||||
it.currentItemIndex_ = index % itemsPerPage;
|
it.currentItemIndex_ = index % itemsPerPage;
|
||||||
it.currentPageIndex_ = pages_ + 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(const ValueInternalArray& other)
|
ValueInternalArray::ValueInternalArray()
|
||||||
: pages_(0), size_(other.size_), pageCount_(0) {
|
: pages_( 0 )
|
||||||
|
, size_( 0 )
|
||||||
|
, pageCount_( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
|
||||||
|
: pages_( 0 )
|
||||||
|
, pageCount_( 0 )
|
||||||
|
, size_( other.size_ )
|
||||||
|
{
|
||||||
PageIndex minNewPages = other.size_ / itemsPerPage;
|
PageIndex minNewPages = other.size_ / itemsPerPage;
|
||||||
arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
|
arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
|
||||||
JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
|
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages,
|
||||||
"ValueInternalArray::reserve(): bad reallocation");
|
"ValueInternalArray::reserve(): bad reallocation" );
|
||||||
IteratorState itOther;
|
IteratorState itOther;
|
||||||
other.makeBeginIterator(itOther);
|
other.makeBeginIterator( itOther );
|
||||||
Value* value;
|
Value *value;
|
||||||
for (ArrayIndex index = 0; index < size_; ++index, increment(itOther)) {
|
for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
|
||||||
if (index % itemsPerPage == 0) {
|
{
|
||||||
|
if ( index % itemsPerPage == 0 )
|
||||||
|
{
|
||||||
PageIndex pageIndex = index / itemsPerPage;
|
PageIndex pageIndex = index / itemsPerPage;
|
||||||
value = arrayAllocator()->allocateArrayPage();
|
value = arrayAllocator()->allocateArrayPage();
|
||||||
pages_[pageIndex] = value;
|
pages_[pageIndex] = value;
|
||||||
}
|
}
|
||||||
new (value) Value(dereference(itOther));
|
new (value) Value( dereference( itOther ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueInternalArray& ValueInternalArray::operator=(ValueInternalArray other) {
|
|
||||||
swap(other);
|
ValueInternalArray &
|
||||||
|
ValueInternalArray::operator =( const ValueInternalArray &other )
|
||||||
|
{
|
||||||
|
ValueInternalArray temp( other );
|
||||||
|
swap( temp );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueInternalArray::~ValueInternalArray() {
|
|
||||||
|
ValueInternalArray::~ValueInternalArray()
|
||||||
|
{
|
||||||
// destroy all constructed items
|
// destroy all constructed items
|
||||||
IteratorState it;
|
IteratorState it;
|
||||||
IteratorState itEnd;
|
IteratorState itEnd;
|
||||||
makeBeginIterator(it);
|
makeBeginIterator( it);
|
||||||
makeEndIterator(itEnd);
|
makeEndIterator( itEnd );
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
Value* value = &dereference(it);
|
{
|
||||||
|
Value *value = &dereference(it);
|
||||||
value->~Value();
|
value->~Value();
|
||||||
}
|
}
|
||||||
// release all pages
|
// release all pages
|
||||||
PageIndex lastPageIndex = size_ / itemsPerPage;
|
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||||
for (PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex)
|
for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
|
||||||
arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
|
arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
|
||||||
// release pages index
|
// release pages index
|
||||||
arrayAllocator()->releaseArrayPageIndex(pages_, pageCount_);
|
arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalArray::swap(ValueInternalArray& other) {
|
|
||||||
Value** tempPages = pages_;
|
void
|
||||||
|
ValueInternalArray::swap( ValueInternalArray &other )
|
||||||
|
{
|
||||||
|
Value **tempPages = pages_;
|
||||||
pages_ = other.pages_;
|
pages_ = other.pages_;
|
||||||
other.pages_ = tempPages;
|
other.pages_ = tempPages;
|
||||||
ArrayIndex tempSize = size_;
|
ArrayIndex tempSize = size_;
|
||||||
@@ -255,103 +325,129 @@ void ValueInternalArray::swap(ValueInternalArray& other) {
|
|||||||
other.pageCount_ = tempPageCount;
|
other.pageCount_ = tempPageCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalArray::clear() {
|
void
|
||||||
|
ValueInternalArray::clear()
|
||||||
|
{
|
||||||
ValueInternalArray dummy;
|
ValueInternalArray dummy;
|
||||||
swap(dummy);
|
swap( dummy );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalArray::resize(ArrayIndex newSize) {
|
|
||||||
if (newSize == 0)
|
void
|
||||||
|
ValueInternalArray::resize( ArrayIndex newSize )
|
||||||
|
{
|
||||||
|
if ( newSize == 0 )
|
||||||
clear();
|
clear();
|
||||||
else if (newSize < size_) {
|
else if ( newSize < size_ )
|
||||||
|
{
|
||||||
IteratorState it;
|
IteratorState it;
|
||||||
IteratorState itEnd;
|
IteratorState itEnd;
|
||||||
makeIterator(it, newSize);
|
makeIterator( it, newSize );
|
||||||
makeIterator(itEnd, size_);
|
makeIterator( itEnd, size_ );
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
Value* value = &dereference(it);
|
{
|
||||||
|
Value *value = &dereference(it);
|
||||||
value->~Value();
|
value->~Value();
|
||||||
}
|
}
|
||||||
PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
|
PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
|
||||||
PageIndex lastPageIndex = size_ / itemsPerPage;
|
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||||
for (; pageIndex < lastPageIndex; ++pageIndex)
|
for ( ; pageIndex < lastPageIndex; ++pageIndex )
|
||||||
arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
|
arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
|
||||||
size_ = newSize;
|
size_ = newSize;
|
||||||
} else if (newSize > size_)
|
}
|
||||||
resolveReference(newSize);
|
else if ( newSize > size_ )
|
||||||
|
resolveReference( newSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalArray::makeIndexValid(ArrayIndex index) {
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::makeIndexValid( ArrayIndex index )
|
||||||
|
{
|
||||||
// Need to enlarge page index ?
|
// Need to enlarge page index ?
|
||||||
if (index >= pageCount_ * itemsPerPage) {
|
if ( index >= pageCount_ * itemsPerPage )
|
||||||
|
{
|
||||||
PageIndex minNewPages = (index + 1) / itemsPerPage;
|
PageIndex minNewPages = (index + 1) / itemsPerPage;
|
||||||
arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
|
arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
|
||||||
JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
|
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
|
||||||
"ValueInternalArray::reserve(): bad reallocation");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to allocate new pages ?
|
// Need to allocate new pages ?
|
||||||
ArrayIndex nextPageIndex = (size_ % itemsPerPage) != 0
|
ArrayIndex nextPageIndex =
|
||||||
? size_ - (size_ % itemsPerPage) + itemsPerPage
|
(size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
|
||||||
: size_;
|
: size_;
|
||||||
if (nextPageIndex <= index) {
|
if ( nextPageIndex <= index )
|
||||||
|
{
|
||||||
PageIndex pageIndex = nextPageIndex / itemsPerPage;
|
PageIndex pageIndex = nextPageIndex / itemsPerPage;
|
||||||
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
|
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
|
||||||
for (; pageToAllocate-- > 0; ++pageIndex)
|
for ( ; pageToAllocate-- > 0; ++pageIndex )
|
||||||
pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
|
pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize all new entries
|
// Initialize all new entries
|
||||||
IteratorState it;
|
IteratorState it;
|
||||||
IteratorState itEnd;
|
IteratorState itEnd;
|
||||||
makeIterator(it, size_);
|
makeIterator( it, size_ );
|
||||||
size_ = index + 1;
|
size_ = index + 1;
|
||||||
makeIterator(itEnd, size_);
|
makeIterator( itEnd, size_ );
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
Value* value = &dereference(it);
|
{
|
||||||
|
Value *value = &dereference(it);
|
||||||
new (value) Value(); // Construct a default value using placement new
|
new (value) Value(); // Construct a default value using placement new
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& ValueInternalArray::resolveReference(ArrayIndex index) {
|
Value &
|
||||||
if (index >= size_)
|
ValueInternalArray::resolveReference( ArrayIndex index )
|
||||||
makeIndexValid(index);
|
{
|
||||||
return pages_[index / itemsPerPage][index % itemsPerPage];
|
if ( index >= size_ )
|
||||||
|
makeIndexValid( index );
|
||||||
|
return pages_[index/itemsPerPage][index%itemsPerPage];
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* ValueInternalArray::find(ArrayIndex index) const {
|
Value *
|
||||||
if (index >= size_)
|
ValueInternalArray::find( ArrayIndex index ) const
|
||||||
|
{
|
||||||
|
if ( index >= size_ )
|
||||||
return 0;
|
return 0;
|
||||||
return &(pages_[index / itemsPerPage][index % itemsPerPage]);
|
return &(pages_[index/itemsPerPage][index%itemsPerPage]);
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalArray::ArrayIndex ValueInternalArray::size() const {
|
|
||||||
return size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ValueInternalArray::distance(const IteratorState& x,
|
|
||||||
const IteratorState& y) {
|
|
||||||
return indexOf(y) - indexOf(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueInternalArray::ArrayIndex
|
ValueInternalArray::ArrayIndex
|
||||||
ValueInternalArray::indexOf(const IteratorState& iterator) {
|
ValueInternalArray::size() const
|
||||||
if (!iterator.array_)
|
{
|
||||||
return ArrayIndex(-1);
|
return size_;
|
||||||
return ArrayIndex((iterator.currentPageIndex_ - iterator.array_->pages_) *
|
|
||||||
itemsPerPage +
|
|
||||||
iterator.currentItemIndex_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ValueInternalArray::compare(const ValueInternalArray& other) const {
|
int
|
||||||
int sizeDiff(size_ - other.size_);
|
ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
|
||||||
if (sizeDiff != 0)
|
{
|
||||||
|
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;
|
return sizeDiff;
|
||||||
|
|
||||||
for (ArrayIndex index = 0; index < size_; ++index) {
|
for ( ArrayIndex index =0; index < size_; ++index )
|
||||||
int diff = pages_[index / itemsPerPage][index % itemsPerPage].compare(
|
{
|
||||||
other.pages_[index / itemsPerPage][index % itemsPerPage]);
|
int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare(
|
||||||
if (diff != 0)
|
other.pages_[index/itemsPerPage][index%itemsPerPage] );
|
||||||
|
if ( diff != 0 )
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -15,106 +15,146 @@ namespace Json {
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/** \internal MUST be safely initialized using memset( this, 0,
|
/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
|
||||||
* sizeof(ValueInternalLink) );
|
|
||||||
* This optimization is used by the fast allocator.
|
* This optimization is used by the fast allocator.
|
||||||
*/
|
*/
|
||||||
ValueInternalLink::ValueInternalLink() : previous_(0), next_(0) {}
|
ValueInternalLink::ValueInternalLink()
|
||||||
|
: previous_( 0 )
|
||||||
|
, next_( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ValueInternalLink::~ValueInternalLink() {
|
ValueInternalLink::~ValueInternalLink()
|
||||||
for (int index = 0; index < itemPerLink; ++index) {
|
{
|
||||||
if (!items_[index].isItemAvailable()) {
|
for ( int index =0; index < itemPerLink; ++index )
|
||||||
if (!items_[index].isMemberNameStatic())
|
{
|
||||||
free(keys_[index]);
|
if ( !items_[index].isItemAvailable() )
|
||||||
} else
|
{
|
||||||
|
if ( !items_[index].isMemberNameStatic() )
|
||||||
|
free( keys_[index] );
|
||||||
|
}
|
||||||
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueMapAllocator::~ValueMapAllocator() {}
|
|
||||||
|
|
||||||
|
ValueMapAllocator::~ValueMapAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
class DefaultValueMapAllocator : public ValueMapAllocator {
|
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||||
|
{
|
||||||
public: // overridden from ValueMapAllocator
|
public: // overridden from ValueMapAllocator
|
||||||
virtual ValueInternalMap* newMap() { return new ValueInternalMap(); }
|
virtual ValueInternalMap *newMap()
|
||||||
|
{
|
||||||
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
|
return new ValueInternalMap();
|
||||||
return new ValueInternalMap(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void destructMap(ValueInternalMap* map) { delete map; }
|
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||||
|
{
|
||||||
|
return new ValueInternalMap( other );
|
||||||
|
}
|
||||||
|
|
||||||
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
|
virtual void destructMap( ValueInternalMap *map )
|
||||||
|
{
|
||||||
|
delete map;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||||
|
{
|
||||||
return new ValueInternalLink[size];
|
return new ValueInternalLink[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
|
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||||
|
{
|
||||||
|
delete [] links;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ValueInternalLink* allocateMapLink() {
|
virtual ValueInternalLink *allocateMapLink()
|
||||||
|
{
|
||||||
return new ValueInternalLink();
|
return new ValueInternalLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void releaseMapLink(ValueInternalLink* link) { delete link; }
|
virtual void releaseMapLink( ValueInternalLink *link )
|
||||||
|
{
|
||||||
|
delete link;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||||
class DefaultValueMapAllocator : public ValueMapAllocator {
|
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||||
|
{
|
||||||
public: // overridden from ValueMapAllocator
|
public: // overridden from ValueMapAllocator
|
||||||
virtual ValueInternalMap* newMap() {
|
virtual ValueInternalMap *newMap()
|
||||||
ValueInternalMap* map = mapsAllocator_.allocate();
|
{
|
||||||
|
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||||
new (map) ValueInternalMap(); // placement new
|
new (map) ValueInternalMap(); // placement new
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
|
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||||
ValueInternalMap* map = mapsAllocator_.allocate();
|
{
|
||||||
new (map) ValueInternalMap(other); // placement new
|
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||||
|
new (map) ValueInternalMap( other ); // placement new
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void destructMap(ValueInternalMap* map) {
|
virtual void destructMap( ValueInternalMap *map )
|
||||||
if (map) {
|
{
|
||||||
|
if ( map )
|
||||||
|
{
|
||||||
map->~ValueInternalMap();
|
map->~ValueInternalMap();
|
||||||
mapsAllocator_.release(map);
|
mapsAllocator_.release( map );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
|
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||||
|
{
|
||||||
return new ValueInternalLink[size];
|
return new ValueInternalLink[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
|
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||||
|
{
|
||||||
|
delete [] links;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ValueInternalLink* allocateMapLink() {
|
virtual ValueInternalLink *allocateMapLink()
|
||||||
ValueInternalLink* link = linksAllocator_.allocate();
|
{
|
||||||
memset(link, 0, sizeof(ValueInternalLink));
|
ValueInternalLink *link = linksAllocator_.allocate();
|
||||||
|
memset( link, 0, sizeof(ValueInternalLink) );
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void releaseMapLink(ValueInternalLink* link) {
|
virtual void releaseMapLink( ValueInternalLink *link )
|
||||||
|
{
|
||||||
link->~ValueInternalLink();
|
link->~ValueInternalLink();
|
||||||
linksAllocator_.release(link);
|
linksAllocator_.release( link );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BatchAllocator<ValueInternalMap, 1> mapsAllocator_;
|
BatchAllocator<ValueInternalMap,1> mapsAllocator_;
|
||||||
BatchAllocator<ValueInternalLink, 1> linksAllocator_;
|
BatchAllocator<ValueInternalLink,1> linksAllocator_;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static ValueMapAllocator*& mapAllocator() {
|
static ValueMapAllocator *&mapAllocator()
|
||||||
|
{
|
||||||
static DefaultValueMapAllocator defaultAllocator;
|
static DefaultValueMapAllocator defaultAllocator;
|
||||||
static ValueMapAllocator* mapAllocator = &defaultAllocator;
|
static ValueMapAllocator *mapAllocator = &defaultAllocator;
|
||||||
return mapAllocator;
|
return mapAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct DummyMapAllocatorInitializer {
|
static struct DummyMapAllocatorInitializer {
|
||||||
DummyMapAllocatorInitializer() {
|
DummyMapAllocatorInitializer()
|
||||||
mapAllocator(); // ensure mapAllocator() statics are initialized before
|
{
|
||||||
// main().
|
mapAllocator(); // ensure mapAllocator() statics are initialized before main().
|
||||||
}
|
}
|
||||||
} dummyMapAllocatorInitializer;
|
} dummyMapAllocatorInitializer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
|
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -124,49 +164,72 @@ linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
|
|||||||
value have extra state: valid, available, deleted
|
value have extra state: valid, available, deleted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ValueInternalMap::ValueInternalMap()
|
|
||||||
: buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {}
|
|
||||||
|
|
||||||
ValueInternalMap::ValueInternalMap(const ValueInternalMap& other)
|
ValueInternalMap::ValueInternalMap()
|
||||||
: buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {
|
: buckets_( 0 )
|
||||||
reserve(other.itemCount_);
|
, 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 it;
|
||||||
IteratorState itEnd;
|
IteratorState itEnd;
|
||||||
other.makeBeginIterator(it);
|
other.makeBeginIterator( it );
|
||||||
other.makeEndIterator(itEnd);
|
other.makeEndIterator( itEnd );
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
|
{
|
||||||
bool isStatic;
|
bool isStatic;
|
||||||
const char* memberName = key(it, isStatic);
|
const char *memberName = key( it, isStatic );
|
||||||
const Value& aValue = value(it);
|
const Value &aValue = value( it );
|
||||||
resolveReference(memberName, isStatic) = aValue;
|
resolveReference(memberName, isStatic) = aValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueInternalMap& ValueInternalMap::operator=(ValueInternalMap other) {
|
|
||||||
swap(other);
|
ValueInternalMap &
|
||||||
|
ValueInternalMap::operator =( const ValueInternalMap &other )
|
||||||
|
{
|
||||||
|
ValueInternalMap dummy( other );
|
||||||
|
swap( dummy );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueInternalMap::~ValueInternalMap() {
|
|
||||||
if (buckets_) {
|
ValueInternalMap::~ValueInternalMap()
|
||||||
for (BucketIndex bucketIndex = 0; bucketIndex < bucketsSize_;
|
{
|
||||||
++bucketIndex) {
|
if ( buckets_ )
|
||||||
ValueInternalLink* link = buckets_[bucketIndex].next_;
|
{
|
||||||
while (link) {
|
for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
|
||||||
ValueInternalLink* linkToRelease = link;
|
{
|
||||||
|
ValueInternalLink *link = buckets_[bucketIndex].next_;
|
||||||
|
while ( link )
|
||||||
|
{
|
||||||
|
ValueInternalLink *linkToRelease = link;
|
||||||
link = link->next_;
|
link = link->next_;
|
||||||
mapAllocator()->releaseMapLink(linkToRelease);
|
mapAllocator()->releaseMapLink( linkToRelease );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mapAllocator()->releaseMapBuckets(buckets_);
|
mapAllocator()->releaseMapBuckets( buckets_ );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::swap(ValueInternalMap& other) {
|
|
||||||
ValueInternalLink* tempBuckets = buckets_;
|
void
|
||||||
|
ValueInternalMap::swap( ValueInternalMap &other )
|
||||||
|
{
|
||||||
|
ValueInternalLink *tempBuckets = buckets_;
|
||||||
buckets_ = other.buckets_;
|
buckets_ = other.buckets_;
|
||||||
other.buckets_ = tempBuckets;
|
other.buckets_ = tempBuckets;
|
||||||
ValueInternalLink* tempTailLink = tailLink_;
|
ValueInternalLink *tempTailLink = tailLink_;
|
||||||
tailLink_ = other.tailLink_;
|
tailLink_ = other.tailLink_;
|
||||||
other.tailLink_ = tempTailLink;
|
other.tailLink_ = tempTailLink;
|
||||||
BucketIndex tempBucketsSize = bucketsSize_;
|
BucketIndex tempBucketsSize = bucketsSize_;
|
||||||
@@ -177,264 +240,336 @@ void ValueInternalMap::swap(ValueInternalMap& other) {
|
|||||||
other.itemCount_ = tempItemCount;
|
other.itemCount_ = tempItemCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::clear() {
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::clear()
|
||||||
|
{
|
||||||
ValueInternalMap dummy;
|
ValueInternalMap dummy;
|
||||||
swap(dummy);
|
swap( dummy );
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueInternalMap::BucketIndex ValueInternalMap::size() const {
|
|
||||||
|
ValueInternalMap::BucketIndex
|
||||||
|
ValueInternalMap::size() const
|
||||||
|
{
|
||||||
return itemCount_;
|
return itemCount_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValueInternalMap::reserveDelta(BucketIndex growth) {
|
bool
|
||||||
return reserve(itemCount_ + growth);
|
ValueInternalMap::reserveDelta( BucketIndex growth )
|
||||||
|
{
|
||||||
|
return reserve( itemCount_ + growth );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValueInternalMap::reserve(BucketIndex newItemCount) {
|
bool
|
||||||
if (!buckets_ && newItemCount > 0) {
|
ValueInternalMap::reserve( BucketIndex newItemCount )
|
||||||
buckets_ = mapAllocator()->allocateMapBuckets(1);
|
{
|
||||||
|
if ( !buckets_ && newItemCount > 0 )
|
||||||
|
{
|
||||||
|
buckets_ = mapAllocator()->allocateMapBuckets( 1 );
|
||||||
bucketsSize_ = 1;
|
bucketsSize_ = 1;
|
||||||
tailLink_ = &buckets_[0];
|
tailLink_ = &buckets_[0];
|
||||||
}
|
}
|
||||||
// BucketIndex idealBucketCount = (newItemCount +
|
// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
|
||||||
// ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Value* ValueInternalMap::find(const char* key) const {
|
|
||||||
if (!bucketsSize_)
|
const Value *
|
||||||
|
ValueInternalMap::find( const char *key ) const
|
||||||
|
{
|
||||||
|
if ( !bucketsSize_ )
|
||||||
return 0;
|
return 0;
|
||||||
HashKey hashedKey = hash(key);
|
HashKey hashedKey = hash( key );
|
||||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
for (const ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
|
for ( const ValueInternalLink *current = &buckets_[bucketIndex];
|
||||||
current = current->next_) {
|
current != 0;
|
||||||
for (BucketIndex index = 0; index < ValueInternalLink::itemPerLink;
|
current = current->next_ )
|
||||||
++index) {
|
{
|
||||||
if (current->items_[index].isItemAvailable())
|
for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
|
||||||
|
{
|
||||||
|
if ( current->items_[index].isItemAvailable() )
|
||||||
return 0;
|
return 0;
|
||||||
if (strcmp(key, current->keys_[index]) == 0)
|
if ( strcmp( key, current->keys_[index] ) == 0 )
|
||||||
return ¤t->items_[index];
|
return ¤t->items_[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* ValueInternalMap::find(const char* key) {
|
|
||||||
const ValueInternalMap* constThis = this;
|
Value *
|
||||||
return const_cast<Value*>(constThis->find(key));
|
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);
|
Value &
|
||||||
if (bucketsSize_) {
|
ValueInternalMap::resolveReference( const char *key,
|
||||||
|
bool isStatic )
|
||||||
|
{
|
||||||
|
HashKey hashedKey = hash( key );
|
||||||
|
if ( bucketsSize_ )
|
||||||
|
{
|
||||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
ValueInternalLink** previous = 0;
|
ValueInternalLink **previous = 0;
|
||||||
BucketIndex index;
|
BucketIndex index;
|
||||||
for (ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
|
for ( ValueInternalLink *current = &buckets_[bucketIndex];
|
||||||
previous = ¤t->next_, current = current->next_) {
|
current != 0;
|
||||||
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
previous = ¤t->next_, current = current->next_ )
|
||||||
if (current->items_[index].isItemAvailable())
|
{
|
||||||
return setNewItem(key, isStatic, current, index);
|
for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
|
||||||
if (strcmp(key, current->keys_[index]) == 0)
|
{
|
||||||
|
if ( current->items_[index].isItemAvailable() )
|
||||||
|
return setNewItem( key, isStatic, current, index );
|
||||||
|
if ( strcmp( key, current->keys_[index] ) == 0 )
|
||||||
return current->items_[index];
|
return current->items_[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reserveDelta(1);
|
reserveDelta( 1 );
|
||||||
return unsafeAdd(key, isStatic, hashedKey);
|
return unsafeAdd( key, isStatic, hashedKey );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::remove(const char* key) {
|
|
||||||
HashKey hashedKey = hash(key);
|
void
|
||||||
if (!bucketsSize_)
|
ValueInternalMap::remove( const char *key )
|
||||||
|
{
|
||||||
|
HashKey hashedKey = hash( key );
|
||||||
|
if ( !bucketsSize_ )
|
||||||
return;
|
return;
|
||||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
for (ValueInternalLink* link = &buckets_[bucketIndex]; link != 0;
|
for ( ValueInternalLink *link = &buckets_[bucketIndex];
|
||||||
link = link->next_) {
|
link != 0;
|
||||||
|
link = link->next_ )
|
||||||
|
{
|
||||||
BucketIndex index;
|
BucketIndex index;
|
||||||
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
||||||
if (link->items_[index].isItemAvailable())
|
{
|
||||||
|
if ( link->items_[index].isItemAvailable() )
|
||||||
return;
|
return;
|
||||||
if (strcmp(key, link->keys_[index]) == 0) {
|
if ( strcmp( key, link->keys_[index] ) == 0 )
|
||||||
doActualRemove(link, index, bucketIndex);
|
{
|
||||||
|
doActualRemove( link, index, bucketIndex );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::doActualRemove(ValueInternalLink* link,
|
void
|
||||||
|
ValueInternalMap::doActualRemove( ValueInternalLink *link,
|
||||||
BucketIndex index,
|
BucketIndex index,
|
||||||
BucketIndex bucketIndex) {
|
BucketIndex bucketIndex )
|
||||||
|
{
|
||||||
// find last item of the bucket and swap it with the 'removed' one.
|
// find last item of the bucket and swap it with the 'removed' one.
|
||||||
// set removed items flags to 'available'.
|
// set removed items flags to 'available'.
|
||||||
// if last page only contains 'available' items, then desallocate it (it's
|
// if last page only contains 'available' items, then desallocate it (it's empty)
|
||||||
// empty)
|
ValueInternalLink *&lastLink = getLastLinkInBucket( index );
|
||||||
ValueInternalLink*& lastLink = getLastLinkInBucket(index);
|
|
||||||
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
|
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
|
||||||
for (; lastItemIndex < ValueInternalLink::itemPerLink;
|
for ( ;
|
||||||
++lastItemIndex) // may be optimized with dicotomic search
|
lastItemIndex < ValueInternalLink::itemPerLink;
|
||||||
|
++lastItemIndex ) // may be optimized with dicotomic search
|
||||||
{
|
{
|
||||||
if (lastLink->items_[lastItemIndex].isItemAvailable())
|
if ( lastLink->items_[lastItemIndex].isItemAvailable() )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BucketIndex lastUsedIndex = lastItemIndex - 1;
|
BucketIndex lastUsedIndex = lastItemIndex - 1;
|
||||||
Value* valueToDelete = &link->items_[index];
|
Value *valueToDelete = &link->items_[index];
|
||||||
Value* valueToPreserve = &lastLink->items_[lastUsedIndex];
|
Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
|
||||||
if (valueToDelete != valueToPreserve)
|
if ( valueToDelete != valueToPreserve )
|
||||||
valueToDelete->swap(*valueToPreserve);
|
valueToDelete->swap( *valueToPreserve );
|
||||||
if (lastUsedIndex == 0) // page is now empty
|
if ( lastUsedIndex == 0 ) // page is now empty
|
||||||
{ // remove it from bucket linked list and delete it.
|
{ // remove it from bucket linked list and delete it.
|
||||||
ValueInternalLink* linkPreviousToLast = lastLink->previous_;
|
ValueInternalLink *linkPreviousToLast = lastLink->previous_;
|
||||||
if (linkPreviousToLast != 0) // can not deleted bucket link.
|
if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
|
||||||
{
|
{
|
||||||
mapAllocator()->releaseMapLink(lastLink);
|
mapAllocator()->releaseMapLink( lastLink );
|
||||||
linkPreviousToLast->next_ = 0;
|
linkPreviousToLast->next_ = 0;
|
||||||
lastLink = linkPreviousToLast;
|
lastLink = linkPreviousToLast;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Value dummy;
|
Value dummy;
|
||||||
valueToPreserve->swap(dummy); // restore deleted to default Value.
|
valueToPreserve->swap( dummy ); // restore deleted to default Value.
|
||||||
valueToPreserve->setItemUsed(false);
|
valueToPreserve->setItemUsed( false );
|
||||||
}
|
}
|
||||||
--itemCount_;
|
--itemCount_;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueInternalLink*&
|
|
||||||
ValueInternalMap::getLastLinkInBucket(BucketIndex bucketIndex) {
|
ValueInternalLink *&
|
||||||
if (bucketIndex == bucketsSize_ - 1)
|
ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
|
||||||
|
{
|
||||||
|
if ( bucketIndex == bucketsSize_ - 1 )
|
||||||
return tailLink_;
|
return tailLink_;
|
||||||
ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_;
|
ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
|
||||||
if (!previous)
|
if ( !previous )
|
||||||
previous = &buckets_[bucketIndex];
|
previous = &buckets_[bucketIndex];
|
||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& ValueInternalMap::setNewItem(const char* key,
|
|
||||||
|
Value &
|
||||||
|
ValueInternalMap::setNewItem( const char *key,
|
||||||
bool isStatic,
|
bool isStatic,
|
||||||
ValueInternalLink* link,
|
ValueInternalLink *link,
|
||||||
BucketIndex index) {
|
BucketIndex index )
|
||||||
char* duplicatedKey = makeMemberName(key);
|
{
|
||||||
|
char *duplicatedKey = makeMemberName( key );
|
||||||
++itemCount_;
|
++itemCount_;
|
||||||
link->keys_[index] = duplicatedKey;
|
link->keys_[index] = duplicatedKey;
|
||||||
link->items_[index].setItemUsed();
|
link->items_[index].setItemUsed();
|
||||||
link->items_[index].setMemberNameIsStatic(isStatic);
|
link->items_[index].setMemberNameIsStatic( isStatic );
|
||||||
return link->items_[index]; // items already default constructed.
|
return link->items_[index]; // items already default constructed.
|
||||||
}
|
}
|
||||||
|
|
||||||
Value&
|
|
||||||
ValueInternalMap::unsafeAdd(const char* key, bool isStatic, HashKey hashedKey) {
|
Value &
|
||||||
JSON_ASSERT_MESSAGE(bucketsSize_ > 0,
|
ValueInternalMap::unsafeAdd( const char *key,
|
||||||
"ValueInternalMap::unsafeAdd(): internal logic error.");
|
bool isStatic,
|
||||||
|
HashKey hashedKey )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
|
||||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
ValueInternalLink*& previousLink = getLastLinkInBucket(bucketIndex);
|
ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
|
||||||
ValueInternalLink* link = previousLink;
|
ValueInternalLink *link = previousLink;
|
||||||
BucketIndex index;
|
BucketIndex index;
|
||||||
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
||||||
if (link->items_[index].isItemAvailable())
|
{
|
||||||
|
if ( link->items_[index].isItemAvailable() )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (index == ValueInternalLink::itemPerLink) // need to add a new page
|
if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
|
||||||
{
|
{
|
||||||
ValueInternalLink* newLink = mapAllocator()->allocateMapLink();
|
ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
|
||||||
index = 0;
|
index = 0;
|
||||||
link->next_ = newLink;
|
link->next_ = newLink;
|
||||||
previousLink = newLink;
|
previousLink = newLink;
|
||||||
link = newLink;
|
link = newLink;
|
||||||
}
|
}
|
||||||
return setNewItem(key, isStatic, link, index);
|
return setNewItem( key, isStatic, link, index );
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueInternalMap::HashKey ValueInternalMap::hash(const char* key) const {
|
|
||||||
|
ValueInternalMap::HashKey
|
||||||
|
ValueInternalMap::hash( const char *key ) const
|
||||||
|
{
|
||||||
HashKey hash = 0;
|
HashKey hash = 0;
|
||||||
while (*key)
|
while ( *key )
|
||||||
hash += *key++ * 37;
|
hash += *key++ * 37;
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ValueInternalMap::compare(const ValueInternalMap& other) const {
|
|
||||||
int sizeDiff(itemCount_ - other.itemCount_);
|
int
|
||||||
if (sizeDiff != 0)
|
ValueInternalMap::compare( const ValueInternalMap &other ) const
|
||||||
|
{
|
||||||
|
int sizeDiff( itemCount_ - other.itemCount_ );
|
||||||
|
if ( sizeDiff != 0 )
|
||||||
return sizeDiff;
|
return sizeDiff;
|
||||||
// Strict order guaranty is required. Compare all keys FIRST, then compare
|
// Strict order guaranty is required. Compare all keys FIRST, then compare values.
|
||||||
// values.
|
|
||||||
IteratorState it;
|
IteratorState it;
|
||||||
IteratorState itEnd;
|
IteratorState itEnd;
|
||||||
makeBeginIterator(it);
|
makeBeginIterator( it );
|
||||||
makeEndIterator(itEnd);
|
makeEndIterator( itEnd );
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
if (!other.find(key(it)))
|
{
|
||||||
|
if ( !other.find( key( it ) ) )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All keys are equals, let's compare values
|
// All keys are equals, let's compare values
|
||||||
makeBeginIterator(it);
|
makeBeginIterator( it );
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
const Value* otherValue = other.find(key(it));
|
{
|
||||||
int valueDiff = value(it).compare(*otherValue);
|
const Value *otherValue = other.find( key( it ) );
|
||||||
if (valueDiff != 0)
|
int valueDiff = value(it).compare( *otherValue );
|
||||||
|
if ( valueDiff != 0 )
|
||||||
return valueDiff;
|
return valueDiff;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::makeBeginIterator(IteratorState& it) const {
|
|
||||||
it.map_ = const_cast<ValueInternalMap*>(this);
|
void
|
||||||
|
ValueInternalMap::makeBeginIterator( IteratorState &it ) const
|
||||||
|
{
|
||||||
|
it.map_ = const_cast<ValueInternalMap *>( this );
|
||||||
it.bucketIndex_ = 0;
|
it.bucketIndex_ = 0;
|
||||||
it.itemIndex_ = 0;
|
it.itemIndex_ = 0;
|
||||||
it.link_ = buckets_;
|
it.link_ = buckets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::makeEndIterator(IteratorState& it) const {
|
|
||||||
it.map_ = const_cast<ValueInternalMap*>(this);
|
void
|
||||||
|
ValueInternalMap::makeEndIterator( IteratorState &it ) const
|
||||||
|
{
|
||||||
|
it.map_ = const_cast<ValueInternalMap *>( this );
|
||||||
it.bucketIndex_ = bucketsSize_;
|
it.bucketIndex_ = bucketsSize_;
|
||||||
it.itemIndex_ = 0;
|
it.itemIndex_ = 0;
|
||||||
it.link_ = 0;
|
it.link_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValueInternalMap::equals(const IteratorState& x,
|
|
||||||
const IteratorState& other) {
|
bool
|
||||||
return x.map_ == other.map_ && x.bucketIndex_ == other.bucketIndex_ &&
|
ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
|
||||||
x.link_ == other.link_ && x.itemIndex_ == other.itemIndex_;
|
{
|
||||||
|
return x.map_ == other.map_
|
||||||
|
&& x.bucketIndex_ == other.bucketIndex_
|
||||||
|
&& x.link_ == other.link_
|
||||||
|
&& x.itemIndex_ == other.itemIndex_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::incrementBucket(IteratorState& iterator) {
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::incrementBucket( IteratorState &iterator )
|
||||||
|
{
|
||||||
++iterator.bucketIndex_;
|
++iterator.bucketIndex_;
|
||||||
JSON_ASSERT_MESSAGE(
|
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
|
||||||
iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
|
"ValueInternalMap::increment(): attempting to iterate beyond end." );
|
||||||
"ValueInternalMap::increment(): attempting to iterate beyond end.");
|
if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
|
||||||
if (iterator.bucketIndex_ == iterator.map_->bucketsSize_)
|
|
||||||
iterator.link_ = 0;
|
iterator.link_ = 0;
|
||||||
else
|
else
|
||||||
iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
|
iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
|
||||||
iterator.itemIndex_ = 0;
|
iterator.itemIndex_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::increment(IteratorState& iterator) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.map_,
|
void
|
||||||
"Attempting to iterator using invalid iterator.");
|
ValueInternalMap::increment( IteratorState &iterator )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
|
||||||
++iterator.itemIndex_;
|
++iterator.itemIndex_;
|
||||||
if (iterator.itemIndex_ == ValueInternalLink::itemPerLink) {
|
if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
|
||||||
JSON_ASSERT_MESSAGE(
|
{
|
||||||
iterator.link_ != 0,
|
JSON_ASSERT_MESSAGE( iterator.link_ != 0,
|
||||||
"ValueInternalMap::increment(): attempting to iterate beyond end.");
|
"ValueInternalMap::increment(): attempting to iterate beyond end." );
|
||||||
iterator.link_ = iterator.link_->next_;
|
iterator.link_ = iterator.link_->next_;
|
||||||
if (iterator.link_ == 0)
|
if ( iterator.link_ == 0 )
|
||||||
incrementBucket(iterator);
|
incrementBucket( iterator );
|
||||||
} else if (iterator.link_->items_[iterator.itemIndex_].isItemAvailable()) {
|
}
|
||||||
incrementBucket(iterator);
|
else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
|
||||||
|
{
|
||||||
|
incrementBucket( iterator );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueInternalMap::decrement(IteratorState& iterator) {
|
|
||||||
if (iterator.itemIndex_ == 0) {
|
void
|
||||||
JSON_ASSERT_MESSAGE(iterator.map_,
|
ValueInternalMap::decrement( IteratorState &iterator )
|
||||||
"Attempting to iterate using invalid iterator.");
|
{
|
||||||
if (iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_]) {
|
if ( iterator.itemIndex_ == 0 )
|
||||||
JSON_ASSERT_MESSAGE(iterator.bucketIndex_ > 0,
|
{
|
||||||
"Attempting to iterate beyond beginning.");
|
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.bucketIndex_);
|
||||||
}
|
}
|
||||||
iterator.link_ = iterator.link_->previous_;
|
iterator.link_ = iterator.link_->previous_;
|
||||||
@@ -442,31 +577,38 @@ void ValueInternalMap::decrement(IteratorState& iterator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ValueInternalMap::key(const IteratorState& iterator) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.link_,
|
const char *
|
||||||
"Attempting to iterate using invalid iterator.");
|
ValueInternalMap::key( const IteratorState &iterator )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||||
return iterator.link_->keys_[iterator.itemIndex_];
|
return iterator.link_->keys_[iterator.itemIndex_];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ValueInternalMap::key(const IteratorState& iterator,
|
const char *
|
||||||
bool& isStatic) {
|
ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
|
||||||
JSON_ASSERT_MESSAGE(iterator.link_,
|
{
|
||||||
"Attempting to iterate using invalid iterator.");
|
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||||
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
|
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
|
||||||
return iterator.link_->keys_[iterator.itemIndex_];
|
return iterator.link_->keys_[iterator.itemIndex_];
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& ValueInternalMap::value(const IteratorState& iterator) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.link_,
|
Value &
|
||||||
"Attempting to iterate using invalid iterator.");
|
ValueInternalMap::value( const IteratorState &iterator )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||||
return iterator.link_->items_[iterator.itemIndex_];
|
return iterator.link_->items_[iterator.itemIndex_];
|
||||||
}
|
}
|
||||||
|
|
||||||
int ValueInternalMap::distance(const IteratorState& x, const IteratorState& y) {
|
|
||||||
|
int
|
||||||
|
ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
|
||||||
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
IteratorState it = x;
|
IteratorState it = x;
|
||||||
while (!equals(it, y))
|
while ( !equals( it, y ) )
|
||||||
increment(it);
|
increment( it );
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
#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,
|
/* This header provides common string manipulation support, such as UTF-8,
|
||||||
* portable conversion from/to string...
|
* portable conversion from/to string...
|
||||||
@@ -15,24 +15,33 @@
|
|||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
/// Converts a unicode code-point to UTF-8.
|
/// Converts a unicode code-point to UTF-8.
|
||||||
static inline std::string codePointToUTF8(unsigned int cp) {
|
static inline std::string
|
||||||
|
codePointToUTF8(unsigned int cp)
|
||||||
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||||
|
|
||||||
if (cp <= 0x7f) {
|
if (cp <= 0x7f)
|
||||||
|
{
|
||||||
result.resize(1);
|
result.resize(1);
|
||||||
result[0] = static_cast<char>(cp);
|
result[0] = static_cast<char>(cp);
|
||||||
} else if (cp <= 0x7FF) {
|
}
|
||||||
|
else if (cp <= 0x7FF)
|
||||||
|
{
|
||||||
result.resize(2);
|
result.resize(2);
|
||||||
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||||
} else if (cp <= 0xFFFF) {
|
}
|
||||||
|
else if (cp <= 0xFFFF)
|
||||||
|
{
|
||||||
result.resize(3);
|
result.resize(3);
|
||||||
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
||||||
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
||||||
} else if (cp <= 0x10FFFF) {
|
}
|
||||||
|
else if (cp <= 0x10FFFF)
|
||||||
|
{
|
||||||
result.resize(4);
|
result.resize(4);
|
||||||
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||||
@@ -43,43 +52,40 @@ static inline std::string codePointToUTF8(unsigned int cp) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns true if ch is a control character (in range [0,32[).
|
/// 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 {
|
enum {
|
||||||
/// Constant that specify the size of the buffer that must be passed to
|
/// Constant that specify the size of the buffer that must be passed to uintToString.
|
||||||
/// uintToString.
|
uintToStringBufferSize = 3*sizeof(LargestUInt)+1
|
||||||
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defines a char buffer for use with uintToString().
|
// Defines a char buffer for use with uintToString().
|
||||||
typedef char UIntToStringBuffer[uintToStringBufferSize];
|
typedef char UIntToStringBuffer[uintToStringBufferSize];
|
||||||
|
|
||||||
|
|
||||||
/** Converts an unsigned integer to string.
|
/** Converts an unsigned integer to string.
|
||||||
* @param value Unsigned interger to convert 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.
|
* Must have at least uintToStringBufferSize chars free.
|
||||||
*/
|
*/
|
||||||
static inline void uintToString(LargestUInt value, char*& current) {
|
static inline void
|
||||||
|
uintToString( LargestUInt value,
|
||||||
|
char *¤t )
|
||||||
|
{
|
||||||
*--current = 0;
|
*--current = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
*--current = char(value % 10) + '0';
|
*--current = char(value % 10) + '0';
|
||||||
value /= 10;
|
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;
|
|
||||||
}
|
}
|
||||||
|
while ( value != 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Json {
|
} // namespace Json {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -17,165 +17,200 @@ namespace Json {
|
|||||||
|
|
||||||
ValueIteratorBase::ValueIteratorBase()
|
ValueIteratorBase::ValueIteratorBase()
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
: current_(), isNull_(true) {
|
: current_()
|
||||||
|
, isNull_( true )
|
||||||
|
{
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
: isArray_(true), isNull_(true) {
|
: isArray_( true )
|
||||||
|
, isNull_( true )
|
||||||
|
{
|
||||||
iterator_.array_ = ValueInternalArray::IteratorState();
|
iterator_.array_ = ValueInternalArray::IteratorState();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
ValueIteratorBase::ValueIteratorBase(
|
ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t )
|
||||||
const Value::ObjectValues::iterator& current)
|
: current_( current )
|
||||||
: current_(current), isNull_(false) {}
|
, isNull_( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
ValueIteratorBase::ValueIteratorBase(
|
ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
|
||||||
const ValueInternalArray::IteratorState& state)
|
: isArray_( true )
|
||||||
: isArray_(true) {
|
{
|
||||||
iterator_.array_ = state;
|
iterator_.array_ = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueIteratorBase::ValueIteratorBase(
|
|
||||||
const ValueInternalMap::IteratorState& state)
|
ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
|
||||||
: isArray_(false) {
|
: isArray_( false )
|
||||||
|
{
|
||||||
iterator_.map_ = state;
|
iterator_.map_ = state;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Value& ValueIteratorBase::deref() const {
|
Value &
|
||||||
|
ValueIteratorBase::deref() const
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
return current_->second;
|
return current_->second;
|
||||||
#else
|
#else
|
||||||
if (isArray_)
|
if ( isArray_ )
|
||||||
return ValueInternalArray::dereference(iterator_.array_);
|
return ValueInternalArray::dereference( iterator_.array_ );
|
||||||
return ValueInternalMap::value(iterator_.map_);
|
return ValueInternalMap::value( iterator_.map_ );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::increment() {
|
|
||||||
|
void
|
||||||
|
ValueIteratorBase::increment()
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
++current_;
|
++current_;
|
||||||
#else
|
#else
|
||||||
if (isArray_)
|
if ( isArray_ )
|
||||||
ValueInternalArray::increment(iterator_.array_);
|
ValueInternalArray::increment( iterator_.array_ );
|
||||||
ValueInternalMap::increment(iterator_.map_);
|
ValueInternalMap::increment( iterator_.map_ );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::decrement() {
|
|
||||||
|
void
|
||||||
|
ValueIteratorBase::decrement()
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
--current_;
|
--current_;
|
||||||
#else
|
#else
|
||||||
if (isArray_)
|
if ( isArray_ )
|
||||||
ValueInternalArray::decrement(iterator_.array_);
|
ValueInternalArray::decrement( iterator_.array_ );
|
||||||
ValueInternalMap::decrement(iterator_.map_);
|
ValueInternalMap::decrement( iterator_.map_ );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ValueIteratorBase::difference_type
|
ValueIteratorBase::difference_type
|
||||||
ValueIteratorBase::computeDistance(const SelfType& other) const {
|
ValueIteratorBase::computeDistance( const SelfType &other ) const
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
#ifdef JSON_USE_CPPTL_SMALLMAP
|
# ifdef JSON_USE_CPPTL_SMALLMAP
|
||||||
return current_ - other.current_;
|
return current_ - other.current_;
|
||||||
#else
|
# else
|
||||||
// Iterator for null value are initialized using the default
|
// Iterator for null value are initialized using the default
|
||||||
// constructor, which initialize current_ to the default
|
// constructor, which initialize current_ to the default
|
||||||
// std::map::iterator. As begin() and end() are two instance
|
// std::map::iterator. As begin() and end() are two instance
|
||||||
// of the default std::map::iterator, they can not be compared.
|
// of the default std::map::iterator, they can not be compared.
|
||||||
// To allow this, we handle this comparison specifically.
|
// To allow this, we handle this comparison specifically.
|
||||||
if (isNull_ && other.isNull_) {
|
if ( isNull_ && other.isNull_ )
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usage of std::distance is not portable (does not compile with Sun Studio 12
|
|
||||||
// RogueWave STL,
|
// Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
|
||||||
// which is the one used by default).
|
// which is the one used by default).
|
||||||
// Using a portable hand-made version for non random iterator instead:
|
// Using a portable hand-made version for non random iterator instead:
|
||||||
// return difference_type( std::distance( current_, other.current_ ) );
|
// return difference_type( std::distance( current_, other.current_ ) );
|
||||||
difference_type myDistance = 0;
|
difference_type myDistance = 0;
|
||||||
for (Value::ObjectValues::iterator it = current_; it != other.current_;
|
for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
|
||||||
++it) {
|
{
|
||||||
++myDistance;
|
++myDistance;
|
||||||
}
|
}
|
||||||
return myDistance;
|
return myDistance;
|
||||||
#endif
|
# endif
|
||||||
#else
|
#else
|
||||||
if (isArray_)
|
if ( isArray_ )
|
||||||
return ValueInternalArray::distance(iterator_.array_,
|
return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
|
||||||
other.iterator_.array_);
|
return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
|
||||||
return ValueInternalMap::distance(iterator_.map_, other.iterator_.map_);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValueIteratorBase::isEqual(const SelfType& other) const {
|
|
||||||
|
bool
|
||||||
|
ValueIteratorBase::isEqual( const SelfType &other ) const
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
if (isNull_) {
|
if ( isNull_ )
|
||||||
|
{
|
||||||
return other.isNull_;
|
return other.isNull_;
|
||||||
}
|
}
|
||||||
return current_ == other.current_;
|
return current_ == other.current_;
|
||||||
#else
|
#else
|
||||||
if (isArray_)
|
if ( isArray_ )
|
||||||
return ValueInternalArray::equals(iterator_.array_, other.iterator_.array_);
|
return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
|
||||||
return ValueInternalMap::equals(iterator_.map_, other.iterator_.map_);
|
return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::copy(const SelfType& other) {
|
|
||||||
|
void
|
||||||
|
ValueIteratorBase::copy( const SelfType &other )
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
current_ = other.current_;
|
current_ = other.current_;
|
||||||
isNull_ = other.isNull_;
|
|
||||||
#else
|
#else
|
||||||
if (isArray_)
|
if ( isArray_ )
|
||||||
iterator_.array_ = other.iterator_.array_;
|
iterator_.array_ = other.iterator_.array_;
|
||||||
iterator_.map_ = other.iterator_.map_;
|
iterator_.map_ = other.iterator_.map_;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ValueIteratorBase::key() const {
|
|
||||||
|
Value
|
||||||
|
ValueIteratorBase::key() const
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
const Value::CZString czstring = (*current_).first;
|
const Value::CZString czstring = (*current_).first;
|
||||||
if (czstring.c_str()) {
|
if ( czstring.c_str() )
|
||||||
if (czstring.isStaticString())
|
{
|
||||||
return Value(StaticString(czstring.c_str()));
|
if ( czstring.isStaticString() )
|
||||||
return Value(czstring.c_str());
|
return Value( StaticString( czstring.c_str() ) );
|
||||||
|
return Value( czstring.c_str() );
|
||||||
}
|
}
|
||||||
return Value(czstring.index());
|
return Value( czstring.index() );
|
||||||
#else
|
#else
|
||||||
if (isArray_)
|
if ( isArray_ )
|
||||||
return Value(ValueInternalArray::indexOf(iterator_.array_));
|
return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||||
bool isStatic;
|
bool isStatic;
|
||||||
const char* memberName = ValueInternalMap::key(iterator_.map_, isStatic);
|
const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
|
||||||
if (isStatic)
|
if ( isStatic )
|
||||||
return Value(StaticString(memberName));
|
return Value( StaticString( memberName ) );
|
||||||
return Value(memberName);
|
return Value( memberName );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt ValueIteratorBase::index() const {
|
|
||||||
|
UInt
|
||||||
|
ValueIteratorBase::index() const
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
const Value::CZString czstring = (*current_).first;
|
const Value::CZString czstring = (*current_).first;
|
||||||
if (!czstring.c_str())
|
if ( !czstring.c_str() )
|
||||||
return czstring.index();
|
return czstring.index();
|
||||||
return Value::UInt(-1);
|
return Value::UInt( -1 );
|
||||||
#else
|
#else
|
||||||
if (isArray_)
|
if ( isArray_ )
|
||||||
return Value::UInt(ValueInternalArray::indexOf(iterator_.array_));
|
return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||||
return Value::UInt(-1);
|
return Value::UInt( -1 );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ValueIteratorBase::memberName() const {
|
|
||||||
|
const char *
|
||||||
|
ValueIteratorBase::memberName() const
|
||||||
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
const char* name = (*current_).first.c_str();
|
const char *name = (*current_).first.c_str();
|
||||||
return name ? name : "";
|
return name ? name : "";
|
||||||
#else
|
#else
|
||||||
if (!isArray_)
|
if ( !isArray_ )
|
||||||
return ValueInternalMap::key(iterator_.map_);
|
return ValueInternalMap::key( iterator_.map_ );
|
||||||
return "";
|
return "";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@@ -184,28 +219,36 @@ const char* ValueIteratorBase::memberName() const {
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ValueConstIterator::ValueConstIterator() {}
|
ValueConstIterator::ValueConstIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
ValueConstIterator::ValueConstIterator(
|
ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t )
|
||||||
const Value::ObjectValues::iterator& current)
|
: ValueIteratorBase( current )
|
||||||
: ValueIteratorBase(current) {}
|
{
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
ValueConstIterator::ValueConstIterator(
|
ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
|
||||||
const ValueInternalArray::IteratorState& state)
|
: ValueIteratorBase( state )
|
||||||
: ValueIteratorBase(state) {}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ValueConstIterator::ValueConstIterator(
|
ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
|
||||||
const ValueInternalMap::IteratorState& state)
|
: ValueIteratorBase( state )
|
||||||
: ValueIteratorBase(state) {}
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ValueConstIterator& ValueConstIterator::
|
ValueConstIterator &
|
||||||
operator=(const ValueIteratorBase& other) {
|
ValueConstIterator::operator =( const ValueIteratorBase &other )
|
||||||
copy(other);
|
{
|
||||||
|
copy( other );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@@ -214,27 +257,42 @@ operator=(const ValueIteratorBase& other) {
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ValueIterator::ValueIterator() {}
|
ValueIterator::ValueIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t )
|
||||||
: ValueIteratorBase(current) {}
|
: ValueIteratorBase( current )
|
||||||
|
{
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
ValueIterator::ValueIterator(const ValueInternalArray::IteratorState& state)
|
ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
|
||||||
: ValueIteratorBase(state) {}
|
: ValueIteratorBase( state )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ValueIterator::ValueIterator(const ValueInternalMap::IteratorState& state)
|
ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
|
||||||
: ValueIteratorBase(state) {}
|
: ValueIteratorBase( state )
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
ValueIterator::ValueIterator( const ValueConstIterator &other )
|
||||||
: ValueIteratorBase(other) {}
|
: ValueIteratorBase( other )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ValueIterator::ValueIterator(const ValueIterator& other)
|
ValueIterator::ValueIterator( const ValueIterator &other )
|
||||||
: ValueIteratorBase(other) {}
|
: ValueIteratorBase( other )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ValueIterator& ValueIterator::operator=(const SelfType& other) {
|
ValueIterator &
|
||||||
copy(other);
|
ValueIterator::operator =( const SelfType &other )
|
||||||
|
{
|
||||||
|
copy( other );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,14 +0,0 @@
|
|||||||
// 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 "@JSONCPP_VERSION@"
|
|
||||||
# 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
|
|
||||||
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
|
||||||
|
|
||||||
#endif // JSON_VERSION_H_INCLUDED
|
|
@@ -1,22 +0,0 @@
|
|||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
ADD_DEFINITIONS( -DJSON_DLL )
|
|
||||||
ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
|
|
||||||
ADD_EXECUTABLE( jsoncpp_test
|
|
||||||
jsontest.cpp
|
|
||||||
jsontest.h
|
|
||||||
main.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib)
|
|
||||||
|
|
||||||
# Run unit tests in post-build
|
|
||||||
# (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 $<TARGET_FILE:jsoncpp_test>)
|
|
||||||
ENDIF(JSONCPP_WITH_POST_BUILD_UNITTEST)
|
|
||||||
|
|
||||||
SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)
|
|
@@ -10,126 +10,144 @@
|
|||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
// Used to install a report hook that prevent dialog on assertion and error.
|
// Used to install a report hook that prevent dialog on assertion and error.
|
||||||
#include <crtdbg.h>
|
# include <crtdbg.h>
|
||||||
#endif // if defined(_MSC_VER)
|
#endif // if defined(_MSC_VER)
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// Used to prevent dialog on memory fault.
|
// Used to prevent dialog on memory fault.
|
||||||
// Limits headers included by Windows.h
|
// Limits headers included by Windows.h
|
||||||
#define WIN32_LEAN_AND_MEAN
|
# define WIN32_LEAN_AND_MEAN
|
||||||
#define NOSERVICE
|
# define NOSERVICE
|
||||||
#define NOMCX
|
# define NOMCX
|
||||||
#define NOIME
|
# define NOIME
|
||||||
#define NOSOUND
|
# define NOSOUND
|
||||||
#define NOCOMM
|
# define NOCOMM
|
||||||
#define NORPC
|
# define NORPC
|
||||||
#define NOGDI
|
# define NOGDI
|
||||||
#define NOUSER
|
# define NOUSER
|
||||||
#define NODRIVERS
|
# define NODRIVERS
|
||||||
#define NOLOGERROR
|
# define NOLOGERROR
|
||||||
#define NOPROFILER
|
# define NOPROFILER
|
||||||
#define NOMEMMGR
|
# define NOMEMMGR
|
||||||
#define NOLFILEIO
|
# define NOLFILEIO
|
||||||
#define NOOPENFILE
|
# define NOOPENFILE
|
||||||
#define NORESOURCE
|
# define NORESOURCE
|
||||||
#define NOATOM
|
# define NOATOM
|
||||||
#define NOLANGUAGE
|
# define NOLANGUAGE
|
||||||
#define NOLSTRING
|
# define NOLSTRING
|
||||||
#define NODBCS
|
# define NODBCS
|
||||||
#define NOKEYBOARDINFO
|
# define NOKEYBOARDINFO
|
||||||
#define NOGDICAPMASKS
|
# define NOGDICAPMASKS
|
||||||
#define NOCOLOR
|
# define NOCOLOR
|
||||||
#define NOGDIOBJ
|
# define NOGDIOBJ
|
||||||
#define NODRAWTEXT
|
# define NODRAWTEXT
|
||||||
#define NOTEXTMETRIC
|
# define NOTEXTMETRIC
|
||||||
#define NOSCALABLEFONT
|
# define NOSCALABLEFONT
|
||||||
#define NOBITMAP
|
# define NOBITMAP
|
||||||
#define NORASTEROPS
|
# define NORASTEROPS
|
||||||
#define NOMETAFILE
|
# define NOMETAFILE
|
||||||
#define NOSYSMETRICS
|
# define NOSYSMETRICS
|
||||||
#define NOSYSTEMPARAMSINFO
|
# define NOSYSTEMPARAMSINFO
|
||||||
#define NOMSG
|
# define NOMSG
|
||||||
#define NOWINSTYLES
|
# define NOWINSTYLES
|
||||||
#define NOWINOFFSETS
|
# define NOWINOFFSETS
|
||||||
#define NOSHOWWINDOW
|
# define NOSHOWWINDOW
|
||||||
#define NODEFERWINDOWPOS
|
# define NODEFERWINDOWPOS
|
||||||
#define NOVIRTUALKEYCODES
|
# define NOVIRTUALKEYCODES
|
||||||
#define NOKEYSTATES
|
# define NOKEYSTATES
|
||||||
#define NOWH
|
# define NOWH
|
||||||
#define NOMENUS
|
# define NOMENUS
|
||||||
#define NOSCROLL
|
# define NOSCROLL
|
||||||
#define NOCLIPBOARD
|
# define NOCLIPBOARD
|
||||||
#define NOICONS
|
# define NOICONS
|
||||||
#define NOMB
|
# define NOMB
|
||||||
#define NOSYSCOMMANDS
|
# define NOSYSCOMMANDS
|
||||||
#define NOMDI
|
# define NOMDI
|
||||||
#define NOCTLMGR
|
# define NOCTLMGR
|
||||||
#define NOWINMESSAGES
|
# define NOWINMESSAGES
|
||||||
#include <windows.h>
|
# include <windows.h>
|
||||||
#endif // if defined(_WIN32)
|
#endif // if defined(_WIN32)
|
||||||
|
|
||||||
namespace JsonTest {
|
namespace JsonTest {
|
||||||
|
|
||||||
|
|
||||||
// class TestResult
|
// class TestResult
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TestResult::TestResult()
|
TestResult::TestResult()
|
||||||
: predicateId_(1), lastUsedPredicateId_(0), messageTarget_(0) {
|
: predicateId_( 1 )
|
||||||
|
, lastUsedPredicateId_( 0 )
|
||||||
|
, messageTarget_( 0 )
|
||||||
|
{
|
||||||
// The root predicate has id 0
|
// The root predicate has id 0
|
||||||
rootPredicateNode_.id_ = 0;
|
rootPredicateNode_.id_ = 0;
|
||||||
rootPredicateNode_.next_ = 0;
|
rootPredicateNode_.next_ = 0;
|
||||||
predicateStackTail_ = &rootPredicateNode_;
|
predicateStackTail_ = &rootPredicateNode_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestResult::setTestName(const std::string& name) { name_ = name; }
|
|
||||||
|
|
||||||
TestResult&
|
void
|
||||||
TestResult::addFailure(const char* file, unsigned int line, const char* expr) {
|
TestResult::setTestName( const std::string &name )
|
||||||
/// Walks the PredicateContext stack adding them to failures_ if not already
|
{
|
||||||
/// added.
|
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;
|
unsigned int nestingLevel = 0;
|
||||||
PredicateContext* lastNode = rootPredicateNode_.next_;
|
PredicateContext *lastNode = rootPredicateNode_.next_;
|
||||||
for (; lastNode != 0; lastNode = lastNode->next_) {
|
for ( ; lastNode != 0; lastNode = lastNode->next_ )
|
||||||
if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
|
{
|
||||||
|
if ( lastNode->id_ > lastUsedPredicateId_ ) // new PredicateContext
|
||||||
{
|
{
|
||||||
lastUsedPredicateId_ = lastNode->id_;
|
lastUsedPredicateId_ = lastNode->id_;
|
||||||
addFailureInfo(
|
addFailureInfo( lastNode->file_, lastNode->line_, lastNode->expr_,
|
||||||
lastNode->file_, lastNode->line_, lastNode->expr_, nestingLevel);
|
nestingLevel );
|
||||||
// Link the PredicateContext to the failure for message target when
|
// Link the PredicateContext to the failure for message target when
|
||||||
// popping the PredicateContext.
|
// popping the PredicateContext.
|
||||||
lastNode->failure_ = &(failures_.back());
|
lastNode->failure_ = &( failures_.back() );
|
||||||
}
|
}
|
||||||
++nestingLevel;
|
++nestingLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds the failed assertion
|
// Adds the failed assertion
|
||||||
addFailureInfo(file, line, expr, nestingLevel);
|
addFailureInfo( file, line, expr, nestingLevel );
|
||||||
messageTarget_ = &(failures_.back());
|
messageTarget_ = &( failures_.back() );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestResult::addFailureInfo(const char* file,
|
|
||||||
unsigned int line,
|
void
|
||||||
const char* expr,
|
TestResult::addFailureInfo( const char *file, unsigned int line,
|
||||||
unsigned int nestingLevel) {
|
const char *expr, unsigned int nestingLevel )
|
||||||
|
{
|
||||||
Failure failure;
|
Failure failure;
|
||||||
failure.file_ = file;
|
failure.file_ = file;
|
||||||
failure.line_ = line;
|
failure.line_ = line;
|
||||||
if (expr) {
|
if ( expr )
|
||||||
|
{
|
||||||
failure.expr_ = expr;
|
failure.expr_ = expr;
|
||||||
}
|
}
|
||||||
failure.nestingLevel_ = nestingLevel;
|
failure.nestingLevel_ = nestingLevel;
|
||||||
failures_.push_back(failure);
|
failures_.push_back( failure );
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult& TestResult::popPredicateContext() {
|
|
||||||
PredicateContext* lastNode = &rootPredicateNode_;
|
TestResult &
|
||||||
while (lastNode->next_ != 0 && lastNode->next_->next_ != 0) {
|
TestResult::popPredicateContext()
|
||||||
|
{
|
||||||
|
PredicateContext *lastNode = &rootPredicateNode_;
|
||||||
|
while ( lastNode->next_ != 0 && lastNode->next_->next_ != 0 )
|
||||||
|
{
|
||||||
lastNode = lastNode->next_;
|
lastNode = lastNode->next_;
|
||||||
}
|
}
|
||||||
// Set message target to popped failure
|
// Set message target to popped failure
|
||||||
PredicateContext* tail = lastNode->next_;
|
PredicateContext *tail = lastNode->next_;
|
||||||
if (tail != 0 && tail->failure_ != 0) {
|
if ( tail != 0 && tail->failure_ != 0 )
|
||||||
|
{
|
||||||
messageTarget_ = tail->failure_;
|
messageTarget_ = tail->failure_;
|
||||||
}
|
}
|
||||||
// Remove tail from list
|
// Remove tail from list
|
||||||
@@ -138,176 +156,285 @@ TestResult& TestResult::popPredicateContext() {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestResult::failed() const { return !failures_.empty(); }
|
|
||||||
|
|
||||||
unsigned int TestResult::getAssertionNestingLevel() const {
|
bool
|
||||||
|
TestResult::failed() const
|
||||||
|
{
|
||||||
|
return !failures_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
TestResult::getAssertionNestingLevel() const
|
||||||
|
{
|
||||||
unsigned int level = 0;
|
unsigned int level = 0;
|
||||||
const PredicateContext* lastNode = &rootPredicateNode_;
|
const PredicateContext *lastNode = &rootPredicateNode_;
|
||||||
while (lastNode->next_ != 0) {
|
while ( lastNode->next_ != 0 )
|
||||||
|
{
|
||||||
lastNode = lastNode->next_;
|
lastNode = lastNode->next_;
|
||||||
++level;
|
++level;
|
||||||
}
|
}
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestResult::printFailure(bool printTestName) const {
|
|
||||||
if (failures_.empty()) {
|
void
|
||||||
|
TestResult::printFailure( bool printTestName ) const
|
||||||
|
{
|
||||||
|
if ( failures_.empty() )
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (printTestName) {
|
if ( printTestName )
|
||||||
printf("* Detail of %s test failure:\n", name_.c_str());
|
{
|
||||||
|
printf( "* Detail of %s test failure:\n", name_.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print in reverse to display the callstack in the right order
|
// Print in reverse to display the callstack in the right order
|
||||||
Failures::const_iterator itEnd = failures_.end();
|
Failures::const_iterator itEnd = failures_.end();
|
||||||
for (Failures::const_iterator it = failures_.begin(); it != itEnd; ++it) {
|
for ( Failures::const_iterator it = failures_.begin(); it != itEnd; ++it )
|
||||||
const Failure& failure = *it;
|
{
|
||||||
std::string indent(failure.nestingLevel_ * 2, ' ');
|
const Failure &failure = *it;
|
||||||
if (failure.file_) {
|
std::string indent( failure.nestingLevel_ * 2, ' ' );
|
||||||
printf("%s%s(%d): ", indent.c_str(), failure.file_, failure.line_);
|
if ( failure.file_ )
|
||||||
|
{
|
||||||
|
printf( "%s%s(%d): ", indent.c_str(), failure.file_, failure.line_ );
|
||||||
}
|
}
|
||||||
if (!failure.expr_.empty()) {
|
if ( !failure.expr_.empty() )
|
||||||
printf("%s\n", failure.expr_.c_str());
|
{
|
||||||
} else if (failure.file_) {
|
printf( "%s\n", failure.expr_.c_str() );
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
if (!failure.message_.empty()) {
|
else if ( failure.file_ )
|
||||||
std::string reindented = indentText(failure.message_, indent + " ");
|
{
|
||||||
printf("%s\n", reindented.c_str());
|
printf( "\n" );
|
||||||
|
}
|
||||||
|
if ( !failure.message_.empty() )
|
||||||
|
{
|
||||||
|
std::string reindented = indentText( failure.message_, indent + " " );
|
||||||
|
printf( "%s\n", reindented.c_str() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TestResult::indentText(const std::string& text,
|
|
||||||
const std::string& indent) {
|
std::string
|
||||||
|
TestResult::indentText( const std::string &text,
|
||||||
|
const std::string &indent )
|
||||||
|
{
|
||||||
std::string reindented;
|
std::string reindented;
|
||||||
std::string::size_type lastIndex = 0;
|
std::string::size_type lastIndex = 0;
|
||||||
while (lastIndex < text.size()) {
|
while ( lastIndex < text.size() )
|
||||||
std::string::size_type nextIndex = text.find('\n', lastIndex);
|
{
|
||||||
if (nextIndex == std::string::npos) {
|
std::string::size_type nextIndex = text.find( '\n', lastIndex );
|
||||||
|
if ( nextIndex == std::string::npos )
|
||||||
|
{
|
||||||
nextIndex = text.size() - 1;
|
nextIndex = text.size() - 1;
|
||||||
}
|
}
|
||||||
reindented += indent;
|
reindented += indent;
|
||||||
reindented += text.substr(lastIndex, nextIndex - lastIndex + 1);
|
reindented += text.substr( lastIndex, nextIndex - lastIndex + 1 );
|
||||||
lastIndex = nextIndex + 1;
|
lastIndex = nextIndex + 1;
|
||||||
}
|
}
|
||||||
return reindented;
|
return reindented;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult& TestResult::addToLastFailure(const std::string& message) {
|
|
||||||
if (messageTarget_ != 0) {
|
TestResult &
|
||||||
|
TestResult::addToLastFailure( const std::string &message )
|
||||||
|
{
|
||||||
|
if ( messageTarget_ != 0 )
|
||||||
|
{
|
||||||
messageTarget_->message_ += message;
|
messageTarget_->message_ += message;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 << ( int value )
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
sprintf( buffer, "%d", value );
|
||||||
|
return addToLastFailure( buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult& TestResult::operator<<(bool value) {
|
|
||||||
return addToLastFailure(value ? "true" : "false");
|
TestResult &
|
||||||
|
TestResult::operator << ( unsigned int value )
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
sprintf( buffer, "%u", value );
|
||||||
|
return addToLastFailure( buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestResult &
|
||||||
|
TestResult::operator << ( double value )
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
sprintf( buffer, "%16g", value );
|
||||||
|
return addToLastFailure( buffer );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestResult &
|
||||||
|
TestResult::operator << ( const char *value )
|
||||||
|
{
|
||||||
|
return addToLastFailure( value ? value
|
||||||
|
: "<NULL>" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestResult &
|
||||||
|
TestResult::operator << ( const std::string &value )
|
||||||
|
{
|
||||||
|
return addToLastFailure( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// class TestCase
|
// class TestCase
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TestCase::TestCase() : result_(0) {}
|
TestCase::TestCase()
|
||||||
|
: result_( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
TestCase::~TestCase() {}
|
|
||||||
|
|
||||||
void TestCase::run(TestResult& result) {
|
TestCase::~TestCase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TestCase::run( TestResult &result )
|
||||||
|
{
|
||||||
result_ = &result;
|
result_ = &result;
|
||||||
runTestCase();
|
runTestCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// class Runner
|
// class Runner
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Runner::Runner() {}
|
Runner::Runner()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Runner& Runner::add(TestCaseFactory factory) {
|
|
||||||
tests_.push_back(factory);
|
Runner &
|
||||||
|
Runner::add( TestCaseFactory factory )
|
||||||
|
{
|
||||||
|
tests_.push_back( factory );
|
||||||
return *this;
|
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
|
||||||
|
Runner::testNameAt( unsigned int index ) const
|
||||||
|
{
|
||||||
|
TestCase *test = tests_[index]();
|
||||||
std::string name = test->testName();
|
std::string name = test->testName();
|
||||||
delete test;
|
delete test;
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runner::runTestAt(unsigned int index, TestResult& result) const {
|
|
||||||
TestCase* test = tests_[index]();
|
void
|
||||||
result.setTestName(test->testName());
|
Runner::runTestAt( unsigned int index, TestResult &result ) const
|
||||||
printf("Testing %s: ", test->testName());
|
{
|
||||||
fflush(stdout);
|
TestCase *test = tests_[index]();
|
||||||
|
result.setTestName( test->testName() );
|
||||||
|
printf( "Testing %s: ", test->testName() );
|
||||||
|
fflush( stdout );
|
||||||
#if JSON_USE_EXCEPTION
|
#if JSON_USE_EXCEPTION
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
#endif // if JSON_USE_EXCEPTION
|
#endif // if JSON_USE_EXCEPTION
|
||||||
test->run(result);
|
test->run( result );
|
||||||
#if JSON_USE_EXCEPTION
|
#if JSON_USE_EXCEPTION
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch ( const std::exception &e )
|
||||||
result.addFailure(__FILE__, __LINE__, "Unexpected exception caught:")
|
{
|
||||||
<< e.what();
|
result.addFailure( __FILE__, __LINE__,
|
||||||
|
"Unexpected exception caugth:" ) << e.what();
|
||||||
}
|
}
|
||||||
#endif // if JSON_USE_EXCEPTION
|
#endif // if JSON_USE_EXCEPTION
|
||||||
delete test;
|
delete test;
|
||||||
const char* status = result.failed() ? "FAILED" : "OK";
|
const char *status = result.failed() ? "FAILED"
|
||||||
printf("%s\n", status);
|
: "OK";
|
||||||
fflush(stdout);
|
printf( "%s\n", status );
|
||||||
|
fflush( stdout );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Runner::runAllTest(bool printSummary) const {
|
|
||||||
|
bool
|
||||||
|
Runner::runAllTest( bool printSummary ) const
|
||||||
|
{
|
||||||
unsigned int count = testCount();
|
unsigned int count = testCount();
|
||||||
std::deque<TestResult> failures;
|
std::deque<TestResult> failures;
|
||||||
for (unsigned int index = 0; index < count; ++index) {
|
for ( unsigned int index = 0; index < count; ++index )
|
||||||
|
{
|
||||||
TestResult result;
|
TestResult result;
|
||||||
runTestAt(index, result);
|
runTestAt( index, result );
|
||||||
if (result.failed()) {
|
if ( result.failed() )
|
||||||
failures.push_back(result);
|
{
|
||||||
|
failures.push_back( result );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failures.empty()) {
|
if ( failures.empty() )
|
||||||
if (printSummary) {
|
{
|
||||||
printf("All %d tests passed\n", count);
|
if ( printSummary )
|
||||||
|
{
|
||||||
|
printf( "All %d tests passed\n", count );
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
for (unsigned int index = 0; index < failures.size(); ++index) {
|
else
|
||||||
TestResult& result = failures[index];
|
{
|
||||||
result.printFailure(count > 1);
|
for ( unsigned int index = 0; index < failures.size(); ++index )
|
||||||
|
{
|
||||||
|
TestResult &result = failures[index];
|
||||||
|
result.printFailure( count > 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (printSummary) {
|
if ( printSummary )
|
||||||
unsigned int failedCount = static_cast<unsigned int>(failures.size());
|
{
|
||||||
|
unsigned int failedCount = static_cast<unsigned int>( failures.size() );
|
||||||
unsigned int passedCount = count - failedCount;
|
unsigned int passedCount = count - failedCount;
|
||||||
printf("%d/%d tests passed (%d failure(s))\n",
|
printf( "%d/%d tests passed (%d failure(s))\n", passedCount, count, failedCount );
|
||||||
passedCount,
|
|
||||||
count,
|
|
||||||
failedCount);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Runner::testIndex(const std::string& testName,
|
|
||||||
unsigned int& indexOut) const {
|
bool
|
||||||
|
Runner::testIndex( const std::string &testName,
|
||||||
|
unsigned int &indexOut ) const
|
||||||
|
{
|
||||||
unsigned int count = testCount();
|
unsigned int count = testCount();
|
||||||
for (unsigned int index = 0; index < count; ++index) {
|
for ( unsigned int index = 0; index < count; ++index )
|
||||||
if (testNameAt(index) == testName) {
|
{
|
||||||
|
if ( testNameAt(index) == testName )
|
||||||
|
{
|
||||||
indexOut = index;
|
indexOut = index;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -315,73 +442,103 @@ bool Runner::testIndex(const std::string& testName,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runner::listTests() const {
|
|
||||||
|
void
|
||||||
|
Runner::listTests() const
|
||||||
|
{
|
||||||
unsigned int count = testCount();
|
unsigned int count = testCount();
|
||||||
for (unsigned int index = 0; index < count; ++index) {
|
for ( unsigned int index = 0; index < count; ++index )
|
||||||
printf("%s\n", testNameAt(index).c_str());
|
{
|
||||||
|
printf( "%s\n", testNameAt( index ).c_str() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Runner::runCommandLine(int argc, const char* argv[]) const {
|
|
||||||
|
int
|
||||||
|
Runner::runCommandLine( int argc, const char *argv[] ) const
|
||||||
|
{
|
||||||
typedef std::deque<std::string> TestNames;
|
typedef std::deque<std::string> TestNames;
|
||||||
Runner subrunner;
|
Runner subrunner;
|
||||||
for (int index = 1; index < argc; ++index) {
|
for ( int index = 1; index < argc; ++index )
|
||||||
|
{
|
||||||
std::string opt = argv[index];
|
std::string opt = argv[index];
|
||||||
if (opt == "--list-tests") {
|
if ( opt == "--list-tests" )
|
||||||
|
{
|
||||||
listTests();
|
listTests();
|
||||||
return 0;
|
return 0;
|
||||||
} else if (opt == "--test-auto") {
|
}
|
||||||
|
else if ( opt == "--test-auto" )
|
||||||
|
{
|
||||||
preventDialogOnCrash();
|
preventDialogOnCrash();
|
||||||
} else if (opt == "--test") {
|
}
|
||||||
|
else if ( opt == "--test" )
|
||||||
|
{
|
||||||
++index;
|
++index;
|
||||||
if (index < argc) {
|
if ( index < argc )
|
||||||
|
{
|
||||||
unsigned int testNameIndex;
|
unsigned int testNameIndex;
|
||||||
if (testIndex(argv[index], testNameIndex)) {
|
if ( testIndex( argv[index], testNameIndex ) )
|
||||||
subrunner.add(tests_[testNameIndex]);
|
{
|
||||||
} else {
|
subrunner.add( tests_[testNameIndex] );
|
||||||
fprintf(stderr, "Test '%s' does not exist!\n", argv[index]);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf( stderr, "Test '%s' does not exist!\n", argv[index] );
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
printUsage(argv[0]);
|
else
|
||||||
|
{
|
||||||
|
printUsage( argv[0] );
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
printUsage(argv[0]);
|
else
|
||||||
|
{
|
||||||
|
printUsage( argv[0] );
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool succeeded;
|
bool succeeded;
|
||||||
if (subrunner.testCount() > 0) {
|
if ( subrunner.testCount() > 0 )
|
||||||
succeeded = subrunner.runAllTest(subrunner.testCount() > 1);
|
{
|
||||||
} else {
|
succeeded = subrunner.runAllTest( subrunner.testCount() > 1 );
|
||||||
succeeded = runAllTest(true);
|
|
||||||
}
|
}
|
||||||
return succeeded ? 0 : 1;
|
else
|
||||||
|
{
|
||||||
|
succeeded = runAllTest( true );
|
||||||
|
}
|
||||||
|
return succeeded ? 0
|
||||||
|
: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
// Hook MSVCRT assertions to prevent dialog from appearing
|
// Hook MSVCRT assertions to prevent dialog from appearing
|
||||||
static int
|
static int
|
||||||
msvcrtSilentReportHook(int reportType, char* message, int* /*returnValue*/) {
|
msvcrtSilentReportHook( int reportType, char *message, int *returnValue )
|
||||||
|
{
|
||||||
// The default CRT handling of error and assertion is to display
|
// The default CRT handling of error and assertion is to display
|
||||||
// an error dialog to the user.
|
// an error dialog to the user.
|
||||||
// Instead, when an error or an assertion occurs, we force the
|
// Instead, when an error or an assertion occurs, we force the
|
||||||
// application to terminate using abort() after display
|
// application to terminate using abort() after display
|
||||||
// the message on stderr.
|
// the message on stderr.
|
||||||
if (reportType == _CRT_ERROR || reportType == _CRT_ASSERT) {
|
if ( reportType == _CRT_ERROR ||
|
||||||
|
reportType == _CRT_ASSERT )
|
||||||
|
{
|
||||||
// calling abort() cause the ReportHook to be called
|
// calling abort() cause the ReportHook to be called
|
||||||
// The following is used to detect this case and let's the
|
// The following is used to detect this case and let's the
|
||||||
// error handler fallback on its default behaviour (
|
// error handler fallback on its default behaviour (
|
||||||
// display a warning message)
|
// display a warning message)
|
||||||
static volatile bool isAborting = false;
|
static volatile bool isAborting = false;
|
||||||
if (isAborting) {
|
if ( isAborting )
|
||||||
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
isAborting = true;
|
isAborting = true;
|
||||||
|
|
||||||
fprintf(stderr, "CRT Error/Assert:\n%s\n", message);
|
fprintf( stderr, "CRT Error/Assert:\n%s\n", message );
|
||||||
fflush(stderr);
|
fflush( stderr );
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
// Let's other reportType (_CRT_WARNING) be handled as they would by default
|
// Let's other reportType (_CRT_WARNING) be handled as they would by default
|
||||||
@@ -389,28 +546,33 @@ msvcrtSilentReportHook(int reportType, char* message, int* /*returnValue*/) {
|
|||||||
}
|
}
|
||||||
#endif // if defined(_MSC_VER)
|
#endif // if defined(_MSC_VER)
|
||||||
|
|
||||||
void Runner::preventDialogOnCrash() {
|
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
void
|
||||||
|
Runner::preventDialogOnCrash()
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER)
|
||||||
// Install a hook to prevent MSVCRT error and assertion from
|
// Install a hook to prevent MSVCRT error and assertion from
|
||||||
// popping a dialog
|
// popping a dialog.
|
||||||
// This function a NO-OP in release configuration
|
_CrtSetReportHook( &msvcrtSilentReportHook );
|
||||||
// (which cause warning since msvcrtSilentReportHook is not referenced)
|
|
||||||
_CrtSetReportHook(&msvcrtSilentReportHook);
|
|
||||||
#endif // if defined(_MSC_VER)
|
#endif // if defined(_MSC_VER)
|
||||||
|
|
||||||
// @todo investiguate this handler (for buffer overflow)
|
// @todo investiguate this handler (for buffer overflow)
|
||||||
// _set_security_error_handler
|
// _set_security_error_handler
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// Prevents the system from popping a dialog for debugging if the
|
// Prevents the system from popping a dialog for debugging if the
|
||||||
// application fails due to invalid memory access.
|
// application fails due to invalid memory access.
|
||||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
SetErrorMode( SEM_FAILCRITICALERRORS
|
||||||
SEM_NOOPENFILEERRORBOX);
|
| SEM_NOGPFAULTERRORBOX
|
||||||
|
| SEM_NOOPENFILEERRORBOX );
|
||||||
#endif // if defined(_WIN32)
|
#endif // if defined(_WIN32)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runner::printUsage(const char* appName) {
|
void
|
||||||
printf("Usage: %s [options]\n"
|
Runner::printUsage( const char *appName )
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"Usage: %s [options]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"If --test is not specified, then all the test cases be run.\n"
|
"If --test is not specified, then all the test cases be run.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -419,25 +581,28 @@ void Runner::printUsage(const char* appName) {
|
|||||||
" output and exit.\n"
|
" output and exit.\n"
|
||||||
"--test TESTNAME: executes the test case with the specified name.\n"
|
"--test TESTNAME: executes the test case with the specified name.\n"
|
||||||
" May be repeated.\n"
|
" May be repeated.\n"
|
||||||
"--test-auto: prevent dialog prompting for debugging on crash.\n",
|
"--test-auto: prevent dialog prompting for debugging on crash.\n"
|
||||||
appName);
|
, appName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Assertion functions
|
// Assertion functions
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TestResult& checkStringEqual(TestResult& result,
|
TestResult &
|
||||||
const std::string& expected,
|
checkStringEqual( TestResult &result,
|
||||||
const std::string& actual,
|
const std::string &expected, const std::string &actual,
|
||||||
const char* file,
|
const char *file, unsigned int line, const char *expr )
|
||||||
unsigned int line,
|
{
|
||||||
const char* expr) {
|
if ( expected != actual )
|
||||||
if (expected != actual) {
|
{
|
||||||
result.addFailure(file, line, expr);
|
result.addFailure( file, line, expr );
|
||||||
result << "Expected: '" << expected << "'\n";
|
result << "Expected: '" << expected << "'\n";
|
||||||
result << "Actual : '" << actual << "'";
|
result << "Actual : '" << actual << "'";
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace JsonTest
|
} // namespace JsonTest
|
||||||
|
@@ -4,15 +4,12 @@
|
|||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef JSONTEST_H_INCLUDED
|
#ifndef JSONTEST_H_INCLUDED
|
||||||
#define JSONTEST_H_INCLUDED
|
# define JSONTEST_H_INCLUDED
|
||||||
|
|
||||||
#include <json/config.h>
|
# include <json/config.h>
|
||||||
#include <json/value.h>
|
# include <stdio.h>
|
||||||
#include <json/writer.h>
|
# include <deque>
|
||||||
#include <stdio.h>
|
# include <string>
|
||||||
#include <deque>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@@ -20,6 +17,8 @@
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Unit testing framework.
|
/** \brief Unit testing framework.
|
||||||
* \warning: all assertions are non-aborting, test case execution will continue
|
* \warning: all assertions are non-aborting, test case execution will continue
|
||||||
* even if an assertion namespace.
|
* even if an assertion namespace.
|
||||||
@@ -28,32 +27,37 @@
|
|||||||
*/
|
*/
|
||||||
namespace JsonTest {
|
namespace JsonTest {
|
||||||
|
|
||||||
class Failure {
|
|
||||||
public:
|
class Failure
|
||||||
const char* file_;
|
{
|
||||||
|
public:
|
||||||
|
const char *file_;
|
||||||
unsigned int line_;
|
unsigned int line_;
|
||||||
std::string expr_;
|
std::string expr_;
|
||||||
std::string message_;
|
std::string message_;
|
||||||
unsigned int nestingLevel_;
|
unsigned int nestingLevel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Context used to create the assertion callstack on failure.
|
|
||||||
/// Must be a POD to allow inline initialisation without stepping
|
/// Context used to create the assertion callstack on failure.
|
||||||
/// into the debugger.
|
/// Must be a POD to allow inline initialisation without stepping
|
||||||
struct PredicateContext {
|
/// into the debugger.
|
||||||
|
struct PredicateContext
|
||||||
|
{
|
||||||
typedef unsigned int Id;
|
typedef unsigned int Id;
|
||||||
Id id_;
|
Id id_;
|
||||||
const char* file_;
|
const char *file_;
|
||||||
unsigned int line_;
|
unsigned int line_;
|
||||||
const char* expr_;
|
const char *expr_;
|
||||||
PredicateContext* next_;
|
PredicateContext *next_;
|
||||||
/// Related Failure, set when the PredicateContext is converted
|
/// Related Failure, set when the PredicateContext is converted
|
||||||
/// into a Failure.
|
/// into a Failure.
|
||||||
Failure* failure_;
|
Failure *failure_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestResult {
|
class TestResult
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
TestResult();
|
TestResult();
|
||||||
|
|
||||||
/// \internal Implementation detail for assertion macros
|
/// \internal Implementation detail for assertion macros
|
||||||
@@ -63,48 +67,38 @@ public:
|
|||||||
PredicateContext::Id predicateId_;
|
PredicateContext::Id predicateId_;
|
||||||
|
|
||||||
/// \internal Implementation detail for predicate macros
|
/// \internal Implementation detail for predicate macros
|
||||||
PredicateContext* predicateStackTail_;
|
PredicateContext *predicateStackTail_;
|
||||||
|
|
||||||
void setTestName(const std::string& name);
|
void setTestName( const std::string &name );
|
||||||
|
|
||||||
/// Adds an assertion failure.
|
/// Adds an assertion failure.
|
||||||
TestResult&
|
TestResult &addFailure( const char *file, unsigned int line,
|
||||||
addFailure(const char* file, unsigned int line, const char* expr = 0);
|
const char *expr = 0 );
|
||||||
|
|
||||||
/// Removes the last PredicateContext added to the predicate stack
|
/// Removes the last PredicateContext added to the predicate stack
|
||||||
/// chained list.
|
/// chained list.
|
||||||
/// Next messages will be targed at the PredicateContext that was removed.
|
/// Next messages will be targed at the PredicateContext that was removed.
|
||||||
TestResult& popPredicateContext();
|
TestResult &popPredicateContext();
|
||||||
|
|
||||||
bool failed() const;
|
bool failed() const;
|
||||||
|
|
||||||
void printFailure(bool printTestName) const;
|
void printFailure( bool printTestName ) const;
|
||||||
|
|
||||||
// Generic operator that will work with anything ostream can deal with.
|
TestResult &operator << ( bool value );
|
||||||
template <typename T> TestResult& operator<<(const T& value) {
|
TestResult &operator << ( int value );
|
||||||
std::ostringstream oss;
|
TestResult &operator << ( unsigned int value );
|
||||||
oss.precision(16);
|
TestResult &operator << ( double value );
|
||||||
oss.setf(std::ios_base::floatfield);
|
TestResult &operator << ( const char *value );
|
||||||
oss << value;
|
TestResult &operator << ( const std::string &value );
|
||||||
return addToLastFailure(oss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specialized versions.
|
private:
|
||||||
TestResult& operator<<(bool value);
|
TestResult &addToLastFailure( const std::string &message );
|
||||||
// std:ostream does not support 64bits integers on all STL implementation
|
|
||||||
TestResult& operator<<(Json::Int64 value);
|
|
||||||
TestResult& operator<<(Json::UInt64 value);
|
|
||||||
|
|
||||||
private:
|
|
||||||
TestResult& addToLastFailure(const std::string& message);
|
|
||||||
unsigned int getAssertionNestingLevel() const;
|
unsigned int getAssertionNestingLevel() const;
|
||||||
/// Adds a failure or a predicate context
|
/// Adds a failure or a predicate context
|
||||||
void addFailureInfo(const char* file,
|
void addFailureInfo( const char *file, unsigned int line,
|
||||||
unsigned int line,
|
const char *expr, unsigned int nestingLevel );
|
||||||
const char* expr,
|
static std::string indentText( const std::string &text,
|
||||||
unsigned int nestingLevel);
|
const std::string &indent );
|
||||||
static std::string indentText(const std::string& text,
|
|
||||||
const std::string& indent);
|
|
||||||
|
|
||||||
typedef std::deque<Failure> Failures;
|
typedef std::deque<Failure> Failures;
|
||||||
Failures failures_;
|
Failures failures_;
|
||||||
@@ -112,169 +106,154 @@ private:
|
|||||||
PredicateContext rootPredicateNode_;
|
PredicateContext rootPredicateNode_;
|
||||||
PredicateContext::Id lastUsedPredicateId_;
|
PredicateContext::Id lastUsedPredicateId_;
|
||||||
/// Failure which is the target of the messages added using operator <<
|
/// Failure which is the target of the messages added using operator <<
|
||||||
Failure* messageTarget_;
|
Failure *messageTarget_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestCase {
|
|
||||||
public:
|
class TestCase
|
||||||
|
{
|
||||||
|
public:
|
||||||
TestCase();
|
TestCase();
|
||||||
|
|
||||||
virtual ~TestCase();
|
virtual ~TestCase();
|
||||||
|
|
||||||
void run(TestResult& result);
|
void run( TestResult &result );
|
||||||
|
|
||||||
virtual const char* testName() const = 0;
|
virtual const char *testName() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TestResult* result_;
|
TestResult *result_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void runTestCase() = 0;
|
virtual void runTestCase() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Function pointer type for TestCase factory
|
/// Function pointer type for TestCase factory
|
||||||
typedef TestCase* (*TestCaseFactory)();
|
typedef TestCase *(*TestCaseFactory)();
|
||||||
|
|
||||||
class Runner {
|
class Runner
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
Runner();
|
Runner();
|
||||||
|
|
||||||
/// Adds a test to the suite
|
/// Adds a test to the suite
|
||||||
Runner& add(TestCaseFactory factory);
|
Runner &add( TestCaseFactory factory );
|
||||||
|
|
||||||
/// Runs test as specified on the command-line
|
/// Runs test as specified on the command-line
|
||||||
/// If no command-line arguments are provided, run all tests.
|
/// If no command-line arguments are provided, run all tests.
|
||||||
/// If --list-tests is provided, then print the list of all test cases
|
/// If --list-tests is provided, then print the list of all test cases
|
||||||
/// If --test <testname> is provided, then run test testname.
|
/// If --test <testname> is provided, then run test testname.
|
||||||
int runCommandLine(int argc, const char* argv[]) const;
|
int runCommandLine( int argc, const char *argv[] ) const;
|
||||||
|
|
||||||
/// Runs all the test cases
|
/// Runs all the test cases
|
||||||
bool runAllTest(bool printSummary) const;
|
bool runAllTest( bool printSummary ) const;
|
||||||
|
|
||||||
/// Returns the number of test case in the suite
|
/// Returns the number of test case in the suite
|
||||||
unsigned int testCount() const;
|
unsigned int testCount() const;
|
||||||
|
|
||||||
/// Returns the name of the test case at the specified index
|
/// Returns the name of the test case at the specified index
|
||||||
std::string testNameAt(unsigned int index) const;
|
std::string testNameAt( unsigned int index ) const;
|
||||||
|
|
||||||
/// Runs the test case at the specified index using the specified TestResult
|
/// Runs the test case at the specified index using the specified TestResult
|
||||||
void runTestAt(unsigned int index, TestResult& result) const;
|
void runTestAt( unsigned int index, TestResult &result ) const;
|
||||||
|
|
||||||
static void printUsage(const char* appName);
|
static void printUsage( const char *appName );
|
||||||
|
|
||||||
private: // prevents copy construction and assignment
|
private: // prevents copy construction and assignment
|
||||||
Runner(const Runner& other);
|
Runner( const Runner &other );
|
||||||
Runner& operator=(const Runner& other);
|
Runner &operator =( const Runner &other );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void listTests() const;
|
void listTests() const;
|
||||||
bool testIndex(const std::string& testName, unsigned int& index) const;
|
bool testIndex( const std::string &testName, unsigned int &index ) const;
|
||||||
static void preventDialogOnCrash();
|
static void preventDialogOnCrash();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::deque<TestCaseFactory> Factories;
|
typedef std::deque<TestCaseFactory> Factories;
|
||||||
Factories tests_;
|
Factories tests_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename U>
|
template<typename T>
|
||||||
TestResult& checkEqual(TestResult& result,
|
TestResult &
|
||||||
const T& expected,
|
checkEqual( TestResult &result, const T &expected, const T &actual,
|
||||||
const U& actual,
|
const char *file, unsigned int line, const char *expr )
|
||||||
const char* file,
|
{
|
||||||
unsigned int line,
|
if ( expected != actual )
|
||||||
const char* expr) {
|
{
|
||||||
if (static_cast<U>(expected) != actual) {
|
result.addFailure( file, line, expr );
|
||||||
result.addFailure(file, line, expr);
|
result << "Expected: " << expected << "\n";
|
||||||
result << "Expected: " << static_cast<U>(expected) << "\n";
|
|
||||||
result << "Actual : " << actual;
|
result << "Actual : " << actual;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult& checkStringEqual(TestResult& result,
|
TestResult &
|
||||||
const std::string& expected,
|
checkStringEqual( TestResult &result,
|
||||||
const std::string& actual,
|
const std::string &expected, const std::string &actual,
|
||||||
const char* file,
|
const char *file, unsigned int line, const char *expr );
|
||||||
unsigned int line,
|
|
||||||
const char* expr);
|
|
||||||
|
|
||||||
} // namespace JsonTest
|
} // namespace JsonTest
|
||||||
|
|
||||||
|
|
||||||
/// \brief Asserts that the given expression is true.
|
/// \brief Asserts that the given expression is true.
|
||||||
/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
|
/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
|
||||||
/// JSONTEST_ASSERT( x == y );
|
/// JSONTEST_ASSERT( x == y );
|
||||||
#define JSONTEST_ASSERT(expr) \
|
#define JSONTEST_ASSERT( expr ) \
|
||||||
if (expr) { \
|
if ( expr ) \
|
||||||
} else \
|
{ \
|
||||||
result_->addFailure(__FILE__, __LINE__, #expr)
|
} \
|
||||||
|
else \
|
||||||
|
result_->addFailure( __FILE__, __LINE__, #expr )
|
||||||
|
|
||||||
/// \brief Asserts that the given predicate is true.
|
/// \brief Asserts that the given predicate is true.
|
||||||
/// The predicate may do other assertions and be a member function of the
|
/// The predicate may do other assertions and be a member function of the fixture.
|
||||||
/// fixture.
|
#define JSONTEST_ASSERT_PRED( expr ) \
|
||||||
#define JSONTEST_ASSERT_PRED(expr) \
|
|
||||||
{ \
|
{ \
|
||||||
JsonTest::PredicateContext _minitest_Context = { \
|
JsonTest::PredicateContext _minitest_Context = { \
|
||||||
result_->predicateId_, __FILE__, __LINE__, #expr \
|
result_->predicateId_, __FILE__, __LINE__, #expr }; \
|
||||||
}; \
|
|
||||||
result_->predicateStackTail_->next_ = &_minitest_Context; \
|
result_->predicateStackTail_->next_ = &_minitest_Context; \
|
||||||
result_->predicateId_ += 1; \
|
result_->predicateId_ += 1; \
|
||||||
result_->predicateStackTail_ = &_minitest_Context; \
|
result_->predicateStackTail_ = &_minitest_Context; \
|
||||||
(expr); \
|
(expr); \
|
||||||
result_->popPredicateContext(); \
|
result_->popPredicateContext(); \
|
||||||
}
|
} \
|
||||||
|
*result_
|
||||||
|
|
||||||
/// \brief Asserts that two values are equals.
|
/// \brief Asserts that two values are equals.
|
||||||
#define JSONTEST_ASSERT_EQUAL(expected, actual) \
|
#define JSONTEST_ASSERT_EQUAL( expected, actual ) \
|
||||||
JsonTest::checkEqual(*result_, \
|
JsonTest::checkEqual( *result_, expected, actual, \
|
||||||
expected, \
|
__FILE__, __LINE__, \
|
||||||
actual, \
|
#expected " == " #actual )
|
||||||
__FILE__, \
|
|
||||||
__LINE__, \
|
|
||||||
#expected " == " #actual)
|
|
||||||
|
|
||||||
/// \brief Asserts that two values are equals.
|
/// \brief Asserts that two values are equals.
|
||||||
#define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \
|
#define JSONTEST_ASSERT_STRING_EQUAL( expected, actual ) \
|
||||||
JsonTest::checkStringEqual(*result_, \
|
JsonTest::checkStringEqual( *result_, \
|
||||||
std::string(expected), \
|
std::string(expected), std::string(actual), \
|
||||||
std::string(actual), \
|
#expected " == " #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.
|
/// \brief Begin a fixture test case.
|
||||||
#define JSONTEST_FIXTURE(FixtureType, name) \
|
#define JSONTEST_FIXTURE( FixtureType, name ) \
|
||||||
class Test##FixtureType##name : public FixtureType { \
|
class Test##FixtureType##name : public FixtureType \
|
||||||
|
{ \
|
||||||
public: \
|
public: \
|
||||||
static JsonTest::TestCase* factory() { \
|
static JsonTest::TestCase *factory() \
|
||||||
|
{ \
|
||||||
return new Test##FixtureType##name(); \
|
return new Test##FixtureType##name(); \
|
||||||
} \
|
} \
|
||||||
\
|
|
||||||
public: /* overidden from TestCase */ \
|
public: /* overidden from TestCase */ \
|
||||||
virtual const char* testName() const { return #FixtureType "/" #name; } \
|
virtual const char *testName() const \
|
||||||
|
{ \
|
||||||
|
return #FixtureType "/" #name; \
|
||||||
|
} \
|
||||||
virtual void runTestCase(); \
|
virtual void runTestCase(); \
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
void Test##FixtureType##name::runTestCase()
|
void Test##FixtureType##name::runTestCase()
|
||||||
|
|
||||||
#define JSONTEST_FIXTURE_FACTORY(FixtureType, name) \
|
#define JSONTEST_FIXTURE_FACTORY( FixtureType, name ) \
|
||||||
&Test##FixtureType##name::factory
|
&Test##FixtureType##name::factory
|
||||||
|
|
||||||
#define JSONTEST_REGISTER_FIXTURE(runner, FixtureType, name) \
|
#define JSONTEST_REGISTER_FIXTURE( runner, FixtureType, name ) \
|
||||||
(runner).add(JSONTEST_FIXTURE_FACTORY(FixtureType, name))
|
(runner).add( JSONTEST_FIXTURE_FACTORY( FixtureType, name ) )
|
||||||
|
|
||||||
#endif // ifndef JSONTEST_H_INCLUDED
|
#endif // ifndef JSONTEST_H_INCLUDED
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,3 +1,2 @@
|
|||||||
// C++ style comment
|
|
||||||
.=null
|
.=null
|
||||||
|
|
||||||
|
@@ -1,4 +1,2 @@
|
|||||||
/* C style comment
|
|
||||||
*/
|
|
||||||
.=null
|
.=null
|
||||||
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
.={}
|
.={}
|
||||||
// Comment for array
|
|
||||||
.test=[]
|
.test=[]
|
||||||
.test[0]={}
|
.test[0]={}
|
||||||
.test[0].a="aaa"
|
.test[0].a="aaa"
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"test":
|
"test":
|
||||||
// Comment for array
|
|
||||||
[
|
[
|
||||||
{ "a" : "aaa" }, // Comment for a
|
{ "a" : "aaa" }, // Comment for a
|
||||||
{ "b" : "bbb" }, // Comment for b
|
{ "b" : "bbb" }, // Comment for b
|
||||||
|
@@ -1,23 +0,0 @@
|
|||||||
.={}
|
|
||||||
/* 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
|
|
||||||
// Comment before double
|
|
||||||
.cpp-test.d=4.1
|
|
||||||
// Comment before string
|
|
||||||
.cpp-test.e="e-string"
|
|
||||||
// Comment before true
|
|
||||||
.cpp-test.f=true
|
|
||||||
// Comment before false
|
|
||||||
.cpp-test.g=false
|
|
||||||
// Comment before null
|
|
||||||
.cpp-test.h=null
|
|
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
/* C-style comment
|
|
||||||
|
|
||||||
C-style-2 comment */
|
|
||||||
"c-test" : {
|
|
||||||
"a" : 1,
|
|
||||||
/* Internal comment c-style */
|
|
||||||
"b" : 2
|
|
||||||
},
|
|
||||||
// C++-style comment
|
|
||||||
"cpp-test" : {
|
|
||||||
// Multiline comment cpp-style
|
|
||||||
// Second line
|
|
||||||
"c" : 3,
|
|
||||||
// Comment before double
|
|
||||||
"d" : 4.1,
|
|
||||||
// Comment before string
|
|
||||||
"e" : "e-string",
|
|
||||||
// Comment before true
|
|
||||||
"f" : true,
|
|
||||||
// Comment before false
|
|
||||||
"g" : false,
|
|
||||||
// Comment before null
|
|
||||||
"h" : null
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,2 +1 @@
|
|||||||
// Max signed integer
|
|
||||||
.=2147483647
|
.=2147483647
|
||||||
|
@@ -1,2 +1 @@
|
|||||||
// Min signed integer
|
|
||||||
.=-2147483648
|
.=-2147483648
|
||||||
|
@@ -1,2 +1 @@
|
|||||||
// Max unsigned integer
|
|
||||||
.=4294967295
|
.=4294967295
|
||||||
|
@@ -1,3 +1,2 @@
|
|||||||
// Min unsigned integer
|
|
||||||
.=0
|
.=0
|
||||||
|
|
||||||
|
@@ -1,11 +1,3 @@
|
|||||||
/* A comment
|
|
||||||
at the beginning of the file.
|
|
||||||
*/
|
|
||||||
.={}
|
.={}
|
||||||
.first=1
|
.first=1
|
||||||
/* Comment before 'second'
|
|
||||||
*/
|
|
||||||
.second=2
|
.second=2
|
||||||
/* A comment at
|
|
||||||
the end of the file.
|
|
||||||
*/
|
|
||||||
|
@@ -1,3 +1,2 @@
|
|||||||
// 2^33 => out of integer range, switch to double
|
|
||||||
.=8589934592
|
.=8589934592
|
||||||
|
|
||||||
|
@@ -1,3 +1,2 @@
|
|||||||
// -2^32 => out of signed integer range, switch to double
|
|
||||||
.=-4294967295
|
.=-4294967295
|
||||||
|
|
||||||
|
@@ -1,3 +1,2 @@
|
|||||||
// -2^32 => out of signed integer range, switch to double
|
|
||||||
.=-4294967295
|
.=-4294967295
|
||||||
|
|
||||||
|
@@ -1,3 +1,2 @@
|
|||||||
// 1.2345678
|
|
||||||
.=1.2345678
|
.=1.2345678
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
// 1234567.8
|
|
||||||
.=1234567.8
|
.=1234567.8
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
// -1.2345678
|
|
||||||
.=-1.2345678
|
.=-1.2345678
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
// -1234567.8
|
|
||||||
.=-1234567.8
|
.=-1234567.8
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,4 +0,0 @@
|
|||||||
// 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,4 +0,0 @@
|
|||||||
// 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,4 +0,0 @@
|
|||||||
// 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,4 +0,0 @@
|
|||||||
// 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.
|
|
||||||
19000000000000000001
|
|
@@ -1,4 +0,0 @@
|
|||||||
// 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,4 +0,0 @@
|
|||||||
// 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,4 +0,0 @@
|
|||||||
// 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,4 +0,0 @@
|
|||||||
// 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.
|
|
||||||
-9300000000000000001
|
|
@@ -1,2 +0,0 @@
|
|||||||
// 2^64 -> switch to double.
|
|
||||||
.=1.844674407370955e+19
|
|
@@ -1,2 +0,0 @@
|
|||||||
// 2^64 -> switch to double.
|
|
||||||
18446744073709551616
|
|
@@ -1,2 +0,0 @@
|
|||||||
.=""abc\def""
|
|
||||||
|
|
@@ -1,2 +0,0 @@
|
|||||||
"\"abc\\def\""
|
|
||||||
|
|
@@ -1,2 +0,0 @@
|
|||||||
.="\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"
|
|
||||||
|
|
@@ -1,2 +0,0 @@
|
|||||||
"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"
|
|
||||||
|
|
@@ -1,12 +1,11 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import glob
|
import glob
|
||||||
import os.path
|
import os.path
|
||||||
for path in glob.glob( '*.json' ):
|
for path in glob.glob( '*.json' ):
|
||||||
text = file(path,'rt').read()
|
text = file(path,'rt').read()
|
||||||
target = os.path.splitext(path)[0] + '.expected'
|
target = os.path.splitext(path)[0] + '.expected'
|
||||||
if os.path.exists( target ):
|
if os.path.exists( target ):
|
||||||
print('skipping:', target)
|
print 'skipping:', target
|
||||||
else:
|
else:
|
||||||
print('creating:', target)
|
print 'creating:', target
|
||||||
file(target,'wt').write(text)
|
file(target,'wt').write(text)
|
||||||
|
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
# Simple implementation of a json test runner to run the test against json-py.
|
# Simple implementation of a json test runner to run the test against json-py.
|
||||||
from __future__ import print_function
|
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
import json
|
import json
|
||||||
import types
|
import types
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print("Usage: %s input-json-file", sys.argv[0])
|
print "Usage: %s input-json-file", sys.argv[0]
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
|
||||||
input_path = sys.argv[1]
|
input_path = sys.argv[1]
|
||||||
|
@@ -1,36 +1,17 @@
|
|||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from io import open
|
|
||||||
from glob import glob
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
from glob import glob
|
||||||
import optparse
|
import optparse
|
||||||
|
|
||||||
VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes '
|
VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes '
|
||||||
|
|
||||||
def getStatusOutput(cmd):
|
|
||||||
"""
|
|
||||||
Return int, unicode (for both Python 2 and 3).
|
|
||||||
Note: os.popen().close() would return None for 0.
|
|
||||||
"""
|
|
||||||
pipe = os.popen(cmd)
|
|
||||||
process_output = pipe.read()
|
|
||||||
try:
|
|
||||||
# We have been using os.popen(). When we read() the result
|
|
||||||
# we get 'str' (bytes) in py2, and 'str' (unicode) in py3.
|
|
||||||
# Ugh! There must be a better way to handle this.
|
|
||||||
process_output = process_output.decode('utf-8')
|
|
||||||
except AttributeError:
|
|
||||||
pass # python3
|
|
||||||
status = pipe.close()
|
|
||||||
return status, process_output
|
|
||||||
def compareOutputs( expected, actual, message ):
|
def compareOutputs( expected, actual, message ):
|
||||||
expected = expected.strip().replace('\r','').split('\n')
|
expected = expected.strip().replace('\r','').split('\n')
|
||||||
actual = actual.strip().replace('\r','').split('\n')
|
actual = actual.strip().replace('\r','').split('\n')
|
||||||
diff_line = 0
|
diff_line = 0
|
||||||
max_line_to_compare = min( len(expected), len(actual) )
|
max_line_to_compare = min( len(expected), len(actual) )
|
||||||
for index in range(0,max_line_to_compare):
|
for index in xrange(0,max_line_to_compare):
|
||||||
if expected[index].strip() != actual[index].strip():
|
if expected[index].strip() != actual[index].strip():
|
||||||
diff_line = index + 1
|
diff_line = index + 1
|
||||||
break
|
break
|
||||||
@@ -52,8 +33,8 @@ def compareOutputs( expected, actual, message ):
|
|||||||
|
|
||||||
def safeReadFile( path ):
|
def safeReadFile( path ):
|
||||||
try:
|
try:
|
||||||
return open( path, 'rt', encoding = 'utf-8' ).read()
|
return file( path, 'rt' ).read()
|
||||||
except IOError as e:
|
except IOError, e:
|
||||||
return '<File "%s" is missing: %s>' % (path,e)
|
return '<File "%s" is missing: %s>' % (path,e)
|
||||||
|
|
||||||
def runAllTests( jsontest_executable_path, input_dir = None,
|
def runAllTests( jsontest_executable_path, input_dir = None,
|
||||||
@@ -70,57 +51,58 @@ def runAllTests( jsontest_executable_path, input_dir = None,
|
|||||||
for input_path in tests + test_jsonchecker:
|
for input_path in tests + test_jsonchecker:
|
||||||
expect_failure = os.path.basename( input_path ).startswith( 'fail' )
|
expect_failure = os.path.basename( input_path ).startswith( 'fail' )
|
||||||
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
|
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
|
||||||
print('TESTING:', input_path, end=' ')
|
print 'TESTING:', input_path,
|
||||||
options = is_json_checker_test and '--json-checker' or ''
|
options = is_json_checker_test and '--json-checker' or ''
|
||||||
cmd = '%s%s %s "%s"' % (
|
pipe = os.popen( "%s%s %s %s" % (
|
||||||
valgrind_path, jsontest_executable_path, options,
|
valgrind_path, jsontest_executable_path, options,
|
||||||
input_path)
|
input_path) )
|
||||||
status, process_output = getStatusOutput(cmd)
|
process_output = pipe.read()
|
||||||
|
status = pipe.close()
|
||||||
if is_json_checker_test:
|
if is_json_checker_test:
|
||||||
if expect_failure:
|
if expect_failure:
|
||||||
if not status:
|
if status is None:
|
||||||
print('FAILED')
|
print 'FAILED'
|
||||||
failed_tests.append( (input_path, 'Parsing should have failed:\n%s' %
|
failed_tests.append( (input_path, 'Parsing should have failed:\n%s' %
|
||||||
safeReadFile(input_path)) )
|
safeReadFile(input_path)) )
|
||||||
else:
|
else:
|
||||||
print('OK')
|
print 'OK'
|
||||||
else:
|
else:
|
||||||
if status:
|
if status is not None:
|
||||||
print('FAILED')
|
print 'FAILED'
|
||||||
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
|
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
|
||||||
else:
|
else:
|
||||||
print('OK')
|
print 'OK'
|
||||||
else:
|
else:
|
||||||
base_path = os.path.splitext(input_path)[0]
|
base_path = os.path.splitext(input_path)[0]
|
||||||
actual_output = safeReadFile( base_path + '.actual' )
|
actual_output = safeReadFile( base_path + '.actual' )
|
||||||
actual_rewrite_output = safeReadFile( base_path + '.actual-rewrite' )
|
actual_rewrite_output = safeReadFile( base_path + '.actual-rewrite' )
|
||||||
open(base_path + '.process-output', 'wt', encoding = 'utf-8').write( process_output )
|
file(base_path + '.process-output','wt').write( process_output )
|
||||||
if status:
|
if status:
|
||||||
print('parsing failed')
|
print 'parsing failed'
|
||||||
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
|
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
|
||||||
else:
|
else:
|
||||||
expected_output_path = os.path.splitext(input_path)[0] + '.expected'
|
expected_output_path = os.path.splitext(input_path)[0] + '.expected'
|
||||||
expected_output = open( expected_output_path, 'rt', encoding = 'utf-8' ).read()
|
expected_output = file( expected_output_path, 'rt' ).read()
|
||||||
detail = ( compareOutputs( expected_output, actual_output, 'input' )
|
detail = ( compareOutputs( expected_output, actual_output, 'input' )
|
||||||
or compareOutputs( expected_output, actual_rewrite_output, 'rewrite' ) )
|
or compareOutputs( expected_output, actual_rewrite_output, 'rewrite' ) )
|
||||||
if detail:
|
if detail:
|
||||||
print('FAILED')
|
print 'FAILED'
|
||||||
failed_tests.append( (input_path, detail) )
|
failed_tests.append( (input_path, detail) )
|
||||||
else:
|
else:
|
||||||
print('OK')
|
print 'OK'
|
||||||
|
|
||||||
if failed_tests:
|
if failed_tests:
|
||||||
print()
|
print
|
||||||
print('Failure details:')
|
print 'Failure details:'
|
||||||
for failed_test in failed_tests:
|
for failed_test in failed_tests:
|
||||||
print('* Test', failed_test[0])
|
print '* Test', failed_test[0]
|
||||||
print(failed_test[1])
|
print failed_test[1]
|
||||||
print()
|
print
|
||||||
print('Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests),
|
print 'Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests),
|
||||||
len(failed_tests) ))
|
len(failed_tests) )
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
print('All %d tests passed.' % len(tests))
|
print 'All %d tests passed.' % len(tests)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@@ -1,11 +1,8 @@
|
|||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from io import open
|
|
||||||
from glob import glob
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from glob import glob
|
||||||
import optparse
|
import optparse
|
||||||
|
|
||||||
VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes'
|
VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes'
|
||||||
@@ -21,11 +18,7 @@ class TestProxy(object):
|
|||||||
else:
|
else:
|
||||||
cmd = []
|
cmd = []
|
||||||
cmd.extend( [self.test_exe_path, '--test-auto'] + options )
|
cmd.extend( [self.test_exe_path, '--test-auto'] + options )
|
||||||
try:
|
|
||||||
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
||||||
except:
|
|
||||||
print(cmd)
|
|
||||||
raise
|
|
||||||
stdout = process.communicate()[0]
|
stdout = process.communicate()[0]
|
||||||
if process.returncode:
|
if process.returncode:
|
||||||
return False, stdout
|
return False, stdout
|
||||||
@@ -35,29 +28,29 @@ def runAllTests( exe_path, use_valgrind=False ):
|
|||||||
test_proxy = TestProxy( exe_path, use_valgrind=use_valgrind )
|
test_proxy = TestProxy( exe_path, use_valgrind=use_valgrind )
|
||||||
status, test_names = test_proxy.run( ['--list-tests'] )
|
status, test_names = test_proxy.run( ['--list-tests'] )
|
||||||
if not status:
|
if not status:
|
||||||
print("Failed to obtain unit tests list:\n" + test_names, file=sys.stderr)
|
print >> sys.stderr, "Failed to obtain unit tests list:\n" + test_names
|
||||||
return 1
|
return 1
|
||||||
test_names = [name.strip() for name in test_names.decode('utf-8').strip().split('\n')]
|
test_names = [name.strip() for name in test_names.strip().split('\n')]
|
||||||
failures = []
|
failures = []
|
||||||
for name in test_names:
|
for name in test_names:
|
||||||
print('TESTING %s:' % name, end=' ')
|
print 'TESTING %s:' % name,
|
||||||
succeed, result = test_proxy.run( ['--test', name] )
|
succeed, result = test_proxy.run( ['--test', name] )
|
||||||
if succeed:
|
if succeed:
|
||||||
print('OK')
|
print 'OK'
|
||||||
else:
|
else:
|
||||||
failures.append( (name, result) )
|
failures.append( (name, result) )
|
||||||
print('FAILED')
|
print 'FAILED'
|
||||||
failed_count = len(failures)
|
failed_count = len(failures)
|
||||||
pass_count = len(test_names) - failed_count
|
pass_count = len(test_names) - failed_count
|
||||||
if failed_count:
|
if failed_count:
|
||||||
print()
|
print
|
||||||
for name, result in failures:
|
for name, result in failures:
|
||||||
print(result)
|
print result
|
||||||
print('%d/%d tests passed (%d failure(s))' % (
|
print '%d/%d tests passed (%d failure(s))' % (
|
||||||
pass_count, len(test_names), failed_count))
|
pass_count, len(test_names), failed_count)
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
print('All %d tests passed' % len(test_names))
|
print 'All %d tests passed' % len(test_names)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
Reference in New Issue
Block a user