Merge branch 'develop' of https://github.com/nlohmann/json into string_view
This commit is contained in:
commit
8ba8c43707
22
.drone.yml
Normal file
22
.drone.yml
Normal file
@ -0,0 +1,22 @@
|
||||
kind: pipeline
|
||||
name: test-on-arm64
|
||||
|
||||
platform:
|
||||
arch: arm64
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: gcc
|
||||
commands:
|
||||
- wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2.tar.gz
|
||||
- tar xfz cmake-3.20.2.tar.gz
|
||||
- cd cmake-3.20.2
|
||||
- ./configure
|
||||
- make cmake ctest -j10
|
||||
- cd ..
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../cmake-3.20.2/bin/cmake .. -DJSON_FastTests=ON
|
||||
- make -j10
|
||||
- cd test
|
||||
- ../../cmake-3.20.2/bin/ctest -j10
|
||||
17
.github/workflows/macos.yml
vendored
17
.github/workflows/macos.yml
vendored
@ -24,3 +24,20 @@ jobs:
|
||||
run: cmake --build build --parallel 10
|
||||
- name: test
|
||||
run: cd build ; ctest -j 10 --output-on-failure
|
||||
|
||||
xcode_standards:
|
||||
runs-on: macos-10.15
|
||||
strategy:
|
||||
matrix:
|
||||
standard: [11, 14, 17, 20]
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: cmake
|
||||
run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DCMAKE_CXX_STANDARD_REQUIRED=ON
|
||||
- name: build
|
||||
run: cmake --build build --parallel 10
|
||||
- name: test
|
||||
run: cd build ; ctest -j 10 --output-on-failure
|
||||
|
||||
2
.github/workflows/windows.yml
vendored
2
.github/workflows/windows.yml
vendored
@ -98,7 +98,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
version: [10, 11]
|
||||
version: [11, 12]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@ -12,7 +12,7 @@ project(nlohmann_json VERSION 3.9.1 LANGUAGES CXX)
|
||||
##
|
||||
set(MAIN_PROJECT OFF)
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(MAIN_PROJECT ON)
|
||||
set(MAIN_PROJECT ON)
|
||||
endif()
|
||||
|
||||
##
|
||||
@ -113,8 +113,8 @@ endif()
|
||||
|
||||
# Install a pkg-config file, so other tools can find this.
|
||||
CONFIGURE_FILE(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
|
||||
)
|
||||
|
||||
##
|
||||
@ -160,7 +160,7 @@ if(JSON_Install)
|
||||
FILES ${NLOHMANN_NATVIS_FILE}
|
||||
DESTINATION .
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
export(
|
||||
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
|
||||
21
README.md
21
README.md
@ -206,7 +206,7 @@ If you are using the [Meson Build System](https://mesonbuild.com), add this sour
|
||||
|
||||
The provided meson.build can also be used as an alternative to cmake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly.
|
||||
|
||||
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `nlohmann_json/x.y.z` to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages.
|
||||
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add [`nlohmann_json/x.y.z`](https://conan.io/center/nlohmann_json) to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages.
|
||||
|
||||
If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging.
|
||||
|
||||
@ -870,7 +870,7 @@ assert(p == p2);
|
||||
To make this work with one of your types, you only need to provide two functions:
|
||||
|
||||
```cpp
|
||||
using nlohmann::json;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace ns {
|
||||
void to_json(json& j, const person& p) {
|
||||
@ -1126,7 +1126,7 @@ Other Important points:
|
||||
|
||||
### Binary formats (BSON, CBOR, MessagePack, and UBJSON)
|
||||
|
||||
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](http://bsonspec.org) (Binary JSON), [CBOR](https://cbor.io) (Concise Binary Object Representation), [MessagePack](https://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors.
|
||||
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](https://bsonspec.org) (Binary JSON), [CBOR](https://cbor.io) (Concise Binary Object Representation), [MessagePack](https://msgpack.org), and [UBJSON](https://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors.
|
||||
|
||||
```cpp
|
||||
// create a JSON value
|
||||
@ -1227,7 +1227,7 @@ Please note:
|
||||
|
||||
- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case.
|
||||
|
||||
The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), and [GitHub Actions](https://github.com/nlohmann/json/actions):
|
||||
The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [Drone CI](https://cloud.drone.io/nlohmann/json), and [GitHub Actions](https://github.com/nlohmann/json/actions):
|
||||
|
||||
| Compiler | Operating System | CI Provider |
|
||||
|-------------------------------------------------------------------|--------------------|----------------|
|
||||
@ -1256,6 +1256,7 @@ The following compilers are currently used in continuous integration at [Travis]
|
||||
| GCC 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| GCC 10.2.0 (Ubuntu 10.2.0-5ubuntu1~20.04) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| GCC 11.0.1 20210321 (experimental) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| GCC 11.1.0 | Ubuntu (aarch64) | Drone CI |
|
||||
| Clang 3.5.2 (3.5.2-3ubuntu1) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 3.6.2 (3.6.2-3ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 3.7.1 (3.7.1-2ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
@ -1281,9 +1282,9 @@ The following compilers are currently used in continuous integration at [Travis]
|
||||
|
||||
## License
|
||||
|
||||
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
|
||||
<img align="right" src="https://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
|
||||
|
||||
The class is licensed under the [MIT License](http://opensource.org/licenses/MIT):
|
||||
The class is licensed under the [MIT License](https://opensource.org/licenses/MIT):
|
||||
|
||||
Copyright © 2013-2021 [Niels Lohmann](https://nlohmann.me)
|
||||
|
||||
@ -1295,9 +1296,9 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
|
||||
|
||||
* * *
|
||||
|
||||
The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>
|
||||
The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>
|
||||
|
||||
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/)
|
||||
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/)
|
||||
|
||||
The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
||||
@ -1573,7 +1574,7 @@ The library itself consists of a single header file licensed under the MIT licen
|
||||
- [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz
|
||||
- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json))
|
||||
- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments.
|
||||
- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox)
|
||||
- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](https://wandbox.org)
|
||||
- [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS
|
||||
- [**Valgrind**](https://valgrind.org) to check for correct memory management
|
||||
- [**Wandbox**](https://wandbox.org) for [online examples](https://wandbox.org/permlink/3lCHrFUZANONKv7a)
|
||||
@ -1649,7 +1650,7 @@ $ ctest --output-on-failure
|
||||
|
||||
Note that during the `ctest` stage, several JSON test files are downloaded from an [external repository](https://github.com/nlohmann/json_test_data). If policies forbid downloading artifacts during testing, you can download the files yourself and pass the directory with the test files via `-DJSON_TestDataDirectory=path` to CMake. Then, no Internet connectivity is required. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
|
||||
|
||||
In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure`. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
|
||||
In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure` will fail. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
|
||||
|
||||
Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information.
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
benchmark
|
||||
GIT_REPOSITORY https://github.com/google/benchmark.git
|
||||
GIT_TAG origin/main
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
|
||||
@ -467,7 +467,7 @@ add_custom_target(ci_test_diagnostics
|
||||
###############################################################################
|
||||
|
||||
add_custom_target(ci_test_coverage
|
||||
COMMAND CXX=${GCC_TOOL} ${CMAKE_COMMAND}
|
||||
COMMAND CXX=g++ ${CMAKE_COMMAND}
|
||||
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_FLAGS="--coverage;-fprofile-arcs;-ftest-coverage"
|
||||
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON
|
||||
-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON
|
||||
@ -476,7 +476,7 @@ add_custom_target(ci_test_coverage
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_coverage && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
|
||||
|
||||
COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc lcov_branch_coverage=1
|
||||
COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --gcov-tool ${GCOV_TOOL} --rc lcov_branch_coverage=1
|
||||
COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc lcov_branch_coverage=1
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/test/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept
|
||||
COMMAND genhtml --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.filtered.noexcept
|
||||
|
||||
@ -561,7 +561,7 @@ add_custom_target(ci_clang_analyze
|
||||
###############################################################################
|
||||
|
||||
add_custom_target(ci_cppcheck
|
||||
COMMAND ${CPPCHECK_TOOL} --enable=warning --inline-suppr --inconclusive --force --std=c++11 ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp --error-exitcode=1
|
||||
COMMAND ${CPPCHECK_TOOL} --enable=warning --suppress=missingReturn --inline-suppr --inconclusive --force --std=c++11 ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp --error-exitcode=1
|
||||
COMMENT "Check code with Cppcheck"
|
||||
)
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ assert(p == p2);
|
||||
To make this work with one of your types, you only need to provide two functions:
|
||||
|
||||
```cpp
|
||||
using nlohmann::json;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace ns {
|
||||
void to_json(json& j, const person& p) {
|
||||
|
||||
@ -32,6 +32,10 @@ When defining `JSON_NOEXCEPTION`, `#!cpp try` is replaced by `#!cpp if (true)`,
|
||||
|
||||
The same effect is achieved by setting the compiler flag `-fno-exceptions`.
|
||||
|
||||
## `JSON_NO_IO`
|
||||
|
||||
When defined, headers `<cstdio>`, `<ios>`, `<iosfwd>`, `<istream>`, and `<ostream>` are not included and parse functions relying on these headers are excluded. This is relevant for environment where these I/O functions are disallowed for security reasons (e.g., Intel Software Guard Extensions (SGX)).
|
||||
|
||||
## `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`
|
||||
|
||||
When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows to use the library with compilers that do not fully support C++11 and may only work if unsupported features are not used.
|
||||
|
||||
@ -96,6 +96,21 @@ This is the same behavior as the code `#!c double x = 3.141592653589793238462643
|
||||
- All integers outside the range $[-2^{63}, 2^{64}-1]$, as well as floating-point numbers are stored as `double`.
|
||||
This also concurs with the specification above.
|
||||
|
||||
### Zeros
|
||||
|
||||
The JSON number grammar allows for different ways to express zero, and this library will store zeros differently:
|
||||
|
||||
| Literal | Stored value and type | Serialization |
|
||||
| ------- | --------------------- | ------------- |
|
||||
| `0` | `#!c std::uint64_t(0)` | `0` |
|
||||
| `-0` | `#!c std::int64_t(0)` | `0` |
|
||||
| `0.0` | `#!c double(0.0)` | `0.0` |
|
||||
| `-0.0` | `#!c double(-0.0)` | `-0.0` |
|
||||
| `0E0` | `#!c double(0.0)` | `0.0` |
|
||||
| `-0E0` | `#!c double(-0.0)` | `-0.0` |
|
||||
|
||||
That is, `-0` is stored as a signed integer, but the serialization does not reproduce the `-`.
|
||||
|
||||
### Number serialization
|
||||
|
||||
- Integer numbers are serialized as is; that is, no scientific notation is used.
|
||||
|
||||
@ -22,6 +22,13 @@ namespace detail
|
||||
// constructors //
|
||||
//////////////////
|
||||
|
||||
/*
|
||||
* Note all external_constructor<>::construct functions need to call
|
||||
* j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an
|
||||
* allocated value (e.g., a string). See bug issue
|
||||
* https://github.com/nlohmann/json/issues/2865 for more information.
|
||||
*/
|
||||
|
||||
template<value_t> struct external_constructor;
|
||||
|
||||
template<>
|
||||
@ -30,6 +37,7 @@ struct external_constructor<value_t::boolean>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::boolean;
|
||||
j.m_value = b;
|
||||
j.assert_invariant();
|
||||
@ -42,6 +50,7 @@ struct external_constructor<value_t::string>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::string;
|
||||
j.m_value = s;
|
||||
j.assert_invariant();
|
||||
@ -50,6 +59,7 @@ struct external_constructor<value_t::string>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::string;
|
||||
j.m_value = std::move(s);
|
||||
j.assert_invariant();
|
||||
@ -60,6 +70,7 @@ struct external_constructor<value_t::string>
|
||||
int > = 0 >
|
||||
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::string;
|
||||
j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
|
||||
j.assert_invariant();
|
||||
@ -72,6 +83,7 @@ struct external_constructor<value_t::binary>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::binary;
|
||||
j.m_value = typename BasicJsonType::binary_t(b);
|
||||
j.assert_invariant();
|
||||
@ -80,6 +92,7 @@ struct external_constructor<value_t::binary>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::binary;
|
||||
j.m_value = typename BasicJsonType::binary_t(std::move(b));;
|
||||
j.assert_invariant();
|
||||
@ -92,6 +105,7 @@ struct external_constructor<value_t::number_float>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::number_float;
|
||||
j.m_value = val;
|
||||
j.assert_invariant();
|
||||
@ -104,6 +118,7 @@ struct external_constructor<value_t::number_unsigned>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::number_unsigned;
|
||||
j.m_value = val;
|
||||
j.assert_invariant();
|
||||
@ -116,6 +131,7 @@ struct external_constructor<value_t::number_integer>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::number_integer;
|
||||
j.m_value = val;
|
||||
j.assert_invariant();
|
||||
@ -128,6 +144,7 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value = arr;
|
||||
j.set_parents();
|
||||
@ -137,6 +154,7 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value = std::move(arr);
|
||||
j.set_parents();
|
||||
@ -150,6 +168,8 @@ struct external_constructor<value_t::array>
|
||||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
||||
j.set_parents();
|
||||
@ -159,6 +179,7 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value = value_t::array;
|
||||
j.m_value.array->reserve(arr.size());
|
||||
@ -174,6 +195,7 @@ struct external_constructor<value_t::array>
|
||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value = value_t::array;
|
||||
j.m_value.array->resize(arr.size());
|
||||
@ -192,6 +214,7 @@ struct external_constructor<value_t::object>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::object;
|
||||
j.m_value = obj;
|
||||
j.set_parents();
|
||||
@ -201,6 +224,7 @@ struct external_constructor<value_t::object>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::object;
|
||||
j.m_value = std::move(obj);
|
||||
j.set_parents();
|
||||
@ -214,6 +238,7 @@ struct external_constructor<value_t::object>
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::object;
|
||||
j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
||||
j.set_parents();
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
|
||||
#include <array> // array
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdio> //FILE *
|
||||
#include <cstring> // strlen
|
||||
#include <istream> // istream
|
||||
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
|
||||
#include <memory> // shared_ptr, make_shared, addressof
|
||||
#include <numeric> // accumulate
|
||||
@ -12,6 +10,11 @@
|
||||
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
|
||||
#include <utility> // pair, declval
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
#include <cstdio> //FILE *
|
||||
#include <istream> // istream
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
#include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
@ -26,6 +29,7 @@ enum class input_format_t { json, cbor, msgpack, ubjson, bson };
|
||||
// input adapters //
|
||||
////////////////////
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/*!
|
||||
Input adapter for stdio file access. This adapter read only 1 byte and do not use any
|
||||
buffer. This adapter is a very low level adapter.
|
||||
@ -105,7 +109,7 @@ class input_stream_adapter
|
||||
{
|
||||
auto res = sb->sbumpc();
|
||||
// set eof manually, as we don't use the istream interface.
|
||||
if (JSON_HEDLEY_UNLIKELY(res == EOF))
|
||||
if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
|
||||
{
|
||||
is->clear(is->rdstate() | std::ios::eofbit);
|
||||
}
|
||||
@ -117,6 +121,7 @@ class input_stream_adapter
|
||||
std::istream* is = nullptr;
|
||||
std::streambuf* sb = nullptr;
|
||||
};
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
// General-purpose iterator-based adapter. It might not be as fast as
|
||||
// theoretically possible for some containers, but it is extremely versatile.
|
||||
@ -403,6 +408,7 @@ typename container_input_adapter_factory_impl::container_input_adapter_factory<C
|
||||
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
|
||||
}
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
// Special cases with fast paths
|
||||
inline file_input_adapter input_adapter(std::FILE* file)
|
||||
{
|
||||
@ -418,6 +424,7 @@ inline input_stream_adapter input_adapter(std::istream&& stream)
|
||||
{
|
||||
return input_stream_adapter(stream);
|
||||
}
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
|
||||
|
||||
|
||||
@ -2,12 +2,16 @@
|
||||
|
||||
#include <algorithm> // copy
|
||||
#include <cstddef> // size_t
|
||||
#include <ios> // streamsize
|
||||
#include <iterator> // back_inserter
|
||||
#include <memory> // shared_ptr, make_shared
|
||||
#include <ostream> // basic_ostream
|
||||
#include <string> // basic_string
|
||||
#include <vector> // vector
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
#include <ios> // streamsize
|
||||
#include <ostream> // basic_ostream
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
@ -56,6 +60,7 @@ class output_vector_adapter : public output_adapter_protocol<CharType>
|
||||
std::vector<CharType>& v;
|
||||
};
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/// output adapter for output streams
|
||||
template<typename CharType>
|
||||
class output_stream_adapter : public output_adapter_protocol<CharType>
|
||||
@ -79,6 +84,7 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
|
||||
private:
|
||||
std::basic_ostream<CharType>& stream;
|
||||
};
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
/// output adapter for basic_string
|
||||
template<typename CharType, typename StringType = std::basic_string<CharType>>
|
||||
@ -111,8 +117,10 @@ class output_adapter
|
||||
output_adapter(std::vector<CharType>& vec)
|
||||
: oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
output_adapter(std::basic_ostream<CharType>& s)
|
||||
: oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
output_adapter(StringType& s)
|
||||
: oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
|
||||
|
||||
@ -499,7 +499,7 @@ class serializer
|
||||
{
|
||||
case error_handler_t::strict:
|
||||
{
|
||||
std::string sn(3, '\0');
|
||||
std::string sn(9, '\0');
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
(std::snprintf)(&sn[0], sn.size(), "%.2X", byte);
|
||||
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn, BasicJsonType()));
|
||||
@ -594,7 +594,7 @@ class serializer
|
||||
{
|
||||
case error_handler_t::strict:
|
||||
{
|
||||
std::string sn(3, '\0');
|
||||
std::string sn(9, '\0');
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
(std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<std::uint8_t>(s.back()));
|
||||
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn, BasicJsonType()));
|
||||
|
||||
@ -38,7 +38,9 @@ SOFTWARE.
|
||||
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
|
||||
#include <functional> // hash, less
|
||||
#include <initializer_list> // initializer_list
|
||||
#include <iosfwd> // istream, ostream
|
||||
#ifndef JSON_NO_IO
|
||||
#include <iosfwd> // istream, ostream
|
||||
#endif // JSON_NO_IO
|
||||
#include <iterator> // random_access_iterator_tag
|
||||
#include <memory> // unique_ptr
|
||||
#include <numeric> // accumulate
|
||||
@ -1131,53 +1133,55 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
binary = create<binary_t>(std::move(value));
|
||||
}
|
||||
|
||||
void destroy(value_t t) noexcept
|
||||
void destroy(value_t t)
|
||||
{
|
||||
// flatten the current json_value to a heap-allocated stack
|
||||
std::vector<basic_json> stack;
|
||||
if (t == value_t::array || t == value_t::object)
|
||||
{
|
||||
// flatten the current json_value to a heap-allocated stack
|
||||
std::vector<basic_json> stack;
|
||||
|
||||
// move the top-level items to stack
|
||||
if (t == value_t::array)
|
||||
{
|
||||
stack.reserve(array->size());
|
||||
std::move(array->begin(), array->end(), std::back_inserter(stack));
|
||||
}
|
||||
else if (t == value_t::object)
|
||||
{
|
||||
stack.reserve(object->size());
|
||||
for (auto&& it : *object)
|
||||
// move the top-level items to stack
|
||||
if (t == value_t::array)
|
||||
{
|
||||
stack.push_back(std::move(it.second));
|
||||
stack.reserve(array->size());
|
||||
std::move(array->begin(), array->end(), std::back_inserter(stack));
|
||||
}
|
||||
}
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
// move the last item to local variable to be processed
|
||||
basic_json current_item(std::move(stack.back()));
|
||||
stack.pop_back();
|
||||
|
||||
// if current_item is array/object, move
|
||||
// its children to the stack to be processed later
|
||||
if (current_item.is_array())
|
||||
else
|
||||
{
|
||||
std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(),
|
||||
std::back_inserter(stack));
|
||||
|
||||
current_item.m_value.array->clear();
|
||||
}
|
||||
else if (current_item.is_object())
|
||||
{
|
||||
for (auto&& it : *current_item.m_value.object)
|
||||
stack.reserve(object->size());
|
||||
for (auto&& it : *object)
|
||||
{
|
||||
stack.push_back(std::move(it.second));
|
||||
}
|
||||
|
||||
current_item.m_value.object->clear();
|
||||
}
|
||||
|
||||
// it's now safe that current_item get destructed
|
||||
// since it doesn't have any children
|
||||
while (!stack.empty())
|
||||
{
|
||||
// move the last item to local variable to be processed
|
||||
basic_json current_item(std::move(stack.back()));
|
||||
stack.pop_back();
|
||||
|
||||
// if current_item is array/object, move
|
||||
// its children to the stack to be processed later
|
||||
if (current_item.is_array())
|
||||
{
|
||||
std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack));
|
||||
|
||||
current_item.m_value.array->clear();
|
||||
}
|
||||
else if (current_item.is_object())
|
||||
{
|
||||
for (auto&& it : *current_item.m_value.object)
|
||||
{
|
||||
stack.push_back(std::move(it.second));
|
||||
}
|
||||
|
||||
current_item.m_value.object->clear();
|
||||
}
|
||||
|
||||
// it's now safe that current_item get destructed
|
||||
// since it doesn't have any children
|
||||
}
|
||||
}
|
||||
|
||||
switch (t)
|
||||
@ -1304,12 +1308,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return it;
|
||||
}
|
||||
|
||||
reference set_parent(reference j)
|
||||
reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1))
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
if (old_capacity != std::size_t(-1))
|
||||
{
|
||||
// see https://github.com/nlohmann/json/issues/2838
|
||||
JSON_ASSERT(type() == value_t::array);
|
||||
if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
|
||||
{
|
||||
// capacity has changed: update all parents
|
||||
set_parents();
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
j.m_parent = this;
|
||||
#else
|
||||
static_cast<void>(j);
|
||||
static_cast<void>(old_capacity);
|
||||
#endif
|
||||
return j;
|
||||
}
|
||||
@ -5304,8 +5321,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// add element to array (move semantics)
|
||||
const auto old_capacity = m_value.array->capacity();
|
||||
m_value.array->push_back(std::move(val));
|
||||
set_parent(m_value.array->back());
|
||||
set_parent(m_value.array->back(), old_capacity);
|
||||
// if val is moved from, basic_json move constructor marks it null so we do not call the destructor
|
||||
}
|
||||
|
||||
@ -5340,8 +5358,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// add element to array
|
||||
const auto old_capacity = m_value.array->capacity();
|
||||
m_value.array->push_back(val);
|
||||
set_parent(m_value.array->back());
|
||||
set_parent(m_value.array->back(), old_capacity);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -5495,12 +5514,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// add element to array (perfect forwarding)
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
return set_parent(m_value.array->emplace_back(std::forward<Args>(args)...));
|
||||
#else
|
||||
const auto old_capacity = m_value.array->capacity();
|
||||
m_value.array->emplace_back(std::forward<Args>(args)...);
|
||||
return set_parent(m_value.array->back());
|
||||
#endif
|
||||
return set_parent(m_value.array->back(), old_capacity);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -5576,6 +5592,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
|
||||
// but the return value of insert is missing in GCC 4.8, so it is written this way instead.
|
||||
|
||||
set_parents();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -5613,7 +5630,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// insert to array and return iterator
|
||||
return set_parents(insert_iterator(pos, val), static_cast<typename iterator::difference_type>(1));
|
||||
return insert_iterator(pos, val);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this));
|
||||
@ -5664,7 +5681,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// insert to array and return iterator
|
||||
return set_parents(insert_iterator(pos, cnt, val), static_cast<typename iterator::difference_type>(cnt));
|
||||
return insert_iterator(pos, cnt, val);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this));
|
||||
@ -5726,7 +5743,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// insert to array and return iterator
|
||||
return set_parents(insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator), std::distance(first, last));
|
||||
return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -5768,7 +5785,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// insert to array and return iterator
|
||||
return set_parents(insert_iterator(pos, ilist.begin(), ilist.end()), static_cast<typename iterator::difference_type>(ilist.size()));
|
||||
return insert_iterator(pos, ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -6594,7 +6611,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @name serialization
|
||||
/// @{
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/*!
|
||||
@brief serialize to stream
|
||||
|
||||
@ -6654,7 +6671,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return o << j;
|
||||
}
|
||||
|
||||
#endif // JSON_NO_IO
|
||||
/// @}
|
||||
|
||||
|
||||
@ -6912,7 +6929,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);
|
||||
}
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/*!
|
||||
@brief deserialize from stream
|
||||
@deprecated This stream operator is deprecated and will be removed in
|
||||
@ -6957,7 +6974,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
parser(detail::input_adapter(i)).parse(false, j);
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif // JSON_NO_IO
|
||||
/// @}
|
||||
|
||||
///////////////////////////
|
||||
|
||||
@ -38,7 +38,9 @@ SOFTWARE.
|
||||
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
|
||||
#include <functional> // hash, less
|
||||
#include <initializer_list> // initializer_list
|
||||
#include <iosfwd> // istream, ostream
|
||||
#ifndef JSON_NO_IO
|
||||
#include <iosfwd> // istream, ostream
|
||||
#endif // JSON_NO_IO
|
||||
#include <iterator> // random_access_iterator_tag
|
||||
#include <memory> // unique_ptr
|
||||
#include <numeric> // accumulate
|
||||
@ -4505,6 +4507,13 @@ namespace detail
|
||||
// constructors //
|
||||
//////////////////
|
||||
|
||||
/*
|
||||
* Note all external_constructor<>::construct functions need to call
|
||||
* j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an
|
||||
* allocated value (e.g., a string). See bug issue
|
||||
* https://github.com/nlohmann/json/issues/2865 for more information.
|
||||
*/
|
||||
|
||||
template<value_t> struct external_constructor;
|
||||
|
||||
template<>
|
||||
@ -4513,6 +4522,7 @@ struct external_constructor<value_t::boolean>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::boolean;
|
||||
j.m_value = b;
|
||||
j.assert_invariant();
|
||||
@ -4525,6 +4535,7 @@ struct external_constructor<value_t::string>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::string;
|
||||
j.m_value = s;
|
||||
j.assert_invariant();
|
||||
@ -4533,6 +4544,7 @@ struct external_constructor<value_t::string>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::string;
|
||||
j.m_value = std::move(s);
|
||||
j.assert_invariant();
|
||||
@ -4543,6 +4555,7 @@ struct external_constructor<value_t::string>
|
||||
int > = 0 >
|
||||
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::string;
|
||||
j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
|
||||
j.assert_invariant();
|
||||
@ -4555,6 +4568,7 @@ struct external_constructor<value_t::binary>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::binary;
|
||||
j.m_value = typename BasicJsonType::binary_t(b);
|
||||
j.assert_invariant();
|
||||
@ -4563,6 +4577,7 @@ struct external_constructor<value_t::binary>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::binary;
|
||||
j.m_value = typename BasicJsonType::binary_t(std::move(b));;
|
||||
j.assert_invariant();
|
||||
@ -4575,6 +4590,7 @@ struct external_constructor<value_t::number_float>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::number_float;
|
||||
j.m_value = val;
|
||||
j.assert_invariant();
|
||||
@ -4587,6 +4603,7 @@ struct external_constructor<value_t::number_unsigned>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::number_unsigned;
|
||||
j.m_value = val;
|
||||
j.assert_invariant();
|
||||
@ -4599,6 +4616,7 @@ struct external_constructor<value_t::number_integer>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::number_integer;
|
||||
j.m_value = val;
|
||||
j.assert_invariant();
|
||||
@ -4611,6 +4629,7 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value = arr;
|
||||
j.set_parents();
|
||||
@ -4620,6 +4639,7 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value = std::move(arr);
|
||||
j.set_parents();
|
||||
@ -4633,6 +4653,8 @@ struct external_constructor<value_t::array>
|
||||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
||||
j.set_parents();
|
||||
@ -4642,6 +4664,7 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value = value_t::array;
|
||||
j.m_value.array->reserve(arr.size());
|
||||
@ -4657,6 +4680,7 @@ struct external_constructor<value_t::array>
|
||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::array;
|
||||
j.m_value = value_t::array;
|
||||
j.m_value.array->resize(arr.size());
|
||||
@ -4675,6 +4699,7 @@ struct external_constructor<value_t::object>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::object;
|
||||
j.m_value = obj;
|
||||
j.set_parents();
|
||||
@ -4684,6 +4709,7 @@ struct external_constructor<value_t::object>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||
{
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::object;
|
||||
j.m_value = std::move(obj);
|
||||
j.set_parents();
|
||||
@ -4697,6 +4723,7 @@ struct external_constructor<value_t::object>
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
j.m_value.destroy(j.m_type);
|
||||
j.m_type = value_t::object;
|
||||
j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
||||
j.set_parents();
|
||||
@ -5254,9 +5281,7 @@ std::size_t hash(const BasicJsonType& j)
|
||||
|
||||
#include <array> // array
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdio> //FILE *
|
||||
#include <cstring> // strlen
|
||||
#include <istream> // istream
|
||||
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
|
||||
#include <memory> // shared_ptr, make_shared, addressof
|
||||
#include <numeric> // accumulate
|
||||
@ -5264,6 +5289,11 @@ std::size_t hash(const BasicJsonType& j)
|
||||
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
|
||||
#include <utility> // pair, declval
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
#include <cstdio> //FILE *
|
||||
#include <istream> // istream
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
// #include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
@ -5280,6 +5310,7 @@ enum class input_format_t { json, cbor, msgpack, ubjson, bson };
|
||||
// input adapters //
|
||||
////////////////////
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/*!
|
||||
Input adapter for stdio file access. This adapter read only 1 byte and do not use any
|
||||
buffer. This adapter is a very low level adapter.
|
||||
@ -5359,7 +5390,7 @@ class input_stream_adapter
|
||||
{
|
||||
auto res = sb->sbumpc();
|
||||
// set eof manually, as we don't use the istream interface.
|
||||
if (JSON_HEDLEY_UNLIKELY(res == EOF))
|
||||
if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
|
||||
{
|
||||
is->clear(is->rdstate() | std::ios::eofbit);
|
||||
}
|
||||
@ -5371,6 +5402,7 @@ class input_stream_adapter
|
||||
std::istream* is = nullptr;
|
||||
std::streambuf* sb = nullptr;
|
||||
};
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
// General-purpose iterator-based adapter. It might not be as fast as
|
||||
// theoretically possible for some containers, but it is extremely versatile.
|
||||
@ -5657,6 +5689,7 @@ typename container_input_adapter_factory_impl::container_input_adapter_factory<C
|
||||
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
|
||||
}
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
// Special cases with fast paths
|
||||
inline file_input_adapter input_adapter(std::FILE* file)
|
||||
{
|
||||
@ -5672,6 +5705,7 @@ inline input_stream_adapter input_adapter(std::istream&& stream)
|
||||
{
|
||||
return input_stream_adapter(stream);
|
||||
}
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
|
||||
|
||||
@ -13146,12 +13180,16 @@ class json_ref
|
||||
|
||||
#include <algorithm> // copy
|
||||
#include <cstddef> // size_t
|
||||
#include <ios> // streamsize
|
||||
#include <iterator> // back_inserter
|
||||
#include <memory> // shared_ptr, make_shared
|
||||
#include <ostream> // basic_ostream
|
||||
#include <string> // basic_string
|
||||
#include <vector> // vector
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
#include <ios> // streamsize
|
||||
#include <ostream> // basic_ostream
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
|
||||
@ -13201,6 +13239,7 @@ class output_vector_adapter : public output_adapter_protocol<CharType>
|
||||
std::vector<CharType>& v;
|
||||
};
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/// output adapter for output streams
|
||||
template<typename CharType>
|
||||
class output_stream_adapter : public output_adapter_protocol<CharType>
|
||||
@ -13224,6 +13263,7 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
|
||||
private:
|
||||
std::basic_ostream<CharType>& stream;
|
||||
};
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
/// output adapter for basic_string
|
||||
template<typename CharType, typename StringType = std::basic_string<CharType>>
|
||||
@ -13256,8 +13296,10 @@ class output_adapter
|
||||
output_adapter(std::vector<CharType>& vec)
|
||||
: oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
output_adapter(std::basic_ostream<CharType>& s)
|
||||
: oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
output_adapter(StringType& s)
|
||||
: oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
|
||||
@ -16469,7 +16511,7 @@ class serializer
|
||||
{
|
||||
case error_handler_t::strict:
|
||||
{
|
||||
std::string sn(3, '\0');
|
||||
std::string sn(9, '\0');
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
(std::snprintf)(&sn[0], sn.size(), "%.2X", byte);
|
||||
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn, BasicJsonType()));
|
||||
@ -16564,7 +16606,7 @@ class serializer
|
||||
{
|
||||
case error_handler_t::strict:
|
||||
{
|
||||
std::string sn(3, '\0');
|
||||
std::string sn(9, '\0');
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
(std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<std::uint8_t>(s.back()));
|
||||
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn, BasicJsonType()));
|
||||
@ -18178,53 +18220,55 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
binary = create<binary_t>(std::move(value));
|
||||
}
|
||||
|
||||
void destroy(value_t t) noexcept
|
||||
void destroy(value_t t)
|
||||
{
|
||||
// flatten the current json_value to a heap-allocated stack
|
||||
std::vector<basic_json> stack;
|
||||
if (t == value_t::array || t == value_t::object)
|
||||
{
|
||||
// flatten the current json_value to a heap-allocated stack
|
||||
std::vector<basic_json> stack;
|
||||
|
||||
// move the top-level items to stack
|
||||
if (t == value_t::array)
|
||||
{
|
||||
stack.reserve(array->size());
|
||||
std::move(array->begin(), array->end(), std::back_inserter(stack));
|
||||
}
|
||||
else if (t == value_t::object)
|
||||
{
|
||||
stack.reserve(object->size());
|
||||
for (auto&& it : *object)
|
||||
// move the top-level items to stack
|
||||
if (t == value_t::array)
|
||||
{
|
||||
stack.push_back(std::move(it.second));
|
||||
stack.reserve(array->size());
|
||||
std::move(array->begin(), array->end(), std::back_inserter(stack));
|
||||
}
|
||||
}
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
// move the last item to local variable to be processed
|
||||
basic_json current_item(std::move(stack.back()));
|
||||
stack.pop_back();
|
||||
|
||||
// if current_item is array/object, move
|
||||
// its children to the stack to be processed later
|
||||
if (current_item.is_array())
|
||||
else
|
||||
{
|
||||
std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(),
|
||||
std::back_inserter(stack));
|
||||
|
||||
current_item.m_value.array->clear();
|
||||
}
|
||||
else if (current_item.is_object())
|
||||
{
|
||||
for (auto&& it : *current_item.m_value.object)
|
||||
stack.reserve(object->size());
|
||||
for (auto&& it : *object)
|
||||
{
|
||||
stack.push_back(std::move(it.second));
|
||||
}
|
||||
|
||||
current_item.m_value.object->clear();
|
||||
}
|
||||
|
||||
// it's now safe that current_item get destructed
|
||||
// since it doesn't have any children
|
||||
while (!stack.empty())
|
||||
{
|
||||
// move the last item to local variable to be processed
|
||||
basic_json current_item(std::move(stack.back()));
|
||||
stack.pop_back();
|
||||
|
||||
// if current_item is array/object, move
|
||||
// its children to the stack to be processed later
|
||||
if (current_item.is_array())
|
||||
{
|
||||
std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack));
|
||||
|
||||
current_item.m_value.array->clear();
|
||||
}
|
||||
else if (current_item.is_object())
|
||||
{
|
||||
for (auto&& it : *current_item.m_value.object)
|
||||
{
|
||||
stack.push_back(std::move(it.second));
|
||||
}
|
||||
|
||||
current_item.m_value.object->clear();
|
||||
}
|
||||
|
||||
// it's now safe that current_item get destructed
|
||||
// since it doesn't have any children
|
||||
}
|
||||
}
|
||||
|
||||
switch (t)
|
||||
@ -18351,12 +18395,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return it;
|
||||
}
|
||||
|
||||
reference set_parent(reference j)
|
||||
reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1))
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
if (old_capacity != std::size_t(-1))
|
||||
{
|
||||
// see https://github.com/nlohmann/json/issues/2838
|
||||
JSON_ASSERT(type() == value_t::array);
|
||||
if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
|
||||
{
|
||||
// capacity has changed: update all parents
|
||||
set_parents();
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
j.m_parent = this;
|
||||
#else
|
||||
static_cast<void>(j);
|
||||
static_cast<void>(old_capacity);
|
||||
#endif
|
||||
return j;
|
||||
}
|
||||
@ -22351,8 +22408,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// add element to array (move semantics)
|
||||
const auto old_capacity = m_value.array->capacity();
|
||||
m_value.array->push_back(std::move(val));
|
||||
set_parent(m_value.array->back());
|
||||
set_parent(m_value.array->back(), old_capacity);
|
||||
// if val is moved from, basic_json move constructor marks it null so we do not call the destructor
|
||||
}
|
||||
|
||||
@ -22387,8 +22445,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// add element to array
|
||||
const auto old_capacity = m_value.array->capacity();
|
||||
m_value.array->push_back(val);
|
||||
set_parent(m_value.array->back());
|
||||
set_parent(m_value.array->back(), old_capacity);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -22542,12 +22601,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// add element to array (perfect forwarding)
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
return set_parent(m_value.array->emplace_back(std::forward<Args>(args)...));
|
||||
#else
|
||||
const auto old_capacity = m_value.array->capacity();
|
||||
m_value.array->emplace_back(std::forward<Args>(args)...);
|
||||
return set_parent(m_value.array->back());
|
||||
#endif
|
||||
return set_parent(m_value.array->back(), old_capacity);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -22623,6 +22679,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
|
||||
// but the return value of insert is missing in GCC 4.8, so it is written this way instead.
|
||||
|
||||
set_parents();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -22660,7 +22717,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// insert to array and return iterator
|
||||
return set_parents(insert_iterator(pos, val), static_cast<typename iterator::difference_type>(1));
|
||||
return insert_iterator(pos, val);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this));
|
||||
@ -22711,7 +22768,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// insert to array and return iterator
|
||||
return set_parents(insert_iterator(pos, cnt, val), static_cast<typename iterator::difference_type>(cnt));
|
||||
return insert_iterator(pos, cnt, val);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this));
|
||||
@ -22773,7 +22830,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// insert to array and return iterator
|
||||
return set_parents(insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator), std::distance(first, last));
|
||||
return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -22815,7 +22872,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// insert to array and return iterator
|
||||
return set_parents(insert_iterator(pos, ilist.begin(), ilist.end()), static_cast<typename iterator::difference_type>(ilist.size()));
|
||||
return insert_iterator(pos, ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -23641,7 +23698,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @name serialization
|
||||
/// @{
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/*!
|
||||
@brief serialize to stream
|
||||
|
||||
@ -23701,7 +23758,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return o << j;
|
||||
}
|
||||
|
||||
#endif // JSON_NO_IO
|
||||
/// @}
|
||||
|
||||
|
||||
@ -23959,7 +24016,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);
|
||||
}
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/*!
|
||||
@brief deserialize from stream
|
||||
@deprecated This stream operator is deprecated and will be removed in
|
||||
@ -24004,7 +24061,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
parser(detail::input_adapter(i)).parse(false, j);
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif // JSON_NO_IO
|
||||
/// @}
|
||||
|
||||
///////////////////////////
|
||||
|
||||
@ -109,4 +109,69 @@ TEST_CASE("Better diagnostics")
|
||||
j["/foo"] = {1, 2, 3};
|
||||
CHECK_THROWS_WITH_AS(j.unflatten(), "[json.exception.type_error.315] (/~1foo) values in object must be primitive", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("Regression test for https://github.com/nlohmann/json/issues/2838")
|
||||
{
|
||||
// void push_back(basic_json&& val)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr.push_back(json::object());
|
||||
j_arr.push_back(json::object());
|
||||
j_arr.push_back(json::object());
|
||||
j_arr.push_back(json::object());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// void push_back(const basic_json& val)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
auto object = json::object();
|
||||
j_arr.push_back(object);
|
||||
j_arr.push_back(object);
|
||||
j_arr.push_back(object);
|
||||
j_arr.push_back(object);
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// reference emplace_back(Args&& ... args)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr.emplace_back(json::object());
|
||||
j_arr.emplace_back(json::object());
|
||||
j_arr.emplace_back(json::object());
|
||||
j_arr.emplace_back(json::object());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// iterator insert(const_iterator pos, const basic_json& val)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr.insert(j_arr.begin(), json::object());
|
||||
j_arr.insert(j_arr.begin(), json::object());
|
||||
j_arr.insert(j_arr.begin(), json::object());
|
||||
j_arr.insert(j_arr.begin(), json::object());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr.insert(j_arr.begin(), 2, json::object());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// iterator insert(const_iterator pos, const_iterator first, const_iterator last)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
json j_objects = {json::object(), json::object()};
|
||||
j_arr.insert(j_arr.begin(), j_objects.begin(), j_objects.end());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,4 +594,30 @@ TEST_CASE("regression tests 2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("issue #2865 - ASAN detects memory leaks")
|
||||
{
|
||||
// the code below is expected to not leak memory
|
||||
{
|
||||
nlohmann::json o;
|
||||
std::string s = "bar";
|
||||
|
||||
nlohmann::to_json(o["foo"], s);
|
||||
|
||||
nlohmann::json p = o;
|
||||
|
||||
// call to_json with a non-null JSON value
|
||||
nlohmann::to_json(p["foo"], s);
|
||||
}
|
||||
|
||||
{
|
||||
nlohmann::json o;
|
||||
std::string s = "bar";
|
||||
|
||||
nlohmann::to_json(o["foo"], s);
|
||||
|
||||
// call to_json with a non-null JSON value
|
||||
nlohmann::to_json(o["foo"], s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user