Merge branch 'develop' of https://github.com/nlohmann/json into issue3090
This commit is contained in:
commit
cf6903ec00
@ -1,6 +1,9 @@
|
||||
Checks: '*,
|
||||
-altera-id-dependent-backward-branch,
|
||||
-altera-struct-pack-align,
|
||||
-altera-unroll-loops,
|
||||
-android-cloexec-fopen,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-concurrency-mt-unsafe,
|
||||
-cppcoreguidelines-avoid-goto,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
@ -11,6 +14,7 @@ Checks: '*,
|
||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||
-cppcoreguidelines-pro-type-reinterpret-cast,
|
||||
-cppcoreguidelines-pro-type-union-access,
|
||||
-cppcoreguidelines-virtual-class-destructor,
|
||||
-fuchsia-default-arguments-calls,
|
||||
-fuchsia-default-arguments-declarations,
|
||||
-fuchsia-overloaded-operator,
|
||||
@ -34,6 +38,7 @@ Checks: '*,
|
||||
-modernize-use-trailing-return-type,
|
||||
-readability-function-size,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-identifier-length,
|
||||
-readability-magic-numbers,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-uppercase-literal-suffix'
|
||||
|
||||
16
.github/workflows/ubuntu.yml
vendored
16
.github/workflows/ubuntu.yml
vendored
@ -11,7 +11,7 @@ on:
|
||||
jobs:
|
||||
ci_test_clang:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v1.0.0
|
||||
container: ghcr.io/nlohmann/json-ci:v2.0.0
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: cmake
|
||||
@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
ci_test_gcc:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v1.0.0
|
||||
container: ghcr.io/nlohmann/json-ci:v2.0.0
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: cmake
|
||||
@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
ci_static_analysis:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v1.0.0
|
||||
container: ghcr.io/nlohmann/json-ci:v2.0.0
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_clang_tidy, ci_cppcheck, ci_test_valgrind, ci_test_clang_sanitizer, ci_test_amalgamation, ci_clang_analyze, ci_cpplint, ci_cmake_flags, ci_single_binaries, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_infer]
|
||||
@ -44,7 +44,7 @@ jobs:
|
||||
|
||||
ci_cmake_options:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v1.0.0
|
||||
container: ghcr.io/nlohmann/json-ci:v2.0.0
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_test_diagnostics, ci_test_noexceptions, ci_test_noimplicitconversions]
|
||||
@ -57,7 +57,7 @@ jobs:
|
||||
|
||||
ci_test_coverage:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v1.0.0
|
||||
container: ghcr.io/nlohmann/json-ci:v2.0.0
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: cmake
|
||||
@ -77,10 +77,10 @@ jobs:
|
||||
|
||||
ci_test_compilers:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v1.0.0
|
||||
container: ghcr.io/nlohmann/json-ci:v2.0.0
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [g++-4.8, g++-4.9, g++-5, g++-7, g++-8, g++-9, g++-10, clang++-3.5, clang++-3.6, clang++-3.7, clang++-3.8, clang++-3.9, clang++-4.0, clang++-5.0, clang++-6.0, clang++-7, clang++-8, clang++-9, clang++-10, clang++-11, clang++-12]
|
||||
compiler: [g++-4.8, g++-4.9, g++-5, g++-6, g++-7, g++-8, g++-9, g++-10, clang++-3.5, clang++-3.6, clang++-3.7, clang++-3.8, clang++-3.9, clang++-4.0, clang++-5.0, clang++-6.0, clang++-7, clang++-8, clang++-9, clang++-10, clang++-11, clang++-12, clang++-13]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: cmake
|
||||
@ -90,7 +90,7 @@ jobs:
|
||||
|
||||
ci_test_standards:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v1.0.0
|
||||
container: ghcr.io/nlohmann/json-ci:v2.0.0
|
||||
strategy:
|
||||
matrix:
|
||||
standard: [11, 14, 17, 20]
|
||||
|
||||
50
README.md
50
README.md
@ -22,7 +22,7 @@
|
||||
|
||||
- [Design goals](#design-goals)
|
||||
- [Sponsors](#sponsors)
|
||||
- [Support](#support) ([documentation](https://json.nlohmann.me), [FAQ](http://127.0.0.1:8000/home/faq/), [discussions](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [bug issues](https://github.com/nlohmann/json/issues))
|
||||
- [Support](#support) ([documentation](https://json.nlohmann.me), [FAQ](https://json.nlohmann.me/home/faq/), [discussions](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [bug issues](https://github.com/nlohmann/json/issues))
|
||||
- [Examples](#examples)
|
||||
- [JSON as first-class data type](#json-as-first-class-data-type)
|
||||
- [Serialization / Deserialization](#serialization--deserialization)
|
||||
@ -1083,36 +1083,38 @@ The following compilers are currently used in continuous integration at [Travis]
|
||||
| Apple Clang 12.0.0 (clang-1200.0.32.27); Xcode 12.2 | macOS 10.15.7 | GitHub Actions |
|
||||
| Apple Clang 12.0.0 (clang-1200.0.32.28); Xcode 12.3 | macOS 10.15.7 | GitHub Actions |
|
||||
| Apple Clang 12.0.0 (clang-1200.0.32.29); Xcode 12.4 | macOS 10.15.7 | GitHub Actions |
|
||||
| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| GCC 4.9.3 (Ubuntu 4.9.3-13ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| GCC 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.12) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu2) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| GCC 4.9.3 (Ubuntu 4.9.3-13ubuntu2) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| GCC 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.12) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| GCC 6.4.0 (Ubuntu 6.4.0-17ubuntu1) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| GCC 6.5.0 (Ubuntu 6.5.0-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis |
|
||||
| GCC 7.5.0 (Ubuntu 7.5.0-6ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| GCC 7.5.0 (Ubuntu 7.5.0-6ubuntu2) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| GCC 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions |
|
||||
| GCC 8.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions |
|
||||
| GCC 8.4.0 (Ubuntu 8.4.0-3ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| 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 8.4.0 (Ubuntu 8.4.0-3ubuntu2) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| GCC 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| GCC 10.2.0 (Ubuntu 10.2.0-5ubuntu1~20.04) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| GCC 11.0.1 20210321 (experimental) | Ubuntu 20.04.3 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 |
|
||||
| Clang 3.8.0 (3.8.0-2ubuntu4) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 3.9.1 (3.9.1-4ubuntu3\~16.04.2) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 4.0.0 (4.0.0-1ubuntu1\~16.04.2) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 5.0.0 (5.0.0-3\~16.04.1) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 6.0.1 (6.0.1-14) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 7.0.1 (7.0.1-12) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 8.0.1 (8.0.1-9) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 9.0.1 (9.0.1-12) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 10.0.0 (10.0.0-4ubuntu1) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 3.5.2 (3.5.2-3ubuntu1) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 3.6.2 (3.6.2-3ubuntu2) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 3.7.1 (3.7.1-2ubuntu2) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 3.8.0 (3.8.0-2ubuntu4) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 3.9.1 (3.9.1-4ubuntu3\~16.04.2) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 4.0.0 (4.0.0-1ubuntu1\~16.04.2) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 5.0.0 (5.0.0-3\~16.04.1) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 6.0.1 (6.0.1-14) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 7.0.1 (7.0.1-12) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 8.0.1 (8.0.1-9) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 9.0.1 (9.0.1-12) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 10.0.0 (10.0.0-4ubuntu1) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 10.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions |
|
||||
| Clang 11.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions |
|
||||
| Clang 11.0.0 with MSVC-like command-line | Windows-10.0.17763 | GitHub Actions |
|
||||
| Clang 11.0.0 (11.0.0-2~ubuntu20.04.1) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 12.0.0 (12.0.0-3ubuntu1~20.04.3) | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 13.0.0 (13.0.0-++20210828094952+9c49fee5e7ac-1exp120210828075752.71 | Ubuntu 20.04.2 LTS | GitHub Actions |
|
||||
| Clang 11.0.0 (11.0.0-2~ubuntu20.04.1) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 12.0.0 (12.0.0-3ubuntu1~20.04.3) | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 13.0.1 (13.0.1-++20211015123032+cf15ccdeb6d5-1~exp1~20211015003613.5 | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Clang 14.0.0 (14.0.0-++20211015062452+81e9c90686f7-1~exp1~20211015063048.20 | Ubuntu 20.04.3 LTS | GitHub Actions |
|
||||
| Visual Studio 14 2015 MSVC 19.0.24241.7 (Build Engine version 14.0.25420.1) | Windows-6.3.9600 | AppVeyor |
|
||||
| Visual Studio 15 2017 MSVC 19.16.27035.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor |
|
||||
| Visual Studio 15 2017 MSVC 19.16.27045.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | GitHub Actions |
|
||||
|
||||
@ -13,12 +13,12 @@ execute_process(COMMAND ${ASTYLE_TOOL} --version OUTPUT_VARIABLE ASTYLE_TOOL_VER
|
||||
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" ASTYLE_TOOL_VERSION "${ASTYLE_TOOL_VERSION}")
|
||||
message(STATUS "🔖 Artistic Style ${ASTYLE_TOOL_VERSION} (${ASTYLE_TOOL})")
|
||||
|
||||
find_program(CLANG_TOOL NAMES clang++-HEAD clang++-13 clang++-12 clang++-11 clang++)
|
||||
find_program(CLANG_TOOL NAMES clang++-HEAD clang++-14 clang++-13 clang++-12 clang++-11 clang++)
|
||||
execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION)
|
||||
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}")
|
||||
message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})")
|
||||
|
||||
find_program(CLANG_TIDY_TOOL NAMES clang-tidy-12 clang-tidy-11 clang-tidy)
|
||||
find_program(CLANG_TIDY_TOOL NAMES clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy)
|
||||
execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION)
|
||||
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TIDY_TOOL_VERSION "${CLANG_TIDY_TOOL_VERSION}")
|
||||
message(STATUS "🔖 Clang-Tidy ${CLANG_TIDY_TOOL_VERSION} (${CLANG_TIDY_TOOL})")
|
||||
@ -79,7 +79,7 @@ message(STATUS "🔖 Valgrind ${VALGRIND_TOOL_VERSION} (${VALGRIND_TOOL})")
|
||||
find_program(GENHTML_TOOL NAMES genhtml)
|
||||
find_program(PLOG_CONVERTER_TOOL NAMES plog-converter)
|
||||
find_program(PVS_STUDIO_ANALYZER_TOOL NAMES pvs-studio-analyzer)
|
||||
find_program(SCAN_BUILD_TOOL NAMES scan-build-12 scan-build-11 scan-build)
|
||||
find_program(SCAN_BUILD_TOOL NAMES scan-build-14 scan-build-13 scan-build-12 scan-build-11 scan-build)
|
||||
|
||||
# the individual source files
|
||||
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp)
|
||||
@ -811,7 +811,7 @@ add_custom_target(ci_cmake_flags
|
||||
# Use more installed compilers.
|
||||
###############################################################################
|
||||
|
||||
foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-7 g++-8 g++-9 g++-10 clang++-3.5 clang++-3.6 clang++-3.7 clang++-3.8 clang++-3.9 clang++-4.0 clang++-5.0 clang++-6.0 clang++-7 clang++-8 clang++-9 clang++-10 clang++-11 clang++-12)
|
||||
foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6 g++-7 g++-8 g++-9 g++-10 clang++-3.5 clang++-3.6 clang++-3.7 clang++-3.8 clang++-3.9 clang++-4.0 clang++-5.0 clang++-6.0 clang++-7 clang++-8 clang++-9 clang++-10 clang++-11 clang++-12 clang++-13)
|
||||
find_program(COMPILER_TOOL NAMES ${COMPILER})
|
||||
if (COMPILER_TOOL)
|
||||
add_custom_target(ci_test_compiler_${COMPILER}
|
||||
|
||||
15
doc/examples/parse__iterator_pair.cpp
Normal file
15
doc/examples/parse__iterator_pair.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a JSON text given an input with other values
|
||||
std::vector<std::uint8_t> input = {'[', '1', ',', '2', ',', '3', ']', 'o', 't', 'h', 'e', 'r'};
|
||||
|
||||
// parse and serialize JSON
|
||||
json j_complete = json::parse(input.begin(), input.begin() + 7);
|
||||
std::cout << std::setw(4) << j_complete << "\n\n";
|
||||
}
|
||||
1
doc/examples/parse__iterator_pair.link
Normal file
1
doc/examples/parse__iterator_pair.link
Normal file
@ -0,0 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/hUJYo1HWmfTBLMGn"><b>online</b></a>
|
||||
6
doc/examples/parse__iterator_pair.output
Normal file
6
doc/examples/parse__iterator_pair.output
Normal file
@ -0,0 +1,6 @@
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
|
||||
15
doc/examples/parse__pointers.cpp
Normal file
15
doc/examples/parse__pointers.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a JSON text given as string that is not null-terminated
|
||||
const char* ptr = "[1,2,3]another value";
|
||||
|
||||
// parse and serialize JSON
|
||||
json j_complete = json::parse(ptr, ptr + 7);
|
||||
std::cout << std::setw(4) << j_complete << "\n\n";
|
||||
}
|
||||
1
doc/examples/parse__pointers.link
Normal file
1
doc/examples/parse__pointers.link
Normal file
@ -0,0 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/AWbpa8e1xRV3y4MM"><b>online</b></a>
|
||||
6
doc/examples/parse__pointers.output
Normal file
6
doc/examples/parse__pointers.output
Normal file
@ -0,0 +1,6 @@
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
|
||||
@ -7,12 +7,17 @@ using json = nlohmann::json;
|
||||
int main()
|
||||
{
|
||||
// create two JSON objects
|
||||
json o1 = R"( {"color": "red", "price": 17.99} )"_json;
|
||||
json o2 = R"( {"color": "blue", "speed": 100} )"_json;
|
||||
json o1 = R"( {"color": "red", "price": 17.99, "names": {"de": "Flugzeug"}} )"_json;
|
||||
json o2 = R"( {"color": "blue", "speed": 100, "names": {"en": "plane"}} )"_json;
|
||||
json o3 = o1;
|
||||
|
||||
// add all keys from o2 to o1 (updating "color")
|
||||
// add all keys from o2 to o1 (updating "color", replacing "names")
|
||||
o1.update(o2);
|
||||
|
||||
// output updated object o1
|
||||
// add all keys from o2 to o1 (updating "color", merging "names")
|
||||
o3.update(o2, true);
|
||||
|
||||
// output updated object o1 and o3
|
||||
std::cout << std::setw(2) << o1 << '\n';
|
||||
std::cout << std::setw(2) << o3 << '\n';
|
||||
}
|
||||
|
||||
@ -1,5 +1,17 @@
|
||||
{
|
||||
"color": "blue",
|
||||
"names": {
|
||||
"en": "plane"
|
||||
},
|
||||
"price": 17.99,
|
||||
"speed": 100
|
||||
}
|
||||
{
|
||||
"color": "blue",
|
||||
"names": {
|
||||
"de": "Flugzeug",
|
||||
"en": "plane"
|
||||
},
|
||||
"price": 17.99,
|
||||
"speed": 100
|
||||
}
|
||||
|
||||
@ -7,12 +7,17 @@ using json = nlohmann::json;
|
||||
int main()
|
||||
{
|
||||
// create two JSON objects
|
||||
json o1 = R"( {"color": "red", "price": 17.99} )"_json;
|
||||
json o2 = R"( {"color": "blue", "speed": 100} )"_json;
|
||||
json o1 = R"( {"color": "red", "price": 17.99, "names": {"de": "Flugzeug"}} )"_json;
|
||||
json o2 = R"( {"color": "blue", "speed": 100, "names": {"en": "plane"}} )"_json;
|
||||
json o3 = o1;
|
||||
|
||||
// add all keys from o2 to o1 (updating "color")
|
||||
// add all keys from o2 to o1 (updating "color", replacing "names")
|
||||
o1.update(o2.begin(), o2.end());
|
||||
|
||||
// output updated object o1
|
||||
// add all keys from o2 to o1 (updating "color", merging "names")
|
||||
o3.update(o2.begin(), o2.end(), true);
|
||||
|
||||
// output updated object o1 and o3
|
||||
std::cout << std::setw(2) << o1 << '\n';
|
||||
std::cout << std::setw(2) << o3 << '\n';
|
||||
}
|
||||
|
||||
@ -1,5 +1,17 @@
|
||||
{
|
||||
"color": "blue",
|
||||
"names": {
|
||||
"en": "plane"
|
||||
},
|
||||
"price": 17.99,
|
||||
"speed": 100
|
||||
}
|
||||
{
|
||||
"color": "blue",
|
||||
"names": {
|
||||
"de": "Flugzeug",
|
||||
"en": "plane"
|
||||
},
|
||||
"price": 17.99,
|
||||
"speed": 100
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ type `#!cpp binary_t*` must be dereferenced.
|
||||
- MessagePack
|
||||
- If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1,
|
||||
fixext2, fixext4, fixext8) is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The subtype is
|
||||
then added as singed 8-bit integer.
|
||||
then added as signed 8-bit integer.
|
||||
- If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
|
||||
- BSON
|
||||
|
||||
@ -68,7 +68,7 @@ void erase(const size_type idx);
|
||||
- Throws [`invalid_iterator.205`](../../home/exceptions.md#jsonexceptioninvalid_iterator205) if called on a
|
||||
primitive type with invalid iterator (i.e., any iterator which is not `begin()`); example: `"iterator out of
|
||||
range"`
|
||||
2. The function can throw thw following exceptions:
|
||||
2. The function can throw the following exceptions:
|
||||
- Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) if called on a `null` value;
|
||||
example: `"cannot use erase() with null"`
|
||||
- Throws [`invalid_iterator.203`](../../home/exceptions.md#jsonexceptioninvalid_iterator203) if called on iterators
|
||||
@ -76,10 +76,10 @@ void erase(const size_type idx);
|
||||
- Throws [`invalid_iterator.204`](../../home/exceptions.md#jsonexceptioninvalid_iterator204) if called on a
|
||||
primitive type with invalid iterators (i.e., if `first != begin()` and `last != end()`); example: `"iterators out
|
||||
of range"`
|
||||
3. The function can throw thw following exceptions:
|
||||
3. The function can throw the following exceptions:
|
||||
- Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) when called on a type other than
|
||||
JSON object; example: `"cannot use erase() with null"`
|
||||
4. The function can throw thw following exceptions:
|
||||
4. The function can throw the following exceptions:
|
||||
- Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) when called on a type other than
|
||||
JSON object; example: `"cannot use erase() with null"`
|
||||
- Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) when `idx >= size()`; example:
|
||||
|
||||
@ -59,12 +59,12 @@ void insert(const_iterator first, const_iterator last);
|
||||
arrays; example: `"cannot use insert() with string"`
|
||||
- Throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) if called on an
|
||||
iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"`
|
||||
2. The function can throw thw following exceptions:
|
||||
2. The function can throw the following exceptions:
|
||||
- Throws [`type_error.309`](../../home/exceptions.md#jsonexceptiontype_error309) if called on JSON values other than
|
||||
arrays; example: `"cannot use insert() with string"`
|
||||
- Throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) if called on an
|
||||
iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"`
|
||||
3. The function can throw thw following exceptions:
|
||||
3. The function can throw the following exceptions:
|
||||
- Throws [`type_error.309`](../../home/exceptions.md#jsonexceptiontype_error309) if called on JSON values other than
|
||||
arrays; example: `"cannot use insert() with string"`
|
||||
- Throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) if called on an
|
||||
@ -73,12 +73,12 @@ void insert(const_iterator first, const_iterator last);
|
||||
do not belong to the same JSON value; example: `"iterators do not fit"`
|
||||
- Throws [`invalid_iterator.211`](../../home/exceptions.md#jsonexceptioninvalid_iterator211) if `first` or `last`
|
||||
are iterators into container for which insert is called; example: `"passed iterators may not belong to container"`
|
||||
4. The function can throw thw following exceptions:
|
||||
4. The function can throw the following exceptions:
|
||||
- Throws [`type_error.309`](../../home/exceptions.md#jsonexceptiontype_error309) if called on JSON values other than
|
||||
arrays; example: `"cannot use insert() with string"`
|
||||
- Throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) if called on an
|
||||
iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"`
|
||||
5. The function can throw thw following exceptions:
|
||||
5. The function can throw the following exceptions:
|
||||
- Throws [`type_error.309`](../../home/exceptions.md#jsonexceptiontype_error309) if called on JSON values other than
|
||||
objects; example: `"cannot use insert() with string"`
|
||||
- Throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) if called on an
|
||||
|
||||
@ -65,7 +65,7 @@ When iterating over an array, `key()` will return the index of the element as st
|
||||
|
||||
!!! warning
|
||||
|
||||
Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exeeds the iteration. See
|
||||
Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exceeds the iteration. See
|
||||
<https://github.com/nlohmann/json/issues/2040> for more information.
|
||||
|
||||
## Example
|
||||
|
||||
@ -33,7 +33,7 @@ const_reference operator[](const json_pointer& ptr) const;
|
||||
: index of the element to access
|
||||
|
||||
`key` (in)
|
||||
: object key of the elements to remove
|
||||
: object key of the element to access
|
||||
|
||||
`ptr` (in)
|
||||
: JSON pointer to the desired element
|
||||
@ -48,10 +48,10 @@ const_reference operator[](const json_pointer& ptr) const;
|
||||
|
||||
1. The function can throw the following exceptions:
|
||||
- Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if the JSON value is not an array
|
||||
or null; in that cases, using the `[]` operator with an index makes no sense.
|
||||
or null; in that case, using the `[]` operator with an index makes no sense.
|
||||
2. The function can throw the following exceptions:
|
||||
- Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if the JSON value is not an array
|
||||
or null; in that cases, using the `[]` operator with an index makes no sense.
|
||||
- Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if the JSON value is not an object
|
||||
or null; in that case, using the `[]` operator with a key makes no sense.
|
||||
3. The function can throw the following exceptions:
|
||||
- Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index in the passed
|
||||
JSON pointer `ptr` begins with '0'.
|
||||
|
||||
@ -19,7 +19,7 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
1. Deserialize from a compatible input.
|
||||
2. Deserialize from a pair of character iterators
|
||||
|
||||
The value_type of the iterator must be a integral type with size of 1, 2 or 4 bytes, which will be interpreted
|
||||
The `value_type` of the iterator must be an integral type with size of 1, 2 or 4 bytes, which will be interpreted
|
||||
respectively as UTF-8, UTF-16 and UTF-32.
|
||||
|
||||
## Template parameters
|
||||
@ -34,7 +34,10 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
: a compatible iterator type, for instance.
|
||||
|
||||
- a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator`
|
||||
- a pair of pointers such as `ptr` and `ptr + len`
|
||||
|
||||
## Parameters
|
||||
|
||||
@ -135,6 +138,34 @@ super-linear complexity.
|
||||
--8<-- "examples/parse__contiguouscontainer__parser_callback_t.output"
|
||||
```
|
||||
|
||||
??? example "Parsing from a non null-terminated string"
|
||||
|
||||
The example below demonstrates the `parse()` function reading from a string that is not null-terminated.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/parse__pointers.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/parse__pointers.output"
|
||||
```
|
||||
|
||||
??? example "Parsing from an iterator pair"
|
||||
|
||||
The example below demonstrates the `parse()` function reading from an iterator pair.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/parse__iterator_pair.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/parse__iterator_pair.output"
|
||||
```
|
||||
|
||||
??? example "Effect of `allow_exceptions` parameter"
|
||||
|
||||
The example below demonstrates the effect of the `allow_exceptions` parameter in the ´parse()` function.
|
||||
|
||||
@ -2,14 +2,17 @@
|
||||
|
||||
```cpp
|
||||
// (1)
|
||||
void update(const_reference j);
|
||||
void update(const_reference j, bool merge_objects = false);
|
||||
|
||||
// (2)
|
||||
void update(const_iterator first, const_iterator last);
|
||||
void update(const_iterator first, const_iterator last, bool merge_objects = false);
|
||||
```
|
||||
|
||||
1. Inserts all values from JSON object `j` and overwrites existing keys.
|
||||
2. Inserts all values from from range `[first, last)` and overwrites existing keys.
|
||||
1. Inserts all values from JSON object `j`.
|
||||
2. Inserts all values from from range `[first, last)`
|
||||
|
||||
When `merge_objects` is `#!c false` (default), existing keys are overwritten. When `merge_objects` is `#!c true`,
|
||||
recursively merges objects with common keys.
|
||||
|
||||
The function is motivated by Python's [dict.update](https://docs.python.org/3.6/library/stdtypes.html#dict.update)
|
||||
function.
|
||||
@ -19,6 +22,10 @@ function.
|
||||
`j` (in)
|
||||
: JSON object to read values from
|
||||
|
||||
`merge_objects` (in)
|
||||
: when `#!c true`, existing keys are not overwritten, but contents of objects are merged recursively (default:
|
||||
`#!c false`)
|
||||
|
||||
`first` (in)
|
||||
: begin of the range of elements to insert
|
||||
|
||||
@ -30,7 +37,7 @@ function.
|
||||
1. The function can throw the following exceptions:
|
||||
- Throws [`type_error.312`](../../home/exceptions.md#jsonexceptiontype_error312) if called on JSON values other than
|
||||
objects; example: `"cannot use update() with string"`
|
||||
2. The function can throw thw following exceptions:
|
||||
2. The function can throw the following exceptions:
|
||||
- Throws [`type_error.312`](../../home/exceptions.md#jsonexceptiontype_error312) if called on JSON values other than
|
||||
objects; example: `"cannot use update() with string"`
|
||||
- Throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) if called on an
|
||||
@ -73,6 +80,63 @@ function.
|
||||
--8<-- "examples/update__range.output"
|
||||
```
|
||||
|
||||
??? example
|
||||
|
||||
One common usecase for this function is the handling of user settings. Assume your application can configured in
|
||||
some aspects:
|
||||
|
||||
```json
|
||||
{
|
||||
"color": "red",
|
||||
"active": true,
|
||||
"name": {"de": "Maus", "en": "mouse"}
|
||||
}
|
||||
```
|
||||
|
||||
The user may override the default settings selectively:
|
||||
|
||||
```json
|
||||
{
|
||||
"color": "blue",
|
||||
"name": {"es": "ratón"},
|
||||
}
|
||||
```
|
||||
|
||||
Then `update` manages the merging of default settings and user settings:
|
||||
|
||||
```cpp
|
||||
auto user_settings = json::parse("config.json");
|
||||
auto effective_settings = get_default_settings();
|
||||
effective_settings.update(user_settings);
|
||||
```
|
||||
|
||||
Now `effective_settings` contains the default settings, but those keys set by the user are overwritten:
|
||||
|
||||
```json
|
||||
{
|
||||
"color": "blue",
|
||||
"active": true,
|
||||
"name": {"es": "ratón"}
|
||||
}
|
||||
```
|
||||
|
||||
Note existing keys were just overwritten. To merge objects, `merge_objects` setting should be set to `#!c true`:
|
||||
|
||||
```cpp
|
||||
auto user_settings = json::parse("config.json");
|
||||
auto effective_settings = get_default_settings();
|
||||
effective_settings.update(user_settings, true);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"color": "blue",
|
||||
"active": true,
|
||||
"name": {"de": "Maus", "en": "mouse", "es": "ratón"}
|
||||
}
|
||||
```
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.0.0.
|
||||
- Added `merge_objects` parameter in 3.10.4.
|
||||
|
||||
@ -69,12 +69,12 @@ changes to any JSON value.
|
||||
|
||||
## Exceptions
|
||||
|
||||
1. The function can throw thw following exceptions:
|
||||
1. The function can throw the following exceptions:
|
||||
- Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `default_value` does not match
|
||||
the type of the value at `key`
|
||||
- Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if the JSON value is not an object;
|
||||
in that case, using `value()` with a key makes no sense.
|
||||
2. The function can throw thw following exceptions:
|
||||
2. The function can throw the following exceptions:
|
||||
- Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `default_value` does not match
|
||||
the type of the value at `ptr`
|
||||
- Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if the JSON value is not an object;
|
||||
|
||||
@ -198,7 +198,7 @@ JSON does not have a binary type, and this library does not introduce a new type
|
||||
|
||||
### MessagePack
|
||||
|
||||
[MessagePack](binary_formats/messagepack.md) supports binary values and subtypes. If a subtype is given, the ext family is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, ext8, ext16, and ext32. The subtype is then added as singed 8-bit integer.
|
||||
[MessagePack](binary_formats/messagepack.md) supports binary values and subtypes. If a subtype is given, the ext family is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, ext8, ext16, and ext32. The subtype is then added as signed 8-bit integer.
|
||||
|
||||
If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
|
||||
@ -282,7 +282,7 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
0x23 0x69 0x01 // '#' i 1 number of object elements
|
||||
0x69 0x06 // i 6 (length of the key)
|
||||
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
||||
0x24 0x55 // '$' 'U' type of the array elements: unsinged integers
|
||||
0x24 0x55 // '$' 'U' type of the array elements: unsigned integers
|
||||
0x23 0x69 0x04 // '#' i 4 number of array elements
|
||||
0xCA 0xFE 0xBA 0xBE // content
|
||||
```
|
||||
|
||||
@ -25,7 +25,7 @@ However, you can pass set parameter `ignore_comments` to `#!c true` in the parse
|
||||
}
|
||||
```
|
||||
|
||||
When calling `parse` without additional argument, a parse error exception is thrown. If `skip_comments` is set to `#! true`, the comments are skipped during parsing:
|
||||
When calling `parse` without additional argument, a parse error exception is thrown. If `ignore_comments` is set to `#! true`, the comments are ignored during parsing:
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
@ -55,7 +55,7 @@ However, you can pass set parameter `ignore_comments` to `#!c true` in the parse
|
||||
json j = json::parse(s,
|
||||
/* callback */ nullptr,
|
||||
/* allow exceptions */ true,
|
||||
/* skip_comments */ true);
|
||||
/* ignore_comments */ true);
|
||||
std::cout << j.dump(2) << '\n';
|
||||
}
|
||||
```
|
||||
@ -80,4 +80,4 @@ However, you can pass set parameter `ignore_comments` to `#!c true` in the parse
|
||||
"Neptune"
|
||||
]
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@ -100,7 +100,7 @@ for (auto& [key, val] : j_object.items())
|
||||
|
||||
!!! warning
|
||||
|
||||
Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exeeds the iteration. See <https://github.com/nlohmann/json/issues/2040> for more information.
|
||||
Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exceeds the iteration. See <https://github.com/nlohmann/json/issues/2040> for more information.
|
||||
|
||||
### Reverse iteration order
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@ That is, `-0` is stored as a signed integer, but the serialization does not repr
|
||||
- The serialization can be in scientific notation even if the input is not: `#!c 0.0000972439793401814` will be
|
||||
serialized as `#!c 9.72439793401814e-05`. The reverse can also be true: `#!c 12345E-5` will be serialized as
|
||||
`#!c 0.12345`.
|
||||
- Conversions from `#!c float` to `#!c double` can also introduce rouding errors:
|
||||
- Conversions from `#!c float` to `#!c double` can also introduce rounding errors:
|
||||
```cpp
|
||||
float f = 0.3;
|
||||
json j = f;
|
||||
|
||||
@ -177,7 +177,7 @@ This error indicates a syntax error while deserializing a JSON text. The error m
|
||||
|
||||
!!! tip
|
||||
|
||||
- Make sure the input is correctly read. Try to write the input to standard output to check if, for instance, the input file was successfully openened.
|
||||
- Make sure the input is correctly read. Try to write the input to standard output to check if, for instance, the input file was successfully opened.
|
||||
- Paste the input to a JSON validator like <http://jsonlint.com> or a tool like [jq](https://stedolan.github.io/jq/).
|
||||
|
||||
### json.exception.parse_error.102
|
||||
|
||||
@ -468,7 +468,7 @@ This release further fixes several bugs in the library. All changes are backward
|
||||
- allow compare user-defined string types (#1130)
|
||||
- better support for algorithms using iterators from `items()` (#1045, #1134)
|
||||
- added parameter to avoid compilation error with MSVC 2015 debug builds (#1114)
|
||||
- re-added accidentially skipped unit tests (#1176)
|
||||
- re-added accidentally skipped unit tests (#1176)
|
||||
- fixed MSVC issue with `std::swap` (#1168)
|
||||
|
||||
### :zap: Improvements
|
||||
@ -1008,7 +1008,7 @@ This release fixes a few bugs in the JSON parser found in the [Parsing JSON is a
|
||||
This release fixes the semantics of `operator[]` for JSON Pointers (see below). This fix is backwards compatible.
|
||||
|
||||
### Changes
|
||||
- **`operator[]` for JSON Pointers** now behaves like the other versions of `operator[]` and transforms `null` values into objects or arrays if required. This allows to created nested structues like `j["/foo/bar/2"] = 17` (yielding `{"foo": "bar": [null, null, 17]}`) without problems.
|
||||
- **`operator[]` for JSON Pointers** now behaves like the other versions of `operator[]` and transforms `null` values into objects or arrays if required. This allows to created nested structures like `j["/foo/bar/2"] = 17` (yielding `{"foo": "bar": [null, null, 17]}`) without problems.
|
||||
- overworked a helper SFINAE function
|
||||
- fixed some documentation issues
|
||||
- fixed the CMake files to allow to run the test suite outside the main project directory
|
||||
@ -1093,7 +1093,7 @@ This release combines a lot of small fixes and improvements. The release is back
|
||||
### Changes
|
||||
- The **parser** has been overworked, and a lot of small issues have been fixed:
|
||||
- Improved parser performance by avoiding recursion and using move semantics for the return value.
|
||||
- Unescaped control charaters `\x10`-`\x1f` are not accepted any more.
|
||||
- Unescaped control characters `\x10`-`\x1f` are not accepted any more.
|
||||
- Fixed a bug in the parser when reading from an input stream.
|
||||
- Improved test case coverage for UTF-8 parsing: now, all valid Unicode code points are tested both escaped and unescaped.
|
||||
- The precision of output streams is now preserved by the parser.
|
||||
|
||||
@ -60,7 +60,7 @@ class exception : public std::exception
|
||||
|
||||
protected:
|
||||
JSON_HEDLEY_NON_NULL(3)
|
||||
exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}
|
||||
exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
|
||||
|
||||
static std::string name(const std::string& ename, int id_)
|
||||
{
|
||||
@ -198,7 +198,7 @@ class parse_error : public exception
|
||||
{
|
||||
std::string w = exception::name("parse_error", id_) + "parse error" +
|
||||
position_string(pos) + ": " + exception::diagnostics(context) + what_arg;
|
||||
return parse_error(id_, pos.chars_read_total, w.c_str());
|
||||
return {id_, pos.chars_read_total, w.c_str()};
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
@ -207,7 +207,7 @@ class parse_error : public exception
|
||||
std::string w = exception::name("parse_error", id_) + "parse error" +
|
||||
(byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") +
|
||||
": " + exception::diagnostics(context) + what_arg;
|
||||
return parse_error(id_, byte_, w.c_str());
|
||||
return {id_, byte_, w.c_str()};
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -276,7 +276,7 @@ class invalid_iterator : public exception
|
||||
static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context)
|
||||
{
|
||||
std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg;
|
||||
return invalid_iterator(id_, w.c_str());
|
||||
return {id_, w.c_str()};
|
||||
}
|
||||
|
||||
private:
|
||||
@ -331,7 +331,7 @@ class type_error : public exception
|
||||
static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context)
|
||||
{
|
||||
std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg;
|
||||
return type_error(id_, w.c_str());
|
||||
return {id_, w.c_str()};
|
||||
}
|
||||
|
||||
private:
|
||||
@ -379,7 +379,7 @@ class out_of_range : public exception
|
||||
static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context)
|
||||
{
|
||||
std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg;
|
||||
return out_of_range(id_, w.c_str());
|
||||
return {id_, w.c_str()};
|
||||
}
|
||||
|
||||
private:
|
||||
@ -418,7 +418,7 @@ class other_error : public exception
|
||||
static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context)
|
||||
{
|
||||
std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg;
|
||||
return other_error(id_, w.c_str());
|
||||
return {id_, w.c_str()};
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@ -42,7 +42,7 @@ enum class cbor_tag_handler_t
|
||||
|
||||
@note from https://stackoverflow.com/a/1001328/266378
|
||||
*/
|
||||
static inline bool little_endianess(int num = 1) noexcept
|
||||
static inline bool little_endianness(int num = 1) noexcept
|
||||
{
|
||||
return *reinterpret_cast<char*>(&num) == 1;
|
||||
}
|
||||
@ -2341,7 +2341,7 @@ class binary_reader
|
||||
|
||||
@return whether conversion completed
|
||||
|
||||
@note This function needs to respect the system's endianess, because
|
||||
@note This function needs to respect the system's endianness, because
|
||||
bytes in CBOR, MessagePack, and UBJSON are stored in network order
|
||||
(big endian) and therefore need reordering on little endian systems.
|
||||
*/
|
||||
@ -2514,8 +2514,8 @@ class binary_reader
|
||||
/// the number of characters read
|
||||
std::size_t chars_read = 0;
|
||||
|
||||
/// whether we can assume little endianess
|
||||
const bool is_little_endian = little_endianess();
|
||||
/// whether we can assume little endianness
|
||||
const bool is_little_endian = little_endianness();
|
||||
|
||||
/// the SAX parser
|
||||
json_sax_t* sax = nullptr;
|
||||
|
||||
@ -450,7 +450,7 @@ auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) /
|
||||
}
|
||||
|
||||
// This class only handles inputs of input_buffer_adapter type.
|
||||
// It's required so that expressions like {ptr, len} can be implicitely casted
|
||||
// It's required so that expressions like {ptr, len} can be implicitly casted
|
||||
// to the correct adapter.
|
||||
class span_input_adapter
|
||||
{
|
||||
|
||||
@ -36,7 +36,7 @@ This class implements a both iterators (iterator and const_iterator) for the
|
||||
iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
class iter_impl
|
||||
class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||
{
|
||||
/// the iterator with BasicJsonType of different const-ness
|
||||
using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
|
||||
|
||||
@ -1535,7 +1535,7 @@ class binary_writer
|
||||
@tparam OutputIsLittleEndian Set to true if output data is
|
||||
required to be little endian
|
||||
|
||||
@note This function needs to respect the system's endianess, because bytes
|
||||
@note This function needs to respect the system's endianness, because bytes
|
||||
in CBOR, MessagePack, and UBJSON are stored in network order (big
|
||||
endian) and therefore need reordering on little endian systems.
|
||||
*/
|
||||
@ -1625,8 +1625,8 @@ class binary_writer
|
||||
}
|
||||
|
||||
private:
|
||||
/// whether we can assume little endianess
|
||||
const bool is_little_endian = little_endianess();
|
||||
/// whether we can assume little endianness
|
||||
const bool is_little_endian = little_endianness();
|
||||
|
||||
/// the output
|
||||
output_adapter_t<CharType> oa = nullptr;
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
#include <cstdio> // snprintf
|
||||
#include <limits> // numeric_limits
|
||||
#include <string> // string, char_traits
|
||||
#include <iomanip> // setfill, setw
|
||||
#include <sstream> // stringstream
|
||||
#include <type_traits> // is_same
|
||||
#include <utility> // move
|
||||
|
||||
@ -499,10 +501,9 @@ class serializer
|
||||
{
|
||||
case error_handler_t::strict:
|
||||
{
|
||||
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()));
|
||||
std::stringstream ss;
|
||||
ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex << (byte | 0);
|
||||
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str(), BasicJsonType()));
|
||||
}
|
||||
|
||||
case error_handler_t::ignore:
|
||||
@ -594,10 +595,9 @@ class serializer
|
||||
{
|
||||
case error_handler_t::strict:
|
||||
{
|
||||
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()));
|
||||
std::stringstream ss;
|
||||
ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex << (static_cast<std::uint8_t>(s.back()) | 0);
|
||||
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str(), BasicJsonType()));
|
||||
}
|
||||
|
||||
case error_handler_t::ignore:
|
||||
|
||||
@ -908,7 +908,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
- If a subtype is given and the binary array contains exactly 1, 2, 4, 8,
|
||||
or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8)
|
||||
is used. For other sizes, the ext family (ext8, ext16, ext32) is used.
|
||||
The subtype is then added as singed 8-bit integer.
|
||||
The subtype is then added as signed 8-bit integer.
|
||||
- If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
- BSON
|
||||
- If a subtype is given, it is used and added as unsigned 8-bit integer.
|
||||
@ -1073,64 +1073,34 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
/// constructor for strings
|
||||
json_value(const string_t& value)
|
||||
{
|
||||
string = create<string_t>(value);
|
||||
}
|
||||
json_value(const string_t& value) : string(create<string_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue strings
|
||||
json_value(string_t&& value)
|
||||
{
|
||||
string = create<string_t>(std::move(value));
|
||||
}
|
||||
json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
|
||||
|
||||
/// constructor for objects
|
||||
json_value(const object_t& value)
|
||||
{
|
||||
object = create<object_t>(value);
|
||||
}
|
||||
json_value(const object_t& value) : object(create<object_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue objects
|
||||
json_value(object_t&& value)
|
||||
{
|
||||
object = create<object_t>(std::move(value));
|
||||
}
|
||||
json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
|
||||
|
||||
/// constructor for arrays
|
||||
json_value(const array_t& value)
|
||||
{
|
||||
array = create<array_t>(value);
|
||||
}
|
||||
json_value(const array_t& value) : array(create<array_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue arrays
|
||||
json_value(array_t&& value)
|
||||
{
|
||||
array = create<array_t>(std::move(value));
|
||||
}
|
||||
json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
|
||||
|
||||
/// constructor for binary arrays
|
||||
json_value(const typename binary_t::container_type& value)
|
||||
{
|
||||
binary = create<binary_t>(value);
|
||||
}
|
||||
json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue binary arrays
|
||||
json_value(typename binary_t::container_type&& value)
|
||||
{
|
||||
binary = create<binary_t>(std::move(value));
|
||||
}
|
||||
json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
|
||||
|
||||
/// constructor for binary arrays (internal type)
|
||||
json_value(const binary_t& value)
|
||||
{
|
||||
binary = create<binary_t>(value);
|
||||
}
|
||||
json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue binary arrays (internal type)
|
||||
json_value(binary_t&& value)
|
||||
{
|
||||
binary = create<binary_t>(std::move(value));
|
||||
}
|
||||
json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
|
||||
|
||||
void destroy(value_t t)
|
||||
{
|
||||
@ -5051,7 +5021,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
`key()` returns an empty string.
|
||||
|
||||
@warning Using `items()` on temporary objects is dangerous. Make sure the
|
||||
object's lifetime exeeds the iteration. See
|
||||
object's lifetime exceeds the iteration. See
|
||||
<https://github.com/nlohmann/json/issues/2040> for more
|
||||
information.
|
||||
|
||||
@ -5984,6 +5954,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
Inserts all values from JSON object @a j and overwrites existing keys.
|
||||
|
||||
@param[in] j JSON object to read values from
|
||||
@param[in] merge_objects when true, existing keys are not overwritten, but
|
||||
contents of objects are merged recursively
|
||||
(default: false)
|
||||
|
||||
@throw type_error.312 if called on JSON values other than objects; example:
|
||||
`"cannot use update() with string"`
|
||||
@ -5995,34 +5968,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
@sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
|
||||
|
||||
@since version 3.0.0
|
||||
@since version 3.0.0, `merge_objects` parameter added in 3.10.4.
|
||||
*/
|
||||
void update(const_reference j)
|
||||
void update(const_reference j, bool merge_objects = false)
|
||||
{
|
||||
// implicitly convert null value to an empty object
|
||||
if (is_null())
|
||||
{
|
||||
m_type = value_t::object;
|
||||
m_value.object = create<object_t>();
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this));
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()), *this));
|
||||
}
|
||||
|
||||
for (auto it = j.cbegin(); it != j.cend(); ++it)
|
||||
{
|
||||
m_value.object->operator[](it.key()) = it.value();
|
||||
#if JSON_DIAGNOSTICS
|
||||
m_value.object->operator[](it.key()).m_parent = this;
|
||||
#endif
|
||||
}
|
||||
update(j.begin(), j.end(), merge_objects);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -6033,12 +5983,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
@param[in] first begin of the range of elements to insert
|
||||
@param[in] last end of the range of elements to insert
|
||||
@param[in] merge_objects when true, existing keys are not overwritten, but
|
||||
contents of objects are merged recursively
|
||||
(default: false)
|
||||
|
||||
@throw type_error.312 if called on JSON values other than objects; example:
|
||||
`"cannot use update() with string"`
|
||||
@throw invalid_iterator.202 if iterator @a first or @a last does does not
|
||||
point to an object; example: `"iterators first and last must point to
|
||||
objects"`
|
||||
@throw type_error.312 if iterator @a first or @a last does does not
|
||||
point to an object; example: `"cannot use update() with string"`
|
||||
@throw invalid_iterator.210 if @a first and @a last do not belong to the
|
||||
same JSON value; example: `"iterators do not fit"`
|
||||
|
||||
@ -6049,9 +6001,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
@sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
|
||||
|
||||
@since version 3.0.0
|
||||
@since version 3.0.0, `merge_objects` parameter added in 3.10.4.
|
||||
*/
|
||||
void update(const_iterator first, const_iterator last)
|
||||
void update(const_iterator first, const_iterator last, bool merge_objects = false)
|
||||
{
|
||||
// implicitly convert null value to an empty object
|
||||
if (is_null())
|
||||
@ -6073,14 +6025,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// passed iterators must belong to objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()
|
||||
|| !last.m_object->is_object()))
|
||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
||||
{
|
||||
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this));
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(first.m_object->type_name()), *first.m_object));
|
||||
}
|
||||
|
||||
for (auto it = first; it != last; ++it)
|
||||
{
|
||||
if (merge_objects && it.value().is_object())
|
||||
{
|
||||
auto it2 = m_value.object->find(it.key());
|
||||
if (it2 != m_value.object->end())
|
||||
{
|
||||
it2->second.update(it.value(), true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
m_value.object->operator[](it.key()) = it.value();
|
||||
#if JSON_DIAGNOSTICS
|
||||
m_value.object->operator[](it.key()).m_parent = this;
|
||||
@ -8976,20 +8936,19 @@ std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
|
||||
// nonmember support //
|
||||
///////////////////////
|
||||
|
||||
// specialization of std::swap, and std::hash
|
||||
namespace std
|
||||
namespace std // NOLINT(cert-dcl58-cpp)
|
||||
{
|
||||
|
||||
/// hash value for JSON objects
|
||||
template<>
|
||||
struct hash<nlohmann::json>
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL>
|
||||
{
|
||||
/*!
|
||||
@brief return a hash value for a JSON object
|
||||
|
||||
@since version 1.0.0
|
||||
@since version 1.0.0, extended for arbitrary basic_json types in 3.10.5.
|
||||
*/
|
||||
std::size_t operator()(const nlohmann::json& j) const
|
||||
std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
|
||||
{
|
||||
return nlohmann::detail::hash(j);
|
||||
}
|
||||
@ -8999,7 +8958,7 @@ struct hash<nlohmann::json>
|
||||
/// @note: do not remove the space after '<',
|
||||
/// see https://github.com/nlohmann/json/pull/679
|
||||
template<>
|
||||
struct less<::nlohmann::detail::value_t>
|
||||
struct less< ::nlohmann::detail::value_t>
|
||||
{
|
||||
/*!
|
||||
@brief compare two value_t enum values
|
||||
@ -9018,13 +8977,12 @@ struct less<::nlohmann::detail::value_t>
|
||||
/*!
|
||||
@brief exchanges the values of two JSON objects
|
||||
|
||||
@since version 1.0.0
|
||||
@since version 1.0.0, extended for arbitrary basic_json types in 3.10.5.
|
||||
*/
|
||||
template<>
|
||||
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name)
|
||||
is_nothrow_move_constructible<nlohmann::json>::value&& // NOLINT(misc-redundant-expression)
|
||||
is_nothrow_move_assignable<nlohmann::json>::value
|
||||
)
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name)
|
||||
is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression)
|
||||
is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
|
||||
{
|
||||
j1.swap(j2);
|
||||
}
|
||||
|
||||
@ -107,16 +107,55 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
||||
|
||||
iterator erase(iterator pos)
|
||||
{
|
||||
auto it = pos;
|
||||
return erase(pos, std::next(pos));
|
||||
}
|
||||
|
||||
// Since we cannot move const Keys, re-construct them in place
|
||||
for (auto next = it; ++next != this->end(); ++it)
|
||||
iterator erase(iterator first, iterator last)
|
||||
{
|
||||
const auto elements_affected = std::distance(first, last);
|
||||
const auto offset = std::distance(Container::begin(), first);
|
||||
|
||||
// This is the start situation. We need to delete elements_affected
|
||||
// elements (3 in this example: e, f, g), and need to return an
|
||||
// iterator past the last deleted element (h in this example).
|
||||
// Note that offset is the distance from the start of the vector
|
||||
// to first. We will need this later.
|
||||
|
||||
// [ a, b, c, d, e, f, g, h, i, j ]
|
||||
// ^ ^
|
||||
// first last
|
||||
|
||||
// Since we cannot move const Keys, we re-construct them in place.
|
||||
// We start at first and re-construct (viz. copy) the elements from
|
||||
// the back of the vector. Example for first iteration:
|
||||
|
||||
// ,--------.
|
||||
// v | destroy e and re-construct with h
|
||||
// [ a, b, c, d, e, f, g, h, i, j ]
|
||||
// ^ ^
|
||||
// it it + elements_affected
|
||||
|
||||
for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
|
||||
{
|
||||
it->~value_type(); // Destroy but keep allocation
|
||||
new (&*it) value_type{std::move(*next)};
|
||||
it->~value_type(); // destroy but keep allocation
|
||||
new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
|
||||
}
|
||||
Container::pop_back();
|
||||
return pos;
|
||||
|
||||
// [ a, b, c, d, h, i, j, h, i, j ]
|
||||
// ^ ^
|
||||
// first last
|
||||
|
||||
// remove the unneeded elements at the end of the vector
|
||||
Container::resize(this->size() - static_cast<size_type>(elements_affected));
|
||||
|
||||
// [ a, b, c, d, h, i, j ]
|
||||
// ^ ^
|
||||
// first last
|
||||
|
||||
// first is now pointing past the last deleted element, but we cannot
|
||||
// use this iterator, because it may have been invalidated by the
|
||||
// resize call. Instead, we can return begin() + offset.
|
||||
return Container::begin() + offset;
|
||||
}
|
||||
|
||||
size_type count(const Key& key) const
|
||||
|
||||
@ -2836,7 +2836,7 @@ class exception : public std::exception
|
||||
|
||||
protected:
|
||||
JSON_HEDLEY_NON_NULL(3)
|
||||
exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}
|
||||
exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
|
||||
|
||||
static std::string name(const std::string& ename, int id_)
|
||||
{
|
||||
@ -2974,7 +2974,7 @@ class parse_error : public exception
|
||||
{
|
||||
std::string w = exception::name("parse_error", id_) + "parse error" +
|
||||
position_string(pos) + ": " + exception::diagnostics(context) + what_arg;
|
||||
return parse_error(id_, pos.chars_read_total, w.c_str());
|
||||
return {id_, pos.chars_read_total, w.c_str()};
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
@ -2983,7 +2983,7 @@ class parse_error : public exception
|
||||
std::string w = exception::name("parse_error", id_) + "parse error" +
|
||||
(byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") +
|
||||
": " + exception::diagnostics(context) + what_arg;
|
||||
return parse_error(id_, byte_, w.c_str());
|
||||
return {id_, byte_, w.c_str()};
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -3052,7 +3052,7 @@ class invalid_iterator : public exception
|
||||
static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context)
|
||||
{
|
||||
std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg;
|
||||
return invalid_iterator(id_, w.c_str());
|
||||
return {id_, w.c_str()};
|
||||
}
|
||||
|
||||
private:
|
||||
@ -3107,7 +3107,7 @@ class type_error : public exception
|
||||
static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context)
|
||||
{
|
||||
std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg;
|
||||
return type_error(id_, w.c_str());
|
||||
return {id_, w.c_str()};
|
||||
}
|
||||
|
||||
private:
|
||||
@ -3155,7 +3155,7 @@ class out_of_range : public exception
|
||||
static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context)
|
||||
{
|
||||
std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg;
|
||||
return out_of_range(id_, w.c_str());
|
||||
return {id_, w.c_str()};
|
||||
}
|
||||
|
||||
private:
|
||||
@ -3194,7 +3194,7 @@ class other_error : public exception
|
||||
static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context)
|
||||
{
|
||||
std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg;
|
||||
return other_error(id_, w.c_str());
|
||||
return {id_, w.c_str()};
|
||||
}
|
||||
|
||||
private:
|
||||
@ -5955,7 +5955,7 @@ auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) /
|
||||
}
|
||||
|
||||
// This class only handles inputs of input_buffer_adapter type.
|
||||
// It's required so that expressions like {ptr, len} can be implicitely casted
|
||||
// It's required so that expressions like {ptr, len} can be implicitly casted
|
||||
// to the correct adapter.
|
||||
class span_input_adapter
|
||||
{
|
||||
@ -8510,7 +8510,7 @@ enum class cbor_tag_handler_t
|
||||
|
||||
@note from https://stackoverflow.com/a/1001328/266378
|
||||
*/
|
||||
static inline bool little_endianess(int num = 1) noexcept
|
||||
static inline bool little_endianness(int num = 1) noexcept
|
||||
{
|
||||
return *reinterpret_cast<char*>(&num) == 1;
|
||||
}
|
||||
@ -10809,7 +10809,7 @@ class binary_reader
|
||||
|
||||
@return whether conversion completed
|
||||
|
||||
@note This function needs to respect the system's endianess, because
|
||||
@note This function needs to respect the system's endianness, because
|
||||
bytes in CBOR, MessagePack, and UBJSON are stored in network order
|
||||
(big endian) and therefore need reordering on little endian systems.
|
||||
*/
|
||||
@ -10982,8 +10982,8 @@ class binary_reader
|
||||
/// the number of characters read
|
||||
std::size_t chars_read = 0;
|
||||
|
||||
/// whether we can assume little endianess
|
||||
const bool is_little_endian = little_endianess();
|
||||
/// whether we can assume little endianness
|
||||
const bool is_little_endian = little_endianness();
|
||||
|
||||
/// the SAX parser
|
||||
json_sax_t* sax = nullptr;
|
||||
@ -11701,7 +11701,7 @@ This class implements a both iterators (iterator and const_iterator) for the
|
||||
iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
class iter_impl
|
||||
class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||
{
|
||||
/// the iterator with BasicJsonType of different const-ness
|
||||
using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
|
||||
@ -15282,7 +15282,7 @@ class binary_writer
|
||||
@tparam OutputIsLittleEndian Set to true if output data is
|
||||
required to be little endian
|
||||
|
||||
@note This function needs to respect the system's endianess, because bytes
|
||||
@note This function needs to respect the system's endianness, because bytes
|
||||
in CBOR, MessagePack, and UBJSON are stored in network order (big
|
||||
endian) and therefore need reordering on little endian systems.
|
||||
*/
|
||||
@ -15372,8 +15372,8 @@ class binary_writer
|
||||
}
|
||||
|
||||
private:
|
||||
/// whether we can assume little endianess
|
||||
const bool is_little_endian = little_endianess();
|
||||
/// whether we can assume little endianness
|
||||
const bool is_little_endian = little_endianness();
|
||||
|
||||
/// the output
|
||||
output_adapter_t<CharType> oa = nullptr;
|
||||
@ -15395,6 +15395,8 @@ class binary_writer
|
||||
#include <cstdio> // snprintf
|
||||
#include <limits> // numeric_limits
|
||||
#include <string> // string, char_traits
|
||||
#include <iomanip> // setfill, setw
|
||||
#include <sstream> // stringstream
|
||||
#include <type_traits> // is_same
|
||||
#include <utility> // move
|
||||
|
||||
@ -17003,10 +17005,9 @@ class serializer
|
||||
{
|
||||
case error_handler_t::strict:
|
||||
{
|
||||
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()));
|
||||
std::stringstream ss;
|
||||
ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex << (byte | 0);
|
||||
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str(), BasicJsonType()));
|
||||
}
|
||||
|
||||
case error_handler_t::ignore:
|
||||
@ -17098,10 +17099,9 @@ class serializer
|
||||
{
|
||||
case error_handler_t::strict:
|
||||
{
|
||||
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()));
|
||||
std::stringstream ss;
|
||||
ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex << (static_cast<std::uint8_t>(s.back()) | 0);
|
||||
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str(), BasicJsonType()));
|
||||
}
|
||||
|
||||
case error_handler_t::ignore:
|
||||
@ -17574,16 +17574,55 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
||||
|
||||
iterator erase(iterator pos)
|
||||
{
|
||||
auto it = pos;
|
||||
return erase(pos, std::next(pos));
|
||||
}
|
||||
|
||||
// Since we cannot move const Keys, re-construct them in place
|
||||
for (auto next = it; ++next != this->end(); ++it)
|
||||
iterator erase(iterator first, iterator last)
|
||||
{
|
||||
const auto elements_affected = std::distance(first, last);
|
||||
const auto offset = std::distance(Container::begin(), first);
|
||||
|
||||
// This is the start situation. We need to delete elements_affected
|
||||
// elements (3 in this example: e, f, g), and need to return an
|
||||
// iterator past the last deleted element (h in this example).
|
||||
// Note that offset is the distance from the start of the vector
|
||||
// to first. We will need this later.
|
||||
|
||||
// [ a, b, c, d, e, f, g, h, i, j ]
|
||||
// ^ ^
|
||||
// first last
|
||||
|
||||
// Since we cannot move const Keys, we re-construct them in place.
|
||||
// We start at first and re-construct (viz. copy) the elements from
|
||||
// the back of the vector. Example for first iteration:
|
||||
|
||||
// ,--------.
|
||||
// v | destroy e and re-construct with h
|
||||
// [ a, b, c, d, e, f, g, h, i, j ]
|
||||
// ^ ^
|
||||
// it it + elements_affected
|
||||
|
||||
for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
|
||||
{
|
||||
it->~value_type(); // Destroy but keep allocation
|
||||
new (&*it) value_type{std::move(*next)};
|
||||
it->~value_type(); // destroy but keep allocation
|
||||
new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
|
||||
}
|
||||
Container::pop_back();
|
||||
return pos;
|
||||
|
||||
// [ a, b, c, d, h, i, j, h, i, j ]
|
||||
// ^ ^
|
||||
// first last
|
||||
|
||||
// remove the unneeded elements at the end of the vector
|
||||
Container::resize(this->size() - static_cast<size_type>(elements_affected));
|
||||
|
||||
// [ a, b, c, d, h, i, j ]
|
||||
// ^ ^
|
||||
// first last
|
||||
|
||||
// first is now pointing past the last deleted element, but we cannot
|
||||
// use this iterator, because it may have been invalidated by the
|
||||
// resize call. Instead, we can return begin() + offset.
|
||||
return Container::begin() + offset;
|
||||
}
|
||||
|
||||
size_type count(const Key& key) const
|
||||
@ -18489,7 +18528,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
- If a subtype is given and the binary array contains exactly 1, 2, 4, 8,
|
||||
or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8)
|
||||
is used. For other sizes, the ext family (ext8, ext16, ext32) is used.
|
||||
The subtype is then added as singed 8-bit integer.
|
||||
The subtype is then added as signed 8-bit integer.
|
||||
- If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
- BSON
|
||||
- If a subtype is given, it is used and added as unsigned 8-bit integer.
|
||||
@ -18654,64 +18693,34 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
/// constructor for strings
|
||||
json_value(const string_t& value)
|
||||
{
|
||||
string = create<string_t>(value);
|
||||
}
|
||||
json_value(const string_t& value) : string(create<string_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue strings
|
||||
json_value(string_t&& value)
|
||||
{
|
||||
string = create<string_t>(std::move(value));
|
||||
}
|
||||
json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
|
||||
|
||||
/// constructor for objects
|
||||
json_value(const object_t& value)
|
||||
{
|
||||
object = create<object_t>(value);
|
||||
}
|
||||
json_value(const object_t& value) : object(create<object_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue objects
|
||||
json_value(object_t&& value)
|
||||
{
|
||||
object = create<object_t>(std::move(value));
|
||||
}
|
||||
json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
|
||||
|
||||
/// constructor for arrays
|
||||
json_value(const array_t& value)
|
||||
{
|
||||
array = create<array_t>(value);
|
||||
}
|
||||
json_value(const array_t& value) : array(create<array_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue arrays
|
||||
json_value(array_t&& value)
|
||||
{
|
||||
array = create<array_t>(std::move(value));
|
||||
}
|
||||
json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
|
||||
|
||||
/// constructor for binary arrays
|
||||
json_value(const typename binary_t::container_type& value)
|
||||
{
|
||||
binary = create<binary_t>(value);
|
||||
}
|
||||
json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue binary arrays
|
||||
json_value(typename binary_t::container_type&& value)
|
||||
{
|
||||
binary = create<binary_t>(std::move(value));
|
||||
}
|
||||
json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
|
||||
|
||||
/// constructor for binary arrays (internal type)
|
||||
json_value(const binary_t& value)
|
||||
{
|
||||
binary = create<binary_t>(value);
|
||||
}
|
||||
json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
|
||||
|
||||
/// constructor for rvalue binary arrays (internal type)
|
||||
json_value(binary_t&& value)
|
||||
{
|
||||
binary = create<binary_t>(std::move(value));
|
||||
}
|
||||
json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
|
||||
|
||||
void destroy(value_t t)
|
||||
{
|
||||
@ -22632,7 +22641,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
`key()` returns an empty string.
|
||||
|
||||
@warning Using `items()` on temporary objects is dangerous. Make sure the
|
||||
object's lifetime exeeds the iteration. See
|
||||
object's lifetime exceeds the iteration. See
|
||||
<https://github.com/nlohmann/json/issues/2040> for more
|
||||
information.
|
||||
|
||||
@ -23565,6 +23574,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
Inserts all values from JSON object @a j and overwrites existing keys.
|
||||
|
||||
@param[in] j JSON object to read values from
|
||||
@param[in] merge_objects when true, existing keys are not overwritten, but
|
||||
contents of objects are merged recursively
|
||||
(default: false)
|
||||
|
||||
@throw type_error.312 if called on JSON values other than objects; example:
|
||||
`"cannot use update() with string"`
|
||||
@ -23576,34 +23588,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
@sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
|
||||
|
||||
@since version 3.0.0
|
||||
@since version 3.0.0, `merge_objects` parameter added in 3.10.4.
|
||||
*/
|
||||
void update(const_reference j)
|
||||
void update(const_reference j, bool merge_objects = false)
|
||||
{
|
||||
// implicitly convert null value to an empty object
|
||||
if (is_null())
|
||||
{
|
||||
m_type = value_t::object;
|
||||
m_value.object = create<object_t>();
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this));
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()), *this));
|
||||
}
|
||||
|
||||
for (auto it = j.cbegin(); it != j.cend(); ++it)
|
||||
{
|
||||
m_value.object->operator[](it.key()) = it.value();
|
||||
#if JSON_DIAGNOSTICS
|
||||
m_value.object->operator[](it.key()).m_parent = this;
|
||||
#endif
|
||||
}
|
||||
update(j.begin(), j.end(), merge_objects);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -23614,12 +23603,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
@param[in] first begin of the range of elements to insert
|
||||
@param[in] last end of the range of elements to insert
|
||||
@param[in] merge_objects when true, existing keys are not overwritten, but
|
||||
contents of objects are merged recursively
|
||||
(default: false)
|
||||
|
||||
@throw type_error.312 if called on JSON values other than objects; example:
|
||||
`"cannot use update() with string"`
|
||||
@throw invalid_iterator.202 if iterator @a first or @a last does does not
|
||||
point to an object; example: `"iterators first and last must point to
|
||||
objects"`
|
||||
@throw type_error.312 if iterator @a first or @a last does does not
|
||||
point to an object; example: `"cannot use update() with string"`
|
||||
@throw invalid_iterator.210 if @a first and @a last do not belong to the
|
||||
same JSON value; example: `"iterators do not fit"`
|
||||
|
||||
@ -23630,9 +23621,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
@sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
|
||||
|
||||
@since version 3.0.0
|
||||
@since version 3.0.0, `merge_objects` parameter added in 3.10.4.
|
||||
*/
|
||||
void update(const_iterator first, const_iterator last)
|
||||
void update(const_iterator first, const_iterator last, bool merge_objects = false)
|
||||
{
|
||||
// implicitly convert null value to an empty object
|
||||
if (is_null())
|
||||
@ -23654,14 +23645,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
// passed iterators must belong to objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()
|
||||
|| !last.m_object->is_object()))
|
||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
||||
{
|
||||
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this));
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(first.m_object->type_name()), *first.m_object));
|
||||
}
|
||||
|
||||
for (auto it = first; it != last; ++it)
|
||||
{
|
||||
if (merge_objects && it.value().is_object())
|
||||
{
|
||||
auto it2 = m_value.object->find(it.key());
|
||||
if (it2 != m_value.object->end())
|
||||
{
|
||||
it2->second.update(it.value(), true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
m_value.object->operator[](it.key()) = it.value();
|
||||
#if JSON_DIAGNOSTICS
|
||||
m_value.object->operator[](it.key()).m_parent = this;
|
||||
@ -26557,20 +26556,19 @@ std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
|
||||
// nonmember support //
|
||||
///////////////////////
|
||||
|
||||
// specialization of std::swap, and std::hash
|
||||
namespace std
|
||||
namespace std // NOLINT(cert-dcl58-cpp)
|
||||
{
|
||||
|
||||
/// hash value for JSON objects
|
||||
template<>
|
||||
struct hash<nlohmann::json>
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL>
|
||||
{
|
||||
/*!
|
||||
@brief return a hash value for a JSON object
|
||||
|
||||
@since version 1.0.0
|
||||
@since version 1.0.0, extended for arbitrary basic_json types in 3.10.5.
|
||||
*/
|
||||
std::size_t operator()(const nlohmann::json& j) const
|
||||
std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
|
||||
{
|
||||
return nlohmann::detail::hash(j);
|
||||
}
|
||||
@ -26580,7 +26578,7 @@ struct hash<nlohmann::json>
|
||||
/// @note: do not remove the space after '<',
|
||||
/// see https://github.com/nlohmann/json/pull/679
|
||||
template<>
|
||||
struct less<::nlohmann::detail::value_t>
|
||||
struct less< ::nlohmann::detail::value_t>
|
||||
{
|
||||
/*!
|
||||
@brief compare two value_t enum values
|
||||
@ -26599,13 +26597,12 @@ struct less<::nlohmann::detail::value_t>
|
||||
/*!
|
||||
@brief exchanges the values of two JSON objects
|
||||
|
||||
@since version 1.0.0
|
||||
@since version 1.0.0, extended for arbitrary basic_json types in 3.10.5.
|
||||
*/
|
||||
template<>
|
||||
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name)
|
||||
is_nothrow_move_constructible<nlohmann::json>::value&& // NOLINT(misc-redundant-expression)
|
||||
is_nothrow_move_assignable<nlohmann::json>::value
|
||||
)
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name)
|
||||
is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression)
|
||||
is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
|
||||
{
|
||||
j1.swap(j2);
|
||||
}
|
||||
|
||||
@ -97,6 +97,18 @@ TEST_CASE("Better diagnostics")
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse(""), "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error);
|
||||
}
|
||||
|
||||
SECTION("Wrong type in update()")
|
||||
{
|
||||
json j = {{"foo", "bar"}};
|
||||
json k = {{"bla", 1}};
|
||||
|
||||
CHECK_THROWS_WITH_AS(j.update(k["bla"].begin(), k["bla"].end()), "[json.exception.type_error.312] (/bla) cannot use update() with number", json::type_error);
|
||||
CHECK_THROWS_WITH_AS(j.update(k["bla"]), "[json.exception.type_error.312] (/bla) cannot use update() with number", json::type_error);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Regression tests for extended diagnostics")
|
||||
{
|
||||
SECTION("Regression test for https://github.com/nlohmann/json/pull/2562#pullrequestreview-574858448")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(json({"0", "0"})[1].get<int>(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error);
|
||||
@ -110,7 +122,7 @@ TEST_CASE("Better diagnostics")
|
||||
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")
|
||||
SECTION("Regression test for issue #2838 - Assertion failure when inserting into arrays with JSON_DIAGNOSTICS set")
|
||||
{
|
||||
// void push_back(basic_json&& val)
|
||||
{
|
||||
@ -235,7 +247,7 @@ TEST_CASE("Better diagnostics")
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Regression test for https://github.com/nlohmann/json/issues/3032")
|
||||
SECTION("Regression test for issue #3032 - Yet another assertion failure when inserting into arrays with JSON_DIAGNOSTICS set")
|
||||
{
|
||||
// reference operator[](size_type idx)
|
||||
{
|
||||
|
||||
@ -31,10 +31,11 @@ SOFTWARE.
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
using ordered_json = nlohmann::ordered_json;
|
||||
|
||||
#include <set>
|
||||
|
||||
TEST_CASE("hash")
|
||||
TEST_CASE("hash<nlohmann::json>")
|
||||
{
|
||||
// Collect hashes for different JSON values and make sure that they are distinct
|
||||
// We cannot compare against fixed values, because the implementation of
|
||||
@ -82,3 +83,52 @@ TEST_CASE("hash")
|
||||
|
||||
CHECK(hashes.size() == 21);
|
||||
}
|
||||
|
||||
TEST_CASE("hash<nlohmann::ordered_json>")
|
||||
{
|
||||
// Collect hashes for different JSON values and make sure that they are distinct
|
||||
// We cannot compare against fixed values, because the implementation of
|
||||
// std::hash may differ between compilers.
|
||||
|
||||
std::set<std::size_t> hashes;
|
||||
|
||||
// null
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(nullptr)));
|
||||
|
||||
// boolean
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(true)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(false)));
|
||||
|
||||
// string
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json("")));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json("foo")));
|
||||
|
||||
// number
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(0)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(unsigned(0))));
|
||||
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(-1)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(0.0)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(42.23)));
|
||||
|
||||
// array
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::array()));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::array({1, 2, 3})));
|
||||
|
||||
// object
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::object()));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::object({{"foo", "bar"}})));
|
||||
|
||||
// binary
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({})));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({}, 0)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({}, 42)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3})));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3}, 0)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3}, 42)));
|
||||
|
||||
// discarded
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(ordered_json::value_t::discarded)));
|
||||
|
||||
CHECK(hashes.size() == 21);
|
||||
}
|
||||
|
||||
@ -648,7 +648,7 @@ TEST_CASE("JSON patch")
|
||||
CHECK(target == R"({ "D": "Berlin", "F": "Paris", "GB": "London" })"_json);
|
||||
|
||||
// create a diff from two JSONs
|
||||
json p2 = json::diff(target, source);
|
||||
json p2 = json::diff(target, source); // NOLINT(readability-suspicious-call-argument)
|
||||
// p2 = [{"op": "delete", "path": "/GB"}]
|
||||
CHECK(p2 == R"([{"op":"remove","path":"/GB"}])"_json);
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ TEST_CASE("tests on very large JSONs")
|
||||
{
|
||||
const auto depth = 5000000;
|
||||
|
||||
std::string s(2 * depth, '[');
|
||||
std::string s(static_cast<std::size_t>(2 * depth), '[');
|
||||
std::fill(s.begin() + depth, s.end(), ']');
|
||||
|
||||
json _;
|
||||
|
||||
@ -796,64 +796,89 @@ TEST_CASE("modifiers")
|
||||
|
||||
SECTION("update()")
|
||||
{
|
||||
json j_object1 = {{"one", "eins"}, {"two", "zwei"}};
|
||||
json j_object2 = {{"three", "drei"}, {"two", "zwo"}};
|
||||
json j_array = {1, 2, 3, 4};
|
||||
|
||||
SECTION("const reference")
|
||||
SECTION("non-recursive (default)")
|
||||
{
|
||||
SECTION("proper usage")
|
||||
{
|
||||
j_object1.update(j_object2);
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
|
||||
json j_object1 = {{"one", "eins"}, {"two", "zwei"}};
|
||||
json j_object2 = {{"three", "drei"}, {"two", "zwo"}};
|
||||
json j_array = {1, 2, 3, 4};
|
||||
|
||||
json j_null;
|
||||
j_null.update(j_object2);
|
||||
CHECK(j_null == j_object2);
|
||||
SECTION("const reference")
|
||||
{
|
||||
SECTION("proper usage")
|
||||
{
|
||||
j_object1.update(j_object2);
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
|
||||
|
||||
json j_null;
|
||||
j_null.update(j_object2);
|
||||
CHECK(j_null == j_object2);
|
||||
}
|
||||
|
||||
SECTION("wrong types")
|
||||
{
|
||||
CHECK_THROWS_AS(j_array.update(j_object1), json::type_error&);
|
||||
CHECK_THROWS_WITH(j_array.update(j_object1), "[json.exception.type_error.312] cannot use update() with array");
|
||||
|
||||
CHECK_THROWS_AS(j_object1.update(j_array), json::type_error&);
|
||||
CHECK_THROWS_WITH(j_object1.update(j_array), "[json.exception.type_error.312] cannot use update() with array");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("wrong types")
|
||||
SECTION("iterator range")
|
||||
{
|
||||
CHECK_THROWS_AS(j_array.update(j_object1), json::type_error&);
|
||||
CHECK_THROWS_WITH(j_array.update(j_object1), "[json.exception.type_error.312] cannot use update() with array");
|
||||
SECTION("proper usage")
|
||||
{
|
||||
j_object1.update(j_object2.begin(), j_object2.end());
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
|
||||
|
||||
CHECK_THROWS_AS(j_object1.update(j_array), json::type_error&);
|
||||
CHECK_THROWS_WITH(j_object1.update(j_array), "[json.exception.type_error.312] cannot use update() with array");
|
||||
json j_null;
|
||||
j_null.update(j_object2.begin(), j_object2.end());
|
||||
CHECK(j_null == j_object2);
|
||||
}
|
||||
|
||||
SECTION("empty range")
|
||||
{
|
||||
j_object1.update(j_object2.begin(), j_object2.begin());
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwei"}}));
|
||||
}
|
||||
|
||||
SECTION("invalid iterators")
|
||||
{
|
||||
json j_other_array2 = {"first", "second"};
|
||||
|
||||
CHECK_THROWS_AS(j_array.update(j_object2.begin(), j_object2.end()), json::type_error&);
|
||||
CHECK_THROWS_AS(j_object1.update(j_object1.begin(), j_object2.end()), json::invalid_iterator&);
|
||||
CHECK_THROWS_AS(j_object1.update(j_array.begin(), j_array.end()), json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH(j_array.update(j_object2.begin(), j_object2.end()),
|
||||
"[json.exception.type_error.312] cannot use update() with array");
|
||||
CHECK_THROWS_WITH(j_object1.update(j_object1.begin(), j_object2.end()),
|
||||
"[json.exception.invalid_iterator.210] iterators do not fit");
|
||||
CHECK_THROWS_WITH(j_object1.update(j_array.begin(), j_array.end()),
|
||||
"[json.exception.type_error.312] cannot use update() with array");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("iterator range")
|
||||
SECTION("recursive")
|
||||
{
|
||||
SECTION("proper usage")
|
||||
SECTION("const reference")
|
||||
{
|
||||
j_object1.update(j_object2.begin(), j_object2.end());
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
|
||||
SECTION("extend object")
|
||||
{
|
||||
json j1 = {{"string", "s"}, {"numbers", {{"one", 1}}}};
|
||||
json j2 = {{"string", "t"}, {"numbers", {{"two", 2}}}};
|
||||
j1.update(j2, true);
|
||||
CHECK(j1 == json({{"string", "t"}, {"numbers", {{"one", 1}, {"two", 2}}}}));
|
||||
}
|
||||
|
||||
json j_null;
|
||||
j_null.update(j_object2.begin(), j_object2.end());
|
||||
CHECK(j_null == j_object2);
|
||||
}
|
||||
|
||||
SECTION("empty range")
|
||||
{
|
||||
j_object1.update(j_object2.begin(), j_object2.begin());
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwei"}}));
|
||||
}
|
||||
|
||||
SECTION("invalid iterators")
|
||||
{
|
||||
json j_other_array2 = {"first", "second"};
|
||||
|
||||
CHECK_THROWS_AS(j_array.update(j_object2.begin(), j_object2.end()), json::type_error&);
|
||||
CHECK_THROWS_AS(j_object1.update(j_object1.begin(), j_object2.end()), json::invalid_iterator&);
|
||||
CHECK_THROWS_AS(j_object1.update(j_array.begin(), j_array.end()), json::invalid_iterator&);
|
||||
|
||||
CHECK_THROWS_WITH(j_array.update(j_object2.begin(), j_object2.end()),
|
||||
"[json.exception.type_error.312] cannot use update() with array");
|
||||
CHECK_THROWS_WITH(j_object1.update(j_object1.begin(), j_object2.end()),
|
||||
"[json.exception.invalid_iterator.210] iterators do not fit");
|
||||
CHECK_THROWS_WITH(j_object1.update(j_array.begin(), j_array.end()),
|
||||
"[json.exception.invalid_iterator.202] iterators first and last must point to objects");
|
||||
SECTION("replace object")
|
||||
{
|
||||
json j1 = {{"string", "s"}, {"numbers", {{"one", 1}}}};
|
||||
json j2 = {{"string", "t"}, {"numbers", 1}};
|
||||
j1.update(j2, true);
|
||||
CHECK(j1 == json({{"string", "t"}, {"numbers", 1}}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,7 +349,7 @@ TEST_CASE("MessagePack")
|
||||
{
|
||||
for (uint64_t i :
|
||||
{
|
||||
4294967296lu, 9223372036854775807lu
|
||||
4294967296LU, 9223372036854775807LU
|
||||
})
|
||||
{
|
||||
CAPTURE(i)
|
||||
@ -719,7 +719,7 @@ TEST_CASE("MessagePack")
|
||||
{
|
||||
for (uint64_t i :
|
||||
{
|
||||
4294967296lu, 18446744073709551615lu
|
||||
4294967296LU, 18446744073709551615LU
|
||||
})
|
||||
{
|
||||
CAPTURE(i)
|
||||
|
||||
@ -210,6 +210,45 @@ TEST_CASE("ordered_map")
|
||||
++it2;
|
||||
CHECK(it2 == om.end());
|
||||
}
|
||||
|
||||
SECTION("with iterator pair")
|
||||
{
|
||||
SECTION("range in the middle")
|
||||
{
|
||||
// need more elements
|
||||
om["vier"] = "four";
|
||||
om["fünf"] = "five";
|
||||
|
||||
// delete "zwei" and "drei"
|
||||
auto it = om.erase(om.begin() + 1, om.begin() + 3);
|
||||
CHECK(it->first == "vier");
|
||||
CHECK(om.size() == 3);
|
||||
}
|
||||
|
||||
SECTION("range at the beginning")
|
||||
{
|
||||
// need more elements
|
||||
om["vier"] = "four";
|
||||
om["fünf"] = "five";
|
||||
|
||||
// delete "eins" and "zwei"
|
||||
auto it = om.erase(om.begin(), om.begin() + 2);
|
||||
CHECK(it->first == "drei");
|
||||
CHECK(om.size() == 3);
|
||||
}
|
||||
|
||||
SECTION("range at the end")
|
||||
{
|
||||
// need more elements
|
||||
om["vier"] = "four";
|
||||
om["fünf"] = "five";
|
||||
|
||||
// delete "vier" and "fünf"
|
||||
auto it = om.erase(om.begin() + 3, om.end());
|
||||
CHECK(it == om.end());
|
||||
CHECK(om.size() == 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("count")
|
||||
|
||||
@ -602,7 +602,7 @@ TEST_CASE("regression tests 2")
|
||||
auto val2 = j.value("y", defval);
|
||||
}
|
||||
|
||||
SECTION("issue #2293 - eof doesnt cause parsing to stop")
|
||||
SECTION("issue #2293 - eof doesn't cause parsing to stop")
|
||||
{
|
||||
std::vector<uint8_t> data =
|
||||
{
|
||||
@ -818,6 +818,23 @@ TEST_CASE("regression tests 2")
|
||||
std::vector<FooBar> foo;
|
||||
j.get_to(foo);
|
||||
}
|
||||
|
||||
SECTION("issue #3108 - ordered_json doesn't support range based erase")
|
||||
{
|
||||
ordered_json j = {1, 2, 2, 4};
|
||||
|
||||
auto last = std::unique(j.begin(), j.end());
|
||||
j.erase(last, j.end());
|
||||
|
||||
CHECK(j.dump() == "[1,2,4]");
|
||||
|
||||
j.erase(std::remove_if(j.begin(), j.end(), [](const ordered_json & val)
|
||||
{
|
||||
return val == 2;
|
||||
}), j.end());
|
||||
|
||||
CHECK(j.dump() == "[1,4]");
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
|
||||
Loading…
Reference in New Issue
Block a user