Merge branch 'develop' of https://github.com/nlohmann/json into string_view

This commit is contained in:
Niels Lohmann 2021-07-16 08:45:53 +02:00
commit 8ba8c43707
No known key found for this signature in database
GPG Key ID: 7F3CEA63AE251B69
18 changed files with 406 additions and 141 deletions

22
.drone.yml Normal file
View 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

View File

@ -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

View File

@ -98,7 +98,7 @@ jobs:
runs-on: windows-latest
strategy:
matrix:
version: [10, 11]
version: [11, 12]
steps:
- uses: actions/checkout@v2

View File

@ -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}::

View File

@ -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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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.

View File

@ -11,6 +11,7 @@ include(FetchContent)
FetchContent_Declare(
benchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
GIT_TAG origin/main
GIT_SHALLOW TRUE
)

View File

@ -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"
)

View File

@ -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) {

View File

@ -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.

View File

@ -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.

View File

@ -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();

View File

@ -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*>()));

View File

@ -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)) {}

View File

@ -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()));

View File

@ -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
/// @}
///////////////////////////

View File

@ -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
/// @}
///////////////////////////

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}