mirror of
https://github.com/nlohmann/json.git
synced 2026-10-12 09:27:13 +00:00
Merge remote-tracking branch 'origin/develop' into claude/fix-issue-3989-db7e45
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
116 files changed
+4199
-2405
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
# generated files are collapsed in diffs and excluded from language statistics
|
||||||
|
single_include/** linguist-generated
|
||||||
|
nlohmann_json.natvis linguist-generated
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
# JSON for Modern C++ was originally written by Niels Lohmann.
|
# JSON for Modern C++ was originally written by Niels Lohmann.
|
||||||
# Since 2013, over 250 contributors have helped to improve the library.
|
# Since 2013, over 400 contributors have helped to improve the library.
|
||||||
# This CODEOWNERS file is only to make sure that @nlohmann is requested
|
# This CODEOWNERS file is only to make sure that @nlohmann is requested
|
||||||
# for a code review in case of a pull request.
|
# for a code review in case of a pull request.
|
||||||
|
|
||||||
|
|||||||
+16
-14
@@ -98,7 +98,7 @@ $ ctest --test-dir build -j 10
|
|||||||
The test suite should report:
|
The test suite should report:
|
||||||
|
|
||||||
```
|
```
|
||||||
100% tests passed, 0 tests failed out of 98
|
100% tests passed, 0 tests failed out of <number of tests>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Add tests
|
#### Add tests
|
||||||
@@ -151,14 +151,17 @@ make build -C docs/mkdocs # strict build: fails on broken links, anchor
|
|||||||
make check_mermaid -C docs/mkdocs # checks the Mermaid diagrams (requires Node.js)
|
make check_mermaid -C docs/mkdocs # checks the Mermaid diagrams (requires Node.js)
|
||||||
```
|
```
|
||||||
|
|
||||||
A new API page also needs an entry in [`docs/docset/docSet.sql`](https://github.com/nlohmann/json/blob/develop/docs/docset/docSet.sql),
|
The search index of the docset is generated from [`mkdocs.yml`](https://github.com/nlohmann/json/blob/develop/docs/mkdocs/mkdocs.yml)
|
||||||
the search index of the docset; `make build` reports missing entries.
|
and each page's title (H1) and declaration by
|
||||||
|
[`docs/docset/generate_docset.py`](https://github.com/nlohmann/json/blob/develop/docs/docset/generate_docset.py);
|
||||||
|
`make build` reports API pages that cannot be classified.
|
||||||
|
|
||||||
### Amalgamate the source code
|
### Amalgamate the source code
|
||||||
|
|
||||||
The single-header files
|
The single-header files
|
||||||
[`single_include/nlohmann/json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) and
|
[`single_include/nlohmann/json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp),
|
||||||
[`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp)
|
[`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp), and
|
||||||
|
[`single_include/nlohmann/json_literals.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_literals.hpp)
|
||||||
are **generated** from the source files in the
|
are **generated** from the source files in the
|
||||||
[`include/nlohmann` directory](https://github.com/nlohmann/json/tree/develop/include/nlohmann). **Do not** edit the
|
[`include/nlohmann` directory](https://github.com/nlohmann/json/tree/develop/include/nlohmann). **Do not** edit the
|
||||||
files directly; instead, modify the include/nlohmann sources and regenerate the files by executing:
|
files directly; instead, modify the include/nlohmann sources and regenerate the files by executing:
|
||||||
@@ -181,7 +184,7 @@ The amalgamation check in CI fails if any of these generated files is out of dat
|
|||||||
|
|
||||||
## Recommended documentation
|
## Recommended documentation
|
||||||
|
|
||||||
- The library’s [README file](https://github.com/nlohmann/json/blob/master/README.md) is an excellent starting point to
|
- The library’s [README file](https://github.com/nlohmann/json/blob/develop/README.md) is an excellent starting point to
|
||||||
understand its functionality.
|
understand its functionality.
|
||||||
- The [documentation page](https://json.nlohmann.me) is the reference documentation of the library.
|
- The [documentation page](https://json.nlohmann.me) is the reference documentation of the library.
|
||||||
- [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259) is the reference for the JavaScript Object Notation (JSON)
|
- [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259) is the reference for the JavaScript Object Notation (JSON)
|
||||||
@@ -220,9 +223,9 @@ feature macros then allows users to test their code against the library in the n
|
|||||||
### Break C++11 language conformance
|
### Break C++11 language conformance
|
||||||
|
|
||||||
This library is designed to work with C++11 and later. This means that any
|
This library is designed to work with C++11 and later. This means that any
|
||||||
[supported C++11 compiler](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers) should compile
|
[supported C++11 compiler](https://github.com/nlohmann/json/blob/develop/README.md#supported-compilers) should compile
|
||||||
the library without problems. Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual
|
the library without problems. Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual
|
||||||
Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support.
|
C++ 2013 and earlier are known not to work due to missing or incomplete C++11 support.
|
||||||
|
|
||||||
Please do not add features that do not work with the mentioned supported compilers. Please guard features from C++14 and
|
Please do not add features that do not work with the mentioned supported compilers. Please guard features from C++14 and
|
||||||
later against the respective [`JSON_HAS_CPP_14`](https://json.nlohmann.me/api/macros/json_has_cpp_11/) macros.
|
later against the respective [`JSON_HAS_CPP_14`](https://json.nlohmann.me/api/macros/json_has_cpp_11/) macros.
|
||||||
@@ -238,12 +241,11 @@ extension.
|
|||||||
The following areas really need contribution and are always welcomed:
|
The following areas really need contribution and are always welcomed:
|
||||||
|
|
||||||
- Extending the **continuous integration** toward more exotic compilers such as Android NDK, Intel's Compiler, or the
|
- Extending the **continuous integration** toward more exotic compilers such as Android NDK, Intel's Compiler, or the
|
||||||
bleeding-edge versions Clang.
|
bleeding-edge versions of Clang.
|
||||||
- Improving the efficiency of the **JSON parser**. The current parser is implemented as a naive recursive descent parser
|
- Improving the efficiency of the **JSON parser**. The current parser is a hand-written iterative parser that keeps an
|
||||||
with hand-coded string handling. More sophisticated approaches like LALR parsers would be really appreciated. That
|
explicit stack instead of recursing, with hand-coded string handling. Speeding up the lexer or the value construction
|
||||||
said, parser generators like Bison or ANTLR do not play nice with single-header files -- I really would like to keep
|
would be appreciated. Parser generators like Bison or ANTLR do not play nice with single-header files -- I really
|
||||||
the parser inside the `json.hpp` header, and I am not aware of approaches similar to [`re2c`](http://re2c.org) for
|
would like to keep the parser inside the `json.hpp` header.
|
||||||
parsing.
|
|
||||||
- Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency
|
- Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency
|
||||||
is not everything, speed and memory consumption are very important characteristics for C++ developers, so having
|
is not everything, speed and memory consumption are very important characteristics for C++ developers, so having
|
||||||
proper comparisons would be interesting.
|
proper comparisons would be interesting.
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ body:
|
|||||||
If possible, provide a small and self-contained example that triggers
|
If possible, provide a small and self-contained example that triggers
|
||||||
the bug. Please understand that we cannot analyze and debug large code
|
the bug. Please understand that we cannot analyze and debug large code
|
||||||
bases. Please do not paste screenshots here.
|
bases. Please do not paste screenshots here.
|
||||||
render: Shell
|
render: cpp
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: output
|
id: output
|
||||||
attributes:
|
attributes:
|
||||||
@@ -79,7 +79,7 @@ body:
|
|||||||
description: >
|
description: >
|
||||||
Which version of the library did you use? If it is a released version,
|
Which version of the library did you use? If it is a released version,
|
||||||
please enter the version number (e.g., 3.12.0). Otherwise, please enter
|
please enter the version number (e.g., 3.12.0). Otherwise, please enter
|
||||||
the commit hash. If you got the library from another source as the
|
the commit hash. If you got the library from another source than the
|
||||||
GitHub repository (e.g., via a package manager), please also state
|
GitHub repository (e.g., via a package manager), please also state
|
||||||
this.
|
this.
|
||||||
validations:
|
validations:
|
||||||
|
|||||||
@@ -21,6 +21,17 @@ labels:
|
|||||||
files:
|
files:
|
||||||
- "cmake/.*"
|
- "cmake/.*"
|
||||||
|
|
||||||
|
# other build systems
|
||||||
|
- label: "CMake"
|
||||||
|
files:
|
||||||
|
- "(meson\\.build|meson_options\\.txt|BUILD\\.bazel|MODULE\\.bazel|Package\\.swift)"
|
||||||
|
|
||||||
|
- label: "documentation"
|
||||||
|
files:
|
||||||
|
- ".github/ISSUE_TEMPLATE/.*"
|
||||||
|
- ".github/config\\.yml"
|
||||||
|
- ".github/(CONTRIBUTING|SECURITY|CODE_OF_CONDUCT|PULL_REQUEST_TEMPLATE)\\.md"
|
||||||
|
|
||||||
- label: "CI"
|
- label: "CI"
|
||||||
files:
|
files:
|
||||||
- ".github/workflows/.*"
|
- ".github/workflows/.*"
|
||||||
|
|||||||
@@ -83,8 +83,7 @@ jobs:
|
|||||||
# byte for byte), so there is nothing to gain from checking out a
|
# byte for byte), so there is nothing to gain from checking out a
|
||||||
# separate copy, and doing so would make this step fail on a PR
|
# separate copy, and doing so would make this step fail on a PR
|
||||||
# that adds support for a new dispatch table until that PR itself
|
# that adds support for a new dispatch table until that PR itself
|
||||||
# merges to develop, the same way generate_natvis.py's --version
|
# merges to develop.
|
||||||
# requirement briefly did.
|
|
||||||
TMPDIR=$(mktemp -d ./macro_builder_check.XXXXXX)
|
TMPDIR=$(mktemp -d ./macro_builder_check.XXXXXX)
|
||||||
c++ -std=c++11 tools/macro_builder/main.cpp -o "$TMPDIR/macro_builder"
|
c++ -std=c++11 tools/macro_builder/main.cpp -o "$TMPDIR/macro_builder"
|
||||||
"$TMPDIR/macro_builder" > "$TMPDIR/paste.hpp"
|
"$TMPDIR/macro_builder" > "$TMPDIR/paste.hpp"
|
||||||
@@ -117,7 +116,6 @@ jobs:
|
|||||||
|
|
||||||
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json.json -s .
|
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json.json -s .
|
||||||
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json_fwd.json -s .
|
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json_fwd.json -s .
|
||||||
cp include/nlohmann/json_literals.hpp $INCLUDE_DIR/json_literals.hpp
|
|
||||||
|
|
||||||
# the header list of the Bazel "json" target must match the files in include/
|
# the header list of the Bazel "json" target must match the files in include/
|
||||||
cmake -P cmake/scripts/gen_bazel_build_file.cmake
|
cmake -P cmake/scripts/gen_bazel_build_file.cmake
|
||||||
@@ -138,17 +136,13 @@ jobs:
|
|||||||
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
|
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
|
||||||
$(find $SOURCE_DIRS -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort)
|
$(find $SOURCE_DIRS -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort)
|
||||||
|
|
||||||
|
# json_literals.hpp is copied verbatim from the (now formatted) include/
|
||||||
|
# directory, like `make amalgamate` does
|
||||||
|
cp include/nlohmann/json_literals.hpp $INCLUDE_DIR/json_literals.hpp
|
||||||
|
|
||||||
- name: Regenerate nlohmann_json.natvis
|
- name: Regenerate nlohmann_json.natvis
|
||||||
run: |
|
run: |
|
||||||
cd $MAIN_DIR
|
cd $MAIN_DIR
|
||||||
# Pass --version explicitly so this step also works with the tool
|
|
||||||
# copy from develop before this repository's own generate_natvis.py
|
|
||||||
# learns to derive the version itself: the older script requires
|
|
||||||
# --version, and the newer one accepts it as an explicit override.
|
|
||||||
ABI_MACROS=include/nlohmann/detail/abi_macros.hpp
|
|
||||||
VERSION_MAJOR=$(grep -m1 'define NLOHMANN_JSON_VERSION_MAJOR' $ABI_MACROS | grep -o '[0-9]\+')
|
|
||||||
VERSION_MINOR=$(grep -m1 'define NLOHMANN_JSON_VERSION_MINOR' $ABI_MACROS | grep -o '[0-9]\+')
|
|
||||||
VERSION_PATCH=$(grep -m1 'define NLOHMANN_JSON_VERSION_PATCH' $ABI_MACROS | grep -o '[0-9]\+')
|
|
||||||
# The template is what this check verifies the committed natvis
|
# The template is what this check verifies the committed natvis
|
||||||
# file against, so take it from this PR rather than from the
|
# file against, so take it from this PR rather than from the
|
||||||
# develop checkout: generate_natvis.py loads the template from its
|
# develop checkout: generate_natvis.py loads the template from its
|
||||||
@@ -156,7 +150,7 @@ jobs:
|
|||||||
# template could never pass. Like the macro_builder step above,
|
# template could never pass. Like the macro_builder step above,
|
||||||
# this only renders PR content in a job without credentials.
|
# this only renders PR content in a job without credentials.
|
||||||
cp tools/generate_natvis/nlohmann_json.natvis.j2 $NATVIS_TOOL_DIR/
|
cp tools/generate_natvis/nlohmann_json.natvis.j2 $NATVIS_TOOL_DIR/
|
||||||
python3 $NATVIS_TOOL_DIR/generate_natvis.py --version "$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH" $MAIN_DIR
|
python3 $NATVIS_TOOL_DIR/generate_natvis.py $MAIN_DIR
|
||||||
|
|
||||||
- name: Build patch and check for differences
|
- name: Build patch and check for differences
|
||||||
id: diff
|
id: diff
|
||||||
@@ -165,7 +159,7 @@ jobs:
|
|||||||
mkdir -p ${{ github.workspace }}/patch
|
mkdir -p ${{ github.workspace }}/patch
|
||||||
git diff --patch --no-color > ${{ github.workspace }}/patch/amalgamation.patch
|
git diff --patch --no-color > ${{ github.workspace }}/patch/amalgamation.patch
|
||||||
if [ -s ${{ github.workspace }}/patch/amalgamation.patch ]; then
|
if [ -s ${{ github.workspace }}/patch/amalgamation.patch ]; then
|
||||||
echo "The source code has not been amalgamated/formatted correctly or BUILD.bazel is out of date. Diff:"
|
echo "The source code has not been amalgamated/formatted correctly, or BUILD.bazel, nlohmann_json.natvis, or the macro_builder tables in macro_scope.hpp are out of date ('make amalgamate BUILD.bazel natvis' fixes all but the tables, see tools/macro_builder/README.md). Diff:"
|
||||||
cat ${{ github.workspace }}/patch/amalgamation.patch
|
cat ${{ github.workspace }}/patch/amalgamation.patch
|
||||||
echo "has_diff=true" >> "$GITHUB_OUTPUT"
|
echo "has_diff=true" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ jobs:
|
|||||||
issue_number: issue_number,
|
issue_number: issue_number,
|
||||||
owner: context.repo.owner,
|
owner: context.repo.owner,
|
||||||
repo: context.repo.repo,
|
repo: context.repo.repo,
|
||||||
body: '## 🔴 Amalgamation check failed! 🔴\nThe source code has not been amalgamated and/or formatted correctly, or `BUILD.bazel` is out of date.'
|
body: '## 🔴 Amalgamation check failed! 🔴\nThe source code has not been amalgamated and/or formatted correctly, or `BUILD.bazel`, `nlohmann_json.natvis`, or the macro_builder tables in `macro_scope.hpp` are out of date. `make amalgamate BUILD.bazel natvis` fixes all but the tables (see `tools/macro_builder/README.md`).'
|
||||||
+ (hasPatch ? '\n\n📎 A ready-to-apply patch is attached to the [failed workflow run](' + runUrl + ') as the `amalgamation-patch` artifact.'
|
+ (hasPatch ? '\n\n📎 A ready-to-apply patch is attached to the [failed workflow run](' + runUrl + ') as the `amalgamation-patch` artifact.'
|
||||||
+ ' Download it, then apply it locally from the repository root with:'
|
+ ' Download it, then apply it locally from the repository root with:'
|
||||||
+ '\n\n```shell\ngit apply amalgamation.patch\n```\n\n'
|
+ '\n\n```shell\ngit apply amalgamation.patch\n```\n\n'
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ on:
|
|||||||
- .github/SECURITY.md
|
- .github/SECURITY.md
|
||||||
- cmake/clang_flags.cmake
|
- cmake/clang_flags.cmake
|
||||||
- cmake/gcc_flags.cmake
|
- cmake/gcc_flags.cmake
|
||||||
|
- include/nlohmann/detail/abi_macros.hpp
|
||||||
- tests/fmt_formatter/project/main.cpp
|
- tests/fmt_formatter/project/main.cpp
|
||||||
- tools/astyle/.astylerc
|
- tools/astyle/.astylerc
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind]
|
target: [ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind]
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||||
@@ -117,6 +117,7 @@ jobs:
|
|||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- name: Install Valgrind
|
- name: Install Valgrind
|
||||||
|
if: matrix.target == 'ci_test_valgrind'
|
||||||
run: sudo apt-get update ; sudo apt-get install -y valgrind
|
run: sudo apt-get update ; sudo apt-get install -y valgrind
|
||||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with:
|
with:
|
||||||
@@ -279,7 +280,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||||
- name: Set env FORCE_STDCPPFS_FLAG for clang 7 / 8 / 9 / 10
|
- name: Disable filesystem support (std::filesystem is unusable) for clang 7 / 8 / 9 / 10
|
||||||
run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV"
|
run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV"
|
||||||
if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }}
|
if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }}
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ jobs:
|
|||||||
- name: Test
|
- name: Test
|
||||||
run: cd build ; ctest -j 10 -C Debug --output-on-failure
|
run: cd build ; ctest -j 10 -C Debug --output-on-failure
|
||||||
|
|
||||||
clang-cl-12:
|
clang-cl:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -217,8 +217,10 @@ jobs:
|
|||||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||||
with:
|
with:
|
||||||
cmakeVersion: 4.3.4
|
cmakeVersion: 4.3.4
|
||||||
|
# CMAKE_CXX_FLAGS replaces CMake's MSVC defaults (which include /EHsc), and
|
||||||
|
# ci_module_cpp20 forwards it to the module build, so list /EHsc explicitly
|
||||||
- name: Run CMake (Debug)
|
- name: Run CMake (Debug)
|
||||||
run: cmake -S . -B build -G "Visual Studio 17 2022" -DJSON_CI=ON -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /W4 /WX"
|
run: cmake -S . -B build -G "Visual Studio 17 2022" -DJSON_CI=ON -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /EHsc /W4 /WX"
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build --config Debug --target ci_module_cpp20
|
run: cmake --build build --config Debug --target ci_module_cpp20
|
||||||
|
|
||||||
+14
-1
@@ -27,7 +27,6 @@
|
|||||||
/docs/docset/JSON_for_Modern_C++.tgz
|
/docs/docset/JSON_for_Modern_C++.tgz
|
||||||
/docs/docset/docSet.dsidx
|
/docs/docset/docSet.dsidx
|
||||||
/docs/mkdocs/.cache/
|
/docs/mkdocs/.cache/
|
||||||
/docs/mkdocs/docs/__pycache__/
|
|
||||||
/docs/mkdocs/hooks/__pycache__/
|
/docs/mkdocs/hooks/__pycache__/
|
||||||
/docs/mkdocs/scripts/mermaid/node_modules/
|
/docs/mkdocs/scripts/mermaid/node_modules/
|
||||||
/docs/mkdocs/site/
|
/docs/mkdocs/site/
|
||||||
@@ -47,3 +46,17 @@ nlohmann_json.spdx
|
|||||||
|
|
||||||
# Bazel-related
|
# Bazel-related
|
||||||
MODULE.bazel.lock
|
MODULE.bazel.lock
|
||||||
|
|
||||||
|
# backups left by `make check-amalgamation` or the ci_test_amalgamation target if they are interrupted
|
||||||
|
/BUILD.bazel~
|
||||||
|
/nlohmann_json.natvis~
|
||||||
|
/single_include/nlohmann/*.hpp~
|
||||||
|
/venv_astyle/
|
||||||
|
|
||||||
|
# release outputs of `make release`
|
||||||
|
/include.zip
|
||||||
|
/include.zip.asc
|
||||||
|
/json.tar.xz
|
||||||
|
/json.tar.xz.asc
|
||||||
|
/release_files/
|
||||||
|
/single_include/nlohmann/*.asc
|
||||||
@@ -81,6 +81,7 @@ cc_library(
|
|||||||
hdrs = [
|
hdrs = [
|
||||||
"single_include/nlohmann/json.hpp",
|
"single_include/nlohmann/json.hpp",
|
||||||
"single_include/nlohmann/json_fwd.hpp",
|
"single_include/nlohmann/json_fwd.hpp",
|
||||||
|
"single_include/nlohmann/json_literals.hpp",
|
||||||
],
|
],
|
||||||
includes = ["single_include"],
|
includes = ["single_include"],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ authors:
|
|||||||
website: https://nlohmann.me
|
website: https://nlohmann.me
|
||||||
title: "JSON for Modern C++"
|
title: "JSON for Modern C++"
|
||||||
version: 3.12.0
|
version: 3.12.0
|
||||||
date-released: 2025-04-07
|
date-released: 2025-04-11
|
||||||
license: MIT
|
license: MIT
|
||||||
repository-code: "https://github.com/nlohmann/json"
|
repository-code: "https://github.com/nlohmann/json"
|
||||||
url: https://json.nlohmann.me
|
url: https://json.nlohmann.me
|
||||||
+1
-1
@@ -30,7 +30,7 @@ endif ()
|
|||||||
option(NLOHMANN_JSON_BUILD_MODULES "Build C++ modules support" OFF)
|
option(NLOHMANN_JSON_BUILD_MODULES "Build C++ modules support" OFF)
|
||||||
|
|
||||||
if(NLOHMANN_JSON_BUILD_MODULES)
|
if(NLOHMANN_JSON_BUILD_MODULES)
|
||||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28)
|
if(NOT CMAKE_VERSION VERSION_LESS 3.28)
|
||||||
message(STATUS "Building nlohmann.json C++ module")
|
message(STATUS "Building nlohmann.json C++ module")
|
||||||
add_subdirectory(src/modules)
|
add_subdirectory(src/modules)
|
||||||
else()
|
else()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ This file describes the source for supporting files; that is, files that are not
|
|||||||
The [GitHub Actions](https://docs.github.com/en/actions) workflows that build, test, and analyze the library. Each file in this folder defines one workflow:
|
The [GitHub Actions](https://docs.github.com/en/actions) workflows that build, test, and analyze the library. Each file in this folder defines one workflow:
|
||||||
|
|
||||||
- `ubuntu.yml`, `macos.yml`, `windows.yml` — build and run the test suite on Linux, macOS, and Windows.
|
- `ubuntu.yml`, `macos.yml`, `windows.yml` — build and run the test suite on Linux, macOS, and Windows.
|
||||||
- `check_amalgamation.yml` — verify that the single-header amalgamation in `single_include` is up to date on pull requests.
|
- `check_amalgamation.yml` — verify on pull requests and pushes to `develop` that the generated files (the single-header amalgamation in `single_include`, `BUILD.bazel`, and `nlohmann_json.natvis`) are up to date.
|
||||||
- `comment_check_amalgamation.yml` — comment on a pull request when the amalgamation check failed.
|
- `comment_check_amalgamation.yml` — comment on a pull request when the amalgamation check failed.
|
||||||
- `cifuzz.yml` — run short fuzzing sessions via [OSS-Fuzz CIFuzz](https://google.github.io/oss-fuzz/getting-started/continuous-integration/) on pull requests.
|
- `cifuzz.yml` — run short fuzzing sessions via [OSS-Fuzz CIFuzz](https://google.github.io/oss-fuzz/getting-started/continuous-integration/) on pull requests.
|
||||||
- `codeql-analysis.yml` — run [CodeQL](https://codeql.github.com) code scanning.
|
- `codeql-analysis.yml` — run [CodeQL](https://codeql.github.com) code scanning.
|
||||||
@@ -24,7 +24,9 @@ The [GitHub Actions](https://docs.github.com/en/actions) workflows that build, t
|
|||||||
- `dependency-review.yml` — scan dependency changes in pull requests for known vulnerabilities.
|
- `dependency-review.yml` — scan dependency changes in pull requests for known vulnerabilities.
|
||||||
- `labeler.yml` — the "Pull Request Labeler" workflow (see `.github/labeler.yml`).
|
- `labeler.yml` — the "Pull Request Labeler" workflow (see `.github/labeler.yml`).
|
||||||
- `stale.yml` — comment on and close stale issues and pull requests.
|
- `stale.yml` — comment on and close stale issues and pull requests.
|
||||||
- `publish_documentation.yml` — build and publish the documentation on every merge to the `develop` branch.
|
- `publish_documentation.yml` — build and publish the documentation on pushes to the `develop` branch that touch the documentation sources (or the files it embeds).
|
||||||
|
- `check_docs_links.yml` — check the links of the documentation weekly, as external links can break without any change in this repository.
|
||||||
|
- `cancel_closed_pr_runs.yml` — cancel unfinished workflow runs of a pull request once it is closed or merged.
|
||||||
|
|
||||||
Further documentation:
|
Further documentation:
|
||||||
|
|
||||||
@@ -266,8 +268,9 @@ meson setup builddir
|
|||||||
ninja -C builddir
|
ninja -C builddir
|
||||||
```
|
```
|
||||||
|
|
||||||
`meson_options.txt` defines the options, which mirror the CMake options that change the library's target (for example,
|
`meson_options.txt` defines the options, which mirror the names of the CMake options that change the library's target (for example,
|
||||||
`-DDiagnostics=true`). Meson requires this file next to `meson.build`, so it is also part of `include.zip`. `make check_build_options`
|
`-DDiagnostics=true`); their defaults may differ (for example, `MultipleHeaders` defaults to `false` in Meson, while
|
||||||
|
`JSON_MultipleHeaders` is `ON` in CMake). Meson requires this file next to `meson.build`, so it is also part of `include.zip`. `make check_build_options`
|
||||||
([`tools/check_build_options`](tools/check_build_options/README.md)) checks in CI that both files and the pkg-config files
|
([`tools/check_build_options`](tools/check_build_options/README.md)) checks in CI that both files and the pkg-config files
|
||||||
stay in sync with the CMake options.
|
stay in sync with the CMake options.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
module(
|
module(
|
||||||
name = "nlohmann_json",
|
name = "nlohmann_json",
|
||||||
|
version = "3.12.0",
|
||||||
compatibility_level = 1,
|
compatibility_level = 1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis macro_builder_check check_build_options
|
.PHONY: all amalgamate check-amalgamation check_build_options pretty install_astyle clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis macro_builder_check run_benchmarks pvs_studio serve_header reuse spdx
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# configuration
|
# configuration
|
||||||
@@ -41,12 +41,18 @@ all:
|
|||||||
@echo "BUILD.bazel - regenerate the Bazel BUILD file from the include/nlohmann sources"
|
@echo "BUILD.bazel - regenerate the Bazel BUILD file from the include/nlohmann sources"
|
||||||
@echo "ChangeLog.md - generate ChangeLog file"
|
@echo "ChangeLog.md - generate ChangeLog file"
|
||||||
@echo "check-amalgamation - check whether sources have been amalgamated and BUILD.bazel is up to date"
|
@echo "check-amalgamation - check whether sources have been amalgamated and BUILD.bazel is up to date"
|
||||||
|
@echo "check_build_options - check that the Meson build and the pkg-config files offer the options of the CMake target"
|
||||||
@echo "clean - remove built files"
|
@echo "clean - remove built files"
|
||||||
@echo "fuzzing - see tests/fuzzing.md for how to build and run the fuzzers"
|
@echo "(fuzzers) - see tests/fuzzing.md, or run 'make -C tests fuzzers' to build the AFL fuzzers"
|
||||||
@echo "macro_builder_check - check that macro_scope.hpp matches tools/macro_builder's output"
|
@echo "macro_builder_check - check that macro_scope.hpp matches tools/macro_builder's output"
|
||||||
@echo "natvis - regenerate nlohmann_json.natvis from the current ABI tags and version"
|
@echo "natvis - regenerate nlohmann_json.natvis from the current ABI tags and version"
|
||||||
@echo "pretty - beautify code with Artistic Style"
|
@echo "pretty - beautify code with Artistic Style"
|
||||||
|
@echo "pvs_studio - run the PVS-Studio static analyzer and open the report"
|
||||||
|
@echo "release - create the release files (include.zip, json.tar.xz, single headers, signatures, hashes)"
|
||||||
|
@echo "reuse - annotate the source files with REUSE license headers and lint them"
|
||||||
@echo "run_benchmarks - build and run benchmarks"
|
@echo "run_benchmarks - build and run benchmarks"
|
||||||
|
@echo "serve_header - serve the single header, re-amalgamated on demand (see tools/serve_header)"
|
||||||
|
@echo "spdx - generate the SPDX software bill of materials nlohmann_json.spdx"
|
||||||
@echo "update_hedley - download Hedley and regenerate hedley.hpp / hedley_undef.hpp"
|
@echo "update_hedley - download Hedley and regenerate hedley.hpp / hedley_undef.hpp"
|
||||||
@echo "update_hedley_undef - rebuild hedley_undef.hpp from the JSON_HEDLEY_* #define names in hedley.hpp"
|
@echo "update_hedley_undef - rebuild hedley_undef.hpp from the JSON_HEDLEY_* #define names in hedley.hpp"
|
||||||
|
|
||||||
@@ -108,13 +114,18 @@ $(AMALGAMATED_FWD_FILE): $(SRCS)
|
|||||||
$(AMALGAMATED_LITERALS_FILE): include/nlohmann/json_literals.hpp
|
$(AMALGAMATED_LITERALS_FILE): include/nlohmann/json_literals.hpp
|
||||||
cp include/nlohmann/json_literals.hpp $(AMALGAMATED_LITERALS_FILE)
|
cp include/nlohmann/json_literals.hpp $(AMALGAMATED_LITERALS_FILE)
|
||||||
|
|
||||||
|
NATVIS_VENV=tools/generate_natvis/venv
|
||||||
|
|
||||||
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
|
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
|
||||||
|
# (the dependencies are installed into a virtual environment first)
|
||||||
natvis:
|
natvis:
|
||||||
python3 tools/generate_natvis/generate_natvis.py .
|
@test -d $(NATVIS_VENV) || python3 -mvenv $(NATVIS_VENV)
|
||||||
|
@$(NATVIS_VENV)/bin/python3 -c 'import jinja2' 2>/dev/null || $(NATVIS_VENV)/bin/pip3 install --quiet -r tools/generate_natvis/requirements.txt
|
||||||
|
$(NATVIS_VENV)/bin/python3 tools/generate_natvis/generate_natvis.py .
|
||||||
|
|
||||||
# regenerate the two tools/macro_builder blocks of $(MACRO_SCOPE_HPP) (see its README.md) and diff against the
|
# regenerate the two tools/macro_builder blocks of $(MACRO_SCOPE_HPP) (see its README.md) and diff against the
|
||||||
# checked-in header; phony, because it never writes $(MACRO_SCOPE_HPP) itself
|
# checked-in header; phony, because it never writes $(MACRO_SCOPE_HPP) itself
|
||||||
macro_builder_check:
|
macro_builder_check: install_astyle
|
||||||
@set -e; \
|
@set -e; \
|
||||||
TMPDIR=$$(mktemp -d ./macro_builder_check.XXXXXX); \
|
TMPDIR=$$(mktemp -d ./macro_builder_check.XXXXXX); \
|
||||||
trap 'rm -rf "$$TMPDIR"' EXIT; \
|
trap 'rm -rf "$$TMPDIR"' EXIT; \
|
||||||
@@ -131,27 +142,27 @@ macro_builder_check:
|
|||||||
check_build_options:
|
check_build_options:
|
||||||
python3 tools/check_build_options/check_build_options.py .
|
python3 tools/check_build_options/check_build_options.py .
|
||||||
|
|
||||||
# check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources
|
# check if the single headers have been amalgamated from the nlohmann sources and if BUILD.bazel and
|
||||||
|
# nlohmann_json.natvis are up to date; all checks are run, and the checked-in files are always restored
|
||||||
check-amalgamation:
|
check-amalgamation:
|
||||||
@mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~
|
@status=0; \
|
||||||
@mv $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_FWD_FILE)~
|
banner() { printf '===================================================================\n %s\n===================================================================\n' "$$1"; }; \
|
||||||
@mv $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_LITERALS_FILE)~
|
for FILE in $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) BUILD.bazel nlohmann_json.natvis; do \
|
||||||
@$(MAKE) amalgamate
|
mv "$$FILE" "$$FILE~" || exit 1; \
|
||||||
@diff $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) ; false)
|
done; \
|
||||||
@diff $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_FWD_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FWD_FILE)~ $(AMALGAMATED_FWD_FILE) ; false)
|
$(MAKE) amalgamate || status=1; \
|
||||||
@diff $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_LITERALS_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_LITERALS_FILE)~ $(AMALGAMATED_LITERALS_FILE) ; false)
|
$(MAKE) BUILD.bazel || status=1; \
|
||||||
@mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE)
|
$(MAKE) natvis || status=1; \
|
||||||
@mv $(AMALGAMATED_FWD_FILE)~ $(AMALGAMATED_FWD_FILE)
|
for FILE in $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE); do \
|
||||||
@mv $(AMALGAMATED_LITERALS_FILE)~ $(AMALGAMATED_LITERALS_FILE)
|
diff "$$FILE" "$$FILE~" || { banner "$$FILE is out of date! Amalgamation required! Please read the contribution guidelines in file .github/CONTRIBUTING.md."; status=1; }; \
|
||||||
@mv BUILD.bazel BUILD.bazel~
|
done; \
|
||||||
@$(MAKE) BUILD.bazel
|
diff BUILD.bazel BUILD.bazel~ || { banner "BUILD.bazel is out of date! Please run 'make BUILD.bazel'."; status=1; }; \
|
||||||
@diff BUILD.bazel BUILD.bazel~ || (echo "===================================================================\n BUILD.bazel is out of date! Please run 'make BUILD.bazel'.\n===================================================================" ; mv BUILD.bazel~ BUILD.bazel ; false)
|
diff nlohmann_json.natvis nlohmann_json.natvis~ || { banner "nlohmann_json.natvis is out of date! Please run 'make natvis'."; status=1; }; \
|
||||||
@mv BUILD.bazel~ BUILD.bazel
|
for FILE in $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) BUILD.bazel nlohmann_json.natvis; do \
|
||||||
@mv nlohmann_json.natvis nlohmann_json.natvis~
|
mv "$$FILE~" "$$FILE"; \
|
||||||
@$(MAKE) natvis
|
done; \
|
||||||
@diff nlohmann_json.natvis nlohmann_json.natvis~ || (echo "===================================================================\n nlohmann_json.natvis is out of date! Please run 'make natvis'.\n===================================================================" ; mv nlohmann_json.natvis~ nlohmann_json.natvis ; false)
|
$(MAKE) macro_builder_check || status=1; \
|
||||||
@mv nlohmann_json.natvis~ nlohmann_json.natvis
|
exit $$status
|
||||||
@$(MAKE) macro_builder_check
|
|
||||||
|
|
||||||
# generate the Bazel BUILD file; phony, because a removed header would not trigger a rebuild
|
# generate the Bazel BUILD file; phony, because a removed header would not trigger a rebuild
|
||||||
BUILD.bazel:
|
BUILD.bazel:
|
||||||
@@ -212,8 +223,8 @@ release: include.zip json.tar.xz
|
|||||||
|
|
||||||
# clean up
|
# clean up
|
||||||
clean:
|
clean:
|
||||||
rm -fr fuzz fuzz-testing *.dSYM tests/*.dSYM
|
rm -fr *.dSYM tests/*.dSYM tests/parse_*_fuzzer
|
||||||
rm -fr cmake-build-benchmarks fuzz-testing cmake-build-pvs-studio release_files
|
rm -fr cmake-build-benchmarks cmake-build-pvs-studio release_files
|
||||||
$(MAKE) clean -Cdocs
|
$(MAKE) clean -Cdocs
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
- [Pkg-config](#pkg-config)
|
- [Pkg-config](#pkg-config)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
- [Contact](#contact)
|
- [Contact](#contact)
|
||||||
|
- [Security](#security)
|
||||||
- [Thanks](#thanks)
|
- [Thanks](#thanks)
|
||||||
- [Used third-party tools](#used-third-party-tools)
|
- [Used third-party tools](#used-third-party-tools)
|
||||||
- [Notes](#notes)
|
- [Notes](#notes)
|
||||||
@@ -112,9 +113,9 @@ There is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/t
|
|||||||
|
|
||||||
## Quick reference
|
## Quick reference
|
||||||
|
|
||||||
- **Constructors** [basic_json](https://json.nlohmann.me/api/basic_json/basic_json), [array](https://json.nlohmann.me/api/basic_json/array), [binary](https://json.nlohmann.me/api/basic_json/binary), [object](https://json.nlohmann.me/api/basic_json/object)
|
- **Constructors**: [basic_json](https://json.nlohmann.me/api/basic_json/basic_json), [array](https://json.nlohmann.me/api/basic_json/array), [binary](https://json.nlohmann.me/api/basic_json/binary), [object](https://json.nlohmann.me/api/basic_json/object)
|
||||||
- **Object inspection**: [type](https://json.nlohmann.me/api/basic_json/type), [operator value_t](https://json.nlohmann.me/api/basic_json/operator_value_t), [type_name](https://json.nlohmann.me/api/basic_json/type_name), [is_primitive](https://json.nlohmann.me/api/basic_json/is_primitive), [is_structured](https://json.nlohmann.me/api/basic_json/is_structured), [is_null](https://json.nlohmann.me/api/basic_json/is_null), [is_boolean](https://json.nlohmann.me/api/basic_json/is_boolean), [is_number](https://json.nlohmann.me/api/basic_json/is_number), [is_number_integer](https://json.nlohmann.me/api/basic_json/is_number_integer), [is_number_unsigned](https://json.nlohmann.me/api/basic_json/is_number_unsigned), [is_number_float](https://json.nlohmann.me/api/basic_json/is_number_float), [is_object](https://json.nlohmann.me/api/basic_json/is_object), [is_array](https://json.nlohmann.me/api/basic_json/is_array), [is_string](https://json.nlohmann.me/api/basic_json/is_string), [is_binary](https://json.nlohmann.me/api/basic_json/is_binary), [is_discarded](https://json.nlohmann.me/api/basic_json/is_discarded)
|
- **Object inspection**: [type](https://json.nlohmann.me/api/basic_json/type), [operator value_t](https://json.nlohmann.me/api/basic_json/operator_value_t), [type_name](https://json.nlohmann.me/api/basic_json/type_name), [is_primitive](https://json.nlohmann.me/api/basic_json/is_primitive), [is_structured](https://json.nlohmann.me/api/basic_json/is_structured), [is_null](https://json.nlohmann.me/api/basic_json/is_null), [is_boolean](https://json.nlohmann.me/api/basic_json/is_boolean), [is_number](https://json.nlohmann.me/api/basic_json/is_number), [is_number_integer](https://json.nlohmann.me/api/basic_json/is_number_integer), [is_number_unsigned](https://json.nlohmann.me/api/basic_json/is_number_unsigned), [is_number_float](https://json.nlohmann.me/api/basic_json/is_number_float), [is_object](https://json.nlohmann.me/api/basic_json/is_object), [is_array](https://json.nlohmann.me/api/basic_json/is_array), [is_string](https://json.nlohmann.me/api/basic_json/is_string), [is_binary](https://json.nlohmann.me/api/basic_json/is_binary), [is_discarded](https://json.nlohmann.me/api/basic_json/is_discarded)
|
||||||
- **Value access**; [get](https://json.nlohmann.me/api/basic_json/get), [get_to](https://json.nlohmann.me/api/basic_json/get_to), [get_ptr](https://json.nlohmann.me/api/basic_json/get_ptr), [get_ref](https://json.nlohmann.me/api/basic_json/get_ref), [operator ValueType](https://json.nlohmann.me/api/basic_json/operator_ValueType), [get_binary](https://json.nlohmann.me/api/basic_json/get_binary)
|
- **Value access**: [get](https://json.nlohmann.me/api/basic_json/get), [get_to](https://json.nlohmann.me/api/basic_json/get_to), [get_ptr](https://json.nlohmann.me/api/basic_json/get_ptr), [get_ref](https://json.nlohmann.me/api/basic_json/get_ref), [operator ValueType](https://json.nlohmann.me/api/basic_json/operator_ValueType), [get_binary](https://json.nlohmann.me/api/basic_json/get_binary)
|
||||||
- **Element access**: [at](https://json.nlohmann.me/api/basic_json/at), [operator[]](https://json.nlohmann.me/api/basic_json/operator[]), [value](https://json.nlohmann.me/api/basic_json/value), [front](https://json.nlohmann.me/api/basic_json/front), [back](https://json.nlohmann.me/api/basic_json/back)
|
- **Element access**: [at](https://json.nlohmann.me/api/basic_json/at), [operator[]](https://json.nlohmann.me/api/basic_json/operator[]), [value](https://json.nlohmann.me/api/basic_json/value), [front](https://json.nlohmann.me/api/basic_json/front), [back](https://json.nlohmann.me/api/basic_json/back)
|
||||||
- **Lookup**: [find](https://json.nlohmann.me/api/basic_json/find), [count](https://json.nlohmann.me/api/basic_json/count), [contains](https://json.nlohmann.me/api/basic_json/contains)
|
- **Lookup**: [find](https://json.nlohmann.me/api/basic_json/find), [count](https://json.nlohmann.me/api/basic_json/count), [contains](https://json.nlohmann.me/api/basic_json/contains)
|
||||||
- **Iterators**: [begin](https://json.nlohmann.me/api/basic_json/begin), [cbegin](https://json.nlohmann.me/api/basic_json/cbegin), [end](https://json.nlohmann.me/api/basic_json/end), [cend](https://json.nlohmann.me/api/basic_json/cend), [rbegin](https://json.nlohmann.me/api/basic_json/rbegin), [rend](https://json.nlohmann.me/api/basic_json/rend), [crbegin](https://json.nlohmann.me/api/basic_json/crbegin), [crend](https://json.nlohmann.me/api/basic_json/crend), [items](https://json.nlohmann.me/api/basic_json/items)
|
- **Iterators**: [begin](https://json.nlohmann.me/api/basic_json/begin), [cbegin](https://json.nlohmann.me/api/basic_json/cbegin), [end](https://json.nlohmann.me/api/basic_json/end), [cend](https://json.nlohmann.me/api/basic_json/cend), [rbegin](https://json.nlohmann.me/api/basic_json/rbegin), [rend](https://json.nlohmann.me/api/basic_json/rend), [crbegin](https://json.nlohmann.me/api/basic_json/crbegin), [crend](https://json.nlohmann.me/api/basic_json/crend), [items](https://json.nlohmann.me/api/basic_json/items)
|
||||||
@@ -1184,7 +1185,7 @@ binary[1]; // 0xFE
|
|||||||
binary.set_subtype(0x10);
|
binary.set_subtype(0x10);
|
||||||
|
|
||||||
// serialize to MessagePack
|
// serialize to MessagePack
|
||||||
auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE
|
auto msgpack = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE
|
||||||
```
|
```
|
||||||
|
|
||||||
## Customers
|
## Customers
|
||||||
@@ -1220,17 +1221,7 @@ I would be happy to learn about other compilers/versions.
|
|||||||
Please note:
|
Please note:
|
||||||
|
|
||||||
- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler.
|
- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler.
|
||||||
- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default.
|
- For GCC running on MinGW or Android, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`) may occur. Note this is not an issue with the code, but rather with the compiler or C++ standard library itself: use a recent toolchain (for Android, a current [NDK](https://developer.android.com/ndk) with the LLVM C++ library `APP_STL := c++_shared`, and for MinGW, a distribution with a complete C++11 standard library). See [this discussion](https://github.com/nlohmann/json/issues/136) for MinGW and [this discussion](https://github.com/nlohmann/json/issues/219) for the old Android NDK using `APP_STL := gnustl_static`.
|
||||||
|
|
||||||
```makefile
|
|
||||||
APP_STL := c++_shared
|
|
||||||
NDK_TOOLCHAIN_VERSION := clang3.6
|
|
||||||
APP_CPPFLAGS += -frtti -fexceptions
|
|
||||||
```
|
|
||||||
|
|
||||||
The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10.
|
|
||||||
|
|
||||||
- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](https://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219).
|
|
||||||
|
|
||||||
- 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.
|
- 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.
|
||||||
|
|
||||||
@@ -1437,436 +1428,416 @@ I deeply appreciate the help of the following people.
|
|||||||
12. [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual Studio.
|
12. [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual Studio.
|
||||||
13. [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types.
|
13. [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types.
|
||||||
14. [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.
|
14. [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.
|
||||||
15. [dariomt](https://github.com/dariomt) fixed some typos in the examples.
|
15. [dariomt](https://github.com/dariomt) fixed some typos in the examples and fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values.
|
||||||
16. [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.
|
16. [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.
|
||||||
17. [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue.
|
17. [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue.
|
||||||
18. [Huu Nguyen](https://github.com/whoshuu) corrected a variable name in the documentation.
|
18. [Huu Nguyen](https://github.com/whoshuu) corrected a variable name in the documentation.
|
||||||
19. [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference.
|
19. [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference.
|
||||||
20. [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values.
|
20. [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK.
|
||||||
21. [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK.
|
21. [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio.
|
||||||
22. [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio.
|
22. [406345](https://github.com/406345) fixed two small warnings.
|
||||||
23. [406345](https://github.com/406345) fixed two small warnings.
|
23. [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.
|
||||||
24. [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.
|
24. [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
|
||||||
25. [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
|
25. [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers.
|
||||||
26. [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers.
|
26. [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.
|
||||||
27. [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.
|
27. [msm-](https://github.com/msm-) added support for American Fuzzy Lop.
|
||||||
28. [msm-](https://github.com/msm-) added support for American Fuzzy Lop.
|
28. [Annihil](https://github.com/Annihil) fixed an example in the README file.
|
||||||
29. [Annihil](https://github.com/Annihil) fixed an example in the README file.
|
29. [Themercee](https://github.com/Themercee) noted a wrong URL in the README file.
|
||||||
30. [Themercee](https://github.com/Themercee) noted a wrong URL in the README file.
|
30. [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`.
|
||||||
31. [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`.
|
31. [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212).
|
||||||
32. [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212).
|
32. [zewt](https://github.com/zewt) added useful notes to the README file about Android.
|
||||||
33. [zewt](https://github.com/zewt) added useful notes to the README file about Android.
|
33. [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake.
|
||||||
34. [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake.
|
34. [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files.
|
||||||
35. [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files.
|
35. [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal).
|
||||||
36. [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal).
|
36. [Mário Feroldi](https://github.com/thelostt) fixed a small typo.
|
||||||
37. [Mário Feroldi](https://github.com/thelostt) fixed a small typo.
|
37. [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
|
||||||
38. [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
|
38. [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
|
||||||
39. [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
|
39. [Thomas Braun](https://github.com/t-b) fixed a warning in a test case and adjusted MSVC calls in the CI.
|
||||||
40. [Thomas Braun](https://github.com/t-b) fixed a warning in a test case and adjusted MSVC calls in the CI.
|
40. [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks.
|
||||||
41. [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks.
|
41. [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.
|
||||||
42. [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.
|
42. [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.
|
||||||
43. [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.
|
43. [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
|
||||||
44. [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
|
44. [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.
|
||||||
45. [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.
|
45. [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
|
||||||
46. [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
|
46. [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.
|
||||||
47. [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.
|
47. [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.
|
||||||
48. [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.
|
48. [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.
|
||||||
49. [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.
|
49. [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning and supported the implementation of user-defined types.
|
||||||
50. [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning.
|
50. [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check.
|
||||||
51. [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check.
|
51. [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one.
|
||||||
52. [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one.
|
52. [Daniel599](https://github.com/Daniel599) helped to get Travis to execute the tests with Clang's sanitizers and allowed to use more algorithms with the `items()` function.
|
||||||
53. [Daniel599](https://github.com/Daniel599) helped to get Travis to execute the tests with Clang's sanitizers.
|
53. [Jonathan Lee](https://github.com/vjon) fixed an example in the README file.
|
||||||
54. [Jonathan Lee](https://github.com/vjon) fixed an example in the README file.
|
54. [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types.
|
||||||
55. [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types.
|
55. [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio.
|
||||||
56. [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio.
|
56. [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example.
|
||||||
57. [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types.
|
57. [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite.
|
||||||
58. [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example.
|
58. [ukhegg](https://github.com/ukhegg) proposed an improvement for the examples section.
|
||||||
59. [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite.
|
59. [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README.
|
||||||
60. [ukhegg](https://github.com/ukhegg) proposed an improvement for the examples section.
|
60. [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s.
|
||||||
61. [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README.
|
61. [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation.
|
||||||
62. [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s.
|
62. [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings.
|
||||||
63. [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation.
|
63. [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible.
|
||||||
64. [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings.
|
64. [ftillier](https://github.com/ftillier) fixed a compiler warning.
|
||||||
65. [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible.
|
65. [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped.
|
||||||
66. [ftillier](https://github.com/ftillier) fixed a compiler warning.
|
66. [Fytch](https://github.com/Fytch) found a bug in the documentation.
|
||||||
67. [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped.
|
67. [Jay Sistar](https://github.com/Type1J) implemented a Meson build description.
|
||||||
68. [Fytch](https://github.com/Fytch) found a bug in the documentation.
|
68. [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation.
|
||||||
69. [Jay Sistar](https://github.com/Type1J) implemented a Meson build description.
|
69. [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager.
|
||||||
70. [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation.
|
70. [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`.
|
||||||
71. [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager.
|
71. [Mike Tzou](https://github.com/Chocobo1) fixed some typos.
|
||||||
72. [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`.
|
72. [amrcode](https://github.com/amrcode) noted misleading documentation about comparison of floats.
|
||||||
73. [Mike Tzou](https://github.com/Chocobo1) fixed some typos.
|
73. [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `<iostream>` with `<iosfwd>`.
|
||||||
74. [amrcode](https://github.com/amrcode) noted misleading documentation about comparison of floats.
|
74. [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library.
|
||||||
75. [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `<iostream>` with `<iosfwd>`.
|
75. [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists.
|
||||||
76. [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library.
|
76. [Greg Hurrell](https://github.com/wincent) fixed a typo.
|
||||||
77. [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists.
|
77. [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo.
|
||||||
78. [Greg Hurrell](https://github.com/wincent) fixed a typo.
|
78. [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler.
|
||||||
79. [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo.
|
79. [Markus Werle](https://github.com/daixtrose) fixed a typo.
|
||||||
80. [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler.
|
80. [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check.
|
||||||
81. [Markus Werle](https://github.com/daixtrose) fixed a typo.
|
81. [Alex](https://github.com/leha-bot) noted an error in a code sample.
|
||||||
82. [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check.
|
82. [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped to fix them.
|
||||||
83. [Alex](https://github.com/leha-bot) noted an error in a code sample.
|
83. [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams.
|
||||||
84. [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped to fix them.
|
84. [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error, fixed the compilation with MSVC 2015 in debug mode and fixed a warning.
|
||||||
85. [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams.
|
85. [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings and avoided unnecessary string copies in `find()` and `count()`.
|
||||||
86. [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error.
|
86. [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file.
|
||||||
87. [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings.
|
87. [pvleuven](https://github.com/pvleuven) helped to fix a warning in ICC.
|
||||||
88. [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file.
|
88. [Pavel](https://github.com/crea7or) helped to fix some warnings in MSVC.
|
||||||
89. [pvleuven](https://github.com/pvleuven) helped to fix a warning in ICC.
|
89. [Mitja](https://github.com/Itja) fixed some typos.
|
||||||
90. [Pavel](https://github.com/crea7or) helped to fix some warnings in MSVC.
|
90. [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links.
|
||||||
91. [Jamie Seward](https://github.com/jseward) avoided unnecessary string copies in `find()` and `count()`.
|
91. [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view and removed the dependency from `std::stringstream`.
|
||||||
92. [Mitja](https://github.com/Itja) fixed some typos.
|
92. [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings.
|
||||||
93. [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links.
|
93. [Eren Okka](https://github.com/erengy) fixed some MSVC warnings.
|
||||||
94. [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view.
|
94. [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed.
|
||||||
95. [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings.
|
95. [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README.
|
||||||
96. [Eren Okka](https://github.com/erengy) fixed some MSVC warnings.
|
96. [zerodefect](https://github.com/zerodefect) fixed a compiler warning.
|
||||||
97. [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed.
|
97. [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior.
|
||||||
98. [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README.
|
98. [mark-99](https://github.com/mark-99) helped fix an ICC error.
|
||||||
99. [zerodefect](https://github.com/zerodefect) fixed a compiler warning.
|
99. [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file.
|
||||||
100. [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior.
|
100. [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings.
|
||||||
101. [mark-99](https://github.com/mark-99) helped fix an ICC error.
|
101. [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager.
|
||||||
102. [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file.
|
102. [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise.
|
||||||
103. [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings.
|
103. [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback.
|
||||||
104. [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager.
|
104. [agrianius](https://github.com/agrianius) allowed dumping JSON to an alternative string type and added code to use alternative string implementations.
|
||||||
105. [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise.
|
105. [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake.
|
||||||
106. [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback.
|
106. [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io).
|
||||||
107. [agrianius](https://github.com/agrianius) allowed dumping JSON to an alternative string type.
|
107. [Carlos O'Ryan](https://github.com/coryan) fixed a typo.
|
||||||
108. [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake.
|
108. [James Upjohn](https://github.com/jupjohn) fixed a version number in the compilers section.
|
||||||
109. [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io).
|
109. [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration.
|
||||||
110. [Carlos O'Ryan](https://github.com/coryan) fixed a typo.
|
110. [Jan Schöppach](https://github.com/dns13) fixed a typo.
|
||||||
111. [James Upjohn](https://github.com/jupjohn) fixed a version number in the compilers section.
|
111. [martin-mfg](https://github.com/martin-mfg) fixed a typo.
|
||||||
112. [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration.
|
112. [Julius Rakow](https://github.com/juliusrakow) fixed the Meson include directory and fixed the links to [cppreference.com](https://cppreference.com).
|
||||||
113. [Jan Schöppach](https://github.com/dns13) fixed a typo.
|
113. [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases.
|
||||||
114. [martin-mfg](https://github.com/martin-mfg) fixed a typo.
|
114. [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library and fixed an issue with a double macro definition.
|
||||||
115. [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`.
|
115. [thyu](https://github.com/thyu) fixed a compiler warning.
|
||||||
116. [agrianius](https://github.com/agrianius) added code to use alternative string implementations.
|
116. [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2.
|
||||||
117. [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function.
|
117. [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library.
|
||||||
118. [Julius Rakow](https://github.com/juliusrakow) fixed the Meson include directory and fixed the links to [cppreference.com](https://cppreference.com).
|
118. [Ben Berman](https://github.com/rivertam) made some error messages more understandable.
|
||||||
119. [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode.
|
119. [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler.
|
||||||
120. [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases.
|
120. [mandreyel](https://github.com/mandreyel) fixed a compilation problem.
|
||||||
121. [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library.
|
121. [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file.
|
||||||
122. [thyu](https://github.com/thyu) fixed a compiler warning.
|
122. [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8.
|
||||||
123. [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2.
|
123. [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory.
|
||||||
124. [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library.
|
124. [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning.
|
||||||
125. [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition.
|
125. [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define an enum/JSON mapping.
|
||||||
126. [Ben Berman](https://github.com/rivertam) made some error messages more understandable.
|
126. [efp](https://github.com/efp) added line and column information to parse errors.
|
||||||
127. [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler.
|
127. [julian-becker](https://github.com/julian-becker) added BSON support.
|
||||||
128. [mandreyel](https://github.com/mandreyel) fixed a compilation problem.
|
128. [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings.
|
||||||
129. [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file.
|
129. [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version).
|
||||||
130. [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8.
|
130. [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`.
|
||||||
131. [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory.
|
131. [kjpus](https://github.com/kjpus) fixed a link in the documentation.
|
||||||
132. [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning.
|
132. [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation.
|
||||||
133. [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define an enum/JSON mapping.
|
133. [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning.
|
||||||
134. [efp](https://github.com/efp) added line and column information to parse errors.
|
134. [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC.
|
||||||
135. [julian-becker](https://github.com/julian-becker) added BSON support.
|
135. [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream.
|
||||||
136. [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings.
|
136. [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson.
|
||||||
137. [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version).
|
137. [Michael Behrns-Miller](https://github.com/moodboom) found an issue with a missing namespace.
|
||||||
138. [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`.
|
138. [Nasztanovics Ferenc](https://github.com/naszta) fixed a compilation issue with libc 2.12.
|
||||||
139. [kjpus](https://github.com/kjpus) fixed a link in the documentation.
|
139. [Andreas Schwab](https://github.com/andreas-schwab) fixed the endian conversion.
|
||||||
140. [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation.
|
140. [Mark-Dunning](https://github.com/Mark-Dunning) fixed a warning in MSVC.
|
||||||
141. [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning.
|
141. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) added `operator/` for JSON Pointers and fixed a compilation issue with MSVC.
|
||||||
142. [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC.
|
142. [John-Mark](https://github.com/johnmarkwayve) noted a missing header.
|
||||||
143. [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream.
|
143. [Vitaly Zaitsev](https://github.com/xvitaly) fixed compilation with GCC 9.0.
|
||||||
144. [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson.
|
144. [Laurent Stacul](https://github.com/stac47) fixed compilation with GCC 9.0.
|
||||||
145. [Michael Behrns-Miller](https://github.com/moodboom) found an issue with a missing namespace.
|
145. [Ivor Wanders](https://github.com/iwanders) helped to reduce the CMake requirement to version 3.1 and fixed the examples to catch exception by `const&`.
|
||||||
146. [Nasztanovics Ferenc](https://github.com/naszta) fixed a compilation issue with libc 2.12.
|
146. [njlr](https://github.com/njlr) updated the Buckaroo instructions.
|
||||||
147. [Andreas Schwab](https://github.com/andreas-schwab) fixed the endian conversion.
|
147. [Lion](https://github.com/lieff) fixed a compilation issue with GCC 7 on CentOS.
|
||||||
148. [Mark-Dunning](https://github.com/Mark-Dunning) fixed a warning in MSVC.
|
148. [Isaac Nickaein](https://github.com/nickaein) improved the integer serialization performance and implemented the `contains()` function.
|
||||||
149. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) added `operator/` for JSON Pointers.
|
149. [past-due](https://github.com/past-due) suppressed an unfixable warning.
|
||||||
150. [John-Mark](https://github.com/johnmarkwayve) noted a missing header.
|
150. [Elvis Oric](https://github.com/elvisoric) improved Meson support.
|
||||||
151. [Vitaly Zaitsev](https://github.com/xvitaly) fixed compilation with GCC 9.0.
|
151. [Matěj Plch](https://github.com/Afforix) fixed an example in the README.
|
||||||
152. [Laurent Stacul](https://github.com/stac47) fixed compilation with GCC 9.0.
|
152. [Mark Beckwith](https://github.com/wythe) fixed two typos.
|
||||||
153. [Ivor Wanders](https://github.com/iwanders) helped to reduce the CMake requirement to version 3.1.
|
153. [scinart](https://github.com/scinart) fixed a bug in the serializer.
|
||||||
154. [njlr](https://github.com/njlr) updated the Buckaroo instructions.
|
154. [Patrick Boettcher](https://github.com/pboettch) implemented `push_back()` and `pop_back()` for JSON Pointers.
|
||||||
155. [Lion](https://github.com/lieff) fixed a compilation issue with GCC 7 on CentOS.
|
155. [Bruno Oliveira](https://github.com/nicoddemus) added support for Conda.
|
||||||
156. [Isaac Nickaein](https://github.com/nickaein) improved the integer serialization performance and implemented the `contains()` function.
|
156. [Michele Caini](https://github.com/skypjack) fixed links in the README.
|
||||||
157. [past-due](https://github.com/past-due) suppressed an unfixable warning.
|
157. [Hani](https://github.com/hnkb) documented how to install the library with NuGet.
|
||||||
158. [Elvis Oric](https://github.com/elvisoric) improved Meson support.
|
158. [yann-morin-1998](https://github.com/yann-morin-1998) helped to reduce the CMake requirement to version 3.1.
|
||||||
159. [Matěj Plch](https://github.com/Afforix) fixed an example in the README.
|
159. [Konstantin Podsvirov](https://github.com/podsvirov) maintains a package for the MSYS2 software distro and fixed the MSYS2 package documentation.
|
||||||
160. [Mark Beckwith](https://github.com/wythe) fixed a typo.
|
160. [remyabel](https://github.com/remyabel2) added GNUInstallDirs to the CMake files.
|
||||||
161. [scinart](https://github.com/scinart) fixed a bug in the serializer.
|
161. [Taylor Howard](https://github.com/taylorhoward92) fixed a unit test.
|
||||||
162. [Patrick Boettcher](https://github.com/pboettch) implemented `push_back()` and `pop_back()` for JSON Pointers.
|
162. [Gabe Ron](https://github.com/Macr0Nerd) implemented the `to_string` method.
|
||||||
163. [Bruno Oliveira](https://github.com/nicoddemus) added support for Conda.
|
163. [Watal M. Iwasaki](https://github.com/heavywatal) fixed a Clang warning.
|
||||||
164. [Michele Caini](https://github.com/skypjack) fixed links in the README.
|
164. [Viktor Kirilov](https://github.com/onqtam) switched the unit tests from [Catch](https://github.com/philsquared/Catch) to [doctest](https://github.com/doctest/doctest)
|
||||||
165. [Hani](https://github.com/hnkb) documented how to install the library with NuGet.
|
165. [Juncheng E](https://github.com/ejcjason) fixed a typo.
|
||||||
166. [Mark Beckwith](https://github.com/wythe) fixed a typo.
|
166. [tete17](https://github.com/tete17) fixed a bug in the `contains` function.
|
||||||
167. [yann-morin-1998](https://github.com/yann-morin-1998) helped to reduce the CMake requirement to version 3.1.
|
167. [Xav83](https://github.com/Xav83) fixed some cppcheck warnings.
|
||||||
168. [Konstantin Podsvirov](https://github.com/podsvirov) maintains a package for the MSYS2 software distro.
|
168. [0xflotus](https://github.com/0xflotus) fixed some typos.
|
||||||
169. [remyabel](https://github.com/remyabel2) added GNUInstallDirs to the CMake files.
|
169. [Christian Deneke](https://github.com/chris0x44) added a const version of `json_pointer::back`.
|
||||||
170. [Taylor Howard](https://github.com/taylorhoward92) fixed a unit test.
|
170. [Julien Hamaide](https://github.com/crazyjul) made the `items()` function work with custom string types.
|
||||||
171. [Gabe Ron](https://github.com/Macr0Nerd) implemented the `to_string` method.
|
171. [Evan Nemerson](https://github.com/nemequ) updated fixed a bug in Hedley and updated this library accordingly.
|
||||||
172. [Watal M. Iwasaki](https://github.com/heavywatal) fixed a Clang warning.
|
172. [Florian Pigorsch](https://github.com/flopp) fixed a lot of typos.
|
||||||
173. [Viktor Kirilov](https://github.com/onqtam) switched the unit tests from [Catch](https://github.com/philsquared/Catch) to [doctest](https://github.com/onqtam/doctest)
|
173. [Camille Bégué](https://github.com/cbegue) fixed an issue in the conversion from `std::pair` and `std::tuple` to `json`.
|
||||||
174. [Juncheng E](https://github.com/ejcjason) fixed a typo.
|
174. [Anthony VH](https://github.com/AnthonyVH) fixed a compile error in an enum deserialization.
|
||||||
175. [tete17](https://github.com/tete17) fixed a bug in the `contains` function.
|
175. [Yuriy Vountesmery](https://github.com/ua-code-dragon) noted a subtle bug in a preprocessor check.
|
||||||
176. [Xav83](https://github.com/Xav83) fixed some cppcheck warnings.
|
176. [Chen](https://github.com/dota17) fixed numerous issues in the library.
|
||||||
177. [0xflotus](https://github.com/0xflotus) fixed some typos.
|
177. [Antony Kellermann](https://github.com/aokellermann) added a CI step for GCC 10.1.
|
||||||
178. [Christian Deneke](https://github.com/chris0x44) added a const version of `json_pointer::back`.
|
178. [Alex](https://github.com/gistrec) fixed an MSVC warning.
|
||||||
179. [Julien Hamaide](https://github.com/crazyjul) made the `items()` function work with custom string types.
|
179. [Rainer](https://github.com/rvjr) proposed an improvement in the floating-point serialization in CBOR.
|
||||||
180. [Evan Nemerson](https://github.com/nemequ) updated fixed a bug in Hedley and updated this library accordingly.
|
180. [Francois Chabot](https://github.com/FrancoisChabot) made performance improvements in the input adapters.
|
||||||
181. [Florian Pigorsch](https://github.com/flopp) fixed a lot of typos.
|
181. [Arthur Sonzogni](https://github.com/ArthurSonzogni) documented how the library can be included via `FetchContent`.
|
||||||
182. [Camille Bégué](https://github.com/cbegue) fixed an issue in the conversion from `std::pair` and `std::tuple` to `json`.
|
182. [Rimas Misevičius](https://github.com/rmisev) fixed an error message.
|
||||||
183. [Anthony VH](https://github.com/AnthonyVH) fixed a compile error in an enum deserialization.
|
183. [Alexander Myasnikov](https://github.com/alexandermyasnikov) fixed some examples and a link in the README.
|
||||||
184. [Yuriy Vountesmery](https://github.com/ua-code-dragon) noted a subtle bug in a preprocessor check.
|
184. [Hubert Chathi](https://github.com/uhoreg) made CMake's version config file architecture-independent.
|
||||||
185. [Chen](https://github.com/dota17) fixed numerous issues in the library.
|
185. [OmnipotentEntity](https://github.com/OmnipotentEntity) implemented the binary values for CBOR, MessagePack, BSON, and UBJSON.
|
||||||
186. [Antony Kellermann](https://github.com/aokellermann) added a CI step for GCC 10.1.
|
186. [ArtemSarmini](https://github.com/ArtemSarmini) fixed a compilation issue with GCC 10 and fixed a leak.
|
||||||
187. [Alex](https://github.com/gistrec) fixed an MSVC warning.
|
187. [Evgenii Sopov](https://github.com/sea5kg) integrated the library to the wsjcpp package manager.
|
||||||
188. [Rainer](https://github.com/rvjr) proposed an improvement in the floating-point serialization in CBOR.
|
188. [Sergey Linev](https://github.com/linev) fixed a compiler warning.
|
||||||
189. [Francois Chabot](https://github.com/FrancoisChabot) made performance improvements in the input adapters.
|
189. [Miguel Magalhães](https://github.com/magamig) fixed the year in the copyright.
|
||||||
190. [Arthur Sonzogni](https://github.com/ArthurSonzogni) documented how the library can be included via `FetchContent`.
|
190. [Alexander “weej” Jones](https://github.com/alex-weej) fixed an example in the README.
|
||||||
191. [Rimas Misevičius](https://github.com/rmisev) fixed an error message.
|
191. [Antoine Cœur](https://github.com/Coeur) fixed some typos in the documentation.
|
||||||
192. [Alexander Myasnikov](https://github.com/alexandermyasnikov) fixed some examples and a link in the README.
|
192. [jothepro](https://github.com/jothepro) updated links to the Hunter package.
|
||||||
193. [Hubert Chathi](https://github.com/uhoreg) made CMake's version config file architecture-independent.
|
193. [Dave Lee](https://github.com/kastiglione) fixed a link in the README.
|
||||||
194. [OmnipotentEntity](https://github.com/OmnipotentEntity) implemented the binary values for CBOR, MessagePack, BSON, and UBJSON.
|
194. [Joël Lamotte](https://github.com/Klaim) added instruction for using Build2's package manager.
|
||||||
195. [ArtemSarmini](https://github.com/ArtemSarmini) fixed a compilation issue with GCC 10 and fixed a leak.
|
195. [Paul Jurczak](https://github.com/pauljurczak) fixed an example in the README.
|
||||||
196. [Evgenii Sopov](https://github.com/sea5kg) integrated the library to the wsjcpp package manager.
|
196. [Carlos Gomes Martinho](https://github.com/gocarlos) updated the Conan package source.
|
||||||
197. [Sergey Linev](https://github.com/linev) fixed a compiler warning.
|
197. [Tridacnid](https://github.com/Tridacnid) improved the CMake tests.
|
||||||
198. [Miguel Magalhães](https://github.com/magamig) fixed the year in the copyright.
|
198. [Michael](https://github.com/MBalszun) fixed MSVC warnings.
|
||||||
199. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) fixed a compilation issue with MSVC.
|
199. [Quentin Barbarat](https://github.com/quentin-dev) fixed an example in the documentation.
|
||||||
200. [Alexander “weej” Jones](https://github.com/alex-weej) fixed an example in the README.
|
200. [XyFreak](https://github.com/XyFreak) fixed a compiler warning.
|
||||||
201. [Antoine Cœur](https://github.com/Coeur) fixed some typos in the documentation.
|
201. [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README and updated the links in the documentation to use HTTPS.
|
||||||
202. [jothepro](https://github.com/jothepro) updated links to the Hunter package.
|
202. [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input.
|
||||||
203. [Dave Lee](https://github.com/kastiglione) fixed a link in the README.
|
203. [AODQ](https://github.com/AODQ) fixed a compiler warning.
|
||||||
204. [Joël Lamotte](https://github.com/Klaim) added instruction for using Build2's package manager.
|
204. [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline.
|
||||||
205. [Paul Jurczak](https://github.com/pauljurczak) fixed an example in the README.
|
205. [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.
|
||||||
206. [Sonu Lohani](https://github.com/sonulohani) fixed a warning.
|
206. [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values.
|
||||||
207. [Carlos Gomes Martinho](https://github.com/gocarlos) updated the Conan package source.
|
207. [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation.
|
||||||
208. [Konstantin Podsvirov](https://github.com/podsvirov) fixed the MSYS2 package documentation.
|
208. [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes.
|
||||||
209. [Tridacnid](https://github.com/Tridacnid) improved the CMake tests.
|
209. [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`.
|
||||||
210. [Michael](https://github.com/MBalszun) fixed MSVC warnings.
|
210. [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config.
|
||||||
211. [Quentin Barbarat](https://github.com/quentin-dev) fixed an example in the documentation.
|
211. [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.
|
||||||
212. [XyFreak](https://github.com/XyFreak) fixed a compiler warning.
|
212. [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support.
|
||||||
213. [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README.
|
213. [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`.
|
||||||
214. [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input.
|
214. [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer.
|
||||||
215. [AODQ](https://github.com/AODQ) fixed a compiler warning.
|
215. Lars Wirzenius reviewed the README file.
|
||||||
216. [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline.
|
216. [Jun Jie](https://github.com/ongjunjie) fixed a compiler path in the CMake scripts.
|
||||||
217. [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.
|
217. [Ronak Buch](https://github.com/rbuch) fixed typos in the documentation.
|
||||||
218. [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values.
|
218. [Alexander Karzhenkov](https://github.com/karzhenkov) fixed a move constructor and the Travis builds.
|
||||||
219. [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation.
|
219. [Leonardo Lima](https://github.com/leozz37) added CPM.Cmake support.
|
||||||
220. [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes.
|
220. [Joseph Blackman](https://github.com/jbzdarkid) fixed a warning.
|
||||||
221. [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`.
|
221. [Yaroslav](https://github.com/YarikTH) updated doctest and implemented unit tests.
|
||||||
222. [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config.
|
222. [Martin Stump](https://github.com/globberwops) fixed a bug in the CMake files.
|
||||||
223. [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.
|
223. [Jaakko Moisio](https://github.com/jasujm) fixed a bug in the input adapters.
|
||||||
224. [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support.
|
224. [bl-ue](https://github.com/bl-ue) fixed some Markdown issues in the README file.
|
||||||
225. [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`.
|
225. [William A. Wieselquist](https://github.com/wawiesel) fixed an example from the README.
|
||||||
226. [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer.
|
226. [abbaswasim](https://github.com/abbaswasim) fixed an example from the README.
|
||||||
227. Lars Wirzenius reviewed the README file.
|
227. [Remy Jette](https://github.com/remyjette) fixed a warning.
|
||||||
228. [Jun Jie](https://github.com/ongjunjie) fixed a compiler path in the CMake scripts.
|
228. [Fraser](https://github.com/frasermarlow) fixed the documentation.
|
||||||
229. [Ronak Buch](https://github.com/rbuch) fixed typos in the documentation.
|
229. [Ben Beasley](https://github.com/musicinmybrain) updated doctest.
|
||||||
230. [Alexander Karzhenkov](https://github.com/karzhenkov) fixed a move constructor and the Travis builds.
|
230. [Doron Behar](https://github.com/doronbehar) fixed pkg-config.pc.
|
||||||
231. [Leonardo Lima](https://github.com/leozz37) added CPM.Cmake support.
|
231. [raduteo](https://github.com/raduteo) fixed a warning.
|
||||||
232. [Joseph Blackman](https://github.com/jbzdarkid) fixed a warning.
|
232. [David Pfahler](https://github.com/theShmoo) added the possibility to compile the library without I/O support.
|
||||||
233. [Yaroslav](https://github.com/YarikTH) updated doctest and implemented unit tests.
|
233. [Morten Fyhn Amundsen](https://github.com/mortenfyhn) fixed a typo.
|
||||||
234. [Martin Stump](https://github.com/globberwops) fixed a bug in the CMake files.
|
234. [jpl-mac](https://github.com/jpl-mac) allowed treating the library as a system header in CMake.
|
||||||
235. [Jaakko Moisio](https://github.com/jasujm) fixed a bug in the input adapters.
|
235. [Jason Dsouza](https://github.com/jasmcaus) fixed the indentation of the CMake file.
|
||||||
236. [bl-ue](https://github.com/bl-ue) fixed some Markdown issues in the README file.
|
236. [offa](https://github.com/offa) added a link to Conan Center to the documentation.
|
||||||
237. [William A. Wieselquist](https://github.com/wawiesel) fixed an example from the README.
|
237. [Rafail Giavrimis](https://github.com/grafail) fixed the Google Benchmark default branch.
|
||||||
238. [abbaswasim](https://github.com/abbaswasim) fixed an example from the README.
|
238. [Louis Dionne](https://github.com/ldionne) fixed a conversion operator.
|
||||||
239. [Remy Jette](https://github.com/remyjette) fixed a warning.
|
239. [justanotheranonymoususer](https://github.com/justanotheranonymoususer) made the examples in the README more consistent.
|
||||||
240. [Fraser](https://github.com/frasermarlow) fixed the documentation.
|
240. [Finkman](https://github.com/Finkman) suppressed some `-Wfloat-equal` warnings and fixed the debug pretty-printer.
|
||||||
241. [Ben Beasley](https://github.com/musicinmybrain) updated doctest.
|
241. [Ferry Huberts](https://github.com/fhuberts) fixed `-Wswitch-enum` warnings and fixed a typo.
|
||||||
242. [Doron Behar](https://github.com/doronbehar) fixed pkg-config.pc.
|
242. [Arseniy Terekhin](https://github.com/senyai) made the GDB pretty-printer robust against unset variable names.
|
||||||
243. [raduteo](https://github.com/raduteo) fixed a warning.
|
243. [Amir Masoud Abdol](https://github.com/amirmasoudabdol) updated the Homebrew command as nlohmann/json is now in homebrew-core.
|
||||||
244. [David Pfahler](https://github.com/theShmoo) added the possibility to compile the library without I/O support.
|
244. [Hallot](https://github.com/Hallot) fixed some `-Wextra-semi-stmt warnings`.
|
||||||
245. [Morten Fyhn Amundsen](https://github.com/mortenfyhn) fixed a typo.
|
245. [Giovanni Cerretani](https://github.com/gcerretani) fixed `-Wunused` warnings on `JSON_DIAGNOSTICS` and fixed a check for `std::filesystem`.
|
||||||
246. [jpl-mac](https://github.com/jpl-mac) allowed treating the library as a system header in CMake.
|
246. [Bogdan Popescu](https://github.com/Kapeli) hosts the [docset](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for offline documentation viewers.
|
||||||
247. [Jason Dsouza](https://github.com/jasmcaus) fixed the indentation of the CMake file.
|
247. [Carl Smedstad](https://github.com/carlsmedstad) fixed an assertion error when using `JSON_DIAGNOSTICS`.
|
||||||
248. [offa](https://github.com/offa) added a link to Conan Center to the documentation.
|
248. [miikka75](https://github.com/miikka75) provided an important fix to compile C++17 code with Clang 9.
|
||||||
249. [TotalCaesar659](https://github.com/TotalCaesar659) updated the links in the documentation to use HTTPS.
|
249. [Maarten Becker](https://github.com/kernie) fixed a warning for shadowed variables.
|
||||||
250. [Rafail Giavrimis](https://github.com/grafail) fixed the Google Benchmark default branch.
|
250. [Cristi Vîjdea](https://github.com/axnsan12) fixed typos in the `operator[]` documentation.
|
||||||
251. [Louis Dionne](https://github.com/ldionne) fixed a conversion operator.
|
251. [Alex Beregszaszi](https://github.com/axic) fixed spelling mistakes in comments.
|
||||||
252. [justanotheranonymoususer](https://github.com/justanotheranonymoususer) made the examples in the README more consistent.
|
252. [Dirk Stolle](https://github.com/striezel) fixed typos in the documentation.
|
||||||
253. [Finkman](https://github.com/Finkman) suppressed some `-Wfloat-equal` warnings.
|
253. [Daniel Albuschat](https://github.com/daniel-kun) corrected the parameter name in the `parse` documentation.
|
||||||
254. [Ferry Huberts](https://github.com/fhuberts) fixed `-Wswitch-enum` warnings.
|
254. [Prince Mendiratta](https://github.com/Prince-Mendiratta) fixed a link to the FAQ.
|
||||||
255. [Arseniy Terekhin](https://github.com/senyai) made the GDB pretty-printer robust against unset variable names.
|
255. [Florian Albrechtskirchinger](https://github.com/falbrechtskirchinger) implemented `std::string_view` support for object keys and made dozens of other improvements.
|
||||||
256. [Amir Masoud Abdol](https://github.com/amirmasoudabdol) updated the Homebrew command as nlohmann/json is now in homebrew-core.
|
256. [Qianqian Fang](https://github.com/fangq) implemented the Binary JData (BJData) format.
|
||||||
257. [Hallot](https://github.com/Hallot) fixed some `-Wextra-semi-stmt warnings`.
|
257. [pketelsen](https://github.com/pketelsen) added macros `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` and `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`.
|
||||||
258. [Giovanni Cerretani](https://github.com/gcerretani) fixed `-Wunused` warnings on `JSON_DIAGNOSTICS`.
|
258. [DarkZeros](https://github.com/DarkZeros) adjusted to code to not clash with Arduino defines.
|
||||||
259. [Bogdan Popescu](https://github.com/Kapeli) hosts the [docset](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for offline documentation viewers.
|
259. [flagarde](https://github.com/flagarde) fixed the output of `meta()` for MSVC.
|
||||||
260. [Carl Smedstad](https://github.com/carlsmedstad) fixed an assertion error when using `JSON_DIAGNOSTICS`.
|
260. [Dimitris Apostolou](https://github.com/rex4539) fixed a typo.
|
||||||
261. [miikka75](https://github.com/miikka75) provided an important fix to compile C++17 code with Clang 9.
|
261. [Michael Nosthoff](https://github.com/heinemml) fixed a typo.
|
||||||
262. [Maarten Becker](https://github.com/kernie) fixed a warning for shadowed variables.
|
262. [JungHoon Lee](https://github.com/jhnlee) fixed a typo.
|
||||||
263. [Cristi Vîjdea](https://github.com/axnsan12) fixed typos in the `operator[]` documentation.
|
263. [Faruk D.](https://github.com/fdiblen) fixed the CITATION.CFF file.
|
||||||
264. [Alex Beregszaszi](https://github.com/axic) fixed spelling mistakes in comments.
|
264. [Andrea Cocito](https://github.com/puffetto) added a clarification on macro usage to the documentation.
|
||||||
265. [Dirk Stolle](https://github.com/striezel) fixed typos in documentation.
|
265. [Krzysiek Karbowiak](https://github.com/kkarbowiak) refactored the tests to use `CHECK_THROWS_WITH_AS`.
|
||||||
266. [Daniel Albuschat](https://github.com/daniel-kun) corrected the parameter name in the `parse` documentation.
|
266. [Chaoqi Zhang](https://github.com/prncoprs) fixed a typo.
|
||||||
267. [Prince Mendiratta](https://github.com/Prince-Mendiratta) fixed a link to the FAQ.
|
267. [ivanovmp](https://github.com/ivanovmp) fixed a whitespace error.
|
||||||
268. [Florian Albrechtskirchinger](https://github.com/falbrechtskirchinger) implemented `std::string_view` support for object keys and made dozens of other improvements.
|
268. [KsaNL](https://github.com/KsaNL) fixed a build error when including `<windows.h>`.
|
||||||
269. [Qianqian Fang](https://github.com/fangq) implemented the Binary JData (BJData) format.
|
269. [Andrea Pappacoda](https://github.com/Tachi107) moved `.pc` and `.cmake` files to `share` directory.
|
||||||
270. [pketelsen](https://github.com/pketelsen) added macros `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` and `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`.
|
270. [Wolf Vollprecht](https://github.com/wolfv) added the `patch_inplace` function.
|
||||||
271. [DarkZeros](https://github.com/DarkZeros) adjusted to code to not clash with Arduino defines.
|
271. [Jake Zimmerman](https://github.com/jez) highlighted common usage patterns in the README file.
|
||||||
272. [flagarde](https://github.com/flagarde) fixed the output of `meta()` for MSVC.
|
272. [NN](https://github.com/NN---) added the Visual Studio output directory to `.gitignore`.
|
||||||
273. [Giovanni Cerretani](https://github.com/gcerretani) fixed a check for `std::filesystem`.
|
273. [Romain Reignier](https://github.com/romainreignier) improved the performance of the vector output adapter.
|
||||||
274. [Dimitris Apostolou](https://github.com/rex4539) fixed a typo.
|
274. [Mike](https://github.com/Mike-Leo-Smith) fixed the `std::iterator_traits`.
|
||||||
275. [Ferry Huberts](https://github.com/fhuberts) fixed a typo.
|
275. [Richard Hozák](https://github.com/richardhozak) added macro `JSON_NO_ENUM` to disable default enum conversions.
|
||||||
276. [Michael Nosthoff](https://github.com/heinemml) fixed a typo.
|
276. [vakokako](https://github.com/vakokako) fixed tests when compiling with C++20.
|
||||||
277. [JungHoon Lee](https://github.com/jhnlee) fixed a typo.
|
277. [Alexander “weej” Jones](https://github.com/alexweej) fixed an example in the README.
|
||||||
278. [Faruk D.](https://github.com/fdiblen) fixed the CITATION.CFF file.
|
278. [Eli Schwartz](https://github.com/eli-schwartz) added more files to the `include.zip` archive.
|
||||||
279. [Andrea Cocito](https://github.com/puffetto) added a clarification on macro usage to the documentation.
|
279. [Kevin Lu](https://github.com/kevinlul) fixed a compilation issue when typedefs with certain names were present.
|
||||||
280. [Krzysiek Karbowiak](https://github.com/kkarbowiak) refactored the tests to use `CHECK_THROWS_WITH_AS`.
|
280. [Trevor Hickey](https://github.com/luxe) improved the description of an example.
|
||||||
281. [Chaoqi Zhang](https://github.com/prncoprs) fixed a typo.
|
281. [Jef LeCompte](https://github.com/jef) updated the year in the README file.
|
||||||
282. [ivanovmp](https://github.com/ivanovmp) fixed a whitespace error.
|
282. [Alexandre Hamez](https://github.com/ahamez) fixed a warning.
|
||||||
283. [KsaNL](https://github.com/KsaNL) fixed a build error when including `<windows.h>`.
|
283. [Maninderpal Badhan](https://github.com/mbadhan) fixed a typo.
|
||||||
284. [Andrea Pappacoda](https://github.com/Tachi107) moved `.pc` and `.cmake` files to `share` directory.
|
284. [kevin--](https://github.com/kevin--) added a note to an example in the README file.
|
||||||
285. [Wolf Vollprecht](https://github.com/wolfv) added the `patch_inplace` function.
|
285. [I](https://github.com/wx257osn2) fixed a typo.
|
||||||
286. [Jake Zimmerman](https://github.com/jez) highlighted common usage patterns in the README file.
|
286. [Gregorio Litenstein](https://github.com/Lord-Kamina) fixed the Clang detection.
|
||||||
287. [NN](https://github.com/NN---) added the Visual Studio output directory to `.gitignore`.
|
287. [Andreas Smas](https://github.com/andoma) added a Doozer badge.
|
||||||
288. [Romain Reignier](https://github.com/romainreignier) improved the performance of the vector output adapter.
|
288. [WanCW](https://github.com/wancw) fixed the string conversion with Clang.
|
||||||
289. [Mike](https://github.com/Mike-Leo-Smith) fixed the `std::iterator_traits`.
|
289. [zhaohuaxishi](https://github.com/zhaohuaxishi) fixed a Doxygen error.
|
||||||
290. [Richard Hozák](https://github.com/richardhozak) added macro `JSON_NO_ENUM` to disable default enum conversions.
|
290. [emvivre](https://github.com/emvivre) removed an invalid parameter from CMake.
|
||||||
291. [vakokako](https://github.com/vakokako) fixed tests when compiling with C++20.
|
291. [Tobias Hermann](https://github.com/Dobiasd) fixed a link in the README file.
|
||||||
292. [Alexander “weej” Jones](https://github.com/alexweej) fixed an example in the README.
|
292. [Michael](https://github.com/traits) fixed a warning.
|
||||||
293. [Eli Schwartz](https://github.com/eli-schwartz) added more files to the `include.zip` archive.
|
293. [Ryan Mulder](https://github.com/ryanjmulder) added `ensure_ascii` to the `dump` function.
|
||||||
294. [Kevin Lu](https://github.com/kevinlul) fixed a compilation issue when typedefs with certain names were present.
|
294. [Muri Nicanor](https://github.com/murinicanor) fixed the `sed` discovery in the Makefile.
|
||||||
295. [Trevor Hickey](https://github.com/luxe) improved the description of an example.
|
295. [David Avedissian](https://github.com/dgavedissian) implemented SFINAE-friendly `iterator_traits`.
|
||||||
296. [Jef LeCompte](https://github.com/jef) updated the year in the README file.
|
296. [AQNOUCH Mohammed](https://github.com/aqnouch) fixed a typo in the README.
|
||||||
297. [Alexandre Hamez](https://github.com/ahamez) fixed a warning.
|
297. [Gareth Sylvester-Bradley](https://github.com/garethsb) added `operator/=` and `operator/` to construct JSON pointers.
|
||||||
298. [Maninderpal Badhan](https://github.com/mbadhan) fixed a typo.
|
298. [Michael Macnair](https://github.com/mykter) added support for afl-fuzz testing.
|
||||||
299. [kevin--](https://github.com/kevin--) added a note to an example in the README file.
|
299. [Berkus Decker](https://github.com/berkus) fixed a typo in the README.
|
||||||
300. [I](https://github.com/wx257osn2) fixed a typo.
|
300. [Illia Polishchuk](https://github.com/ilqvya) improved the CMake testing.
|
||||||
301. [Gregorio Litenstein](https://github.com/Lord-Kamina) fixed the Clang detection.
|
301. [Ikko Ashimine](https://github.com/eltociear) fixed two typos.
|
||||||
302. [Andreas Smas](https://github.com/andoma) added a Doozer badge.
|
302. [Raphael Grimm](https://github.com/barcode) added the possibility to define a custom base class.
|
||||||
303. [WanCW](https://github.com/wancw) fixed the string conversion with Clang.
|
303. [tocic](https://github.com/tocic) fixed typos in the documentation.
|
||||||
304. [zhaohuaxishi](https://github.com/zhaohuaxishi) fixed a Doxygen error.
|
304. [Vertexwahn](https://github.com/Vertexwahn) added Bazel build support.
|
||||||
305. [emvivre](https://github.com/emvivre) removed an invalid parameter from CMake.
|
305. [DavidKorczynski](https://github.com/DavidKorczynski) added a CIFuzz CI GitHub action.
|
||||||
306. [Tobias Hermann](https://github.com/Dobiasd) fixed a link in the README file.
|
306. [Florian Segginger](https://github.com/floriansegginger) bumped the years in the README.
|
||||||
307. [Michael](https://github.com/traits) fixed a warning.
|
307. [haadfida](https://github.com/haadfida) cleaned up the badges of used services.
|
||||||
308. [Ryan Mulder](https://github.com/ryanjmulder) added `ensure_ascii` to the `dump` function.
|
308. [Arsen Arsenović](https://github.com/ArsenArsen) fixed a build error.
|
||||||
309. [Muri Nicanor](https://github.com/murinicanor) fixed the `sed` discovery in the Makefile.
|
309. [theevilone45](https://github.com/theevilone45) fixed a typo in a CMake file.
|
||||||
310. [David Avedissian](https://github.com/dgavedissian) implemented SFINAE-friendly `iterator_traits`.
|
310. [Sergei Trofimovich](https://github.com/trofi) fixed the custom allocator support.
|
||||||
311. [AQNOUCH Mohammed](https://github.com/aqnouch) fixed a typo in the README.
|
311. [Joyce](https://github.com/joycebrum) fixed some security issues in the GitHub workflows.
|
||||||
312. [Gareth Sylvester-Bradley](https://github.com/garethsb) added `operator/=` and `operator/` to construct JSON pointers.
|
312. [Nicolas Jakob](https://github.com/njakob) add vcpkg version badge.
|
||||||
313. [Michael Macnair](https://github.com/mykter) added support for afl-fuzz testing.
|
313. [Tomerkm](https://github.com/Tomerkm) added tests.
|
||||||
314. [Berkus Decker](https://github.com/berkus) fixed a typo in the README.
|
314. [No.](https://github.com/tusooa) fixed the use of `get<>` calls.
|
||||||
315. [Illia Polishchuk](https://github.com/ilqvya) improved the CMake testing.
|
315. [taro](https://github.com/tarolling) fixed a typo in the `CODEOWNERS` file.
|
||||||
316. [Ikko Ashimine](https://github.com/eltociear) fixed a typo.
|
316. [Felix Yan](https://github.com/felixonmars) fixed a typo in the README.
|
||||||
317. [Raphael Grimm](https://github.com/barcode) added the possibility to define a custom base class.
|
317. [HO-COOH](https://github.com/HO-COOH) fixed a parenthesis in the documentation.
|
||||||
318. [tocic](https://github.com/tocic) fixed typos in the documentation.
|
318. [miny1233](https://github.com/miny1233) fixed a parenthesis in the documentation.
|
||||||
319. [Vertexwahn](https://github.com/Vertexwahn) added Bazel build support.
|
319. [tomalakgeretkal](https://github.com/tomalakgeretkal) fixed a compilation error.
|
||||||
320. [Dirk Stolle](https://github.com/striezel) fixed typos in the documentation.
|
320. [alferov](https://github.com/ALF-ONE) fixed a compilation error and fixed a version in the documentation.
|
||||||
321. [DavidKorczynski](https://github.com/DavidKorczynski) added a CIFuzz CI GitHub action.
|
321. [Craig Scott](https://github.com/craigscott-crascit) fixed a deprecation warning in CMake.
|
||||||
322. [Finkman](https://github.com/Finkman) fixed the debug pretty-printer.
|
322. [Vyacheslav Zhdanovskiy](https://github.com/ZeronSix) added macros for serialization-only types.
|
||||||
323. [Florian Segginger](https://github.com/floriansegginger) bumped the years in the README.
|
323. [Mathieu Westphal](https://github.com/mwestphal) fixed typos.
|
||||||
324. [haadfida](https://github.com/haadfida) cleaned up the badges of used services.
|
324. [scribam](https://github.com/scribam) fixed the MinGW workflow.
|
||||||
325. [Arsen Arsenović](https://github.com/ArsenArsen) fixed a build error.
|
325. [Aleksei Sapitskii](https://github.com/aleksproger) added support for Apple's Swift Package Manager.
|
||||||
326. [theevilone45](https://github.com/theevilone45) fixed a typo in a CMake file.
|
326. [Benjamin Buch](https://github.com/bebuch) fixed the installation path in CMake.
|
||||||
327. [Sergei Trofimovich](https://github.com/trofi) fixed the custom allocator support.
|
327. [Colby Haskell](https://github.com/colbychaskell) clarified the parse error message in case a file cannot be opened.
|
||||||
328. [Joyce](https://github.com/joycebrum) fixed some security issues in the GitHub workflows.
|
328. [Juan Carlos Arevalo Baeza](https://github.com/TheJCAB) fixed the enum conversion.
|
||||||
329. [Nicolas Jakob](https://github.com/njakob) add vcpkg version badge.
|
329. [ss](https://github.com/serge-s) fixed the amalgamation call.
|
||||||
330. [Tomerkm](https://github.com/Tomerkm) added tests.
|
330. [AniketDhemare](https://github.com/AniketDhemare) fixed a version in the documentation.
|
||||||
331. [No.](https://github.com/tusooa) fixed the use of `get<>` calls.
|
331. [Philip Müller](https://github.com/philip-paul-mueller) fixed an example.
|
||||||
332. [taro](https://github.com/tarolling) fixed a typo in the `CODEOWNERS` file.
|
332. [Leila Shcheglova](https://github.com/LeilaShcheglova) fixed a warning in a test.
|
||||||
333. [Ikko Eltociear Ashimine](https://github.com/eltociear) fixed a typo.
|
333. [Alex Prabhat Bara](https://github.com/alexprabhat99) fixed a function name in the documentation.
|
||||||
334. [Felix Yan](https://github.com/felixonmars) fixed a typo in the README.
|
334. [laterlaugh](https://github.com/laterlaugh) fixed some typos.
|
||||||
335. [HO-COOH](https://github.com/HO-COOH) fixed a parenthesis in the documentation.
|
335. [Yuanhao Jia](https://github.com/MrJia1997) fixed the GDB pretty printer.
|
||||||
336. [Ivor Wanders](https://github.com/iwanders) fixed the examples to catch exception by `const&`.
|
336. [Fallen_Breath](https://github.com/Fallen-Breath) fixed an example for JSON Pointer.
|
||||||
337. [miny1233](https://github.com/miny1233) fixed a parenthesis in the documentation.
|
337. [Nikhil Idiculla](https://github.com/tsnl) fixed some typos.
|
||||||
338. [tomalakgeretkal](https://github.com/tomalakgeretkal) fixed a compilation error.
|
338. [Griffin Myers](https://github.com/gmyers18) updated the Natvis file.
|
||||||
339. [alferov](https://github.com/ALF-ONE) fixed a compilation error.
|
339. [thetimr](https://github.com/thetimr) fixed a typo in the documentation.
|
||||||
340. [Craig Scott](https://github.com/craigscott-crascit) fixed a deprecation warning in CMake.
|
340. [Balazs Erseki](https://github.com/zerocukor287) fixed a URL in the contribution guidelines.
|
||||||
341. [Vyacheslav Zhdanovskiy](https://github.com/ZeronSix) added macros for serialization-only types.
|
341. [Niccolò Iardella](https://github.com/rotolof) added `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros.
|
||||||
342. [Mathieu Westphal](https://github.com/mwestphal) fixed typos.
|
342. [Borislav Stanimirov](https://github.com/iboB) allowed overriding the CMake target name.
|
||||||
343. [scribam](https://github.com/scribam) fixed the MinGW workflow.
|
343. [Captain Crutches](https://github.com/captaincrutches) made `iterator_proxy_value` a `std::forward_iterator`.
|
||||||
344. [Aleksei Sapitskii](https://github.com/aleksproger) added support for Apple's Swift Package Manager.
|
344. [Fredrik Sandhei](https://github.com/fsandhei) added type conversion support for `std::optional`.
|
||||||
345. [Benjamin Buch](https://github.com/bebuch) fixed the installation path in CMake.
|
345. [jh96](https://github.com/jordan-hoang) added exceptions when `nullptr` is passed to `parse`.
|
||||||
346. [Colby Haskell](https://github.com/colbychaskell) clarified the parse error message in case a file cannot be opened.
|
346. [Stuart Gorman](https://github.com/StuartGorman) fixed number parsing when `EINTR` set in `errno`.
|
||||||
347. [Juan Carlos Arevalo Baeza](https://github.com/TheJCAB) fixed the enum conversion.
|
347. [Dylan Baker](https://github.com/dcbaker) generated a pkg-config file that follows the pkg-config conventions.
|
||||||
348. [alferov](https://github.com/ALF-ONE) fixed a version in the documentation.
|
348. [Tianyi Chen](https://github.com/TianyiChen) optimized the binary `get_number` implementation.
|
||||||
349. [ss](https://github.com/serge-s) fixed the amalgamation call.
|
349. [peng-wang-cn](https://github.com/peng-wang-cn) added type conversion support for multidimensional arrays.
|
||||||
350. [AniketDhemare](https://github.com/AniketDhemare) fixed a version in the documentation.
|
350. [Einars Netlis-Galejs](https://github.com/EinarsNG) added `ONLY_SERIALIZE` for `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros.
|
||||||
351. [Philip Müller](https://github.com/philip-paul-mueller) fixed an example.
|
351. [Marcel](https://github.com/mering) removed `alwayslink=True` Bazel flag.
|
||||||
352. [Leila Shcheglova](https://github.com/LeilaShcheglova) fixed a warning in a test.
|
352. [Harinath Nampally](https://github.com/hnampally) added diagnostic positions to exceptions.
|
||||||
353. [Alex Prabhat Bara](https://github.com/alexprabhat99) fixed a function name in the documentation.
|
353. [Nissim Armand Ben Danan](https://github.com/NissimBendanan) fixed `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` with an empty JSON instance.
|
||||||
354. [laterlaugh](https://github.com/laterlaugh) fixed some typos.
|
354. [Michael Valladolid](https://github.com/codenut) added support for BSON uint64 serialization/deserialization.
|
||||||
355. [Yuanhao Jia](https://github.com/MrJia1997) fixed the GDB pretty printer.
|
355. [Nikhil](https://github.com/nikhilreddydev) updated the documentation.
|
||||||
356. [Fallen_Breath](https://github.com/Fallen-Breath) fixed an example for JSON Pointer.
|
356. [Nebojša Cvetković](https://github.com/nebkat) added support for BJDATA optimized binary array type.
|
||||||
357. [Nikhil Idiculla](https://github.com/tsnl) fixed some typos.
|
357. [Sushrut Shringarputale](https://github.com/sushshring) added support for diagnostic positions.
|
||||||
358. [Griffin Myers](https://github.com/gmyers18) updated the Natvis file.
|
358. [kimci86](https://github.com/kimci86) templated to `NLOHMANN_DEFINE_TYPE` macros to also support `ordered_json`.
|
||||||
359. [thetimr](https://github.com/thetimr) fixed a typo in the documentation.
|
359. [Richard Topchii](https://github.com/richardtop) added support for VisionOS in the Swift Package Manager.
|
||||||
360. [Balazs Erseki](https://github.com/zerocukor287) fixed a URL in the contribution guidelines.
|
360. [Robert Chisholm](https://github.com/Robadob) fixed a typo.
|
||||||
361. [Niccolò Iardella](https://github.com/rotolof) added `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros.
|
361. [zjyhjqs](https://github.com/zjyhjqs) added CPack support.
|
||||||
362. [Borislav Stanimirov](https://github.com/iboB) allowed overriding the CMake target name.
|
362. [bitFiedler](https://github.com/bitFiedler) made GDB pretty printer work with Python 3.8.
|
||||||
363. [Captain Crutches](https://github.com/captaincrutches) made `iterator_proxy_value` a `std::forward_iterator`.
|
363. [Gianfranco Costamagna](https://github.com/LocutusOfBorg) fixed a compiler warning.
|
||||||
364. [Fredrik Sandhei](https://github.com/fsandhei) added type conversion support for `std::optional`.
|
364. [risa2000](https://github.com/risa2000) made `std::filesystem::path` conversion to/from UTF-8 encoded string explicit.
|
||||||
365. [jh96](https://github.com/jordan-hoang) added exceptions when `nullptr` is passed to `parse`.
|
365. [AM](https://github.com/maqnouch) fixed typos in the README.
|
||||||
366. [Stuart Gorman](https://github.com/StuartGorman) fixed number parsing when `EINTR` set in `errno`.
|
366. [dmenendez-gruposantander](https://github.com/dmenendez-gruposantander) fixed typos in the comments of the examples.
|
||||||
367. [Dylan Baker](https://github.com/dcbaker) generated a pkg-config file that follows the pkg-config conventions.
|
367. [Mihai Stan](https://github.com/mstan-xx) fixed comparisons against the literal `0`.
|
||||||
368. [Tianyi Chen](https://github.com/TianyiChen) optimized the binary `get_number` implementation.
|
368. [Matt Gumbel](https://github.com/intelmatt) fixed some `-Weffc++` warnings.
|
||||||
369. [peng-wang-cn](https://github.com/peng-wang-cn) added type conversion support for multidimensional arrays.
|
369. [vimpunk](https://github.com/vimpunk) moved a lambda out of an unevaluated context to support older compilers.
|
||||||
370. [Einars Netlis-Galejs](https://github.com/EinarsNG) added `ONLY_SERIALIZE` for `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros.
|
370. [Chris Harris](https://github.com/cjh1) fixed the compilation with GCC 4.8.
|
||||||
371. [Marcel](https://github.com/mering) removed `alwayslink=True` Bazel flag.
|
371. [Palmer Dabbelt](https://github.com/palmer-dabbelt) generated and installed a pkg-config file.
|
||||||
372. [Harinath Nampally](https://github.com/hnampally) added diagnostic positions to exceptions.
|
372. [Gus Pozuelo](https://github.com/ap-viavi) made `ordered_map` compatible with GCC 5.5, Clang 3.6, and Xcode 9.
|
||||||
373. [Nissim Armand Ben Danan](https://github.com/NissimBendanan) fixed `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` with an empty JSON instance.
|
373. [AK](https://github.com/Lioncky) fixed an MSVC build error caused by the `min`/`max` macros from `windows.h`.
|
||||||
374. [Michael Valladolid](https://github.com/codenut) added support for BSON uint64 serialization/deserialization.
|
374. [Sergiu Deitsch](https://github.com/sergiud) provided a fallback for missing `char8_t` support.
|
||||||
375. [Nikhil](https://github.com/nikhilreddydev) updated the documentation.
|
375. [Xiaochuan Ye](https://github.com/XueSongTap) fixed `from_msgpack` for `std::byte` input by specializing `std::char_traits`.
|
||||||
376. [Nebojša Cvetković](https://github.com/nebkat) added support for BJDATA optimized binary array type.
|
376. [Ville Vesilehto](https://github.com/thevilledev) fixed an overflow in the BJData size calculation and rejected overflowing negative integers in CBOR.
|
||||||
377. [Sushrut Shringarputale](https://github.com/sushshring) added support for diagnostic positions.
|
377. [NmPassTHFan](https://github.com/nmpassthf) replaced the deprecated `std::is_trivial` for C++26.
|
||||||
378. [kimci86](https://github.com/kimci86) templated to `NLOHMANN_DEFINE_TYPE` macros to also support `ordered_json`.
|
378. [Chris Ever](https://github.com/chirsz-ever) added the `ignore_trailing_commas` parser option.
|
||||||
379. [Richard Topchii](https://github.com/richardtop) added support for VisionOS in the Swift Package Manager.
|
379. [Kuan-Fu Wu](https://github.com/kfwu1999) fixed the example code for `json_pointer` initialization.
|
||||||
380. [Robert Chisholm](https://github.com/Robadob) fixed a typo.
|
380. [David Kilzer](https://github.com/ddkilzer) added a missing header to the input adapters.
|
||||||
381. [zjyhjqs](https://github.com/zjyhjqs) added CPack support.
|
381. [Miko](https://github.com/mikomikotaishi) added proper C++20 module support, simplified the module API, and fixed missing exports.
|
||||||
382. [bitFiedler](https://github.com/bitFiedler) made GDB pretty printer work with Python 3.8.
|
382. [hitgirl](https://github.com/hitgil) fixed the CMake configuration when cross-compiling.
|
||||||
383. [Gianfranco Costamagna](https://github.com/LocutusOfBorg) fixed a compiler warning.
|
383. [Devon Thomas](https://github.com/ThomaDevOSU) mentioned the Artistic Style formatting in the contribution guidelines.
|
||||||
384. [risa2000](https://github.com/risa2000) made `std::filesystem::path` conversion to/from UTF-8 encoded string explicit.
|
384. [Erik Hu](https://github.com/Erikhu1) made Coveralls upload errors non-fatal in the CI.
|
||||||
385. [AM](https://github.com/maqnouch) fixed typos in the README.
|
385. [co63oc](https://github.com/co63oc) fixed typos.
|
||||||
386. [dmenendez-gruposantander](https://github.com/dmenendez-gruposantander) fixed typos in the comments of the examples.
|
386. [DmitriBogdanov](https://github.com/DmitriBogdanov) fixed broken package manager links in the documentation.
|
||||||
387. [Mihai Stan](https://github.com/mstan-xx) fixed comparisons against the literal `0`.
|
387. [Bander](https://github.com/banderzhm) improved the MSVC compatibility of the C++ modules.
|
||||||
388. [Matt Gumbel](https://github.com/intelmatt) fixed some `-Weffc++` warnings.
|
388. [Andy Choi](https://github.com/ccpong) removed an unnecessary `template` keyword before `get` in the README and the documentation.
|
||||||
389. [vimpunk](https://github.com/vimpunk) moved a lambda out of an unevaluated context to support older compilers.
|
389. [SamareshSingh](https://github.com/ssam18) fixed single-element brace initialization to copy/move instead of wrapping in an array, fixed the `WITH_DEFAULT` macros for `ordered_map`, and handled moved events in `serve_header.py`.
|
||||||
390. [Chris Harris](https://github.com/cjh1) fixed the compilation with GCC 4.8.
|
390. [Aditya](https://github.com/Lumowhisp) improved the documentation of the documentation generation.
|
||||||
391. [Palmer Dabbelt](https://github.com/palmer-dabbelt) generated and installed a pkg-config file.
|
391. [cheese1](https://github.com/cheese1) clarified the README.
|
||||||
392. [Gus Pozuelo](https://github.com/ap-viavi) made `ordered_map` compatible with GCC 5.5, Clang 3.6, and Xcode 9.
|
392. [KhloodElhossiny](https://github.com/khloodelhossiny) enabled `std::string_view` keys in `operator[]`.
|
||||||
393. [AK](https://github.com/Lioncky) fixed an MSVC build error caused by the `min`/`max` macros from `windows.h`.
|
393. [Charles Cabergs](https://github.com/cacharle) fixed a `-Wtautological-constant-out-of-range-compare` warning.
|
||||||
394. [Sergiu Deitsch](https://github.com/sergiud) provided a fallback for missing `char8_t` support.
|
394. [EALePain](https://github.com/EALePain) made the `std::tuple` conversion work with reference types such as `std::tie`.
|
||||||
395. [Xiaochuan Ye](https://github.com/XueSongTap) fixed `from_msgpack` for `std::byte` input by specializing `std::char_traits`.
|
395. [koala_oishi](https://github.com/chibi-dogs) fixed grammatical wording in the README.
|
||||||
396. [Ville Vesilehto](https://github.com/thevilledev) fixed an overflow in the BJData size calculation and rejected overflowing negative integers in CBOR.
|
396. [riccardoori11](https://github.com/riccardoori11) fixed a typo in the documentation.
|
||||||
397. [NmPassTHFan](https://github.com/nmpassthf) replaced the deprecated `std::is_trivial` for C++26.
|
397. [Swastik Bose](https://github.com/VasuBhakt) fixed the parent pointers after `update()` with `JSON_DIAGNOSTICS` and fixed the Doxygen autolinking of requirements.
|
||||||
398. [Chris Ever](https://github.com/chirsz-ever) added the `ignore_trailing_commas` parser option.
|
398. [trdesilva](https://github.com/trdesilva) added `front`, `pop_front`, and `push_front` to `json_pointer`.
|
||||||
399. [Kuan-Fu Wu](https://github.com/kfwu1999) fixed the example code for `json_pointer` initialization.
|
399. [Akhilesh Arora](https://github.com/akhilesharora) fixed an incomplete-type error with `ordered_json`.
|
||||||
400. [David Kilzer](https://github.com/ddkilzer) added a missing header to the input adapters.
|
400. [Hariom Phulre](https://github.com/hariomphulre) fixed the C++20 modules compilation with GCC.
|
||||||
401. [Miko](https://github.com/mikomikotaishi) added proper C++20 module support, simplified the module API, and fixed missing exports.
|
401. [Kirill Lokotkov](https://github.com/RUSLoker) fixed printing `long double` values.
|
||||||
402. [hitgirl](https://github.com/hitgil) fixed the CMake configuration when cross-compiling.
|
402. [George Sedov](https://github.com/radistmorse) added the `NLOHMANN_DEFINE_TYPE_*_WITH_NAMES` macros.
|
||||||
403. [Devon Thomas](https://github.com/ThomaDevOSU) mentioned the Artistic Style formatting in the contribution guidelines.
|
403. [Caillin Nugent](https://github.com/nugentcaillin) added the `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` macro.
|
||||||
404. [Erik Hu](https://github.com/Erikhu1) made Coveralls upload errors non-fatal in the CI.
|
404. [Cosmin D.](https://github.com/drcosmin) fixed `std::filesystem::path` conversions and added an MSVC workaround for `std::unique_ptr`.
|
||||||
405. [co63oc](https://github.com/co63oc) fixed typos.
|
405. [Paul Dreik](https://github.com/pauldreik) fixed a test relying on implementation-specific behavior.
|
||||||
406. [DmitriBogdanov](https://github.com/DmitriBogdanov) fixed broken package manager links in the documentation.
|
406. [Daniel Falk](https://github.com/daniel-falk) added missing copyright notices to the SBOM.
|
||||||
407. [Bander](https://github.com/banderzhm) improved the MSVC compatibility of the C++ modules.
|
407. [Federico Sfriso](https://github.com/federicosfriso05-dotcom) added support for constructing JSON values from C++20 range views.
|
||||||
408. [Andy Choi](https://github.com/ccpong) removed an unnecessary `template` keyword before `get` in the README and the documentation.
|
408. [Luke Banicevic](https://github.com/banaboi) fixed corrupt BSON output for lengths exceeding `INT32_MAX`, cleaned up the BSON writer, and improved the documentation.
|
||||||
409. [SamareshSingh](https://github.com/ssam18) fixed single-element brace initialization to copy/move instead of wrapping in an array, fixed the `WITH_DEFAULT` macros for `ordered_map`, and handled moved events in `serve_header.py`.
|
409. [Patrick Armstrong](https://github.com/Patrick10199) updated the CBOR references and the half-precision float assertions.
|
||||||
410. [Aditya](https://github.com/Lumowhisp) improved the documentation of the documentation generation.
|
410. [Yash Bavadiya](https://github.com/xevrion) added checks to all BSON reads.
|
||||||
411. [cheese1](https://github.com/cheese1) clarified the README.
|
411. [hum4nBeing](https://github.com/hum4nBeing) fixed the overflow handling of high-precision numbers in UBJSON.
|
||||||
412. [KhloodElhossiny](https://github.com/khloodelhossiny) enabled `std::string_view` keys in `operator[]`.
|
412. [tomatotomata](https://github.com/tomatotomata) added checks for reading CBOR tagged subtypes.
|
||||||
413. [Charles Cabergs](https://github.com/cacharle) fixed a `-Wtautological-constant-out-of-range-compare` warning.
|
413. [YingqiDuan](https://github.com/YingqiDuan) documented the BSON interoperability.
|
||||||
414. [EALePain](https://github.com/EALePain) made the `std::tuple` conversion work with reference types such as `std::tie`.
|
414. [KBS](https://github.com/youdie006) documented the standards compliance and the strictness of `parse()` and `operator>>`.
|
||||||
415. [koala_oishi](https://github.com/chibi-dogs) fixed grammatical wording in the README.
|
415. [Petr Bělohlávek](https://github.com/petrbel) added Clang 21 and 22 to the CI.
|
||||||
416. [riccardoori11](https://github.com/riccardoori11) fixed a typo in the documentation.
|
416. [Dmitry Rantovov](https://github.com/darkdi) fixed the placement of a CBOR documentation block.
|
||||||
417. [Swastik Bose](https://github.com/VasuBhakt) fixed the parent pointers after `update()` with `JSON_DIAGNOSTICS` and fixed the Doxygen autolinking of requirements.
|
417. [ljcjclljc](https://github.com/ljcjclljc) fixed the comparison of large unsigned integers with signed integers.
|
||||||
418. [trdesilva](https://github.com/trdesilva) added `front`, `pop_front`, and `push_front` to `json_pointer`.
|
418. [Sahil Kamate](https://github.com/sahilkamate03) fixed the handling of CBOR tags 0-5 and 21-23.
|
||||||
419. [Akhilesh Arora](https://github.com/akhilesharora) fixed an incomplete-type error with `ordered_json`.
|
419. [Krishnanand G](https://github.com/Krishnanand-G) made the UBJSON writer reject `use_type` without `use_size`.
|
||||||
420. [Hariom Phulre](https://github.com/hariomphulre) fixed the C++20 modules compilation with GCC.
|
420. [whn](https://github.com/Whning0513) documented the lenient BSON input handling and corrected the complexity of `to_bson`.
|
||||||
421. [Kirill Lokotkov](https://github.com/RUSLoker) fixed printing `long double` values.
|
421. [elix3r](https://github.com/22elix3r) fixed `update()` with `merge_objects` when merging a primitive into an object.
|
||||||
422. [George Sedov](https://github.com/radistmorse) added the `NLOHMANN_DEFINE_TYPE_*_WITH_NAMES` macros.
|
422. [Avionic Harshit](https://github.com/avionicharshit-byte) made `diff()` linear when an array shrinks.
|
||||||
423. [Caillin Nugent](https://github.com/nugentcaillin) added the `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` macro.
|
423. [Qatadaha Bin Matloob](https://github.com/qatcod) fixed comparisons between integers and floats and fixed unparsable BJData output.
|
||||||
424. [Cosmin D.](https://github.com/drcosmin) fixed `std::filesystem::path` conversions and added an MSVC workaround for `std::unique_ptr`.
|
424. [Wu Shuwen](https://github.com/dajiaohuang) removed an unused include.
|
||||||
425. [Paul Dreik](https://github.com/pauldreik) fixed a test relying on implementation-specific behavior.
|
|
||||||
426. [Daniel Falk](https://github.com/daniel-falk) added missing copyright notices to the SBOM.
|
|
||||||
427. [Federico Sfriso](https://github.com/federicosfriso05-dotcom) added support for constructing JSON values from C++20 range views.
|
|
||||||
428. [Luke Banicevic](https://github.com/banaboi) fixed corrupt BSON output for lengths exceeding `INT32_MAX`, cleaned up the BSON writer, and improved the documentation.
|
|
||||||
429. [Patrick Armstrong](https://github.com/Patrick10199) updated the CBOR references and the half-precision float assertions.
|
|
||||||
430. [Yash Bavadiya](https://github.com/xevrion) added checks to all BSON reads.
|
|
||||||
431. [hum4nBeing](https://github.com/hum4nBeing) fixed the overflow handling of high-precision numbers in UBJSON.
|
|
||||||
432. [tomatotomata](https://github.com/tomatotomata) added checks for reading CBOR tagged subtypes.
|
|
||||||
433. [YingqiDuan](https://github.com/YingqiDuan) documented the BSON interoperability.
|
|
||||||
434. [KBS](https://github.com/youdie006) documented the standards compliance and the strictness of `parse()` and `operator>>`.
|
|
||||||
435. [Petr Bělohlávek](https://github.com/petrbel) added Clang 21 and 22 to the CI.
|
|
||||||
436. [Dmitry Rantovov](https://github.com/darkdi) fixed the placement of a CBOR documentation block.
|
|
||||||
437. [ljcjclljc](https://github.com/ljcjclljc) fixed the comparison of large unsigned integers with signed integers.
|
|
||||||
438. [Sahil Kamate](https://github.com/sahilkamate03) fixed the handling of CBOR tags 0-5 and 21-23.
|
|
||||||
439. [Krishnanand G](https://github.com/Krishnanand-G) made the UBJSON writer reject `use_type` without `use_size`.
|
|
||||||
440. [whn](https://github.com/Whning0513) documented the lenient BSON input handling and corrected the complexity of `to_bson`.
|
|
||||||
441. [elix3r](https://github.com/22elix3r) fixed `update()` with `merge_objects` when merging a primitive into an object.
|
|
||||||
442. [Avionic Harshit](https://github.com/avionicharshit-byte) made `diff()` linear when an array shrinks.
|
|
||||||
443. [Qatadaha Bin Matloob](https://github.com/qatcod) fixed comparisons between integers and floats and fixed unparsable BJData output.
|
|
||||||
444. [Wu Shuwen](https://github.com/dajiaohuang) removed an unused include.
|
|
||||||
|
|
||||||
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
|
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
|
||||||
|
|
||||||
@@ -1879,21 +1850,28 @@ The library itself consists of a single header file licensed under the MIT licen
|
|||||||
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
|
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
|
||||||
- [**Artistic Style**](https://astyle.sourceforge.net) for automatic source code indentation
|
- [**Artistic Style**](https://astyle.sourceforge.net) for automatic source code indentation
|
||||||
- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers
|
- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers
|
||||||
|
- [**Clang-Tidy**](https://clang.llvm.org/extra/clang-tidy/) for static analysis and style checks
|
||||||
- [**CMake**](https://cmake.org) for build automation
|
- [**CMake**](https://cmake.org) for build automation
|
||||||
- [**Codacy**](https://www.codacy.com) for further [code analysis](https://app.codacy.com/gh/nlohmann/json/dashboard)
|
- [**Codacy**](https://www.codacy.com) for further [code analysis](https://app.codacy.com/gh/nlohmann/json/dashboard)
|
||||||
|
- [**CodeQL**](https://codeql.github.com) for code scanning
|
||||||
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
|
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
|
||||||
- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)
|
- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)
|
||||||
- [**cppcheck**](https://cppcheck.sourceforge.io) for static analysis
|
- [**cppcheck**](https://cppcheck.sourceforge.io) for static analysis
|
||||||
- [**doctest**](https://github.com/onqtam/doctest) for the unit tests
|
- [**cpplint**](https://github.com/cpplint/cpplint) for style checks
|
||||||
- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)
|
- [**doctest**](https://github.com/doctest/doctest) for the unit tests
|
||||||
|
- [**Flawfinder**](https://dwheeler.com/flawfinder/) for static analysis
|
||||||
|
- [**GitHub Changelog Generator**](https://github.com/github-changelog-generator/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)
|
||||||
- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks
|
- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks
|
||||||
- [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros
|
- [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros
|
||||||
|
- [**include-what-you-use**](https://include-what-you-use.org) to check the included headers
|
||||||
|
- [**Infer**](https://fbinfer.com) for static analysis
|
||||||
- [**lcov**](https://github.com/linux-test-project/lcov) to process coverage information and create an HTML view
|
- [**lcov**](https://github.com/linux-test-project/lcov) to process coverage information and create an HTML view
|
||||||
- [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz
|
- [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz
|
||||||
- [**Material for MkDocs**](https://squidfunk.github.io/mkdocs-material/) for the style of the documentation site
|
- [**Material for MkDocs**](https://squidfunk.github.io/mkdocs-material/) for the style of the documentation site
|
||||||
- [**MkDocs**](https://www.mkdocs.org) for the documentation site
|
- [**MkDocs**](https://www.mkdocs.org) for the documentation site
|
||||||
- [**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))
|
- [**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.
|
- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments.
|
||||||
|
- [**Semgrep**](https://semgrep.dev) for static analysis
|
||||||
- [**Valgrind**](https://valgrind.org) to check for correct memory management
|
- [**Valgrind**](https://valgrind.org) to check for correct memory management
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
@@ -1987,10 +1965,10 @@ If the testdata is not found, several test suites will fail like this:
|
|||||||
|
|
||||||
```
|
```
|
||||||
===============================================================================
|
===============================================================================
|
||||||
json/tests/src/make_test_data_available.hpp:21:
|
json/tests/src/make_test_data_available.hpp:26:
|
||||||
TEST CASE: check test suite is downloaded
|
TEST CASE: check test suite is downloaded
|
||||||
|
|
||||||
json/tests/src/make_test_data_available.hpp:23: FATAL ERROR: REQUIRE( utils::check_testsuite_downloaded() ) is NOT correct!
|
json/tests/src/make_test_data_available.hpp:28: FATAL ERROR: REQUIRE( utils::check_testsuite_downloaded() ) is NOT correct!
|
||||||
values: REQUIRE( false )
|
values: REQUIRE( false )
|
||||||
logged: Test data not found in 'json/cmake-build-debug/json_test_data'.
|
logged: Test data not found in 'json/cmake-build-debug/json_test_data'.
|
||||||
Please execute target 'download_test_data' before running this test suite.
|
Please execute target 'download_test_data' before running this test suite.
|
||||||
@@ -2001,10 +1979,10 @@ json/tests/src/make_test_data_available.hpp:23: FATAL ERROR: REQUIRE( utils::che
|
|||||||
|
|
||||||
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.
|
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 are requiring network to be properly execute. They are labeled as `git_required`. Please execute `ctest -LE git_required` to skip these tests. See [issue #4851](https://github.com/nlohmann/json/issues/4851) for more information.
|
Some tests require network access to execute properly. They are labeled as `git_required`. Please execute `ctest -LE git_required` to skip these tests. See [issue #4851](https://github.com/nlohmann/json/issues/4851) 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. Furthermore, assertions must be switched off to ensure reproducible builds (see [discussion 4494](https://github.com/nlohmann/json/discussions/4494)).
|
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. Furthermore, assertions must be switched off to ensure reproducible builds (see [discussion 4494](https://github.com/nlohmann/json/discussions/4494)).
|
||||||
|
|
||||||
Note you need to call `cmake -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information.
|
Note you need to call `ctest -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information.
|
||||||
|
|
||||||
As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/fp-model-fp.html) then.
|
As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/fp-model-fp.html) then.
|
||||||
+8
-2
@@ -10,10 +10,10 @@ SPDX-FileCopyrightText = "2013-2026 Niels Lohmann <https://nlohmann.me>"
|
|||||||
SPDX-License-Identifier = "MIT"
|
SPDX-License-Identifier = "MIT"
|
||||||
|
|
||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = "include/nlohmann/thirdparty/hedley.hpp"
|
path = "include/nlohmann/thirdparty/hedley/hedley.hpp"
|
||||||
precedence = "aggregate"
|
precedence = "aggregate"
|
||||||
SPDX-FileCopyrightText = "2016-2021 Evan Nemerson <evan@nemerson.com>"
|
SPDX-FileCopyrightText = "2016-2021 Evan Nemerson <evan@nemerson.com>"
|
||||||
SPDX-License-Identifier = "CC0"
|
SPDX-License-Identifier = "CC0-1.0"
|
||||||
|
|
||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = "include/nlohmann/detail/meta/cpp_future.hpp"
|
path = "include/nlohmann/detail/meta/cpp_future.hpp"
|
||||||
@@ -50,3 +50,9 @@ path = "tools/gdb_pretty_printer/**"
|
|||||||
precedence = "aggregate"
|
precedence = "aggregate"
|
||||||
SPDX-FileCopyrightText = "2020 Hannes Domani <https://github.com/ssbssa>"
|
SPDX-FileCopyrightText = "2020 Hannes Domani <https://github.com/ssbssa>"
|
||||||
SPDX-License-Identifier = "MIT"
|
SPDX-License-Identifier = "MIT"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = "docs/docset/icon*.png"
|
||||||
|
precedence = "override"
|
||||||
|
SPDX-FileCopyrightText = "JSON logo (public domain), https://commons.wikimedia.org/wiki/File:JSON_vector_logo.svg"
|
||||||
|
SPDX-License-Identifier = "CC0-1.0"
|
||||||
+14
-17
@@ -5,15 +5,14 @@ set(N 10)
|
|||||||
# Needed tools.
|
# Needed tools.
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
include(FindPython3)
|
|
||||||
find_package(Python3 COMPONENTS Interpreter)
|
find_package(Python3 COMPONENTS Interpreter)
|
||||||
|
|
||||||
find_program(CLANG_TOOL NAMES clang++-HEAD clang++ clang++-22 clang++-21 clang++-20 clang++-19 clang++-18 clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11 clang++)
|
find_program(CLANG_TOOL NAMES clang++ clang++-HEAD clang++-22 clang++-21 clang++-20 clang++-19 clang++-18 clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11)
|
||||||
execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION)
|
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}")
|
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}")
|
||||||
message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})")
|
message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})")
|
||||||
|
|
||||||
find_program(CLANG_TIDY_TOOL NAMES clang-tidy-22 clang-tidy-21 clang-tidy-20 clang-tidy-19 clang-tidy-18 clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy)
|
find_program(CLANG_TIDY_TOOL NAMES clang-tidy clang-tidy-22 clang-tidy-21 clang-tidy-20 clang-tidy-19 clang-tidy-18 clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11)
|
||||||
execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION)
|
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}")
|
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})")
|
message(STATUS "🔖 Clang-Tidy ${CLANG_TIDY_TOOL_VERSION} (${CLANG_TIDY_TOOL})")
|
||||||
@@ -69,9 +68,7 @@ string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" VALGRIND_TOOL_VERSION "${VALGRIND_TOOL_V
|
|||||||
message(STATUS "🔖 Valgrind ${VALGRIND_TOOL_VERSION} (${VALGRIND_TOOL})")
|
message(STATUS "🔖 Valgrind ${VALGRIND_TOOL_VERSION} (${VALGRIND_TOOL})")
|
||||||
|
|
||||||
find_program(GENHTML_TOOL NAMES genhtml)
|
find_program(GENHTML_TOOL NAMES genhtml)
|
||||||
find_program(PLOG_CONVERTER_TOOL NAMES plog-converter)
|
find_program(SCAN_BUILD_TOOL NAMES scan-build scan-build-22 scan-build-21 scan-build-20 scan-build-19 scan-build-18 scan-build-17 scan-build-16 scan-build-15 scan-build-14 scan-build-13 scan-build-12 scan-build-11)
|
||||||
find_program(PVS_STUDIO_ANALYZER_TOOL NAMES pvs-studio-analyzer)
|
|
||||||
find_program(SCAN_BUILD_TOOL NAMES scan-build-15 scan-build-14 scan-build-13 scan-build-12 scan-build-11 scan-build)
|
|
||||||
|
|
||||||
# the individual source files
|
# the individual source files
|
||||||
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp)
|
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp)
|
||||||
@@ -367,7 +364,7 @@ add_custom_target(ci_test_coverage
|
|||||||
COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 --ignore-errors mismatch --ignore-errors unused
|
COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 --ignore-errors mismatch --ignore-errors unused
|
||||||
COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc branch_coverage=1 --ignore-errors unused
|
COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc branch_coverage=1 --ignore-errors unused
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/tests/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept
|
COMMAND ${CMAKE_SOURCE_DIR}/tests/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
|
COMMAND ${GENHTML_TOOL} --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.filtered.noexcept
|
||||||
|
|
||||||
COMMENT "Compile and test with coverage"
|
COMMENT "Compile and test with coverage"
|
||||||
)
|
)
|
||||||
@@ -392,8 +389,8 @@ add_custom_target(ci_test_clang_sanitizer
|
|||||||
# Check if header is amalgamated and sources are properly indented.
|
# Check if header is amalgamated and sources are properly indented.
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# Same file set as .github/workflows/check_amalgamation.yml, so a direct push to develop/master/release/*
|
# Same file set as .github/workflows/check_amalgamation.yml, so this CMake target (which can be run locally) is held
|
||||||
# (which only this CMake target checks, not the pull_request-only workflow) is held to the same standard.
|
# to the same standard as the workflow (which runs for pull requests and for pushes to develop/master/release/*).
|
||||||
file(GLOB_RECURSE INDENT_FILES
|
file(GLOB_RECURSE INDENT_FILES
|
||||||
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.hpp
|
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.hpp
|
||||||
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cpp
|
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cpp
|
||||||
@@ -423,7 +420,7 @@ add_custom_target(ci_test_amalgamation
|
|||||||
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json.json -s .
|
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json.json -s .
|
||||||
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_fwd.json -s .
|
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_fwd.json -s .
|
||||||
COMMAND cp ${PROJECT_SOURCE_DIR}/include/nlohmann/json_literals.hpp ${include_dir}/json_literals.hpp
|
COMMAND cp ${PROJECT_SOURCE_DIR}/include/nlohmann/json_literals.hpp ${include_dir}/json_literals.hpp
|
||||||
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp
|
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp ${include_dir}/json_literals.hpp
|
||||||
COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/scripts/gen_bazel_build_file.cmake
|
COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/scripts/gen_bazel_build_file.cmake
|
||||||
|
|
||||||
COMMAND diff ${include_dir}/json.hpp~ ${include_dir}/json.hpp
|
COMMAND diff ${include_dir}/json.hpp~ ${include_dir}/json.hpp
|
||||||
@@ -434,6 +431,8 @@ add_custom_target(ci_test_amalgamation
|
|||||||
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=orig ${INDENT_FILES}
|
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=orig ${INDENT_FILES}
|
||||||
COMMAND for FILE in `find . -name '*.orig'`\; do false \; done
|
COMMAND for FILE in `find . -name '*.orig'`\; do false \; done
|
||||||
|
|
||||||
|
COMMAND rm -f ${include_dir}/json.hpp~ ${include_dir}/json_fwd.hpp~ ${include_dir}/json_literals.hpp~ ${PROJECT_SOURCE_DIR}/BUILD.bazel~
|
||||||
|
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||||
COMMENT "Check amalgamation, formatting, and BUILD.bazel"
|
COMMENT "Check amalgamation, formatting, and BUILD.bazel"
|
||||||
)
|
)
|
||||||
@@ -719,7 +718,7 @@ ci_get_cmake(4.0.0 CMAKE_4_0_0_BINARY)
|
|||||||
|
|
||||||
# the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0
|
# the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0
|
||||||
set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization
|
set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization
|
||||||
JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind
|
JSON_DisableTupleReferenceConversion JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind
|
||||||
JSON_StrictNulHandling JSON_StrictBinaryUTF8 JSON_DeleteDeprecatedFunctions)
|
JSON_StrictNulHandling JSON_StrictBinaryUTF8 JSON_DeleteDeprecatedFunctions)
|
||||||
set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
|
set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
|
||||||
set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
|
set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
|
||||||
@@ -776,17 +775,14 @@ add_custom_target(ci_cmake_flags
|
|||||||
# Use more installed compilers.
|
# Use more installed compilers.
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6 g++-7 g++-8 g++-9 g++-10 g++-11 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 clang++-14 clang++-15 clang++-16 clang++-17 clang++-18 clang++-19 clang++-20)
|
foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6)
|
||||||
find_program(COMPILER_TOOL NAMES ${COMPILER})
|
find_program(COMPILER_TOOL NAMES ${COMPILER})
|
||||||
if (COMPILER_TOOL)
|
if (COMPILER_TOOL)
|
||||||
unset(ADDITIONAL_FLAGS)
|
|
||||||
|
|
||||||
add_custom_target(ci_test_compiler_${COMPILER}
|
add_custom_target(ci_test_compiler_${COMPILER}
|
||||||
COMMAND CXX=${COMPILER} ${CMAKE_COMMAND}
|
COMMAND CXX=${COMPILER} ${CMAKE_COMMAND}
|
||||||
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
||||||
-DJSON_BuildTests=ON -DJSON_FastTests=ON
|
-DJSON_BuildTests=ON -DJSON_FastTests=ON
|
||||||
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_${COMPILER}
|
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_${COMPILER}
|
||||||
${ADDITIONAL_FLAGS}
|
|
||||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER}
|
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER}
|
||||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
|
COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
|
||||||
COMMENT "Compile and test with ${COMPILER}"
|
COMMENT "Compile and test with ${COMPILER}"
|
||||||
@@ -800,7 +796,6 @@ add_custom_target(ci_test_compiler_default
|
|||||||
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
||||||
-DJSON_BuildTests=ON -DJSON_FastTests=ON
|
-DJSON_BuildTests=ON -DJSON_FastTests=ON
|
||||||
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_default
|
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_default
|
||||||
${ADDITIONAL_FLAGS}
|
|
||||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_default --parallel ${N}
|
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_default --parallel ${N}
|
||||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_default && ${CMAKE_CTEST_COMMAND} --parallel ${N} -LE git_required --output-on-failure
|
COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_default && ${CMAKE_CTEST_COMMAND} --parallel ${N} -LE git_required --output-on-failure
|
||||||
COMMENT "Compile and test with default C++ compiler"
|
COMMENT "Compile and test with default C++ compiler"
|
||||||
@@ -823,10 +818,12 @@ add_custom_target(ci_cuda_example
|
|||||||
|
|
||||||
add_custom_target(ci_module_cpp20
|
add_custom_target(ci_module_cpp20
|
||||||
COMMAND ${CMAKE_COMMAND}
|
COMMAND ${CMAKE_COMMAND}
|
||||||
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
||||||
-DJSON_CI=ON -DNLOHMANN_JSON_BUILD_MODULES=ON -DJSON_Install=ON
|
-DJSON_CI=ON -DNLOHMANN_JSON_BUILD_MODULES=ON -DJSON_Install=ON
|
||||||
|
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
|
||||||
-S${PROJECT_SOURCE_DIR}/tests/module_cpp20 -B${PROJECT_BINARY_DIR}/ci_module_cpp20
|
-S${PROJECT_SOURCE_DIR}/tests/module_cpp20 -B${PROJECT_BINARY_DIR}/ci_module_cpp20
|
||||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/ci_module_cpp20
|
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/ci_module_cpp20
|
||||||
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ cc_library(
|
|||||||
hdrs = [
|
hdrs = [
|
||||||
"single_include/nlohmann/json.hpp",
|
"single_include/nlohmann/json.hpp",
|
||||||
"single_include/nlohmann/json_fwd.hpp",
|
"single_include/nlohmann/json_fwd.hpp",
|
||||||
|
"single_include/nlohmann/json_literals.hpp",
|
||||||
],
|
],
|
||||||
includes = ["single_include"],
|
includes = ["single_include"],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
|
|||||||
+2
-2
@@ -7,12 +7,12 @@ This URL provides the most recent documentation and also applies to previous ver
|
|||||||
functions is not removed; instead, it is marked as deprecated.
|
functions is not removed; instead, it is marked as deprecated.
|
||||||
|
|
||||||
If you want to view the documentation for a specific tag or commit hash, you can generate it locally as follows (example
|
If you want to view the documentation for a specific tag or commit hash, you can generate it locally as follows (example
|
||||||
using tag `v3.10.2`):
|
using tag `v3.12.0`):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/nlohmann/json.git
|
git clone https://github.com/nlohmann/json.git
|
||||||
cd json
|
cd json
|
||||||
git checkout v3.10.2
|
git checkout v3.12.0
|
||||||
make install_venv serve -C docs/mkdocs
|
make install_venv serve -C docs/mkdocs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+11
-55
@@ -1,48 +1,24 @@
|
|||||||
SHELL=/usr/bin/env bash
|
SHELL=/usr/bin/env bash
|
||||||
SED ?= $(shell which gsed 2>/dev/null || which sed)
|
PYTHON=../mkdocs/venv/bin/python3
|
||||||
|
|
||||||
MKDOCS_PAGES=$(shell cd ../mkdocs/docs/ && find * -type f -name '*.md' | sort)
|
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: JSON_for_Modern_C++.tgz
|
all: JSON_for_Modern_C++.tgz
|
||||||
|
|
||||||
docSet.dsidx: docSet.sql
|
# generate the search index (the docset target does this itself, this is
|
||||||
# generate index
|
# only handy for inspecting the index)
|
||||||
sqlite3 docSet.dsidx <docSet.sql
|
docSet.dsidx: generate_docset.py
|
||||||
|
$(PYTHON) generate_docset.py index docSet.dsidx
|
||||||
|
|
||||||
JSON_for_Modern_C++.docset: Info.plist docSet.dsidx
|
# build the documentation and turn it into a self-contained docset
|
||||||
rm -fr JSON_for_Modern_C++.docset JSON_for_Modern_C++.tgz
|
.PHONY: JSON_for_Modern_C++.docset
|
||||||
mkdir -p JSON_for_Modern_C++.docset/Contents/Resources/Documents/
|
JSON_for_Modern_C++.docset:
|
||||||
cp icon*.png JSON_for_Modern_C++.docset
|
|
||||||
cp Info.plist JSON_for_Modern_C++.docset/Contents
|
|
||||||
# build and copy documentation
|
|
||||||
$(MAKE) install_venv -C ../mkdocs
|
$(MAKE) install_venv -C ../mkdocs
|
||||||
$(MAKE) build -C ../mkdocs
|
$(MAKE) build -C ../mkdocs
|
||||||
cp -r ../mkdocs/site/* JSON_for_Modern_C++.docset/Contents/Resources/Documents
|
$(PYTHON) generate_docset.py docset ../mkdocs/site .
|
||||||
# patch CSS to hide navigation items
|
|
||||||
echo -e "\n\nheader, footer, nav.md-tabs, nav.md-tabs--active, div.md-sidebar--primary, a.md-content__button { display: none; }" >> "$$(ls JSON_for_Modern_C++.docset/Contents/Resources/Documents/assets/stylesheets/main.*.min.css)"
|
|
||||||
# fix spacing
|
|
||||||
echo -e "\n\ndiv.md-sidebar div.md-sidebar--secondary, div.md-main__inner { top: 0; margin-top: 0 }" >> "$$(ls JSON_for_Modern_C++.docset/Contents/Resources/Documents/assets/stylesheets/main.*.min.css)"
|
|
||||||
# remove "JSON for Modern C++" from page titles (fallback)
|
|
||||||
find JSON_for_Modern_C++.docset/Contents/Resources/Documents -type f -exec $(SED) -i 's| - JSON for Modern C++</title>|</title>|' {} +
|
|
||||||
# replace page titles with name from index, if available
|
|
||||||
for page in $(MKDOCS_PAGES); do \
|
|
||||||
case "$$page" in \
|
|
||||||
*/index.md) path=$${page/\/index.md/} ;; \
|
|
||||||
*) path=$${page/.md/} ;; \
|
|
||||||
esac; \
|
|
||||||
title=$$(sqlite3 docSet.dsidx "SELECT name FROM searchIndex WHERE path='$$path/index.html'" | tr '\n' ',' | $(SED) -e 's/,/, /g' -e 's/, $$/\n/'); \
|
|
||||||
if [ "x$$title" != "x" ]; then \
|
|
||||||
$(SED) -i "s%<title>.*</title>%<title>$$title</title>%" "JSON_for_Modern_C++.docset/Contents/Resources/Documents/$$path/index.html"; \
|
|
||||||
fi \
|
|
||||||
done
|
|
||||||
# clean up
|
|
||||||
rm JSON_for_Modern_C++.docset/Contents/Resources/Documents/sitemap.*
|
|
||||||
# copy index
|
|
||||||
cp docSet.dsidx JSON_for_Modern_C++.docset/Contents/Resources/
|
|
||||||
|
|
||||||
|
.PHONY: JSON_for_Modern_C++.tgz
|
||||||
JSON_for_Modern_C++.tgz: JSON_for_Modern_C++.docset
|
JSON_for_Modern_C++.tgz: JSON_for_Modern_C++.docset
|
||||||
tar --exclude='.DS_Store' -cvzf JSON_for_Modern_C++.tgz JSON_for_Modern_C++.docset
|
$(PYTHON) generate_docset.py tgz .
|
||||||
|
|
||||||
# install docset for Zeal documentation browser (https://zealdocs.org/)
|
# install docset for Zeal documentation browser (https://zealdocs.org/)
|
||||||
.PHONY: install_docset_zeal
|
.PHONY: install_docset_zeal
|
||||||
@@ -52,26 +28,6 @@ install_docset_zeal: JSON_for_Modern_C++.docset
|
|||||||
mkdir -p $$docset_root; \
|
mkdir -p $$docset_root; \
|
||||||
cp -r JSON_for_Modern_C++.docset $$docset_root/
|
cp -r JSON_for_Modern_C++.docset $$docset_root/
|
||||||
|
|
||||||
# both targets below compare the docset search index with the mkdocs page
|
|
||||||
# set. They share the same normalization (docs/foo/index.md and
|
|
||||||
# docs/foo.md both become foo/index.html, the URL mkdocs itself would
|
|
||||||
# give the page; the top-level index.md is excluded, as it is not part
|
|
||||||
# of the hand-curated docSet.sql) and use comm(1) on two sorted lists
|
|
||||||
# instead of running a sqlite3 query, or an O(n*m) nested shell loop,
|
|
||||||
# once per page.
|
|
||||||
DOCSET_INDEX_PATHS=$(shell sqlite3 docSet.dsidx "SELECT DISTINCT path FROM searchIndex" | sort)
|
|
||||||
DOCSET_PAGE_PATHS=$(shell echo '$(MKDOCS_PAGES)' | tr ' ' '\n' | grep -v '^index\.md$$' | $(SED) -E 's@/index\.md$$@/index.html@; s@\.md$$@/index.html@' | sort)
|
|
||||||
|
|
||||||
# list mkdocs pages missing from the docset index
|
|
||||||
.PHONY: list_missing_pages
|
|
||||||
list_missing_pages: docSet.dsidx
|
|
||||||
@comm -23 <(echo '$(DOCSET_PAGE_PATHS)' | tr ' ' '\n') <(echo '$(DOCSET_INDEX_PATHS)' | tr ' ' '\n')
|
|
||||||
|
|
||||||
# list paths in the docset index without a corresponding mkdocs page
|
|
||||||
.PHONY: list_removed_paths
|
|
||||||
list_removed_paths: docSet.dsidx
|
|
||||||
@comm -13 <(echo '$(DOCSET_PAGE_PATHS)' | tr ' ' '\n') <(echo '$(DOCSET_INDEX_PATHS)' | tr ' ' '\n')
|
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f docSet.dsidx
|
rm -f docSet.dsidx
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ The folder contains the required files to create a [docset](https://kapeli.com/d
|
|||||||
documentation browsers like [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), or
|
documentation browsers like [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), or
|
||||||
[Zeal](https://zealdocs.org).
|
[Zeal](https://zealdocs.org).
|
||||||
|
|
||||||
The docset can be created with
|
The docset (pages and search index) is generated by `generate_docset.py` from the mkdocs site and `mkdocs.yml`. It
|
||||||
|
can be created with
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make JSON_for_Modern_C++.docset
|
make JSON_for_Modern_C++.docset
|
||||||
@@ -12,6 +13,7 @@ make JSON_for_Modern_C++.docset
|
|||||||
|
|
||||||
The generated folder `JSON_for_Modern_C++.docset` can then be opened in the documentation browser. `make all` builds a
|
The generated folder `JSON_for_Modern_C++.docset` can then be opened in the documentation browser. `make all` builds a
|
||||||
`JSON_for_Modern_C++.tgz` archive instead, and `make install_docset_zeal` installs the docset for Zeal directly.
|
`JSON_for_Modern_C++.tgz` archive instead, and `make install_docset_zeal` installs the docset for Zeal directly.
|
||||||
|
`make docSet.dsidx` builds only the search index.
|
||||||
|
|
||||||
A recent version is also part of the [Dash user contributions](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B).
|
A recent version is also part of the [Dash user contributions](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B).
|
||||||
|
|
||||||
|
|||||||
@@ -1,289 +0,0 @@
|
|||||||
DROP TABLE IF EXISTS searchIndex;
|
|
||||||
CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);
|
|
||||||
CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path);
|
|
||||||
|
|
||||||
-- API
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('adl_serializer', 'Class', 'api/adl_serializer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('adl_serializer::from_json', 'Function', 'api/adl_serializer/from_json/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('adl_serializer::to_json', 'Function', 'api/adl_serializer/to_json/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype', 'Class', 'api/byte_container_with_subtype/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::byte_container_with_subtype', 'Constructor', 'api/byte_container_with_subtype/byte_container_with_subtype/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::clear_subtype', 'Method', 'api/byte_container_with_subtype/clear_subtype/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::has_subtype', 'Method', 'api/byte_container_with_subtype/has_subtype/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::operator!=', 'Operator', 'api/byte_container_with_subtype/operator_ne/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::operator==', 'Operator', 'api/byte_container_with_subtype/operator_eq/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::set_subtype', 'Method', 'api/byte_container_with_subtype/set_subtype/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::subtype', 'Method', 'api/byte_container_with_subtype/subtype/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json', 'Class', 'api/basic_json/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('format_as', 'Function', 'api/basic_json/format_as/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::accept', 'Function', 'api/basic_json/accept/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::array', 'Function', 'api/basic_json/array/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::array_t', 'Type', 'api/basic_json/array_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::as_base_class', 'Method', 'api/basic_json/as_base_class/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::at', 'Method', 'api/basic_json/at/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::back', 'Method', 'api/basic_json/back/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::basic_json', 'Constructor', 'api/basic_json/basic_json/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::begin', 'Method', 'api/basic_json/begin/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::binary', 'Function', 'api/basic_json/binary/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::binary_t', 'Type', 'api/basic_json/binary_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::boolean_t', 'Type', 'api/basic_json/boolean_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::cbegin', 'Method', 'api/basic_json/cbegin/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::cbor_tag_handler_t', 'Enum', 'api/basic_json/cbor_tag_handler_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::cend', 'Method', 'api/basic_json/cend/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::clear', 'Method', 'api/basic_json/clear/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::contains', 'Method', 'api/basic_json/contains/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::count', 'Method', 'api/basic_json/count/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::crbegin', 'Method', 'api/basic_json/crbegin/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::crend', 'Method', 'api/basic_json/crend/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::default_object_comparator_t', 'Type', 'api/basic_json/default_object_comparator_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::diff', 'Function', 'api/basic_json/diff/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::dump', 'Method', 'api/basic_json/dump/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::emplace', 'Method', 'api/basic_json/emplace/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::emplace_back', 'Method', 'api/basic_json/emplace_back/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::empty', 'Method', 'api/basic_json/empty/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::end', 'Method', 'api/basic_json/end/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::end_pos', 'Method', 'api/basic_json/end_pos/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::erase', 'Method', 'api/basic_json/erase/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::error_handler_t', 'Enum', 'api/basic_json/error_handler_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::exception', 'Class', 'api/basic_json/exception/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::find', 'Method', 'api/basic_json/find/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::flatten', 'Method', 'api/basic_json/flatten/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_bjdata', 'Function', 'api/basic_json/from_bjdata/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_bson', 'Function', 'api/basic_json/from_bson/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_cbor', 'Function', 'api/basic_json/from_cbor/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_msgpack', 'Function', 'api/basic_json/from_msgpack/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_bon8', 'Function', 'api/basic_json/from_bon8/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_ubjson', 'Function', 'api/basic_json/from_ubjson/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::front', 'Method', 'api/basic_json/front/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get', 'Method', 'api/basic_json/get/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_allocator', 'Function', 'api/basic_json/get_allocator/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_binary', 'Method', 'api/basic_json/get_binary/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_ptr', 'Method', 'api/basic_json/get_ptr/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_ref', 'Method', 'api/basic_json/get_ref/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_to', 'Method', 'api/basic_json/get_to/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::input_format_t', 'Enum', 'api/basic_json/input_format_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::insert', 'Method', 'api/basic_json/insert/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::invalid_iterator', 'Class', 'api/basic_json/invalid_iterator/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_array', 'Method', 'api/basic_json/is_array/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_binary', 'Method', 'api/basic_json/is_binary/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_boolean', 'Method', 'api/basic_json/is_boolean/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_discarded', 'Method', 'api/basic_json/is_discarded/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_null', 'Method', 'api/basic_json/is_null/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_number', 'Method', 'api/basic_json/is_number/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_number_float', 'Method', 'api/basic_json/is_number_float/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_number_integer', 'Method', 'api/basic_json/is_number_integer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_number_unsigned', 'Method', 'api/basic_json/is_number_unsigned/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_object', 'Method', 'api/basic_json/is_object/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_primitive', 'Method', 'api/basic_json/is_primitive/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_string', 'Method', 'api/basic_json/is_string/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_structured', 'Method', 'api/basic_json/is_structured/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::items', 'Method', 'api/basic_json/items/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::json_base_class_t', 'Type', 'api/basic_json/json_base_class_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::json_serializer', 'Class', 'api/basic_json/json_serializer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::max_size', 'Method', 'api/basic_json/max_size/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::merge_patch', 'Method', 'api/basic_json/merge_patch/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::meta', 'Function', 'api/basic_json/meta/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::number_float_t', 'Type', 'api/basic_json/number_float_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::number_integer_t', 'Type', 'api/basic_json/number_integer_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::number_unsigned_t', 'Type', 'api/basic_json/number_unsigned_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::object', 'Function', 'api/basic_json/object/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::object_comparator_t', 'Type', 'api/basic_json/object_comparator_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::object_t', 'Type', 'api/basic_json/object_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator ValueType', 'Operator', 'api/basic_json/operator_ValueType/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator value_t', 'Operator', 'api/basic_json/operator_value_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator[]', 'Operator', 'api/basic_json/operator[]/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator=', 'Operator', 'api/basic_json/operator=/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator+=', 'Operator', 'api/basic_json/operator+=/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator==', 'Operator', 'api/basic_json/operator_eq/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator!=', 'Operator', 'api/basic_json/operator_ne/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator<', 'Operator', 'api/basic_json/operator_lt/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator<=', 'Operator', 'api/basic_json/operator_le/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator>', 'Operator', 'api/basic_json/operator_gt/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator>=', 'Operator', 'api/basic_json/operator_ge/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator<=>', 'Operator', 'api/basic_json/operator_spaceship/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::out_of_range', 'Class', 'api/basic_json/out_of_range/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::other_error', 'Class', 'api/basic_json/other_error/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::parse', 'Function', 'api/basic_json/parse/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::parse_error', 'Class', 'api/basic_json/parse_error/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::parse_event_t', 'Enum', 'api/basic_json/parse_event_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::parser_callback_t', 'Type', 'api/basic_json/parser_callback_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::patch', 'Method', 'api/basic_json/patch/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::patch_inplace', 'Method', 'api/basic_json/patch_inplace/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::push_back', 'Method', 'api/basic_json/push_back/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::rbegin', 'Method', 'api/basic_json/rbegin/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::rend', 'Method', 'api/basic_json/rend/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::sax_parse', 'Function', 'api/basic_json/sax_parse/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::size', 'Method', 'api/basic_json/size/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::start_pos', 'Method', 'api/basic_json/start_pos/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::string_t', 'Type', 'api/basic_json/string_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::swap', 'Method', 'api/basic_json/swap/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::type', 'Method', 'api/basic_json/type/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::type_error', 'Class', 'api/basic_json/type_error/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::type_name', 'Method', 'api/basic_json/type_name/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::unflatten', 'Method', 'api/basic_json/unflatten/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::update', 'Method', 'api/basic_json/update/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_bjdata', 'Function', 'api/basic_json/to_bjdata/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_bson', 'Function', 'api/basic_json/to_bson/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_cbor', 'Function', 'api/basic_json/to_cbor/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_msgpack', 'Function', 'api/basic_json/to_msgpack/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_bon8', 'Function', 'api/basic_json/to_bon8/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_string', 'Method', 'api/basic_json/to_string/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_ubjson', 'Function', 'api/basic_json/to_ubjson/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::value', 'Method', 'api/basic_json/value/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::value_t', 'Enum', 'api/basic_json/value_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::with_t', 'Type', 'api/basic_json/with_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::~basic_json', 'Method', 'api/basic_json/~basic_json/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json', 'Class', 'api/json/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer', 'Class', 'api/json_pointer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::back', 'Method', 'api/json_pointer/back/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::empty', 'Method', 'api/json_pointer/empty/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::front', 'Method', 'api/json_pointer/front/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::json_pointer', 'Constructor', 'api/json_pointer/json_pointer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator==', 'Operator', 'api/json_pointer/operator_eq/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator!=', 'Operator', 'api/json_pointer/operator_ne/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator/', 'Operator', 'api/json_pointer/operator_slash/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator/=', 'Operator', 'api/json_pointer/operator_slasheq/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator string_t', 'Operator', 'api/json_pointer/operator_string_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator<=>', 'Operator', 'api/json_pointer/operator_spaceship/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::parent_pointer', 'Method', 'api/json_pointer/parent_pointer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::pop_back', 'Method', 'api/json_pointer/pop_back/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::pop_front', 'Method', 'api/json_pointer/pop_front/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::push_back', 'Method', 'api/json_pointer/push_back/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::push_front', 'Method', 'api/json_pointer/push_front/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::string_t', 'Type', 'api/json_pointer/string_t/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::to_string', 'Method', 'api/json_pointer/to_string/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax', 'Class', 'api/json_sax/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::binary', 'Method', 'api/json_sax/binary/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::boolean', 'Method', 'api/json_sax/boolean/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::end_array', 'Method', 'api/json_sax/end_array/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::end_object', 'Method', 'api/json_sax/end_object/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::key', 'Method', 'api/json_sax/key/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::null', 'Method', 'api/json_sax/null/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_float', 'Method', 'api/json_sax/number_float/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_integer', 'Method', 'api/json_sax/number_integer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_unsigned', 'Method', 'api/json_sax/number_unsigned/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::parse_error', 'Method', 'api/json_sax/parse_error/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::start_array', 'Method', 'api/json_sax/start_array/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::start_object', 'Method', 'api/json_sax/start_object/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::string', 'Method', 'api/json_sax/string/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('operator""_json', 'Literal', 'api/operator_literal_json/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('operator""_json_pointer', 'Literal', 'api/operator_literal_json_pointer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('operator<<', 'Operator', 'api/operator_ltlt/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('operator>>', 'Operator', 'api/operator_gtgt/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json', 'Class', 'api/ordered_json/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map', 'Class', 'api/ordered_map/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('std::formatter<basic_json>', 'Class', 'api/basic_json/std_formatter/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('std::hash<basic_json>', 'Class', 'api/basic_json/std_hash/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('std::swap<basic_json>', 'Function', 'api/basic_json/std_swap/index.html');
|
|
||||||
|
|
||||||
-- Features
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Arbitrary Type Conversions', 'Guide', 'features/arbitrary_types/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats', 'Guide', 'features/binary_formats/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: BJData', 'Guide', 'features/binary_formats/bjdata/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: BSON', 'Guide', 'features/binary_formats/bson/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: CBOR', 'Guide', 'features/binary_formats/cbor/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: MessagePack', 'Guide', 'features/binary_formats/messagepack/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: BON8', 'Guide', 'features/binary_formats/bon8/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: UBJSON', 'Guide', 'features/binary_formats/ubjson/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Values', 'Guide', 'features/binary_values/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Comments', 'Guide', 'features/comments/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Element Access', 'Guide', 'features/element_access/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Access with default value: value', 'Guide', 'features/element_access/default_value/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Checked access: at', 'Guide', 'features/element_access/checked_access/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Unchecked access: operator[]', 'Guide', 'features/element_access/unchecked_access/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Exceptions', 'Guide', 'home/exceptions/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Migration Guide', 'Guide', 'integration/migration_guide/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: CMake', 'Guide', 'integration/cmake/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Header only', 'Guide', 'integration/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Package Managers', 'Guide', 'integration/package_managers/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Pkg-config', 'Guide', 'integration/pkg-config/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Iterators', 'Guide', 'features/iterators/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Merge Patch', 'Guide', 'features/merge_patch/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Patch and Diff', 'Guide', 'features/json_patch/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Pointer', 'Guide', 'features/json_pointer/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('nlohmann Namespace', 'Guide', 'features/namespace/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Types', 'Guide', 'features/types/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Types: Number Handling', 'Guide', 'features/types/number_handling/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Object Order', 'Guide', 'features/object_order/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Performance', 'Guide', 'features/performance/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing', 'Guide', 'features/parsing/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: JSON Lines', 'Guide', 'features/parsing/json_lines/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Parser Callbacks', 'Guide', 'features/parsing/parser_callbacks/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Parsing and Exceptions', 'Guide', 'features/parsing/parse_exceptions/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: SAX Interface', 'Guide', 'features/parsing/sax_interface/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Untrusted Input', 'Guide', 'features/parsing/untrusted_input/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Runtime Assertions', 'Guide', 'features/assertions/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Specializing enum conversion', 'Guide', 'features/enum_conversion/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Supported Macros', 'Guide', 'features/macros/index.html');
|
|
||||||
|
|
||||||
-- Macros
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'api/macros/json_assert/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_BRACE_INIT_COPY_SEMANTICS', 'Macro', 'api/macros/json_brace_init_copy_semantics/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'api/macros/json_throw_user/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DELETE_DEPRECATED_FUNCTIONS', 'Macro', 'api/macros/json_delete_deprecated_functions/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'api/macros/json_disable_enum_serialization/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_TUPLE_REFERENCE_CONVERSION', 'Macro', 'api/macros/json_disable_tuple_reference_conversion/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_11', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_14', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_17', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_20', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_23', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_26', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_EXPERIMENTAL_FILESYSTEM', 'Macro', 'api/macros/json_has_filesystem/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_FILESYSTEM', 'Macro', 'api/macros/json_has_filesystem/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_RANGES', 'Macro', 'api/macros/json_has_ranges/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_STATIC_RTTI', 'Macro', 'api/macros/json_has_static_rtti/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_STD_FORMAT', 'Macro', 'api/macros/json_has_std_format/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_THREE_WAY_COMPARISON', 'Macro', 'api/macros/json_has_three_way_comparison/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NOEXCEPTION', 'Macro', 'api/macros/json_noexception/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_AUTOMATIC_UDLS', 'Macro', 'api/macros/json_no_automatic_udls/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_IO', 'Macro', 'api/macros/json_no_io/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_THREAD_LOCAL', 'Macro', 'api/macros/json_no_thread_local/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_PRECISE_STREAM_POSITION', 'Macro', 'api/macros/json_precise_stream_position/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_SKIP_LIBRARY_VERSION_CHECK', 'Macro', 'api/macros/json_skip_library_version_check/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_SKIP_UNSUPPORTED_COMPILER_CHECK', 'Macro', 'api/macros/json_skip_unsupported_compiler_check/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_STRICT_BINARY_UTF8', 'Macro', 'api/macros/json_strict_binary_utf8/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_STRICT_NUL_HANDLING', 'Macro', 'api/macros/json_strict_nul_handling/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_THROW_USER', 'Macro', 'api/macros/json_throw_user/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_TRY_USER', 'Macro', 'api/macros/json_throw_user/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro', 'api/macros/json_use_global_udls/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS', 'Macro', 'api/macros/json_use_objects_for_enum_keyed_maps/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_SIMDUTF', 'Macro', 'api/macros/json_use_simdutf/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE', 'Macro', 'api/macros/nlohmann_json_namespace/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_BEGIN', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_END', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_NO_VERSION', 'Macro', 'api/macros/nlohmann_json_namespace_no_version/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM', 'Macro', 'api/macros/nlohmann_json_serialize_enum/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM_STRICT', 'Macro', 'api/macros/nlohmann_json_serialize_enum_strict/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MAJOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MINOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_PATCH', 'Macro', 'api/macros/nlohmann_json_version_major/index.html');
|
|
||||||
Executable
+532
@@ -0,0 +1,532 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""Generate the Dash docset search index from the mkdocs sources."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import glob
|
||||||
|
import hashlib
|
||||||
|
import html
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import sqlite3
|
||||||
|
import sys
|
||||||
|
import tarfile
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
MKDOCS_YML = os.path.join(HERE, '..', 'mkdocs', 'mkdocs.yml')
|
||||||
|
PAGES = os.path.join(HERE, '..', 'mkdocs', 'docs')
|
||||||
|
|
||||||
|
# api pages whose (name, type) cannot be derived by the heuristics
|
||||||
|
OVERRIDES = {
|
||||||
|
}
|
||||||
|
|
||||||
|
DOCSET = 'JSON_for_Modern_C++.docset'
|
||||||
|
TITLE_SUFFIX = ' - JSON for Modern C++</title>'
|
||||||
|
|
||||||
|
# CSS rules appended to the stylesheet: hide navigation items and fix spacing
|
||||||
|
# hide the navigation (the documentation browser has its own); Material's class selectors would win over element
|
||||||
|
# selectors, hence the classes and !important
|
||||||
|
CSS_PATCH = (
|
||||||
|
'\n\n.md-header, .md-footer, .md-tabs, .md-sidebar--primary, .md-content__button { display: none !important; }'
|
||||||
|
'\n\n.md-sidebar--secondary, .md-main__inner { top: 0 !important; margin-top: 0 !important; }'
|
||||||
|
)
|
||||||
|
|
||||||
|
USER_AGENT = ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 '
|
||||||
|
'(KHTML, like Gecko) Chrome/124.0 Safari/537.36')
|
||||||
|
CONTENT_TYPE_EXT = {'image/svg+xml': '.svg', 'image/png': '.png', 'image/jpeg': '.jpg',
|
||||||
|
'image/gif': '.gif', 'image/webp': '.webp'}
|
||||||
|
|
||||||
|
# remote loads that are allowed to remain (URL -> reason)
|
||||||
|
ALLOWED_REMOTE = {
|
||||||
|
# Material only loads this polyfill if the browser has no ResizeObserver
|
||||||
|
'https://unpkg.com/resize-observer-polyfill': 'fallback for browsers without ResizeObserver',
|
||||||
|
}
|
||||||
|
|
||||||
|
problems = []
|
||||||
|
|
||||||
|
|
||||||
|
def problem(page, reason) -> None:
|
||||||
|
"""Record a problem; all problems are reported at the end."""
|
||||||
|
problems.append(f'generate_docset.py: {page}: {reason}')
|
||||||
|
|
||||||
|
|
||||||
|
class Loader(yaml.SafeLoader):
|
||||||
|
"""YAML loader that tolerates the custom tags used in mkdocs.yml."""
|
||||||
|
|
||||||
|
|
||||||
|
Loader.add_multi_constructor('', lambda loader, suffix, node: None)
|
||||||
|
|
||||||
|
|
||||||
|
def walk_nav(items, groups=()):
|
||||||
|
"""Yield (group titles, nav title or None, md path) for all nav leaves."""
|
||||||
|
for item in items:
|
||||||
|
if isinstance(item, str):
|
||||||
|
yield list(groups), None, item
|
||||||
|
elif isinstance(item, dict):
|
||||||
|
for title, value in item.items():
|
||||||
|
if isinstance(value, list):
|
||||||
|
yield from walk_nav(value, groups + (str(title),))
|
||||||
|
else:
|
||||||
|
yield list(groups), str(title), value
|
||||||
|
|
||||||
|
|
||||||
|
def page_path(md_path) -> str:
|
||||||
|
"""Map a markdown path to the HTML path of the rendered page."""
|
||||||
|
if md_path.endswith('/index.md'):
|
||||||
|
return md_path[:-len('index.md')] + 'index.html'
|
||||||
|
return md_path[:-len('.md')] + '/index.html'
|
||||||
|
|
||||||
|
|
||||||
|
def read_page(md_path) -> str:
|
||||||
|
"""Read a page (resolving a snippet include), return '' if it does not exist."""
|
||||||
|
try:
|
||||||
|
with open(os.path.join(PAGES, md_path), encoding='utf-8') as f:
|
||||||
|
text = f.read()
|
||||||
|
m = re.match(r'--8<-- "(.+)"\s*$', text)
|
||||||
|
if m:
|
||||||
|
with open(os.path.join(PAGES, m.group(1)), encoding='utf-8') as f:
|
||||||
|
text = f.read()
|
||||||
|
return text
|
||||||
|
except OSError:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
def clean(text) -> str:
|
||||||
|
"""Strip tags and entities from a heading and normalize whitespace."""
|
||||||
|
text = text.replace('\\>', '\x00') # escaped '>' is not the end of a tag
|
||||||
|
text = html.unescape(re.sub(r'</?[a-zA-Z][^>]*>', '', text)).replace('\x00', '>')
|
||||||
|
return re.sub(r'\s+', ' ', text).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def strip_fences(text) -> str:
|
||||||
|
"""Remove fenced code blocks (their lines may start with '# ')."""
|
||||||
|
return re.sub(r'^(```|~~~).*?^\1[^\n]*$', '', text, flags=re.M | re.S)
|
||||||
|
|
||||||
|
|
||||||
|
def get_h1(text):
|
||||||
|
"""Return the cleaned first H1 of a page or None."""
|
||||||
|
body = strip_fences(text)
|
||||||
|
m = re.search(r'^# (.+)$', body, flags=re.M)
|
||||||
|
if m:
|
||||||
|
return clean(m.group(1))
|
||||||
|
m = re.search(r'<h1>(.*?)</h1>', body, flags=re.S)
|
||||||
|
return clean(m.group(1)) if m else None
|
||||||
|
|
||||||
|
|
||||||
|
def split_top_level(text, seps=','):
|
||||||
|
"""Split at separators that are not nested in <>, () or []."""
|
||||||
|
parts, depth, current = [], 0, ''
|
||||||
|
for c in text:
|
||||||
|
if c in '<([':
|
||||||
|
depth += 1
|
||||||
|
elif c in '>)]':
|
||||||
|
depth -= 1
|
||||||
|
if c in seps and depth <= 0:
|
||||||
|
parts.append(current)
|
||||||
|
current = ''
|
||||||
|
else:
|
||||||
|
current += c
|
||||||
|
parts.append(current)
|
||||||
|
return [p.strip() for p in parts if p.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
OPERATOR_SYMBOLS = ('<=>', '<<', '>>', '<=', '>=', '<', '>')
|
||||||
|
|
||||||
|
|
||||||
|
def api_names(h1) -> list:
|
||||||
|
"""Derive the entry names from the H1 of an api page."""
|
||||||
|
# hide the angle brackets of operators from the nesting detection
|
||||||
|
for i, sym in enumerate(OPERATOR_SYMBOLS):
|
||||||
|
h1 = h1.replace('operator' + sym, f'operator\x01{i}\x01')
|
||||||
|
names = []
|
||||||
|
for part in split_top_level(h1):
|
||||||
|
name = part.replace('\\', '').replace('nlohmann::', '')
|
||||||
|
name = re.sub(r'\x01(\d)\x01', lambda m: OPERATOR_SYMBOLS[int(m.group(1))], name)
|
||||||
|
# drop qualifiers like "operator<<(basic_json)", but keep "operator()"
|
||||||
|
if not name.endswith('operator()'):
|
||||||
|
name = re.sub(r'(?<=\w|[<>=!+\-*/\[\]])\([^()]*\)$', '', name)
|
||||||
|
if name not in names:
|
||||||
|
names.append(name)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def first_cpp_block(text):
|
||||||
|
"""Return the first ```cpp block following the H1."""
|
||||||
|
m = re.search(r'^# .*?^```cpp\n(.*?)^```', text, flags=re.M | re.S)
|
||||||
|
return m.group(1) if m else None
|
||||||
|
|
||||||
|
|
||||||
|
def api_type(name, decl):
|
||||||
|
"""Determine the Dash entry type from name and declaration."""
|
||||||
|
parts = name.split('::')
|
||||||
|
last = parts[-1]
|
||||||
|
if name.startswith('operator""'):
|
||||||
|
return 'Literal'
|
||||||
|
if last.startswith('operator'):
|
||||||
|
return 'Operator'
|
||||||
|
if decl is None:
|
||||||
|
return None
|
||||||
|
if re.search(r'\benum\b', decl):
|
||||||
|
return 'Enum'
|
||||||
|
if re.search(r'^\s*(template\s*<.*>\s*)?(class|struct)\s+\w+\s*(final\b|[:{;<]|$)', decl, flags=re.M):
|
||||||
|
return 'Class'
|
||||||
|
if re.search(r'\busing\s+\w+\s*=', decl) or 'typedef' in decl:
|
||||||
|
return 'Type'
|
||||||
|
if len(parts) > 1 and last == parts[-2]:
|
||||||
|
return 'Constructor'
|
||||||
|
if last.startswith('~'):
|
||||||
|
return 'Method'
|
||||||
|
if re.search(r'\bstatic\b', decl) or len(parts) == 1 or parts[0] == 'std':
|
||||||
|
return 'Function'
|
||||||
|
return 'Method'
|
||||||
|
|
||||||
|
|
||||||
|
def macro_names(h1) -> list:
|
||||||
|
"""Split the H1 of a macro page into macro names."""
|
||||||
|
return [n.strip() for n in re.split(r'[,/]', h1) if n.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def api_entries(md_path):
|
||||||
|
"""Return the (name, type) pairs of an api page."""
|
||||||
|
if md_path in OVERRIDES:
|
||||||
|
return OVERRIDES[md_path]
|
||||||
|
if md_path == 'api/macros/index.md':
|
||||||
|
return [('Macros', 'Macro')]
|
||||||
|
text = read_page(md_path)
|
||||||
|
h1 = get_h1(text)
|
||||||
|
if not h1:
|
||||||
|
problem(md_path, 'no H1 found')
|
||||||
|
return []
|
||||||
|
if md_path.startswith('api/macros/'):
|
||||||
|
return [(n, 'Macro') for n in macro_names(h1)]
|
||||||
|
names = api_names(h1)
|
||||||
|
if not names:
|
||||||
|
problem(md_path, 'no names found')
|
||||||
|
return []
|
||||||
|
decl = first_cpp_block(text)
|
||||||
|
result = []
|
||||||
|
for name in names:
|
||||||
|
kind = api_type(name, decl)
|
||||||
|
if kind is None:
|
||||||
|
problem(md_path, f'no type determinable for {name}')
|
||||||
|
else:
|
||||||
|
result.append((name, kind))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def guide_entries(nav):
|
||||||
|
"""Yield (name, type, md path) for all non-api nav pages."""
|
||||||
|
for groups, title, md_path in walk_nav(nav):
|
||||||
|
if md_path.startswith('api/') or md_path == 'index.md':
|
||||||
|
continue
|
||||||
|
if not md_path.endswith('.md'):
|
||||||
|
continue
|
||||||
|
groups = groups[1:] # drop the top-level tab
|
||||||
|
if title is None:
|
||||||
|
title = get_h1(read_page(md_path))
|
||||||
|
if not title:
|
||||||
|
problem(md_path, 'no title found')
|
||||||
|
continue
|
||||||
|
# "Parsing: Parsing Untrusted Input" -> "Parsing: Untrusted Input"
|
||||||
|
if groups and title.startswith(groups[-1] + ' ') and title[len(groups[-1]) + 1:][:1].isupper():
|
||||||
|
title = title[len(groups[-1]) + 1:]
|
||||||
|
if md_path.endswith('/index.md') and groups and title == groups[-1]:
|
||||||
|
name = ': '.join(groups)
|
||||||
|
else:
|
||||||
|
name = ': '.join(groups + [title])
|
||||||
|
yield name, 'Guide', md_path
|
||||||
|
|
||||||
|
|
||||||
|
def build_entries() -> list:
|
||||||
|
"""Return the sorted list of (name, type, path) index entries."""
|
||||||
|
nav = load_mkdocs_yml()['nav']
|
||||||
|
|
||||||
|
entries = set()
|
||||||
|
for name, kind, md_path in guide_entries(nav):
|
||||||
|
entries.add((name, kind, page_path(md_path)))
|
||||||
|
|
||||||
|
api_root = os.path.join(PAGES, 'api')
|
||||||
|
on_disk = set()
|
||||||
|
for root, _, files in os.walk(api_root):
|
||||||
|
for file in files:
|
||||||
|
if file.endswith('.md'):
|
||||||
|
rel = os.path.relpath(os.path.join(root, file), PAGES)
|
||||||
|
on_disk.add(rel.replace(os.sep, '/'))
|
||||||
|
for _, _, md_path in walk_nav(nav):
|
||||||
|
if md_path.startswith('api/') and md_path not in on_disk:
|
||||||
|
problem(md_path, 'listed in nav but missing on disk')
|
||||||
|
for md_path in sorted(on_disk):
|
||||||
|
for name, kind in api_entries(md_path):
|
||||||
|
entries.add((name, kind, page_path(md_path)))
|
||||||
|
return sorted(entries)
|
||||||
|
|
||||||
|
|
||||||
|
def write_index(entries, out) -> None:
|
||||||
|
"""Write the entries into a SQLite search index."""
|
||||||
|
if os.path.exists(out):
|
||||||
|
os.remove(out)
|
||||||
|
con = sqlite3.connect(out)
|
||||||
|
con.execute('CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT)')
|
||||||
|
con.execute('CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path)')
|
||||||
|
con.executemany('INSERT INTO searchIndex(name, type, path) VALUES (?, ?, ?)', entries)
|
||||||
|
con.commit()
|
||||||
|
con.close()
|
||||||
|
|
||||||
|
|
||||||
|
def html_files(root):
|
||||||
|
"""Yield all HTML files below root."""
|
||||||
|
for base, _, files in os.walk(root):
|
||||||
|
for file in files:
|
||||||
|
if file.endswith('.html'):
|
||||||
|
yield os.path.join(base, file)
|
||||||
|
|
||||||
|
|
||||||
|
def read(path) -> str:
|
||||||
|
with open(path, encoding='utf-8') as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
def write(path, text) -> None:
|
||||||
|
with open(path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(text)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_source_widget(docs) -> None:
|
||||||
|
"""Drop data-md-component=source so Material does not query api.github.com for the stars and version."""
|
||||||
|
pattern = re.compile(r'\sdata-md-component=(?:"source"|source\b)')
|
||||||
|
for path in html_files(docs):
|
||||||
|
text = read(path)
|
||||||
|
new = pattern.sub('', text)
|
||||||
|
if new != text:
|
||||||
|
write(path, new)
|
||||||
|
|
||||||
|
|
||||||
|
def patch_titles(docs, entries) -> None:
|
||||||
|
"""Strip the site name from all titles; use the index names where available."""
|
||||||
|
names = {}
|
||||||
|
for name, _, path in entries:
|
||||||
|
names.setdefault(path, []).append(name)
|
||||||
|
for file in html_files(docs):
|
||||||
|
rel = os.path.relpath(file, docs).replace(os.sep, '/')
|
||||||
|
text = read(file).replace(TITLE_SUFFIX, '</title>')
|
||||||
|
if rel in names:
|
||||||
|
title = html.escape(', '.join(names[rel]), quote=False)
|
||||||
|
text = re.sub(r'<title>.*?</title>', lambda _: f'<title>{title}</title>', text, count=1, flags=re.S)
|
||||||
|
write(file, text)
|
||||||
|
|
||||||
|
|
||||||
|
IMG_RE = re.compile(r'<img\b[^>]*>', re.I)
|
||||||
|
ATTR_RE = r'''(?:{0})\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+))'''
|
||||||
|
|
||||||
|
|
||||||
|
def attr(tag, name):
|
||||||
|
"""Return the value of an attribute in a tag or None."""
|
||||||
|
m = re.search(r'(?<![\w-])' + ATTR_RE.format(name), tag, flags=re.I)
|
||||||
|
return next(g for g in m.groups() if g is not None) if m else None
|
||||||
|
|
||||||
|
|
||||||
|
def is_remote(url) -> bool:
|
||||||
|
return re.match(r'(https?:)?//', url.strip(), flags=re.I) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def download(url, docs) -> str:
|
||||||
|
"""Download url into assets/external and return the path relative to docs."""
|
||||||
|
u = urllib.parse.urlparse(url if not url.startswith('//') else 'https:' + url)
|
||||||
|
if u.scheme.lower() not in ('http', 'https'):
|
||||||
|
raise ValueError(f'not an http(s) URL: {url}')
|
||||||
|
req = urllib.request.Request(u.geturl(), headers={'User-Agent': USER_AGENT})
|
||||||
|
# (the scheme is checked above)
|
||||||
|
with urllib.request.urlopen(req, timeout=20) as r: # nosec B310
|
||||||
|
data = r.read()
|
||||||
|
ctype = r.headers.get_content_type()
|
||||||
|
path = urllib.parse.unquote(u.path).lstrip('/')
|
||||||
|
ext = os.path.splitext(path)[1]
|
||||||
|
if u.query or not ext or path.endswith('/'):
|
||||||
|
digest = hashlib.sha1(url.encode(), usedforsecurity=False).hexdigest()[:12]
|
||||||
|
path = os.path.join(os.path.dirname(path), digest + CONTENT_TYPE_EXT.get(ctype, ext or '.bin'))
|
||||||
|
rel = os.path.normpath(os.path.join('assets', 'external', u.hostname, path))
|
||||||
|
out = os.path.join(docs, rel)
|
||||||
|
os.makedirs(os.path.dirname(out), exist_ok=True)
|
||||||
|
with open(out, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
|
return rel.replace(os.sep, '/')
|
||||||
|
|
||||||
|
|
||||||
|
def localize_images(docs) -> None:
|
||||||
|
"""Download remote images and rewrite their src; drop them on failure."""
|
||||||
|
cache = {}
|
||||||
|
for file in html_files(docs):
|
||||||
|
text = read(file)
|
||||||
|
|
||||||
|
def repl(m):
|
||||||
|
tag = m.group(0)
|
||||||
|
src = attr(tag, 'src')
|
||||||
|
if src is None or not is_remote(src):
|
||||||
|
return tag
|
||||||
|
if src not in cache:
|
||||||
|
try:
|
||||||
|
cache[src] = download(src, docs)
|
||||||
|
except Exception as e: # noqa: BLE001
|
||||||
|
print(f'generate_docset.py: warning: cannot download {src}: {e}', file=sys.stderr)
|
||||||
|
cache[src] = None
|
||||||
|
if cache[src] is None:
|
||||||
|
return attr(tag, 'alt') or ''
|
||||||
|
local = os.path.relpath(os.path.join(docs, cache[src]), os.path.dirname(file))
|
||||||
|
local = local.replace(os.sep, '/')
|
||||||
|
return re.sub(ATTR_RE.format('src'), lambda _: f'src="{local}"', tag, count=1, flags=re.I)
|
||||||
|
|
||||||
|
new = IMG_RE.sub(repl, text)
|
||||||
|
if new != text:
|
||||||
|
write(file, new)
|
||||||
|
|
||||||
|
|
||||||
|
def load_mkdocs_yml() -> dict:
|
||||||
|
"""Load mkdocs.yml, ignoring tags like !ENV and !!python/name."""
|
||||||
|
with open(MKDOCS_YML, encoding='utf-8') as f:
|
||||||
|
# (Loader is a yaml.SafeLoader)
|
||||||
|
return yaml.load(f, Loader=Loader) # nosec B506
|
||||||
|
|
||||||
|
|
||||||
|
def localize_site_urls(docs, site_url) -> None:
|
||||||
|
"""Load assets that the theme's JavaScript references by absolute site URL from the docset.
|
||||||
|
|
||||||
|
The privacy plugin rewrites the mermaid loader to "<site_url>assets/external/unpkg.com/mermaid@11/...", so the
|
||||||
|
docset would fetch mermaid from the live site. __md_scope is the site root that Material defines in every page.
|
||||||
|
"""
|
||||||
|
pattern = re.compile(r'"' + re.escape(site_url) + r'(assets/[^"]*)"')
|
||||||
|
for base, _, files in os.walk(docs):
|
||||||
|
for file in (f for f in files if f.endswith('.js')):
|
||||||
|
path = os.path.join(base, file)
|
||||||
|
text = read(path)
|
||||||
|
new = pattern.sub(r'new URL("\1",__md_scope).href', text)
|
||||||
|
if new != text:
|
||||||
|
write(path, new)
|
||||||
|
|
||||||
|
|
||||||
|
def remote_loads(docs, site_url) -> list:
|
||||||
|
"""Return 'file: url' strings for resources that would be loaded remotely."""
|
||||||
|
found = []
|
||||||
|
cdn = re.compile(r'https://(?:unpkg\.com|cdn\.jsdelivr\.net|cdnjs\.cloudflare\.com|'
|
||||||
|
r'fonts\.googleapis\.com|fonts\.gstatic\.com)/[^\s"\'`)\\]*')
|
||||||
|
css_url = re.compile(r'url\(\s*["\']?((?:https?:)?//[^)"\']+)', re.I)
|
||||||
|
css_import = re.compile(r'@import\s+(?:url\(\s*)?["\']?((?:https?:)?//[^)"\'; ]+)', re.I)
|
||||||
|
for base, _, files in os.walk(docs):
|
||||||
|
for file in files:
|
||||||
|
path = os.path.join(base, file)
|
||||||
|
rel = os.path.relpath(path, docs)
|
||||||
|
urls = []
|
||||||
|
if file.endswith('.html'):
|
||||||
|
text = read(path)
|
||||||
|
for m in re.finditer(r'<[a-zA-Z][^>]*>', text):
|
||||||
|
tag = m.group(0)
|
||||||
|
for name in ('src', 'poster'):
|
||||||
|
v = attr(tag, name)
|
||||||
|
if v and is_remote(v):
|
||||||
|
urls.append(v)
|
||||||
|
v = attr(tag, 'srcset')
|
||||||
|
if v:
|
||||||
|
urls += [c.split()[0] for c in v.split(',') if c.strip() and is_remote(c.strip())]
|
||||||
|
if re.match(r'<link\b', tag, flags=re.I):
|
||||||
|
rel_attr = (attr(tag, 'rel') or '').lower()
|
||||||
|
v = attr(tag, 'href')
|
||||||
|
if v and is_remote(v) and re.search(r'stylesheet|icon|preload|modulepreload|manifest', rel_attr):
|
||||||
|
urls.append(v)
|
||||||
|
urls += css_url.findall(text) + css_import.findall(text)
|
||||||
|
elif file.endswith('.css'):
|
||||||
|
text = read(path)
|
||||||
|
urls += css_url.findall(text) + css_import.findall(text)
|
||||||
|
elif file.endswith('.js'):
|
||||||
|
text = read(path)
|
||||||
|
urls += cdn.findall(text)
|
||||||
|
urls += re.findall(re.escape(site_url) + r'assets/[^\s"\'`)\\]*', text)
|
||||||
|
found += [f'{rel}: {u}' for u in urls if u not in ALLOWED_REMOTE]
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
def make_docset(site, out_dir) -> int:
|
||||||
|
entries = build_entries()
|
||||||
|
if problems:
|
||||||
|
print('\n'.join(problems), file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
docset = os.path.join(out_dir, DOCSET)
|
||||||
|
docs = os.path.join(docset, 'Contents', 'Resources', 'Documents')
|
||||||
|
if os.path.exists(docset):
|
||||||
|
shutil.rmtree(docset)
|
||||||
|
shutil.copytree(site, docs)
|
||||||
|
for icon in ('icon.png', 'icon@2x.png'):
|
||||||
|
shutil.copy(os.path.join(HERE, icon), docset)
|
||||||
|
shutil.copy(os.path.join(HERE, 'Info.plist'), os.path.join(docset, 'Contents'))
|
||||||
|
write_index(entries, os.path.join(docset, 'Contents', 'Resources', 'docSet.dsidx'))
|
||||||
|
|
||||||
|
# patch CSS to hide navigation items and fix spacing
|
||||||
|
css = glob.glob(os.path.join(docs, 'assets', 'stylesheets', 'main.*.min.css'))
|
||||||
|
if len(css) != 1:
|
||||||
|
print(f'generate_docset.py: expected exactly one main.*.min.css, found {len(css)}', file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
with open(css[0], 'a', encoding='utf-8') as f:
|
||||||
|
f.write(CSS_PATCH)
|
||||||
|
|
||||||
|
patch_titles(docs, entries)
|
||||||
|
remove_source_widget(docs)
|
||||||
|
for sitemap in glob.glob(os.path.join(docs, 'sitemap.*')):
|
||||||
|
os.remove(sitemap)
|
||||||
|
|
||||||
|
# make the docset self-contained
|
||||||
|
site_url = load_mkdocs_yml()['site_url']
|
||||||
|
localize_images(docs)
|
||||||
|
localize_site_urls(docs, site_url)
|
||||||
|
remote = remote_loads(docs, site_url)
|
||||||
|
if remote:
|
||||||
|
print('generate_docset.py: remote resources remain in the docset:', file=sys.stderr)
|
||||||
|
print('\n'.join(' ' + r for r in remote), file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def make_tgz(out_dir) -> int:
|
||||||
|
docset = os.path.join(out_dir, DOCSET)
|
||||||
|
if not os.path.isdir(docset):
|
||||||
|
print(f'generate_docset.py: {docset} does not exist', file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
with tarfile.open(os.path.join(out_dir, 'JSON_for_Modern_C++.tgz'), 'w:gz') as tar:
|
||||||
|
tar.add(docset, arcname=DOCSET, filter=lambda i: None if os.path.basename(i.name) == '.DS_Store' else i)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
sub = parser.add_subparsers(dest='command', required=True)
|
||||||
|
sub.add_parser('list', help='print the index entries as TSV')
|
||||||
|
p = sub.add_parser('index', help='write the SQLite search index')
|
||||||
|
p.add_argument('out')
|
||||||
|
p = sub.add_parser('docset', help='build the docset from a built mkdocs site')
|
||||||
|
p.add_argument('site_dir')
|
||||||
|
p.add_argument('out_dir')
|
||||||
|
p = sub.add_parser('tgz', help='pack the docset into a tarball')
|
||||||
|
p.add_argument('out_dir')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.command == 'docset':
|
||||||
|
return make_docset(args.site_dir, args.out_dir)
|
||||||
|
if args.command == 'tgz':
|
||||||
|
return make_tgz(args.out_dir)
|
||||||
|
|
||||||
|
entries = build_entries()
|
||||||
|
if problems:
|
||||||
|
print('\n'.join(problems), file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
if args.command == 'list':
|
||||||
|
for entry in entries:
|
||||||
|
print('\t'.join(entry))
|
||||||
|
elif args.command == 'index':
|
||||||
|
write_index(entries, args.out)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
@@ -17,6 +17,7 @@ build: style_check
|
|||||||
|
|
||||||
style_check:
|
style_check:
|
||||||
@cd docs ; ../venv/bin/python3 ../scripts/check_structure.py
|
@cd docs ; ../venv/bin/python3 ../scripts/check_structure.py
|
||||||
|
@venv/bin/python3 ../docset/generate_docset.py list > /dev/null
|
||||||
|
|
||||||
# check that all Mermaid diagrams parse (needs Node.js)
|
# check that all Mermaid diagrams parse (needs Node.js)
|
||||||
# This target is used in the CI (ci_test_documentation_mermaid).
|
# This target is used in the CI (ci_test_documentation_mermaid).
|
||||||
|
|||||||
@@ -241,4 +241,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
|||||||
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
|
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
|
||||||
already supported by [`operator[]`](operator[].md), [`value`](value.md), [`find`](find.md), and other lookup
|
already supported by [`operator[]`](operator[].md), [`value`](value.md), [`find`](find.md), and other lookup
|
||||||
functions.
|
functions.
|
||||||
4. Added in version 2.0.0.
|
4. Added in version 2.0.0. Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
|
||||||
|
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is not
|
||||||
|
a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones.
|
||||||
@@ -10,6 +10,10 @@ bool contains(KeyType&& key) const;
|
|||||||
|
|
||||||
// (3)
|
// (3)
|
||||||
bool contains(const json_pointer& ptr) const;
|
bool contains(const json_pointer& ptr) const;
|
||||||
|
|
||||||
|
// (4)
|
||||||
|
template<typename T>
|
||||||
|
bool contains(T) const = delete;
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Check whether an element exists in a JSON object with a key equivalent to `key`. If the element is not found or the
|
1. Check whether an element exists in a JSON object with a key equivalent to `key`. If the element is not found or the
|
||||||
@@ -17,6 +21,9 @@ bool contains(const json_pointer& ptr) const;
|
|||||||
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
|
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
|
||||||
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
|
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
|
||||||
3. Check whether the given JSON pointer `ptr` can be resolved in the current JSON value.
|
3. Check whether the given JSON pointer `ptr` can be resolved in the current JSON value.
|
||||||
|
4. Deleted: this overload is only available if `T` is an integral type and is declared as deleted, so that a call with
|
||||||
|
an integer `key` (for example, `#!cpp j.contains(0)`) fails to compile. Otherwise, the integer literal `0` would convert to
|
||||||
|
a null `#!cpp const char*` and, from there, to the key type, causing undefined behavior at runtime.
|
||||||
|
|
||||||
## Template parameters
|
## Template parameters
|
||||||
|
|
||||||
@@ -39,6 +46,7 @@ bool contains(const json_pointer& ptr) const;
|
|||||||
is not an object, `#!cpp false` is returned.
|
is not an object, `#!cpp false` is returned.
|
||||||
2. See 1.
|
2. See 1.
|
||||||
3. `#!cpp true` if the JSON pointer can be resolved to a stored value, `#!cpp false` otherwise.
|
3. `#!cpp true` if the JSON pointer can be resolved to a stored value, `#!cpp false` otherwise.
|
||||||
|
4. Deleted; a call with an integral argument does not compile.
|
||||||
|
|
||||||
## Exception safety
|
## Exception safety
|
||||||
|
|
||||||
@@ -49,6 +57,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
|||||||
1. The function does not throw exceptions.
|
1. The function does not throw exceptions.
|
||||||
2. The function does not throw exceptions.
|
2. The function does not throw exceptions.
|
||||||
3. The function does not throw exceptions.
|
3. The function does not throw exceptions.
|
||||||
|
4. Deleted; a call with an integral argument does not compile.
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,19 @@ size_type count(const typename object_t::key_type& key) const;
|
|||||||
// (2)
|
// (2)
|
||||||
template<typename KeyType>
|
template<typename KeyType>
|
||||||
size_type count(KeyType&& key) const;
|
size_type count(KeyType&& key) const;
|
||||||
|
|
||||||
|
// (3)
|
||||||
|
template<typename T>
|
||||||
|
size_type count(T) const = delete;
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Returns the number of elements with key `key`. If `ObjectType` is the default `std::map` type, the return value will
|
1. Returns the number of elements with key `key`. If `ObjectType` is the default `std::map` type, the return value will
|
||||||
always be `0` (`key` was not found) or `1` (`key` was found).
|
always be `0` (`key` was not found) or `1` (`key` was found).
|
||||||
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
|
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
|
||||||
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
|
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
|
||||||
|
3. Deleted: this overload is only available if `T` is an integral type and is declared as deleted, so that a call with
|
||||||
|
an integer `key` (for example, `#!cpp j.count(0)`) fails to compile. Otherwise, the integer literal `0` would convert to
|
||||||
|
a null `#!cpp const char*` and, from there, to the key type, causing undefined behavior at runtime.
|
||||||
|
|
||||||
## Template parameters
|
## Template parameters
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ ignore
|
|||||||
: ignore invalid UTF-8 sequences; all valid bytes are copied to the output unchanged, and invalid bytes are dropped
|
: ignore invalid UTF-8 sequences; all valid bytes are copied to the output unchanged, and invalid bytes are dropped
|
||||||
|
|
||||||
keep
|
keep
|
||||||
: keep invalid UTF-8 sequences unchanged; only meaningful for the binary formats mentioned above, since [`dump`]
|
: keep invalid UTF-8 sequences unchanged; only meaningful for the binary formats mentioned above, since
|
||||||
(dump.md) itself must produce text, and `keep` there writes the ill-formed bytes to the output as is, so the
|
[`dump`](dump.md) itself must produce text, and `keep` there writes the ill-formed bytes to the output as is, so the
|
||||||
result is then not valid UTF-8 (but still equals the input bytes exactly, including around any well-formed
|
result is then not valid UTF-8 (but still equals the input bytes exactly, including around any well-formed
|
||||||
characters, which are still escaped as usual)
|
characters, which are still escaped as usual)
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,21 @@ template<typename KeyType>
|
|||||||
iterator find(KeyType&& key);
|
iterator find(KeyType&& key);
|
||||||
template<typename KeyType>
|
template<typename KeyType>
|
||||||
const_iterator find(KeyType&& key) const;
|
const_iterator find(KeyType&& key) const;
|
||||||
|
|
||||||
|
// (3)
|
||||||
|
template<typename T>
|
||||||
|
iterator find(T) = delete;
|
||||||
|
template<typename T>
|
||||||
|
const_iterator find(T) const = delete;
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Finds an element in a JSON object with a key equivalent to `key`. If the element is not found or the
|
1. Finds an element in a JSON object with a key equivalent to `key`. If the element is not found or the
|
||||||
JSON value is not an object, `end()` is returned.
|
JSON value is not an object, `end()` is returned.
|
||||||
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
|
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
|
||||||
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
|
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
|
||||||
|
3. Deleted: this overload is only available if `T` is an integral type and is declared as deleted, so that a call with
|
||||||
|
an integer `key` (for example, `#!cpp j.find(0)`) fails to compile. Otherwise, the integer literal `0` would convert to
|
||||||
|
a null `#!cpp const char*` and, from there, to the key type, causing undefined behavior at runtime.
|
||||||
|
|
||||||
## Template parameters
|
## Template parameters
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,8 @@ Linear in the size of the input.
|
|||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
- Overload (2) replaces calls to `from_bjdata` with a pointer and a length as first two parameters, which has been
|
- Overload (2) replaces calls to `from_bjdata` with a pointer and a length as first two parameters, which has been
|
||||||
deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.13.0. In version 4.0.0, this overload
|
||||||
|
will be deleted (`= delete`) rather than removed. Please replace all calls like
|
||||||
`#!cpp from_bjdata(ptr, len, ...);` with `#!cpp from_bjdata(ptr, ptr+len, ...);`.
|
`#!cpp from_bjdata(ptr, len, ...);` with `#!cpp from_bjdata(ptr, ptr+len, ...);`.
|
||||||
|
|
||||||
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
|
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
|
||||||
|
|||||||
@@ -110,7 +110,8 @@ Linear in the size of the input.
|
|||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
- Overload (2) replaces calls to `from_bon8` with a pointer and a length as first two parameters, which has been
|
- Overload (2) replaces calls to `from_bon8` with a pointer and a length as first two parameters, which has been
|
||||||
deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.13.0. In version 4.0.0, this overload
|
||||||
|
will be deleted (`= delete`) rather than removed. Please replace all calls like
|
||||||
`#!cpp from_bon8(ptr, len, ...);` with `#!cpp from_bon8(ptr, ptr+len, ...);`.
|
`#!cpp from_bon8(ptr, len, ...);` with `#!cpp from_bon8(ptr, ptr+len, ...);`.
|
||||||
|
|
||||||
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
|
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ Linear in the size of the input.
|
|||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
- Overload (2) replaces calls to `from_bson` with a pointer and a length as first two parameters, which has been
|
- Overload (2) replaces calls to `from_bson` with a pointer and a length as first two parameters, which has been
|
||||||
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.8.0. In version 4.0.0, this overload
|
||||||
|
will be deleted (`= delete`) rather than removed. Please replace all calls like
|
||||||
`#!cpp from_bson(ptr, len, ...);` with `#!cpp from_bson(ptr, ptr+len, ...);`.
|
`#!cpp from_bson(ptr, len, ...);` with `#!cpp from_bson(ptr, ptr+len, ...);`.
|
||||||
- Overload (2) replaces calls to `from_bson` with a pair of iterators as their first parameter, which has been
|
- Overload (2) replaces calls to `from_bson` with a pair of iterators as their first parameter, which has been
|
||||||
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ Linear in the size of the input.
|
|||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
- Overload (2) replaces calls to `from_cbor` with a pointer and a length as first two parameters, which has been
|
- Overload (2) replaces calls to `from_cbor` with a pointer and a length as first two parameters, which has been
|
||||||
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.8.0. In version 4.0.0, this overload
|
||||||
|
will be deleted (`= delete`) rather than removed. Please replace all calls like
|
||||||
`#!cpp from_cbor(ptr, len, ...);` with `#!cpp from_cbor(ptr, ptr+len, ...);`.
|
`#!cpp from_cbor(ptr, len, ...);` with `#!cpp from_cbor(ptr, ptr+len, ...);`.
|
||||||
- Overload (2) replaces calls to `from_cbor` with a pair of iterators as their first parameter, which has been
|
- Overload (2) replaces calls to `from_cbor` with a pair of iterators as their first parameter, which has been
|
||||||
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
||||||
|
|||||||
@@ -127,7 +127,8 @@ Linear in the size of the input.
|
|||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
- Overload (2) replaces calls to `from_msgpack` with a pointer and a length as first two parameters, which has been
|
- Overload (2) replaces calls to `from_msgpack` with a pointer and a length as first two parameters, which has been
|
||||||
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.8.0. In version 4.0.0, this overload
|
||||||
|
will be deleted (`= delete`) rather than removed. Please replace all calls like
|
||||||
`#!cpp from_msgpack(ptr, len, ...);` with `#!cpp from_msgpack(ptr, ptr+len, ...);`.
|
`#!cpp from_msgpack(ptr, len, ...);` with `#!cpp from_msgpack(ptr, ptr+len, ...);`.
|
||||||
- Overload (2) replaces calls to `from_msgpack` with a pair of iterators as their first parameter, which has been
|
- Overload (2) replaces calls to `from_msgpack` with a pair of iterators as their first parameter, which has been
|
||||||
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
||||||
|
|||||||
@@ -125,7 +125,8 @@ Linear in the size of the input.
|
|||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
- Overload (2) replaces calls to `from_ubjson` with a pointer and a length as first two parameters, which has been
|
- Overload (2) replaces calls to `from_ubjson` with a pointer and a length as first two parameters, which has been
|
||||||
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.8.0. In version 4.0.0, this overload
|
||||||
|
will be deleted (`= delete`) rather than removed. Please replace all calls like
|
||||||
`#!cpp from_ubjson(ptr, len, ...);` with `#!cpp from_ubjson(ptr, ptr+len, ...);`.
|
`#!cpp from_ubjson(ptr, len, ...);` with `#!cpp from_ubjson(ptr, ptr+len, ...);`.
|
||||||
- Overload (2) replaces calls to `from_ubjson` with a pair of iterators as their first parameter, which has been
|
- Overload (2) replaces calls to `from_ubjson` with a pair of iterators as their first parameter, which has been
|
||||||
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
||||||
|
|||||||
@@ -62,5 +62,5 @@ same name. Hidden members remain accessible via [`as_base_class`](as_base_class.
|
|||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.12.0.
|
- Added in version 3.11.3.
|
||||||
- Made a public member type in version 3.13.0; it was private before, so it could not be named outside the class.
|
- Made a public member type in version 3.13.0; it was private before, so it could not be named outside the class.
|
||||||
@@ -26,8 +26,7 @@ To store objects in C++, a type is defined by the template parameters described
|
|||||||
|
|
||||||
`StringType`
|
`StringType`
|
||||||
: the type of the keys or names (e.g., `std::string`). The comparison function `std::less<StringType>` is used to
|
: the type of the keys or names (e.g., `std::string`). The comparison function `std::less<StringType>` is used to
|
||||||
order elements inside the container. `object_t::key_type` must be implicitly convertible to `string_t` (required by the
|
order elements inside the container.
|
||||||
binary formats).
|
|
||||||
|
|
||||||
`AllocatorType`
|
`AllocatorType`
|
||||||
: the allocator to use for objects (e.g., `std::allocator`)
|
: the allocator to use for objects (e.g., `std::allocator`)
|
||||||
|
|||||||
@@ -286,4 +286,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
|||||||
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
|
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
|
||||||
already supported by [`at`](at.md), [`value`](value.md), [`find`](find.md), and other lookup functions.
|
already supported by [`at`](at.md), [`value`](value.md), [`find`](find.md), and other lookup functions.
|
||||||
4. Added in version 2.0.0. A missing array index in the const version is guarded by a runtime assertion since
|
4. Added in version 2.0.0. A missing array index in the const version is guarded by a runtime assertion since
|
||||||
version 3.13.0.
|
version 3.13.0. Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
|
||||||
|
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is not
|
||||||
|
a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones.
|
||||||
@@ -112,3 +112,6 @@ is thrown. In any case, the original value is not changed: the patch is applied
|
|||||||
location has a non-object/non-array parent in version 3.13.0.
|
location has a non-object/non-array parent in version 3.13.0.
|
||||||
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
||||||
prefix of its "path" location instead of silently producing a corrupted result in version 3.13.0.
|
prefix of its "path" location instead of silently producing a corrupted result in version 3.13.0.
|
||||||
|
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
|
||||||
|
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is
|
||||||
|
not a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones.
|
||||||
@@ -110,3 +110,6 @@ function throws an exception.
|
|||||||
location has a non-object/non-array parent in version 3.13.0.
|
location has a non-object/non-array parent in version 3.13.0.
|
||||||
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
||||||
prefix of its "path" location instead of silently producing a corrupted result in version 3.13.0.
|
prefix of its "path" location instead of silently producing a corrupted result in version 3.13.0.
|
||||||
|
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
|
||||||
|
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is
|
||||||
|
not a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones.
|
||||||
@@ -41,6 +41,8 @@ With (2), the bytes written before the exception remain in the output adapter.
|
|||||||
above 9223372036854775807, which BON8 cannot represent
|
above 9223372036854775807, which BON8 cannot represent
|
||||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if `j` contains a string that is not
|
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if `j` contains a string that is not
|
||||||
valid UTF-8
|
valid UTF-8
|
||||||
|
- Throws [type_error.321](../../home/exceptions.md#jsonexceptiontype_error321) if `j` or a value nested in it is
|
||||||
|
discarded; example: `"cannot serialize discarded value to BON8"`
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,9 @@ The function can throw the following exceptions:
|
|||||||
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in a key is not a
|
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in a key is not a
|
||||||
number; example: `"array index 'one' is not a number"`
|
number; example: `"array index 'one' is not a number"`
|
||||||
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if a level becomes an array
|
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if a level becomes an array
|
||||||
(because one of its keys is `0`) and another key at that level cannot be an array index; example:
|
(because one of its keys is `0`) and another key at that level begins with a digit but is not a valid array index
|
||||||
`"unresolved reference token 'x'"`
|
(such as `1a`), or is `-`; example:
|
||||||
|
`"unresolved reference token '-'"`
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
@@ -80,3 +81,6 @@ Apart from these two cases, for a JSON value `j`, the following is always true:
|
|||||||
|
|
||||||
- Added in version 2.0.0.
|
- Added in version 2.0.0.
|
||||||
- Made the array/object decision independent of the object's iteration order in version 3.13.0.
|
- Made the array/object decision independent of the object's iteration order in version 3.13.0.
|
||||||
|
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
|
||||||
|
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is
|
||||||
|
not a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones.
|
||||||
@@ -119,6 +119,14 @@ changes to any JSON value.
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
!!! warning "`null` members are not missing"
|
||||||
|
|
||||||
|
The default value is used only if the key (or JSON Pointer) does not exist. A member that exists but is
|
||||||
|
`#!json null` is converted like any other value, so `#!cpp j.value("k", 0)` throws a
|
||||||
|
[`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `"k"` is `#!json null`. See
|
||||||
|
[Access with default value](../../features/element_access/default_value.md)
|
||||||
|
for alternatives.
|
||||||
|
|
||||||
!!! warning "Return type"
|
!!! warning "Return type"
|
||||||
|
|
||||||
The value function is a template, and the return type of the function is determined by the type of the provided
|
The value function is a template, and the return type of the function is determined by the type of the provided
|
||||||
@@ -227,4 +235,6 @@ changes to any JSON value.
|
|||||||
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), and other lookup functions.
|
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), and other lookup functions.
|
||||||
3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0, including fixing an issue where resolving
|
3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0, including fixing an issue where resolving
|
||||||
`ptr` through an array unexpectedly threw `out_of_range` instead of returning the resolved element (or
|
`ptr` through an array unexpectedly threw `out_of_range` instead of returning the resolved element (or
|
||||||
`default_value`, as documented).
|
`default_value`, as documented). Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109)
|
||||||
|
instead of returning `default_value` for a one-character array index that is not a digit (e.g., `/x`) in version
|
||||||
|
3.13.0, as it already did for longer ones.
|
||||||
@@ -27,6 +27,7 @@ header. See also the [macro overview page](../../features/macros.md).
|
|||||||
|
|
||||||
- [**JSON_HAS_CPP_11**<br>**JSON_HAS_CPP_14**<br>**JSON_HAS_CPP_17**<br>**JSON_HAS_CPP_20**](json_has_cpp_11.md) - set supported C++ standard
|
- [**JSON_HAS_CPP_11**<br>**JSON_HAS_CPP_14**<br>**JSON_HAS_CPP_17**<br>**JSON_HAS_CPP_20**](json_has_cpp_11.md) - set supported C++ standard
|
||||||
- [**JSON_HAS_FILESYSTEM**<br>**JSON_HAS_EXPERIMENTAL_FILESYSTEM**](json_has_filesystem.md) - control `std::filesystem` support
|
- [**JSON_HAS_FILESYSTEM**<br>**JSON_HAS_EXPERIMENTAL_FILESYSTEM**](json_has_filesystem.md) - control `std::filesystem` support
|
||||||
|
- [**JSON_HAS_RANGE_VIEW_CONVERSION**](json_has_range_view_conversion.md) - control construction from `std::ranges` views
|
||||||
- [**JSON_HAS_RANGES**](json_has_ranges.md) - control `std::ranges` support
|
- [**JSON_HAS_RANGES**](json_has_ranges.md) - control `std::ranges` support
|
||||||
- [**JSON_HAS_STATIC_RTTI**](json_has_static_rtti.md) - control RTTI (run time type information) support
|
- [**JSON_HAS_STATIC_RTTI**](json_has_static_rtti.md) - control RTTI (run time type information) support
|
||||||
- [**JSON_HAS_STD_FORMAT**](json_has_std_format.md) - control `std::format`/`std::formatter` support
|
- [**JSON_HAS_STD_FORMAT**](json_has_std_format.md) - control `std::format`/`std::formatter` support
|
||||||
|
|||||||
@@ -49,6 +49,6 @@ The default value is detected based on preprocessor macros such as `#!cpp __cplu
|
|||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.10.5.
|
- Added in version 3.10.0.
|
||||||
- Added `JSON_HAS_CPP_23` in version 3.12.0.
|
- Added `JSON_HAS_CPP_23` in version 3.12.0.
|
||||||
- Added `JSON_HAS_CPP_26` in version 3.13.0.
|
- Added `JSON_HAS_CPP_26` in version 3.13.0.
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# JSON_HAS_RANGE_VIEW_CONVERSION
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define JSON_HAS_RANGE_VIEW_CONVERSION /* value */
|
||||||
|
```
|
||||||
|
|
||||||
|
This macro indicates whether a JSON array can be constructed directly from a C++20 range view (`std::ranges::view`),
|
||||||
|
such as the result of `std::views::filter` or `std::views::transform`. Possible values are `1` when supported or `0`
|
||||||
|
when unsupported.
|
||||||
|
|
||||||
|
## Default definition
|
||||||
|
|
||||||
|
The default value is `1` if [`JSON_HAS_RANGES`](json_has_ranges.md) is `1` and the compiler is not MinGW (that is,
|
||||||
|
`#!cpp __MINGW32__` is not defined), and `0` otherwise.
|
||||||
|
|
||||||
|
When the macro is not defined, the library will define it to its default value.
|
||||||
|
|
||||||
|
!!! info "Known compiler/stdlib exclusions"
|
||||||
|
|
||||||
|
- **MinGW** -- disabled, because its `std::ranges` support is incomplete ([issue #4916](https://github.com/nlohmann/json/issues/4916)).
|
||||||
|
- All toolchains for which [`JSON_HAS_RANGES`](json_has_ranges.md#default-definition) is disabled.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The code below forces the library to disable the conversion from range views:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define JSON_HAS_RANGE_VIEW_CONVERSION 0
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
- [JSON_HAS_RANGES](json_has_ranges.md) - control `std::ranges` support
|
||||||
|
- [Constructing from a C++20 range view](../../features/conversions.md#putting-values-in) - usage of the feature
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
- Added in version 3.13.0.
|
||||||
@@ -20,7 +20,7 @@ When the macro is not defined, the library will define it to its default value.
|
|||||||
|
|
||||||
- **GCC 11.1.0** — disabled (the shipped `<ranges>` header has a syntax error; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
- **GCC 11.1.0** — disabled (the shipped `<ranges>` header has a syntax error; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
||||||
- **libstdc++ < 11** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
- **libstdc++ < 11** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
||||||
- **Clang < 16 with libstdc++** — disabled (incomplete ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
- **Clang < 16 with libstdc++** — disabled (incomplete ranges support; [issue #5161](https://github.com/nlohmann/json/issues/5161))
|
||||||
- **libc++ < 160000** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
- **libc++ < 160000** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
||||||
- **nvcc (CUDA) 12.0.x and 12.1.x** — disabled (the `enable_borrowed_range` variable-template syntax triggers a parse error
|
- **nvcc (CUDA) 12.0.x and 12.1.x** — disabled (the `enable_borrowed_range` variable-template syntax triggers a parse error
|
||||||
under these two toolkit versions; fixed in CUDA 12.2; [issue #3907](https://github.com/nlohmann/json/issues/3907))
|
under these two toolkit versions; fixed in CUDA 12.2; [issue #3907](https://github.com/nlohmann/json/issues/3907))
|
||||||
@@ -44,9 +44,12 @@ When the macro is not defined, the library will define it to its default value.
|
|||||||
|
|
||||||
- [JSON_HAS_CPP_11 / JSON_HAS_CPP_14 / JSON_HAS_CPP_17 / JSON_HAS_CPP_20 / JSON_HAS_CPP_23 /
|
- [JSON_HAS_CPP_11 / JSON_HAS_CPP_14 / JSON_HAS_CPP_17 / JSON_HAS_CPP_20 / JSON_HAS_CPP_23 /
|
||||||
JSON_HAS_CPP_26](json_has_cpp_11.md) - set supported C++ standard
|
JSON_HAS_CPP_26](json_has_cpp_11.md) - set supported C++ standard
|
||||||
|
- [JSON_HAS_RANGE_VIEW_CONVERSION](json_has_range_view_conversion.md) - control construction from `std::ranges` views
|
||||||
- [JSON_HAS_STD_FORMAT](json_has_std_format.md) - a similar feature-detection macro, for `std::format`/`std::formatter`
|
- [JSON_HAS_STD_FORMAT](json_has_std_format.md) - a similar feature-detection macro, for `std::format`/`std::formatter`
|
||||||
support
|
support
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.11.0.
|
- Added in version 3.11.0.
|
||||||
|
- Added the exclusions for libstdc++ < 11, Clang < 16 with libstdc++, libc++ < 16, and nvcc (CUDA) 12.0.x and 12.1.x in
|
||||||
|
version 3.13.0. Before, only GCC 11.1.0 was excluded.
|
||||||
@@ -20,7 +20,10 @@ The macro does not affect:
|
|||||||
- The binary readers ([`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md),
|
- The binary readers ([`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md),
|
||||||
[`from_ubjson`](../basic_json/from_ubjson.md), [`from_bjdata`](../basic_json/from_bjdata.md),
|
[`from_ubjson`](../basic_json/from_ubjson.md), [`from_bjdata`](../basic_json/from_bjdata.md),
|
||||||
[`from_bson`](../basic_json/from_bson.md)): none of these formats requires a decoder to reject ill-formed UTF-8, so
|
[`from_bson`](../basic_json/from_bson.md)): none of these formats requires a decoder to reject ill-formed UTF-8, so
|
||||||
they always return the bytes unchanged.
|
by default they return the bytes unchanged (`error_handler_t::keep`), independent of this macro. Pass an
|
||||||
|
`error_handler` argument explicitly to validate or sanitize the strings they read.
|
||||||
|
- [`from_bon8`](../basic_json/from_bon8.md): BON8 always validates, because the UTF-8 lead bytes mark where a string
|
||||||
|
ends.
|
||||||
|
|
||||||
## Default definition
|
## Default definition
|
||||||
|
|
||||||
|
|||||||
@@ -190,3 +190,5 @@ void to_json(BasicJsonType& j, const B& b) {
|
|||||||
4. Added in version 3.12.0.
|
4. Added in version 3.12.0.
|
||||||
5. Added in version 3.12.0.
|
5. Added in version 3.12.0.
|
||||||
6. Added in version 3.12.0.
|
6. Added in version 3.12.0.
|
||||||
|
|
||||||
|
All six macros were changed to allow an empty member list in version 3.13.0.
|
||||||
@@ -186,3 +186,6 @@ See the examples below for the concrete generated code.
|
|||||||
1. Added in version 3.9.0.
|
1. Added in version 3.9.0.
|
||||||
2. Added in version 3.11.0.
|
2. Added in version 3.11.0.
|
||||||
3. Added in version 3.11.3.
|
3. Added in version 3.11.3.
|
||||||
|
|
||||||
|
All three macros were changed to work with any `basic_json` specialization (not only `nlohmann::json`) in version 3.12.0,
|
||||||
|
and to allow an empty member list in version 3.13.0.
|
||||||
@@ -185,3 +185,6 @@ See the examples below for the concrete generated code.
|
|||||||
1. Added in version 3.9.0.
|
1. Added in version 3.9.0.
|
||||||
2. Added in version 3.11.0.
|
2. Added in version 3.11.0.
|
||||||
3. Added in version 3.11.3.
|
3. Added in version 3.11.3.
|
||||||
|
|
||||||
|
All three macros were changed to work with any `basic_json` specialization (not only `nlohmann::json`) in version 3.12.0,
|
||||||
|
and to allow an empty member list in version 3.13.0.
|
||||||
@@ -38,4 +38,6 @@ the library.
|
|||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.11.0. Changed inline namespace name in version 3.11.2.
|
- Added in version 3.11.0. Changed inline namespace name in version 3.11.2. Added the ABI tag `_dp` in
|
||||||
|
version 3.12.0, and the ABI tags `_bics`, `_psp`, `_snul`, `_sbu8`, and `_ekmo` in version 3.13.0; see
|
||||||
|
[`nlohmann` Namespace](../../features/namespace.md#structure).
|
||||||
@@ -14,7 +14,7 @@ These macros can be used to open and close the `nlohmann` namespace. See
|
|||||||
## Default definition
|
## Default definition
|
||||||
|
|
||||||
The default definitions open and close the `nlohmann` namespace. The precise definition of
|
The default definitions open and close the `nlohmann` namespace. The precise definition of
|
||||||
[`NLOHMANN_JSON_NAMESPACE_BEGIN`] varies as described [here](../../features/namespace.md#structure).
|
`NLOHMANN_JSON_NAMESPACE_BEGIN` varies as described [here](../../features/namespace.md#structure).
|
||||||
|
|
||||||
1. Default definition of `NLOHMANN_JSON_NAMESPACE_BEGIN`:
|
1. Default definition of `NLOHMANN_JSON_NAMESPACE_BEGIN`:
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ The library parses, stores, and serializes JSON values in memory. It does not op
|
|||||||
files (it only reads from streams or `std::FILE*` handles that the caller has already opened), does not read environment
|
files (it only reads from streams or `std::FILE*` handles that the caller has already opened), does not read environment
|
||||||
variables, and does not implement cryptography or handle credentials.
|
variables, and does not implement cryptography or handle credentials.
|
||||||
|
|
||||||
The primary threat is therefore **untrusted input**: JSON text or binary data (BJData, BSON, CBOR, MessagePack, UBJSON)
|
The primary threat is therefore **untrusted input**: JSON text or binary data (BJData, BON8, BSON, CBOR, MessagePack, UBJSON)
|
||||||
that an attacker controls, passed to [`parse`](../api/basic_json/parse.md), [`accept`](../api/basic_json/accept.md),
|
that an attacker controls, passed to [`parse`](../api/basic_json/parse.md), [`accept`](../api/basic_json/accept.md),
|
||||||
[`sax_parse`](../api/basic_json/sax_parse.md), or one of the `from_*` functions such as
|
[`sax_parse`](../api/basic_json/sax_parse.md), or one of the `from_*` functions such as
|
||||||
[`from_cbor`](../api/basic_json/from_cbor.md). Such input may try to
|
[`from_cbor`](../api/basic_json/from_cbor.md). Such input may try to
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ violations will result in a failed build.
|
|||||||
|
|
||||||
Note: C++20 modules support may hit compiler-specific issues not covered by the general compiler matrix below. See [Modules](../features/modules.md#known-issues) for known issues and workarounds.
|
Note: C++20 modules support may hit compiler-specific issues not covered by the general compiler matrix below. See [Modules](../features/modules.md#known-issues) for known issues and workarounds.
|
||||||
|
|
||||||
Note: Some modern features (like C++20 ranges or filesystem support) may be disabled on specific broken or incomplete toolchains even when standard feature-test macros indicate support. See [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) and [`JSON_HAS_FILESYSTEM`](../api/macros/json_has_filesystem.md) for details on known exclusions.
|
Note: Some modern features (like C++20 ranges or filesystem support) may be disabled on specific broken or incomplete toolchains even when standard feature-test macros indicate support. See [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md), [`JSON_HAS_RANGE_VIEW_CONVERSION`](../api/macros/json_has_range_view_conversion.md), and [`JSON_HAS_FILESYSTEM`](../api/macros/json_has_filesystem.md) for details on known exclusions.
|
||||||
|
|
||||||
- [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms,
|
- [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms,
|
||||||
including the oldest versions known to compile the library.
|
including the oldest versions known to compile the library.
|
||||||
@@ -107,7 +107,7 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa
|
|||||||
- [x] The library is compiled with all C++ language revisions (C++11, C++14, C++17, C++20, C++23, and C++26) to detect
|
- [x] The library is compiled with all C++ language revisions (C++11, C++14, C++17, C++20, C++23, and C++26) to detect
|
||||||
and fix language deprecations early.
|
and fix language deprecations early.
|
||||||
- [x] The library is checked for compiler warnings:
|
- [x] The library is checked for compiler warnings:
|
||||||
- On Clang, `-Weverything` is used with 8 exceptions.
|
- On Clang, `-Weverything` is used with 7 exceptions.
|
||||||
|
|
||||||
??? abstract "Clang warnings"
|
??? abstract "Clang warnings"
|
||||||
|
|
||||||
|
|||||||
@@ -347,6 +347,13 @@ struct adl_serializer<boost::optional<T>> {
|
|||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! tip "`std::optional` needs no serializer"
|
||||||
|
|
||||||
|
Since version 3.12.0, `std::optional<T>` is supported out of the box when compiling with C++17
|
||||||
|
(`std::nullopt` is converted to and from `null`). Do not write an `adl_serializer` for it; this pattern is only
|
||||||
|
needed for types such as `boost::optional` or for custom semantics. See [Conversions](conversions.md) and
|
||||||
|
[Omitting a field when serializing `std::optional`](conversions.md#omitting-a-field-when-serializing-stdoptional).
|
||||||
|
|
||||||
!!! note "ABI compatibility"
|
!!! note "ABI compatibility"
|
||||||
|
|
||||||
Use [`NLOHMANN_JSON_NAMESPACE_BEGIN`](../api/macros/nlohmann_json_namespace_begin.md) and `NLOHMANN_JSON_NAMESPACE_END`
|
Use [`NLOHMANN_JSON_NAMESPACE_BEGIN`](../api/macros/nlohmann_json_namespace_begin.md) and `NLOHMANN_JSON_NAMESPACE_END`
|
||||||
|
|||||||
@@ -217,7 +217,8 @@ json j = numbers; // [1,2,3]
|
|||||||
```
|
```
|
||||||
|
|
||||||
This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due
|
This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due
|
||||||
to incomplete C++20 ranges support there.
|
to incomplete C++20 ranges support there; see
|
||||||
|
[`JSON_HAS_RANGE_VIEW_CONVERSION`](../api/macros/json_has_range_view_conversion.md).
|
||||||
|
|
||||||
## Your own types
|
## Your own types
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,47 @@ you want to access and a default value in case there is no value stored with tha
|
|||||||
| `#!cpp j.value("append", false)` | `#!json true` |
|
| `#!cpp j.value("append", false)` | `#!json true` |
|
||||||
| `#!cpp j.value("logLevel", "verbose")` | `#!json "verbose"` |
|
| `#!cpp j.value("logLevel", "verbose")` | `#!json "verbose"` |
|
||||||
|
|
||||||
|
## Nested values
|
||||||
|
|
||||||
|
To read a value deep inside a document, pass a [JSON Pointer](../json_pointer.md) instead of a key. The default value is
|
||||||
|
returned if the value at the pointer does not exist, including the case that an intermediate key is missing. There is
|
||||||
|
no need to check each level with [`contains`](../../api/basic_json/contains.md) first.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
json j = {{"server", {{"port", 8080}}}, {"list", {10, 20}}};
|
||||||
|
|
||||||
|
int port = j.value("/server/port"_json_pointer, 80); // 8080
|
||||||
|
int timeout = j.value("/server/limits/timeout"_json_pointer, 30); // 30 (missing intermediate key)
|
||||||
|
int second = j.value("/list/1"_json_pointer, 0); // 20 (numeric tokens index arrays)
|
||||||
|
int third = j.value("/list/5"_json_pointer, 0); // 0 (index out of range)
|
||||||
|
|
||||||
|
bool has_port = j.contains("/server/port"_json_pointer); // true
|
||||||
|
bool has_host = j.contains("/server/host/name"_json_pointer); // false
|
||||||
|
```
|
||||||
|
|
||||||
|
If the path is only available as a dotted string such as `#!cpp "server.port"`, do not build the pointer by
|
||||||
|
concatenating `#!cpp "/"` and the parts: keys containing `/` or `~` would be misinterpreted. Append each part as a
|
||||||
|
reference token with [`operator/=`](../../api/json_pointer/operator_slasheq.md) instead. It escapes the token for you.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
json::json_pointer to_pointer(const std::string& dotted)
|
||||||
|
{
|
||||||
|
json::json_pointer ptr;
|
||||||
|
std::istringstream in(dotted);
|
||||||
|
for (std::string token; std::getline(in, token, '.');)
|
||||||
|
{
|
||||||
|
ptr /= token;
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int port = j.value(to_pointer("server.port"), 80); // 8080
|
||||||
|
int first = j.value(to_pointer("list.0"), 0); // 10
|
||||||
|
```
|
||||||
|
|
||||||
|
The key `#!cpp "a/b"` yields the pointer `#!cpp "/a~1b"`; the dot-splitting itself is up to the caller, so keys
|
||||||
|
containing `.` need a different separator.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
!!! failure "Exceptions"
|
!!! failure "Exceptions"
|
||||||
@@ -37,6 +78,31 @@ you want to access and a default value in case there is no value stored with tha
|
|||||||
- With string keys, `value` can only be used with objects. For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error306) is thrown.
|
- With string keys, `value` can only be used with objects. For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error306) is thrown.
|
||||||
- With JSON Pointers, `value` can be used with both objects and arrays. For other types (null, boolean, number, string), a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error306) is thrown.
|
- With JSON Pointers, `value` can be used with both objects and arrays. For other types (null, boolean, number, string), a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error306) is thrown.
|
||||||
|
|
||||||
|
!!! warning "`null` and mistyped members are not missing"
|
||||||
|
|
||||||
|
`value` returns the default value only if the key is **absent**. If the member exists, it is converted to the type
|
||||||
|
of the default value, even if it is `#!json null`. For `#!json {"k": null}`, the call `#!cpp j.value("k", 0)` throws
|
||||||
|
a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error302), and so does a member of another
|
||||||
|
type such as a string where a number is expected. The same holds for JSON Pointers.
|
||||||
|
|
||||||
|
To treat `#!json null` like a missing value, check for it explicitly:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int n = (j.contains("k") && !j["k"].is_null()) ? j["k"].get<int>() : 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
With C++17, [`get<std::optional<T>>()`](../../api/basic_json/get.md) maps `#!json null` to an empty optional. As
|
||||||
|
[`at`](../../api/basic_json/at.md) throws [`out_of_range`](../../home/exceptions.md#jsonexceptionout_of_range403)
|
||||||
|
for an absent key, use [`find`](../../api/basic_json/find.md) to cover both cases:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::optional<int> n; // empty if "k" is absent or null
|
||||||
|
if (const auto it = j.find("k"); it != j.end())
|
||||||
|
{
|
||||||
|
n = it->get<std::optional<int>>(); // still throws for a non-number such as "text"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
!!! warning "Return type"
|
!!! warning "Return type"
|
||||||
|
|
||||||
The value function is a template, and the return type of the function is determined by the type of the provided
|
The value function is a template, and the return type of the function is determined by the type of the provided
|
||||||
@@ -63,3 +129,6 @@ you want to access and a default value in case there is no value stored with tha
|
|||||||
|
|
||||||
- [`value`](../../api/basic_json/value.md) for access with default value
|
- [`value`](../../api/basic_json/value.md) for access with default value
|
||||||
- documentation on [checked access](checked_access.md)
|
- documentation on [checked access](checked_access.md)
|
||||||
|
- documentation on [JSON Pointer](../json_pointer.md)
|
||||||
|
- [`contains`](../../api/basic_json/contains.md) to check whether a key or JSON Pointer exists
|
||||||
|
- [`json_pointer::operator/=`](../../api/json_pointer/operator_slasheq.md) to build a pointer token by token
|
||||||
@@ -77,6 +77,10 @@ auto val2 = j.at(json::json_pointer("/nested/three/1")); // false
|
|||||||
auto val3 = j.value(json::json_pointer("/nested/four"), 0); // 0
|
auto val3 = j.value(json::json_pointer("/nested/four"), 0); // 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To read a value with a fallback, use [`value`](../api/basic_json/value.md) with a JSON Pointer; to test for existence,
|
||||||
|
use [`contains`](../api/basic_json/contains.md). Neither needs intermediate checks, see
|
||||||
|
[Nested values](element_access/default_value.md#nested-values).
|
||||||
|
|
||||||
!!! note "Creating intermediate levels that don't exist"
|
!!! note "Creating intermediate levels that don't exist"
|
||||||
|
|
||||||
See the [`operator[]` notes](../api/basic_json/operator%5B%5D.md#return-value) for how array vs. object is
|
See the [`operator[]` notes](../api/basic_json/operator%5B%5D.md#return-value) for how array vs. object is
|
||||||
@@ -126,6 +130,8 @@ auto j_original = j_flat.unflatten();
|
|||||||
## See also
|
## See also
|
||||||
|
|
||||||
- Class [`json_pointer`](../api/json_pointer/index.md)
|
- Class [`json_pointer`](../api/json_pointer/index.md)
|
||||||
|
- Functions [`value`](../api/basic_json/value.md), [`contains`](../api/basic_json/contains.md), and
|
||||||
|
[`at`](../api/basic_json/at.md) accept JSON Pointers; see [Nested values](element_access/default_value.md#nested-values)
|
||||||
- Function [`flatten`](../api/basic_json/flatten.md)
|
- Function [`flatten`](../api/basic_json/flatten.md)
|
||||||
- Function [`unflatten`](../api/basic_json/unflatten.md)
|
- Function [`unflatten`](../api/basic_json/unflatten.md)
|
||||||
- [JSON Patch](json_patch.md) - paths inside a patch are JSON Pointers
|
- [JSON Patch](json_patch.md) - paths inside a patch are JSON Pointers
|
||||||
|
|||||||
@@ -82,6 +82,45 @@ To override the built-in check, define `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERI
|
|||||||
|
|
||||||
See [full documentation of `JSON_HAS_FILESYSTEM` and `JSON_HAS_EXPERIMENTAL_FILESYSTEM`](../api/macros/json_has_filesystem.md).
|
See [full documentation of `JSON_HAS_FILESYSTEM` and `JSON_HAS_EXPERIMENTAL_FILESYSTEM`](../api/macros/json_has_filesystem.md).
|
||||||
|
|
||||||
|
## `JSON_HAS_RANGES`
|
||||||
|
|
||||||
|
The library uses `std::ranges` (and concepts) where available, for example, to parse from C++20 ranges and to
|
||||||
|
construct JSON arrays from range views. The library detects whether the standard library supports ranges and
|
||||||
|
disables the support on toolchains with an incomplete implementation. To override the built-in check, define
|
||||||
|
`JSON_HAS_RANGES` to `1` or `0`.
|
||||||
|
|
||||||
|
See [full documentation of `JSON_HAS_RANGES`](../api/macros/json_has_ranges.md).
|
||||||
|
|
||||||
|
## `JSON_HAS_RANGE_VIEW_CONVERSION`
|
||||||
|
|
||||||
|
When `JSON_HAS_RANGES` is enabled (and the compiler is not MinGW), a JSON array can be constructed directly from a C++20
|
||||||
|
range view such as `std::views::filter(...)`. To override the built-in check, define `JSON_HAS_RANGE_VIEW_CONVERSION` to
|
||||||
|
`1` or `0`.
|
||||||
|
|
||||||
|
See [full documentation of `JSON_HAS_RANGE_VIEW_CONVERSION`](../api/macros/json_has_range_view_conversion.md).
|
||||||
|
|
||||||
|
## `JSON_HAS_STATIC_RTTI`
|
||||||
|
|
||||||
|
The library detects whether the compiler supports run time type information (RTTI), which it needs, for instance, to
|
||||||
|
exclude `std::any` from the candidate types of the implicit conversion on C++17. To override the built-in check, define
|
||||||
|
`JSON_HAS_STATIC_RTTI` to `1` or `0`.
|
||||||
|
|
||||||
|
See [full documentation of `JSON_HAS_STATIC_RTTI`](../api/macros/json_has_static_rtti.md).
|
||||||
|
|
||||||
|
## `JSON_HAS_STD_FORMAT`
|
||||||
|
|
||||||
|
When compiling with C++20 and a standard library that provides `<format>`, the library provides a `std::formatter`
|
||||||
|
specialization for JSON values. To override the built-in check, define `JSON_HAS_STD_FORMAT` to `1` or `0`.
|
||||||
|
|
||||||
|
See [full documentation of `JSON_HAS_STD_FORMAT`](../api/macros/json_has_std_format.md).
|
||||||
|
|
||||||
|
## `JSON_HAS_THREE_WAY_COMPARISON`
|
||||||
|
|
||||||
|
When the compiler and standard library support 3-way comparison (the spaceship operator `<=>`), the library provides it
|
||||||
|
for JSON values. To override the built-in check, define `JSON_HAS_THREE_WAY_COMPARISON` to `1` or `0`.
|
||||||
|
|
||||||
|
See [full documentation of `JSON_HAS_THREE_WAY_COMPARISON`](../api/macros/json_has_three_way_comparison.md).
|
||||||
|
|
||||||
## `JSON_NOEXCEPTION`
|
## `JSON_NOEXCEPTION`
|
||||||
|
|
||||||
Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`.
|
Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`.
|
||||||
|
|||||||
@@ -9,6 +9,13 @@ syntax that closely mimics the document being modified. Unlike [JSON Patch](json
|
|||||||
express every kind of change (e.g., it cannot reorder array elements or remove a specific array element), but it is
|
express every kind of change (e.g., it cannot reorder array elements or remove a specific array element), but it is
|
||||||
easier to read and write for object-shaped documents.
|
easier to read and write for object-shaped documents.
|
||||||
|
|
||||||
|
!!! tip "Not a general deep merge"
|
||||||
|
|
||||||
|
A merge patch is not a general deep merge: a `#!json null` value in the patch deletes the key from the target.
|
||||||
|
To merge two objects recursively (e.g., defaults and user settings), use
|
||||||
|
[`update`](../api/basic_json/update.md) with `merge_objects` set to `#!cpp true`; see
|
||||||
|
[Merging objects](modifying_values.md#merging-objects).
|
||||||
|
|
||||||
??? example
|
??? example
|
||||||
|
|
||||||
The following code shows how a JSON Merge Patch is applied to a JSON document.
|
The following code shows how a JSON Merge Patch is applied to a JSON document.
|
||||||
@@ -28,3 +35,4 @@ easier to read and write for object-shaped documents.
|
|||||||
- [JSON Patch and Diff](json_patch.md) - a more expressive alternative that describes a sequence of operations
|
- [JSON Patch and Diff](json_patch.md) - a more expressive alternative that describes a sequence of operations
|
||||||
- [JSON Pointer](json_pointer.md) - the addressing scheme used by JSON Patch
|
- [JSON Pointer](json_pointer.md) - the addressing scheme used by JSON Patch
|
||||||
- Function [`merge_patch`](../api/basic_json/merge_patch.md)
|
- Function [`merge_patch`](../api/basic_json/merge_patch.md)
|
||||||
|
- Function [`update`](../api/basic_json/update.md) - merge objects, optionally recursively
|
||||||
@@ -35,8 +35,12 @@ the insertion happened — useful for "add if absent" semantics.
|
|||||||
|
|
||||||
## Merging objects
|
## Merging objects
|
||||||
|
|
||||||
To merge one object into another, [`update`](../api/basic_json/update.md) copies all members from another object,
|
To merge one object into another, [`update`](../api/basic_json/update.md) copies all members from another object
|
||||||
overwriting existing keys (similar to Python's `dict.update`). This is the idiomatic way to combine two objects.
|
(similar to Python's `dict.update`). This is the idiomatic way to combine two objects. It has two modes:
|
||||||
|
|
||||||
|
- By default, the merge is shallow: existing keys are overwritten, even if both values are objects.
|
||||||
|
- With `merge_objects = #!cpp true`, keys whose values are objects in both JSON values are merged recursively.
|
||||||
|
Everything else is overwritten. In particular, arrays are replaced, not concatenated.
|
||||||
|
|
||||||
??? example
|
??? example
|
||||||
|
|
||||||
@@ -50,9 +54,22 @@ overwriting existing keys (similar to Python's `dict.update`). This is the idiom
|
|||||||
--8<-- "examples/update.output"
|
--8<-- "examples/update.output"
|
||||||
```
|
```
|
||||||
|
|
||||||
For a recursive merge that follows [RFC 7386](https://tools.ietf.org/html/rfc7386), see
|
A common use of the recursive mode is combining defaults with user settings. Nested defaults that the user did not set
|
||||||
[JSON Merge Patch](merge_patch.md). To apply a sequence of well-defined edit operations, see
|
are kept:
|
||||||
[JSON Patch](json_patch.md).
|
|
||||||
|
```cpp
|
||||||
|
json defaults = {{"log", {{"level", "info"}, {"file", "app.log"}}}, {"retries", 3}};
|
||||||
|
json user_settings = {{"log", {{"level", "debug"}}}};
|
||||||
|
|
||||||
|
json config = defaults;
|
||||||
|
config.update(user_settings, true);
|
||||||
|
// {"log":{"file":"app.log","level":"debug"},"retries":3}
|
||||||
|
```
|
||||||
|
|
||||||
|
[JSON Merge Patch](merge_patch.md) ([RFC 7386](https://tools.ietf.org/html/rfc7386)) also merges objects recursively,
|
||||||
|
but it is a different tool: a `#!json null` in the patch means "remove this key". It is meant for applying merge patch
|
||||||
|
documents (e.g., received via HTTP PATCH). To merge configuration-like objects, use `#!cpp update(..., true)`. To apply
|
||||||
|
a sequence of well-defined edit operations, see [JSON Patch](json_patch.md).
|
||||||
|
|
||||||
## Removing elements
|
## Removing elements
|
||||||
|
|
||||||
@@ -72,6 +89,7 @@ a.erase(1); // [1,3,4] (erase by index)
|
|||||||
|
|
||||||
- [`push_back`](../api/basic_json/push_back.md) / [`emplace_back`](../api/basic_json/emplace_back.md) - append to an array
|
- [`push_back`](../api/basic_json/push_back.md) / [`emplace_back`](../api/basic_json/emplace_back.md) - append to an array
|
||||||
- [`emplace`](../api/basic_json/emplace.md) - insert into an object if the key is absent
|
- [`emplace`](../api/basic_json/emplace.md) - insert into an object if the key is absent
|
||||||
- [`update`](../api/basic_json/update.md) - merge objects
|
- [`update`](../api/basic_json/update.md) - merge objects (shallow, or recursive with `merge_objects`)
|
||||||
|
- [`merge_patch`](../api/basic_json/merge_patch.md) - apply an RFC 7386 merge patch
|
||||||
- [`erase`](../api/basic_json/erase.md) / [`clear`](../api/basic_json/clear.md) - remove elements
|
- [`erase`](../api/basic_json/erase.md) / [`clear`](../api/basic_json/clear.md) - remove elements
|
||||||
- [JSON Patch and Diff](json_patch.md) and [JSON Merge Patch](merge_patch.md) - structured modifications
|
- [JSON Patch and Diff](json_patch.md) and [JSON Merge Patch](merge_patch.md) - structured modifications
|
||||||
@@ -101,3 +101,9 @@ follows:
|
|||||||
|
|
||||||
- Introduced inline namespace (`json_v3_11_0[_abi-tag]*`) in version 3.11.0.
|
- Introduced inline namespace (`json_v3_11_0[_abi-tag]*`) in version 3.11.0.
|
||||||
- Changed structure of inline namespace in version 3.11.2.
|
- Changed structure of inline namespace in version 3.11.2.
|
||||||
|
- Added ABI tag `_dp` ([`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md)) in version 3.12.0.
|
||||||
|
- Added ABI tags `_bics` ([`JSON_BRACE_INIT_COPY_SEMANTICS`](../api/macros/json_brace_init_copy_semantics.md)), `_psp`
|
||||||
|
([`JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md)), `_snul`
|
||||||
|
([`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md)), `_sbu8`
|
||||||
|
([`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md)), and `_ekmo`
|
||||||
|
([`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md)) in version 3.13.0.
|
||||||
@@ -34,7 +34,7 @@ flowchart LR
|
|||||||
|
|
||||||
- **JSON text** is read by an [input adapter](#input-adapters), tokenized by the lexer, and turned into SAX events by
|
- **JSON text** is read by an [input adapter](#input-adapters), tokenized by the lexer, and turned into SAX events by
|
||||||
the parser.
|
the parser.
|
||||||
- **Binary formats** (BJData, BSON, CBOR, MessagePack, UBJSON) are read by an input adapter and turned into the same SAX
|
- **Binary formats** (BJData, BON8, BSON, CBOR, MessagePack, UBJSON) are read by an input adapter and turned into the same SAX
|
||||||
events by the `binary_reader`.
|
events by the `binary_reader`.
|
||||||
- A [SAX consumer](#sax-interface) receives the events. The one used by [`parse`](../api/basic_json/parse.md) builds a
|
- A [SAX consumer](#sax-interface) receives the events. The one used by [`parse`](../api/basic_json/parse.md) builds a
|
||||||
`basic_json` value tree.
|
`basic_json` value tree.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ There are myriads of [JSON](https://json.org) libraries out there, and each may
|
|||||||
|
|
||||||
- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.
|
- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.
|
||||||
|
|
||||||
- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [OpenSSF Best Practices](https://www.bestpractices.dev/projects/289).
|
- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [OpenSSF Best Practices](https://www.bestpractices.dev/projects/289).
|
||||||
|
|
||||||
Other aspects were not so important to us:
|
Other aspects were not so important to us:
|
||||||
|
|
||||||
@@ -14,4 +14,4 @@ Other aspects were not so important to us:
|
|||||||
|
|
||||||
- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set.
|
- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set.
|
||||||
|
|
||||||
See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information.
|
See the [contribution guidelines](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md#please-dont) for more information.
|
||||||
@@ -104,7 +104,7 @@ See [documentation of `JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) for
|
|||||||
## Parse errors
|
## Parse errors
|
||||||
|
|
||||||
The library throws this exception when a parse error occurs. Parse errors
|
The library throws this exception when a parse error occurs. Parse errors
|
||||||
can occur during the deserialization of JSON text, CBOR, MessagePack, as well
|
can occur during the deserialization of JSON text or of one of the binary formats (BJData, BON8, BSON, CBOR, MessagePack, UBJSON), as well
|
||||||
as when using JSON Patch.
|
as when using JSON Patch.
|
||||||
|
|
||||||
Exceptions have ids 1xx.
|
Exceptions have ids 1xx.
|
||||||
@@ -190,7 +190,7 @@ This error indicates a syntax error while deserializing a JSON text. The error m
|
|||||||
!!! tip
|
!!! 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 opened.
|
- 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/).
|
- Paste the input to a JSON validator like <https://jsonlint.com> or a tool like [jq](https://jqlang.github.io/jq/).
|
||||||
|
|
||||||
### json.exception.parse_error.102
|
### json.exception.parse_error.102
|
||||||
|
|
||||||
@@ -278,7 +278,9 @@ In a JSON Pointer, only `~0` and `~1` are valid escape sequences.
|
|||||||
|
|
||||||
### json.exception.parse_error.109
|
### json.exception.parse_error.109
|
||||||
|
|
||||||
A JSON Pointer array index must be a number.
|
A JSON Pointer array index must be a number. This exception is thrown for an array index that does not begin with a
|
||||||
|
digit, except for `-` and the empty reference token, which throw [`out_of_range.404`](#jsonexceptionout_of_range404)
|
||||||
|
where they cannot be resolved.
|
||||||
|
|
||||||
!!! failure "Example messages"
|
!!! failure "Example messages"
|
||||||
|
|
||||||
@@ -289,6 +291,11 @@ A JSON Pointer array index must be a number.
|
|||||||
[json.exception.parse_error.109] parse error: array index '+1' is not a number
|
[json.exception.parse_error.109] parse error: array index '+1' is not a number
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
|
||||||
|
Before version 3.13.0, a one-character array index that is not a digit (e.g., `x`) threw
|
||||||
|
[`out_of_range.404`](#jsonexceptionout_of_range404) instead.
|
||||||
|
|
||||||
### json.exception.parse_error.110
|
### json.exception.parse_error.110
|
||||||
|
|
||||||
When parsing a [binary format](../features/binary_formats/index.md), the byte vector ends before the complete value has
|
When parsing a [binary format](../features/binary_formats/index.md), the byte vector ends before the complete value has
|
||||||
@@ -810,7 +817,7 @@ does not list an enumerator and it is therefore converted like the first listed
|
|||||||
A discarded value (one created by [`parse()`](../api/basic_json/parse.md) with a callback that returns `false` for the
|
A discarded value (one created by [`parse()`](../api/basic_json/parse.md) with a callback that returns `false` for the
|
||||||
value, or by default-constructing a [`basic_json`](../api/basic_json/index.md) with
|
value, or by default-constructing a [`basic_json`](../api/basic_json/index.md) with
|
||||||
[`value_t::discarded`](../api/basic_json/value_t.md)) was passed to a binary serialization function, either directly or
|
[`value_t::discarded`](../api/basic_json/value_t.md)) was passed to a binary serialization function, either directly or
|
||||||
nested in an array or object. There is no way to represent a discarded value in CBOR, MessagePack, UBJSON, BJData, or BSON.
|
nested in an array or object. There is no way to represent a discarded value in CBOR, MessagePack, UBJSON, BJData, BSON, or BON8.
|
||||||
|
|
||||||
!!! failure "Example message"
|
!!! failure "Example message"
|
||||||
|
|
||||||
@@ -871,7 +878,8 @@ The provided key was not found in the JSON object.
|
|||||||
|
|
||||||
### json.exception.out_of_range.404
|
### json.exception.out_of_range.404
|
||||||
|
|
||||||
A reference token in a JSON Pointer could not be resolved.
|
A reference token in a JSON Pointer could not be resolved, for instance an array index that begins with a digit but
|
||||||
|
contains other characters (e.g., `1a`), or `-` where it cannot be used.
|
||||||
|
|
||||||
!!! failure "Example message"
|
!!! failure "Example message"
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Fixes bugs found in 3.11.3 and adds several features. All changes are backward-c
|
|||||||
[BJData](../features/binary_formats/bjdata.md) draft 3 and unsigned 64-bit integers for
|
[BJData](../features/binary_formats/bjdata.md) draft 3 and unsigned 64-bit integers for
|
||||||
[BSON](../features/binary_formats/bson.md).
|
[BSON](../features/binary_formats/bson.md).
|
||||||
- Adds multidimensional C-array conversion and UTF-8 encoded `std::filesystem::path` conversions, and
|
- Adds multidimensional C-array conversion and UTF-8 encoded `std::filesystem::path` conversions, and
|
||||||
lowers the minimum [CMake](../integration/cmake.md) version to allow CMake 4.0.
|
raises the minimum [CMake](../integration/cmake.md) version to 3.5 and supports CMake 4.0.
|
||||||
|
|
||||||
[Full release notes](https://github.com/nlohmann/json/releases/tag/v3.12.0).
|
[Full release notes](https://github.com/nlohmann/json/releases/tag/v3.12.0).
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.15)
|
|||||||
|
|
||||||
include("cmake/HunterGate.cmake")
|
include("cmake/HunterGate.cmake")
|
||||||
HunterGate(
|
HunterGate(
|
||||||
URL "https://github.com/cpp-pm/hunter/archive/v0.23.297.tar.gz"
|
URL "https://github.com/cpp-pm/hunter/archive/v0.26.12.tar.gz"
|
||||||
SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3"
|
SHA1 "6498c5d0dec25d7fffb2b0574ebaf265179b894d"
|
||||||
)
|
)
|
||||||
|
|
||||||
project(json_example)
|
project(json_example)
|
||||||
|
|||||||
@@ -2,12 +2,30 @@
|
|||||||
|
|
||||||
# Creates a `<path>.md` sibling of each HTML output (for example,
|
# Creates a `<path>.md` sibling of each HTML output (for example,
|
||||||
# `features/comments/` becomes `features/comments.md`) so agents and tools can
|
# `features/comments/` becomes `features/comments.md`) so agents and tools can
|
||||||
# fetch the raw Markdown directly instead of parsing rendered HTML.
|
# fetch the raw Markdown directly instead of parsing rendered HTML. The
|
||||||
|
# `--8<-- "path"` lines of pymdownx.snippets are expanded with the extension's
|
||||||
|
# own preprocessor and the settings from mkdocs.yml, so the copies contain the
|
||||||
|
# included example code and files instead of the include directives.
|
||||||
|
|
||||||
|
import io
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
|
import markdown
|
||||||
|
from pymdownx.snippets import SnippetMissingError
|
||||||
|
|
||||||
_pages = []
|
_pages = []
|
||||||
|
_snippets = None
|
||||||
|
|
||||||
|
|
||||||
|
def on_config(config):
|
||||||
|
global _snippets
|
||||||
|
md = markdown.Markdown(
|
||||||
|
extensions=["pymdownx.snippets"],
|
||||||
|
extension_configs={"pymdownx.snippets": config["mdx_configs"].get("pymdownx.snippets", {})},
|
||||||
|
)
|
||||||
|
_snippets = md.preprocessors["snippet"]
|
||||||
|
_snippets.auto_append = [] # the glossary is only needed to render abbreviations
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
def on_files(files, config):
|
def on_files(files, config):
|
||||||
@@ -22,4 +40,11 @@ def on_post_build(config):
|
|||||||
url = file.url.rstrip("/")
|
url = file.url.rstrip("/")
|
||||||
target = os.path.join(site_dir, (url or "index") + ".md")
|
target = os.path.join(site_dir, (url or "index") + ".md")
|
||||||
os.makedirs(os.path.dirname(target), exist_ok=True)
|
os.makedirs(os.path.dirname(target), exist_ok=True)
|
||||||
shutil.copyfile(file.abs_src_path, target)
|
with io.open(file.abs_src_path, encoding="utf-8", newline="") as source:
|
||||||
|
text = source.read()
|
||||||
|
try:
|
||||||
|
text = "\n".join(_snippets.run(text.split("\n")))
|
||||||
|
except (SnippetMissingError, OSError):
|
||||||
|
pass # keep the include directives; the regular build reports the missing file
|
||||||
|
with io.open(target, "w", encoding="utf-8", newline="") as copy:
|
||||||
|
copy.write(text)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary -->
|
<!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary -->
|
||||||
|
|
||||||
*[ADL]: Argument-dependent lookup
|
*[ADL]: Argument-dependent lookup
|
||||||
*[API]: Application Programming Interfaces
|
*[API]: Application Programming Interface
|
||||||
*[ASCII]: American Standard Code for Information Interchange
|
*[ASCII]: American Standard Code for Information Interchange
|
||||||
*[BDFL]: Benevolent Dictator for Life
|
*[BDFL]: Benevolent Dictator for Life
|
||||||
*[BJData]: Binary JData
|
*[BJData]: Binary JData
|
||||||
|
|||||||
@@ -300,6 +300,7 @@ nav:
|
|||||||
- 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md
|
- 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md
|
||||||
- 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26': api/macros/json_has_cpp_11.md
|
- 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26': api/macros/json_has_cpp_11.md
|
||||||
- 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md
|
- 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md
|
||||||
|
- 'JSON_HAS_RANGE_VIEW_CONVERSION': api/macros/json_has_range_view_conversion.md
|
||||||
- 'JSON_HAS_RANGES': api/macros/json_has_ranges.md
|
- 'JSON_HAS_RANGES': api/macros/json_has_ranges.md
|
||||||
- 'JSON_HAS_STATIC_RTTI': api/macros/json_has_static_rtti.md
|
- 'JSON_HAS_STATIC_RTTI': api/macros/json_has_static_rtti.md
|
||||||
- 'JSON_HAS_STD_FORMAT': api/macros/json_has_std_format.md
|
- 'JSON_HAS_STD_FORMAT': api/macros/json_has_std_format.md
|
||||||
|
|||||||
@@ -288,36 +288,6 @@ def check_header_links() -> None:
|
|||||||
f'link to "{match.group(0)}" does not point to a documentation page')
|
f'link to "{match.group(0)}" does not point to a documentation page')
|
||||||
|
|
||||||
|
|
||||||
def check_docset() -> None:
|
|
||||||
"""Every API page and every macro has an entry in the docset index; no entry points to a missing page."""
|
|
||||||
entry_re = re.compile(r"VALUES \('((?:[^']|'')*)', '(\w+)', '([^']*)'\);")
|
|
||||||
names_by_path = {}
|
|
||||||
with open("../../docset/docSet.sql", encoding="utf-8") as sql:
|
|
||||||
for name, _, path in entry_re.findall(sql.read()):
|
|
||||||
names_by_path.setdefault(path, set()).add(name.replace("''", "'"))
|
|
||||||
|
|
||||||
def to_path(page):
|
|
||||||
if os.path.basename(page) == "index.md":
|
|
||||||
return page[:-len("index.md")] + "index.html"
|
|
||||||
return page[:-len(".md")] + "/index.html"
|
|
||||||
|
|
||||||
pages = sorted(glob.glob("**/*.md", recursive=True))
|
|
||||||
for path in sorted(set(names_by_path) - {to_path(p) for p in pages}):
|
|
||||||
report("docset/stale_entry", "../../docset/docSet.sql", f'entry "{path}" has no documentation page')
|
|
||||||
for page in (p for p in pages if p.startswith("api/")):
|
|
||||||
names = names_by_path.get(to_path(page))
|
|
||||||
if not names:
|
|
||||||
report("docset/missing_entry", page, "page has no entry in docs/docset/docSet.sql")
|
|
||||||
elif page.startswith("api/macros/") and os.path.basename(page) != "index.md":
|
|
||||||
with open(page, encoding="utf-8") as content:
|
|
||||||
text = content.read()
|
|
||||||
match = re.search(r"^# (.+)$", text, re.MULTILINE) or re.search(r"<h1>(.*?)</h1>", text, re.DOTALL)
|
|
||||||
title = re.sub(r"<[^>]+>|\s+", " ", match.group(1))
|
|
||||||
for macro in filter(None, (x.strip() for x in re.split(r"[,/]", title))):
|
|
||||||
if macro not in names:
|
|
||||||
report("docset/missing_macro", page, f'macro "{macro}" has no entry in docs/docset/docSet.sql')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print(120 * "-")
|
print(120 * "-")
|
||||||
check_structure()
|
check_structure()
|
||||||
@@ -327,7 +297,6 @@ if __name__ == "__main__":
|
|||||||
check_heading_levels()
|
check_heading_levels()
|
||||||
check_image_alt_text()
|
check_image_alt_text()
|
||||||
check_header_links()
|
check_header_links()
|
||||||
check_docset()
|
|
||||||
print(120 * "-")
|
print(120 * "-")
|
||||||
|
|
||||||
if warnings > 0:
|
if warnings > 0:
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j));
|
throw_type_must_be("null", j);
|
||||||
}
|
}
|
||||||
n = nullptr;
|
n = nullptr;
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
|||||||
case value_t::binary:
|
case value_t::binary:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
|
throw_type_must_be("number", j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t&
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j));
|
throw_type_must_be("boolean", j);
|
||||||
}
|
}
|
||||||
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t&
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
throw_type_must_be("string", j);
|
||||||
}
|
}
|
||||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ inline void from_json(const BasicJsonType& j, StringType& s)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
throw_type_must_be("string", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
@@ -183,7 +183,7 @@ inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
throw_type_must_be("array", j);
|
||||||
}
|
}
|
||||||
l.clear();
|
l.clear();
|
||||||
std::transform(j.rbegin(), j.rend(),
|
std::transform(j.rbegin(), j.rend(),
|
||||||
@@ -200,7 +200,7 @@ inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
throw_type_must_be("array", j);
|
||||||
}
|
}
|
||||||
l.resize(j.size());
|
l.resize(j.size());
|
||||||
std::transform(j.begin(), j.end(), std::begin(l),
|
std::transform(j.begin(), j.end(), std::begin(l),
|
||||||
@@ -305,7 +305,7 @@ void())
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
throw_type_must_be("array", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
from_json_array_impl(j, arr, priority_tag<3> {});
|
from_json_array_impl(j, arr, priority_tag<3> {});
|
||||||
@@ -324,7 +324,7 @@ auto from_json(const BasicJsonType& j, identity_tag<std::array<T, N>> tag)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
throw_type_must_be("array", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
return from_json_inplace_array_impl(j, tag, make_index_sequence<N> {});
|
return from_json_inplace_array_impl(j, tag, make_index_sequence<N> {});
|
||||||
@@ -335,7 +335,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t&
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j));
|
throw_type_must_be("binary", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||||
@@ -356,7 +356,7 @@ inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be binary or array, but is ", j.type_name()), &j));
|
throw_type_must_be("binary or array", j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +377,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j));
|
throw_type_must_be("object", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstructibleObjectType ret;
|
ConstructibleObjectType ret;
|
||||||
@@ -432,7 +432,7 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
|||||||
case value_t::binary:
|
case value_t::binary:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
|
throw_type_must_be("number", j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +504,7 @@ auto from_json(const BasicJsonType& j, TupleRelated&& t)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
throw_type_must_be("array", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
return from_json_tuple_impl(j, std::forward<TupleRelated>(t), priority_tag<3> {});
|
return from_json_tuple_impl(j, std::forward<TupleRelated>(t), priority_tag<3> {});
|
||||||
@@ -517,14 +517,14 @@ void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
throw_type_must_be("array", j);
|
||||||
}
|
}
|
||||||
m.clear();
|
m.clear();
|
||||||
for (const auto& p : j)
|
for (const auto& p : j)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &p));
|
throw_type_must_be("array", p);
|
||||||
}
|
}
|
||||||
m.emplace(p.at(0).template get<typename MapType::key_type>(), p.at(1).template get<typename MapType::mapped_type>());
|
m.emplace(p.at(0).template get<typename MapType::key_type>(), p.at(1).template get<typename MapType::mapped_type>());
|
||||||
}
|
}
|
||||||
@@ -591,7 +591,7 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
throw_type_must_be("string", j);
|
||||||
}
|
}
|
||||||
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
// Checking for C++20 standard or later can be insufficient in case the
|
// Checking for C++20 standard or later can be insufficient in case the
|
||||||
|
|||||||
@@ -414,13 +414,13 @@ inline void to_json(BasicJsonType& j, const EnumKeyedMap& map)
|
|||||||
BasicJsonType key = p.first;
|
BasicJsonType key = p.first;
|
||||||
if (JSON_HEDLEY_UNLIKELY(!key.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(!key.is_string()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be string, but is ", key.type_name()), &key));
|
throw_type_must_be("string", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& key_string = *key.template get_ptr<typename BasicJsonType::string_t*>();
|
auto& key_string = *key.template get_ptr<typename BasicJsonType::string_t*>();
|
||||||
if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second))
|
if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(318, concat("duplicate object key '", key_string, "'"), &key));
|
JSON_THROW(type_error::create(exception_id::enum_key_duplicate, concat("duplicate object key '", key_string, "'"), &key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
external_constructor<value_t::object>::construct(j, std::move(obj));
|
external_constructor<value_t::object>::construct(j, std::move(obj));
|
||||||
|
|||||||
@@ -45,6 +45,84 @@ namespace detail
|
|||||||
// exceptions //
|
// exceptions //
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief the ids of the exceptions thrown by the library
|
||||||
|
@note The values are part of the public API: they are the `id` member of the
|
||||||
|
exceptions and appear in their `what()` messages.
|
||||||
|
@sa https://json.nlohmann.me/home/exceptions/
|
||||||
|
*/
|
||||||
|
enum class exception_id : int
|
||||||
|
{
|
||||||
|
// parse_error
|
||||||
|
syntax_error = 101, ///< unexpected token or invalid literal while parsing JSON
|
||||||
|
patch_not_an_array = 104, ///< a JSON Patch document is not an array of objects
|
||||||
|
patch_invalid_operation = 105, ///< a JSON Patch operation is malformed
|
||||||
|
pointer_index_leading_zero = 106, ///< a JSON Pointer array index has a leading zero
|
||||||
|
pointer_missing_slash = 107, ///< a JSON Pointer does not start with '/'
|
||||||
|
pointer_invalid_escape = 108, ///< a JSON Pointer contains an escape other than ~0 and ~1
|
||||||
|
pointer_index_not_a_number = 109, ///< a JSON Pointer array index is not a number
|
||||||
|
unexpected_end_of_input = 110, ///< a binary input ends early, or has bytes left at its end
|
||||||
|
unexpected_byte = 112, ///< a binary input contains an unexpected byte or invalid length
|
||||||
|
invalid_string_or_size = 113, ///< a binary input contains an invalid string or size specification
|
||||||
|
bson_unsupported_type = 114, ///< a BSON record type is not supported
|
||||||
|
invalid_high_precision_number = 115, ///< a UBJSON/BJData high-precision number cannot be parsed
|
||||||
|
// invalid_iterator
|
||||||
|
iterators_incompatible = 201, ///< the iterators of a range belong to different values
|
||||||
|
iterator_from_other_value = 202, ///< an iterator does not belong to the value it is used with
|
||||||
|
iterator_range_from_other_value = 203, ///< an iterator range does not belong to the value it is used with
|
||||||
|
iterator_range_out_of_range = 204, ///< an iterator range of a primitive value is not [begin, end)
|
||||||
|
iterator_out_of_range = 205, ///< an iterator of a primitive value is not begin()
|
||||||
|
iterator_range_of_null = 206, ///< an iterator range belongs to a null value
|
||||||
|
iterator_key_not_object = 207, ///< key() is called on an iterator of a non-object
|
||||||
|
iterator_subscript_on_object = 208, ///< operator[] is called on an iterator of an object
|
||||||
|
iterator_arithmetic_on_object = 209, ///< an offset operator is used on an iterator of an object
|
||||||
|
insert_range_incompatible = 210, ///< the iterators of an inserted range belong to different values
|
||||||
|
insert_range_into_itself = 211, ///< an inserted range belongs to the value it is inserted into
|
||||||
|
iterators_compare_different_values = 212, ///< iterators of different values are compared
|
||||||
|
iterator_order_on_object = 213, ///< iterators of an object are compared by order
|
||||||
|
iterator_value_unavailable = 214, ///< an iterator does not refer to a value
|
||||||
|
// type_error
|
||||||
|
object_from_non_pairs = 301, ///< an object is created from an initializer list that is not a list of pairs
|
||||||
|
type_mismatch = 302, ///< a value has the wrong type for a conversion
|
||||||
|
incompatible_reference_type = 303, ///< get_ref() is called with a reference type that does not match the value
|
||||||
|
at_wrong_type = 304, ///< at() is called on a value of the wrong type
|
||||||
|
subscript_wrong_type = 305, ///< operator[] is called on a value of the wrong type
|
||||||
|
value_wrong_type = 306, ///< value() is called on a value of the wrong type
|
||||||
|
erase_wrong_type = 307, ///< erase() is called on a value of the wrong type
|
||||||
|
push_back_wrong_type = 308, ///< push_back() or operator+= is called on a value of the wrong type
|
||||||
|
insert_wrong_type = 309, ///< insert() is called on a value of the wrong type
|
||||||
|
swap_wrong_type = 310, ///< swap() is called on a value of the wrong type
|
||||||
|
emplace_wrong_type = 311, ///< emplace() or emplace_back() is called on a value of the wrong type
|
||||||
|
update_wrong_type = 312, ///< update() is called on a value of the wrong type
|
||||||
|
unflatten_invalid_value = 313, ///< unflatten() finds conflicting paths
|
||||||
|
unflatten_not_object = 314, ///< unflatten() is called on a non-object
|
||||||
|
unflatten_value_not_primitive = 315, ///< unflatten() is called on an object with non-primitive values
|
||||||
|
invalid_utf8 = 316, ///< dump() finds a string that is not valid UTF-8
|
||||||
|
type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format
|
||||||
|
enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string
|
||||||
|
discarded_value_used = 321, ///< a discarded value is used
|
||||||
|
// out_of_range
|
||||||
|
array_index_out_of_range = 401, ///< an array index is out of range
|
||||||
|
pointer_past_the_end_index = 402, ///< a JSON Pointer uses the array index '-'
|
||||||
|
key_not_found = 403, ///< an object key is not found
|
||||||
|
pointer_unresolved = 404, ///< a JSON Pointer reference token cannot be resolved
|
||||||
|
patch_on_root = 405, ///< the root of a value has no parent, e.g. for a JSON Patch 'remove' or 'add' at the root
|
||||||
|
number_overflow = 406, ///< a number cannot be stored without overflowing to NaN or INF
|
||||||
|
integer_too_large = 407, ///< an integer cannot be represented in the binary format
|
||||||
|
container_too_large = 408, ///< the size of a container in a binary input exceeds the maximal capacity
|
||||||
|
bson_key_with_null = 409, ///< a BSON key contains U+0000
|
||||||
|
value_out_of_range = 410, ///< an enum value is undefined, or a JSON Pointer array index exceeds size_type
|
||||||
|
patch_add_parent_not_container = 411, ///< the parent of a JSON Patch 'add' target is not a container
|
||||||
|
length_too_large = 412, ///< a length does not fit into the length field of a binary format
|
||||||
|
patch_remove_parent_not_container = 413, ///< the parent of a JSON Patch 'remove' target is not a container
|
||||||
|
patch_move_into_child = 414, ///< a JSON Patch 'move' moves a value into one of its children
|
||||||
|
subtype_out_of_range = 415, ///< a binary subtype does not fit into one byte
|
||||||
|
// other_error
|
||||||
|
internal_error = 500, ///< unreachable code was reached
|
||||||
|
patch_test_failed = 501, ///< a JSON Patch 'test' operation failed
|
||||||
|
size_marker_required = 502 ///< UBJSON/BJData output with type markers requires size markers
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief general exception of the @ref basic_json class
|
/// @brief general exception of the @ref basic_json class
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/exception/
|
/// @sa https://json.nlohmann.me/api/basic_json/exception/
|
||||||
class exception : public std::exception
|
class exception : public std::exception
|
||||||
@@ -195,6 +273,18 @@ class parse_error : public exception
|
|||||||
return {id_, byte_, w.c_str()};
|
return {id_, byte_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static parse_error create(exception_id id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
return create(static_cast<int>(id_), pos, what_arg, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static parse_error create(exception_id id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
return create(static_cast<int>(id_), byte_, what_arg, context);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief byte index of the parse error
|
@brief byte index of the parse error
|
||||||
|
|
||||||
@@ -229,6 +319,12 @@ class invalid_iterator : public exception
|
|||||||
return {id_, w.c_str()};
|
return {id_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static invalid_iterator create(exception_id id_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
return create(static_cast<int>(id_), what_arg, context);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSON_HEDLEY_NON_NULL(3)
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
invalid_iterator(int id_, const char* what_arg)
|
invalid_iterator(int id_, const char* what_arg)
|
||||||
@@ -247,6 +343,12 @@ class type_error : public exception
|
|||||||
return {id_, w.c_str()};
|
return {id_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static type_error create(exception_id id_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
return create(static_cast<int>(id_), what_arg, context);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSON_HEDLEY_NON_NULL(3)
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
@@ -264,6 +366,12 @@ class out_of_range : public exception
|
|||||||
return {id_, w.c_str()};
|
return {id_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static out_of_range create(exception_id id_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
return create(static_cast<int>(id_), what_arg, context);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSON_HEDLEY_NON_NULL(3)
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
@@ -281,6 +389,12 @@ class other_error : public exception
|
|||||||
return {id_, w.c_str()};
|
return {id_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static other_error create(exception_id id_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
return create(static_cast<int>(id_), what_arg, context);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSON_HEDLEY_NON_NULL(3)
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
@@ -307,6 +421,36 @@ void templated_json_throw(ExceptionType exception)
|
|||||||
(void)exception;
|
(void)exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief throws because @a j does not have the type a conversion expects
|
||||||
|
@param[in] expected the expected type(s), e.g. "array" or "binary or array"
|
||||||
|
@param[in] j the value with the wrong type
|
||||||
|
@throw type_error.302 always
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
JSON_HEDLEY_NO_RETURN inline void throw_type_must_be(const char* expected, const BasicJsonType& j)
|
||||||
|
{
|
||||||
|
static_cast<void>(expected); // unused when JSON_NOEXCEPTION is defined
|
||||||
|
static_cast<void>(j);
|
||||||
|
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief throws because an operation is not supported for the type of @a j
|
||||||
|
@param[in] id_ the id of the type_error exception (at_wrong_type..update_wrong_type)
|
||||||
|
@param[in] operation the operation, e.g. "erase()"
|
||||||
|
@param[in] j the value the operation was called on
|
||||||
|
@throw type_error always
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
JSON_HEDLEY_NO_RETURN inline void throw_cannot_use_with(const exception_id id_, const char* operation, const BasicJsonType& j)
|
||||||
|
{
|
||||||
|
static_cast<void>(id_); // unused when JSON_NOEXCEPTION is defined
|
||||||
|
static_cast<void>(operation);
|
||||||
|
static_cast<void>(j);
|
||||||
|
JSON_THROW(type_error::create(id_, concat("cannot use ", operation, " with ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include <cmath> // ldexp
|
#include <cmath> // ldexp
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t, uintmax_t
|
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t, uintmax_t
|
||||||
#include <cstdio> // snprintf
|
|
||||||
#include <cstring> // memcpy
|
#include <cstring> // memcpy
|
||||||
#include <iterator> // back_inserter
|
#include <iterator> // back_inserter
|
||||||
#include <limits> // numeric_limits
|
#include <limits> // numeric_limits
|
||||||
@@ -224,8 +223,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
|
if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
|
return last_byte_error(exception_id::unexpected_end_of_input, concat("expected end of input; last byte: 0x", get_token_string()), "value");
|
||||||
exception_message(concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,8 +354,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast<std::size_t>(document_size) != chars_read - document_start))
|
if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast<std::size_t>(document_size) != chars_read - document_start))
|
||||||
{
|
{
|
||||||
static_cast<void>(report_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
|
static_cast<void>(last_byte_error(exception_id::unexpected_byte, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"));
|
||||||
exception_message(concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"), nullptr)));
|
|
||||||
return repair_requested();
|
return repair_requested();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -681,9 +678,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
// the end of the element is lost (see resync)
|
// the end of the element is lost (see resync)
|
||||||
skip_requested = true;
|
skip_requested = true;
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::unexpected_byte, concat("string length must be at least 1, is ", std::to_string(len)), "string");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_string(len - static_cast<NumberType>(1), result)))
|
if (JSON_HEDLEY_UNLIKELY(!get_string(len - static_cast<NumberType>(1), result)))
|
||||||
@@ -693,10 +688,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(get() != 0x00))
|
if (JSON_HEDLEY_UNLIKELY(get() != 0x00))
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
static_cast<void>(last_byte_error(exception_id::unexpected_byte, "BSON string is not null-terminated", "string"));
|
||||||
static_cast<void>(report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message("BSON string is not null-terminated",
|
|
||||||
"string"), nullptr)));
|
|
||||||
// when recovering, a byte in place of the terminator is dropped;
|
// when recovering, a byte in place of the terminator is dropped;
|
||||||
// the end of the input is not
|
// the end of the input is not
|
||||||
return current != char_traits<char_type>::eof() && repair_requested();
|
return current != char_traits<char_type>::eof() && repair_requested();
|
||||||
@@ -721,9 +713,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
// the end of the element is lost (see resync)
|
// the end of the element is lost (see resync)
|
||||||
skip_requested = true;
|
skip_requested = true;
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::unexpected_byte, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All BSON binary values have a subtype
|
// All BSON binary values have a subtype
|
||||||
@@ -813,11 +803,9 @@ class binary_reader
|
|||||||
|
|
||||||
default: // anything else is not supported (yet)
|
default: // anything else is not supported (yet)
|
||||||
{
|
{
|
||||||
std::array<char, 3> cr{{}};
|
const std::string cr_str = hex_byte(static_cast<std::uint8_t>(element_type));
|
||||||
static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
|
||||||
const std::string cr_str{cr.data()};
|
|
||||||
static_cast<void>(report_error(element_type_parse_position, cr_str,
|
static_cast<void>(report_error(element_type_parse_position, cr_str,
|
||||||
parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)));
|
parse_error::create(exception_id::bson_unsupported_type, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)));
|
||||||
return skip_unsupported_bson_element(element_type);
|
return skip_unsupported_bson_element(element_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1142,9 +1130,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (tag_handler == cbor_tag_handler_t::error)
|
if (tag_handler == cbor_tag_handler_t::error)
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
static_cast<void>(unexpected_byte("invalid byte", "value"));
|
||||||
static_cast<void>(report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)));
|
|
||||||
if (!repair_requested())
|
if (!repair_requested())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -1170,9 +1156,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
case cbor_tag_handler_t::error:
|
case cbor_tag_handler_t::error:
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
static_cast<void>(unexpected_byte("invalid byte", "value"));
|
||||||
static_cast<void>(report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)));
|
|
||||||
if (!repair_requested())
|
if (!repair_requested())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -1253,12 +1237,10 @@ class binary_reader
|
|||||||
|
|
||||||
default: // anything else (0xFF is handled inside the other types)
|
default: // anything else (0xFF is handled inside the other types)
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
|
||||||
// the simple values other than false, true, and null (0xE0..0xF3,
|
// the simple values other than false, true, and null (0xE0..0xF3,
|
||||||
// 0xF7 for undefined, and 0xF8 followed by a byte) are complete
|
// 0xF7 for undefined, and 0xF8 followed by a byte) are complete
|
||||||
const bool simple_value = (current >= 0xE0 && current <= 0xF3) || current == 0xF7 || current == 0xF8;
|
const bool simple_value = (current >= 0xE0 && current <= 0xF3) || current == 0xF7 || current == 0xF8;
|
||||||
static_cast<void>(report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
static_cast<void>(unexpected_byte("invalid byte", "value"));
|
||||||
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)));
|
|
||||||
if (!simple_value || !repair_requested())
|
if (!simple_value || !repair_requested())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -1279,10 +1261,7 @@ class binary_reader
|
|||||||
*/
|
*/
|
||||||
bool cbor_indefinite_string_error(const char* type_name, const char* context)
|
bool cbor_indefinite_string_error(const char* type_name, const char* context)
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::invalid_string_or_size, concat("indefinite-length ", type_name, " is not allowed inside indefinite-length ", type_name, "; last byte: 0x", get_token_string()), context);
|
||||||
return report_error(chars_read, last_token, parse_error::create(113, chars_read,
|
|
||||||
exception_message(concat("indefinite-length ", type_name,
|
|
||||||
" is not allowed inside indefinite-length ", type_name, "; last byte: 0x", last_token), context), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1359,9 +1338,7 @@ class binary_reader
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", get_token_string()), "string");
|
||||||
return report_error(chars_read, last_token, parse_error::create(113, chars_read,
|
|
||||||
exception_message(concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", last_token), "string"), nullptr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1495,9 +1472,7 @@ class binary_reader
|
|||||||
// a key that begins an item is skipped with its value when recovering
|
// a key that begins an item is skipped with its value when recovering
|
||||||
// (see resync); a break stop code or a reserved byte begins none
|
// (see resync); a break stop code or a reserved byte begins none
|
||||||
skip_requested = is_cbor_item_head(static_cast<unsigned int>(current));
|
skip_requested = is_cbor_item_head(static_cast<unsigned int>(current));
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::invalid_string_or_size, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key");
|
||||||
return report_error(chars_read, last_token, parse_error::create(113, chars_read,
|
|
||||||
exception_message(concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1578,9 +1553,7 @@ class binary_reader
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", get_token_string()), "binary");
|
||||||
return report_error(chars_read, last_token, parse_error::create(113, chars_read,
|
|
||||||
exception_message(concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", last_token), "binary"), nullptr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1726,7 +1699,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(len) || len == detail::unknown_size()))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(len) || len == detail::unknown_size()))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), out_of_range::create(408,
|
return report_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large,
|
||||||
exception_message(concat("excessive ", context, " size"), "size"), nullptr));
|
exception_message(concat("excessive ", context, " size"), "size"), nullptr));
|
||||||
}
|
}
|
||||||
result = conditional_static_cast<std::size_t>(len);
|
result = conditional_static_cast<std::size_t>(len);
|
||||||
@@ -1876,9 +1849,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_cbor_item_head(static_cast<unsigned int>(current))))
|
if (JSON_HEDLEY_UNLIKELY(!is_cbor_item_head(static_cast<unsigned int>(current))))
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return unexpected_byte("invalid byte", "value");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto major_type = static_cast<unsigned int>(current) >> 5u;
|
const auto major_type = static_cast<unsigned int>(current) >> 5u;
|
||||||
@@ -2336,9 +2307,7 @@ class binary_reader
|
|||||||
|
|
||||||
default: // anything else
|
default: // anything else
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return unexpected_byte("invalid byte", "value");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2419,9 +2388,7 @@ class binary_reader
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", get_token_string()), "string");
|
||||||
return report_error(chars_read, last_token, parse_error::create(113, chars_read,
|
|
||||||
exception_message(concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2516,9 +2483,7 @@ class binary_reader
|
|||||||
|
|
||||||
// the key is skipped with its value when recovering (see resync)
|
// the key is skipped with its value when recovering (see resync)
|
||||||
skip_requested = true;
|
skip_requested = true;
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::invalid_string_or_size, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key");
|
||||||
return report_error(chars_read, last_token, parse_error::create(113, chars_read,
|
|
||||||
exception_message(concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -2845,9 +2810,7 @@ class binary_reader
|
|||||||
|
|
||||||
default: // 0xC1, which is never used
|
default: // 0xC1, which is never used
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return unexpected_byte("invalid byte", "value");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2976,8 +2939,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(len < 0))
|
if (JSON_HEDLEY_UNLIKELY(len < 0))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
return last_byte_error(exception_id::invalid_string_or_size, "string length must not be negative", "string");
|
||||||
exception_message("string length must not be negative", "string"), nullptr));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3077,18 +3039,7 @@ class binary_reader
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto last_token = get_token_string();
|
return length_type_error("", "string");
|
||||||
std::string message;
|
|
||||||
|
|
||||||
if (input_format != input_format_t::bjdata)
|
|
||||||
{
|
|
||||||
message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
|
|
||||||
}
|
|
||||||
return report_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(message, "string"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3173,12 +3124,11 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(number < 0))
|
if (JSON_HEDLEY_UNLIKELY(number < 0))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
return last_byte_error(exception_id::invalid_string_or_size, "count in an optimized container must be positive", "size");
|
||||||
exception_message("count in an optimized container must be positive", "size"), nullptr));
|
|
||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(number)))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(number)))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), out_of_range::create(408,
|
return report_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large,
|
||||||
exception_message("integer value overflow", "size"), nullptr));
|
exception_message("integer value overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
||||||
@@ -3276,7 +3226,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (!value_in_range_of<std::size_t>(number))
|
if (!value_in_range_of<std::size_t>(number))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), out_of_range::create(408,
|
return report_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large,
|
||||||
exception_message("integer value overflow", "size"), nullptr));
|
exception_message("integer value overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
result = detail::conditional_static_cast<std::size_t>(number);
|
result = detail::conditional_static_cast<std::size_t>(number);
|
||||||
@@ -3291,7 +3241,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array
|
if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message("ndarray dimensional vector is not allowed", "size"), nullptr));
|
return last_byte_error(exception_id::invalid_string_or_size, "ndarray dimensional vector is not allowed", "size");
|
||||||
}
|
}
|
||||||
std::vector<size_t> dim;
|
std::vector<size_t> dim;
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
|
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
|
||||||
@@ -3329,9 +3279,7 @@ class binary_reader
|
|||||||
const char* type_name = bjd_type_name(ndarray_dtype);
|
const char* type_name = bjd_type_name(ndarray_dtype);
|
||||||
if (JSON_HEDLEY_UNLIKELY(type_name == nullptr))
|
if (JSON_HEDLEY_UNLIKELY(type_name == nullptr))
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return unexpected_byte("invalid byte", "type");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message("invalid byte: 0x" + last_token, "type"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t type_key = "_ArrayType_";
|
string_t type_key = "_ArrayType_";
|
||||||
@@ -3360,7 +3308,7 @@ class binary_reader
|
|||||||
// or SIZE_MAX.
|
// or SIZE_MAX.
|
||||||
if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits<std::size_t>::max)() / i))
|
if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits<std::size_t>::max)() / i))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr));
|
return report_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive ndarray size caused overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
result *= i;
|
result *= i;
|
||||||
// the pre-check above already rules out result becoming 0
|
// the pre-check above already rules out result becoming 0
|
||||||
@@ -3369,7 +3317,7 @@ class binary_reader
|
|||||||
// unknown-size container (see get_ubjson_size_type())
|
// unknown-size container (see get_ubjson_size_type())
|
||||||
if (result == npos)
|
if (result == npos)
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr));
|
return report_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive ndarray size caused overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(!emit_unsigned(i)))
|
if (JSON_HEDLEY_UNLIKELY(!emit_unsigned(i)))
|
||||||
{
|
{
|
||||||
@@ -3387,18 +3335,7 @@ class binary_reader
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto last_token = get_token_string();
|
return length_type_error(" after '#'", "size");
|
||||||
std::string message;
|
|
||||||
|
|
||||||
if (input_format != input_format_t::bjdata)
|
|
||||||
{
|
|
||||||
message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
|
|
||||||
}
|
|
||||||
return report_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(message, "size"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3431,9 +3368,7 @@ class binary_reader
|
|||||||
if (input_format == input_format_t::bjdata
|
if (input_format == input_format_t::bjdata
|
||||||
&& JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second)))
|
&& JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second)))
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::unexpected_byte, concat("marker 0x", get_token_string(), " is not a permitted optimized array type"), "type");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type")))
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type")))
|
||||||
@@ -3448,9 +3383,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::unexpected_byte, concat("expected '#' after type information; last byte: 0x", get_token_string()), "size");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool is_error = get_ubjson_size_value(result.first, is_ndarray, 0, result.second);
|
const bool is_error = get_ubjson_size_value(result.first, is_ndarray, 0, result.second);
|
||||||
@@ -3469,8 +3402,7 @@ class binary_reader
|
|||||||
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
||||||
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
|
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
|
return last_byte_error(exception_id::unexpected_byte, "ndarray requires both type and size", "size");
|
||||||
exception_message("ndarray requires both type and size", "size"), nullptr));
|
|
||||||
}
|
}
|
||||||
return is_error;
|
return is_error;
|
||||||
}
|
}
|
||||||
@@ -3602,9 +3534,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(current > 127))
|
if (JSON_HEDLEY_UNLIKELY(current > 127))
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
static_cast<void>(last_byte_error(exception_id::invalid_string_or_size, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", get_token_string()), "char"));
|
||||||
static_cast<void>(report_error(chars_read, last_token, parse_error::create(113, chars_read,
|
|
||||||
exception_message(concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)));
|
|
||||||
if (!repair_requested())
|
if (!repair_requested())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -3633,8 +3563,7 @@ class binary_reader
|
|||||||
default: // anything else
|
default: // anything else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto last_token = get_token_string();
|
return unexpected_byte("invalid byte", "value");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message("invalid byte: 0x" + last_token, "value"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3699,7 +3628,7 @@ class binary_reader
|
|||||||
if (JSON_HEDLEY_UNLIKELY((size_and_type.second == 'Z' || size_and_type.second == 'T' || size_and_type.second == 'F')
|
if (JSON_HEDLEY_UNLIKELY((size_and_type.second == 'Z' || size_and_type.second == 'T' || size_and_type.second == 'F')
|
||||||
&& size_and_type.first > max_valueless_container_size))
|
&& size_and_type.first > max_valueless_container_size))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, get_token_string(), out_of_range::create(408,
|
return report_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large,
|
||||||
exception_message("excessive array size", "size"), nullptr));
|
exception_message("excessive array size", "size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3735,9 +3664,7 @@ class binary_reader
|
|||||||
// do not accept ND-array size in objects in BJData
|
// do not accept ND-array size in objects in BJData
|
||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
return last_byte_error(exception_id::unexpected_byte, "BJData object does not support ND-array size in optimized format", "object");
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message("BJData object does not support ND-array size in optimized format", "object"), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size_and_type.first != npos)
|
if (size_and_type.first != npos)
|
||||||
@@ -3774,7 +3701,7 @@ class binary_reader
|
|||||||
// the lexer would stop at a NUL and accept the digits before it
|
// the lexer would stop at a NUL and accept the digits before it
|
||||||
if (JSON_HEDLEY_UNLIKELY(current == '\0'))
|
if (JSON_HEDLEY_UNLIKELY(current == '\0'))
|
||||||
{
|
{
|
||||||
static_cast<void>(report_error(chars_read, "00", parse_error::create(115, chars_read,
|
static_cast<void>(report_error(chars_read, "00", parse_error::create(exception_id::invalid_high_precision_number, chars_read,
|
||||||
exception_message("invalid number text; last byte: 0x00", "high-precision number"), nullptr)));
|
exception_message("invalid number text; last byte: 0x00", "high-precision number"), nullptr)));
|
||||||
// when recovering, the number ends at the NUL, as it would in
|
// when recovering, the number ends at the NUL, as it would in
|
||||||
// JSON text, and the rest of its bytes are skipped
|
// JSON text, and the rest of its bytes are skipped
|
||||||
@@ -3794,7 +3721,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
|
if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
|
||||||
{
|
{
|
||||||
static_cast<void>(report_error(chars_read, number_string, parse_error::create(115, chars_read,
|
static_cast<void>(report_error(chars_read, number_string, parse_error::create(exception_id::invalid_high_precision_number, chars_read,
|
||||||
exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)));
|
exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)));
|
||||||
return recover_high_precision_number(number_vector);
|
return recover_high_precision_number(number_vector);
|
||||||
}
|
}
|
||||||
@@ -3815,7 +3742,7 @@ class binary_reader
|
|||||||
static_cast<void>(report_error(
|
static_cast<void>(report_error(
|
||||||
chars_read,
|
chars_read,
|
||||||
number_string,
|
number_string,
|
||||||
out_of_range::create(406, concat("number overflow parsing '", number_string, '\''), nullptr)));
|
out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", number_string, '\''), nullptr)));
|
||||||
if (!repair_requested())
|
if (!repair_requested())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -3841,7 +3768,7 @@ class binary_reader
|
|||||||
case token_type::end_of_input:
|
case token_type::end_of_input:
|
||||||
case token_type::literal_or_value:
|
case token_type::literal_or_value:
|
||||||
default:
|
default:
|
||||||
static_cast<void>(report_error(chars_read, number_string, parse_error::create(115, chars_read,
|
static_cast<void>(report_error(chars_read, number_string, parse_error::create(exception_id::invalid_high_precision_number, chars_read,
|
||||||
exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)));
|
exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)));
|
||||||
return recover_high_precision_number(number_vector);
|
return recover_high_precision_number(number_vector);
|
||||||
}
|
}
|
||||||
@@ -3966,20 +3893,6 @@ class binary_reader
|
|||||||
return 0x80 <= c && c <= 0xBF;
|
return 0x80 <= c && c <= 0xBF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief report a parse error at the last read byte
|
|
||||||
|
|
||||||
@param[in] detail a detailed error message
|
|
||||||
@param[in] context further context information
|
|
||||||
@return false
|
|
||||||
*/
|
|
||||||
bool bon8_error(const std::string& detail, const char* context)
|
|
||||||
{
|
|
||||||
auto last_token = get_token_string();
|
|
||||||
return report_error(chars_read, last_token, parse_error::create(112, chars_read,
|
|
||||||
exception_message(concat(detail, ": 0x", last_token), context), nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief read a BON8 value and everything nested inside it
|
@brief read a BON8 value and everything nested inside it
|
||||||
|
|
||||||
@@ -4203,7 +4116,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0xFE: end of container where a value is expected
|
// 0xFE: end of container where a value is expected
|
||||||
return bon8_error("invalid byte", "value");
|
return unexpected_byte("invalid byte", "value");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -4333,7 +4246,7 @@ class binary_reader
|
|||||||
// an end-of-container marker is no value; any other byte begins one,
|
// an end-of-container marker is no value; any other byte begins one,
|
||||||
// and the member is skipped when recovering (see skip_member)
|
// and the member is skipped when recovering (see skip_member)
|
||||||
skip_requested = byte != 0xFE;
|
skip_requested = byte != 0xFE;
|
||||||
return bon8_error("expected a string; last byte", "key");
|
return unexpected_byte("expected a string; last byte", "key");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -4399,7 +4312,7 @@ class binary_reader
|
|||||||
return skip_bon8_bytes(8);
|
return skip_bon8_bytes(8);
|
||||||
|
|
||||||
case 0xFE: // end of container where a value is expected
|
case 0xFE: // end of container where a value is expected
|
||||||
return bon8_error("invalid byte", "value");
|
return unexpected_byte("invalid byte", "value");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -4568,7 +4481,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!valid_second))
|
if (JSON_HEDLEY_UNLIKELY(!valid_second))
|
||||||
{
|
{
|
||||||
return bon8_error("invalid UTF-8 byte", "string");
|
return unexpected_byte("invalid UTF-8 byte", "string");
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push_back(static_cast<typename string_t::value_type>(byte));
|
result.push_back(static_cast<typename string_t::value_type>(byte));
|
||||||
@@ -4582,7 +4495,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_bon8_continuation(current)))
|
if (JSON_HEDLEY_UNLIKELY(!is_bon8_continuation(current)))
|
||||||
{
|
{
|
||||||
return bon8_error("invalid UTF-8 byte", "string");
|
return unexpected_byte("invalid UTF-8 byte", "string");
|
||||||
}
|
}
|
||||||
result.push_back(static_cast<typename string_t::value_type>(current));
|
result.push_back(static_cast<typename string_t::value_type>(current));
|
||||||
}
|
}
|
||||||
@@ -4627,7 +4540,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
// in case of failure, advance position by 1 to report the failing location
|
// in case of failure, advance position by 1 to report the failing location
|
||||||
++chars_read;
|
++chars_read;
|
||||||
return report_error(chars_read, "<end of file>", parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr));
|
return report_error(chars_read, "<end of file>", parse_error::create(exception_id::unexpected_end_of_input, chars_read, exception_message("unexpected end of input", context), nullptr));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -4780,7 +4693,7 @@ class binary_reader
|
|||||||
if (JSON_HEDLEY_UNLIKELY(std::isfinite(number) && !std::isfinite(result)))
|
if (JSON_HEDLEY_UNLIKELY(std::isfinite(number) && !std::isfinite(result)))
|
||||||
{
|
{
|
||||||
static_cast<void>(report_error(chars_read, get_token_string(),
|
static_cast<void>(report_error(chars_read, get_token_string(),
|
||||||
out_of_range::create(406, exception_message("number overflow", "value"), nullptr)));
|
out_of_range::create(exception_id::number_overflow, exception_message("number overflow", "value"), nullptr)));
|
||||||
// when recovering, the number becomes infinity, as in JSON text
|
// when recovering, the number becomes infinity, as in JSON text
|
||||||
if (!repair_requested())
|
if (!repair_requested())
|
||||||
{
|
{
|
||||||
@@ -4905,9 +4818,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (error_handler == error_handler_t::strict)
|
if (error_handler == error_handler_t::strict)
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
static_cast<void>(last_byte_error(exception_id::invalid_string_or_size, "invalid string: ill-formed UTF-8 byte", context));
|
||||||
static_cast<void>(report_error(chars_read, last_token, parse_error::create(113, chars_read,
|
|
||||||
exception_message("invalid string: ill-formed UTF-8 byte", context), nullptr)));
|
|
||||||
// when recovering, the string is repaired as with
|
// when recovering, the string is repaired as with
|
||||||
// error_handler_t::replace
|
// error_handler_t::replace
|
||||||
if (!repair_requested())
|
if (!repair_requested())
|
||||||
@@ -5303,19 +5214,53 @@ class binary_reader
|
|||||||
if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
|
if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
|
||||||
{
|
{
|
||||||
return report_error(chars_read, "<end of file>",
|
return report_error(chars_read, "<end of file>",
|
||||||
parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr));
|
parse_error::create(exception_id::unexpected_end_of_input, chars_read, exception_message("unexpected end of input", context), nullptr));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief reports a parse error at the last read byte
|
||||||
|
@param[in] id_ the id of the parse_error exception
|
||||||
|
@param[in] detail a detailed error message
|
||||||
|
@param[in] context further context information
|
||||||
|
@return false, so that the caller stops reading (see report_error)
|
||||||
|
*/
|
||||||
|
bool last_byte_error(const exception_id id_, const std::string& detail, const std::string& context)
|
||||||
|
{
|
||||||
|
return report_error(chars_read, get_token_string(), parse_error::create(id_, chars_read, exception_message(detail, context), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief reports the last read byte as unexpected (parse_error.112)
|
||||||
|
@param[in] detail what is wrong with the byte, e.g. "invalid byte"
|
||||||
|
@param[in] context further context information
|
||||||
|
@return false, so that the caller stops reading (see report_error)
|
||||||
|
*/
|
||||||
|
bool unexpected_byte(const char* detail, const std::string& context)
|
||||||
|
{
|
||||||
|
return last_byte_error(exception_id::unexpected_byte, concat(detail, ": 0x", get_token_string()), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief reports that the last read byte is not a UBJSON/BJData length type (parse_error.113)
|
||||||
|
@param[in] position where the length type was expected, e.g. " after '#'"
|
||||||
|
@param[in] context further context information
|
||||||
|
@return false, so that the caller stops reading (see report_error)
|
||||||
|
*/
|
||||||
|
bool length_type_error(const char* position, const char* context)
|
||||||
|
{
|
||||||
|
const char* types = input_format == input_format_t::bjdata ? "U, i, u, I, m, l, M, L" : "U, i, I, l, L";
|
||||||
|
return last_byte_error(exception_id::invalid_string_or_size,
|
||||||
|
concat("expected length type specification (", types, ")", position, "; last byte: 0x", get_token_string()), context);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@return a string representation of the last read byte
|
@return a string representation of the last read byte
|
||||||
*/
|
*/
|
||||||
std::string get_token_string() const
|
std::string get_token_string() const
|
||||||
{
|
{
|
||||||
std::array<char, 3> cr{{}};
|
return hex_byte(static_cast<std::uint8_t>(current));
|
||||||
static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
|
||||||
return std::string{cr.data()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -581,7 +581,7 @@ class wide_string_input_adapter
|
|||||||
template<class T>
|
template<class T>
|
||||||
JSON_HEDLEY_NO_RETURN std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1)
|
JSON_HEDLEY_NO_RETURN std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1)
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr));
|
JSON_THROW(parse_error::create(exception_id::unexpected_byte, 1, "wide string type cannot be interpreted as binary data", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -793,7 +793,7 @@ inline file_input_adapter input_adapter(std::FILE* file)
|
|||||||
{
|
{
|
||||||
if (file == nullptr)
|
if (file == nullptr)
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||||
}
|
}
|
||||||
return file_input_adapter(file);
|
return file_input_adapter(file);
|
||||||
}
|
}
|
||||||
@@ -802,7 +802,7 @@ inline input_stream_adapter input_adapter(std::istream& stream)
|
|||||||
{
|
{
|
||||||
if (stream.rdbuf() == nullptr)
|
if (stream.rdbuf() == nullptr)
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||||
}
|
}
|
||||||
return input_stream_adapter(stream);
|
return input_stream_adapter(stream);
|
||||||
}
|
}
|
||||||
@@ -827,7 +827,7 @@ contiguous_bytes_input_adapter input_adapter(CharT b)
|
|||||||
{
|
{
|
||||||
if (b == nullptr)
|
if (b == nullptr)
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||||
}
|
}
|
||||||
auto length = std::strlen(reinterpret_cast<const char*>(b));
|
auto length = std::strlen(reinterpret_cast<const char*>(b));
|
||||||
const auto* ptr = reinterpret_cast<const char*>(b);
|
const auto* ptr = reinterpret_cast<const char*>(b);
|
||||||
|
|||||||
@@ -178,6 +178,27 @@ template<typename ArrayType>
|
|||||||
inline void reserve_array(ArrayType& /*arr*/, std::size_t /*len*/, priority_tag<0> /*unused*/)
|
inline void reserve_array(ArrayType& /*arr*/, std::size_t /*len*/, priority_tag<0> /*unused*/)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief reports an object or array whose announced size exceeds max_size()
|
||||||
|
|
||||||
|
Shared by json_sax_dom_parser and json_sax_dom_callback_parser.
|
||||||
|
|
||||||
|
@param[in] sax the SAX parser to report the error to
|
||||||
|
@param[in] len the number of elements announced by the input, or unknown_size()
|
||||||
|
@param[in] kind "object" or "array"
|
||||||
|
@param[in] ref the object or array that was just created
|
||||||
|
@return whether parsing should continue (false after reporting out_of_range.408)
|
||||||
|
*/
|
||||||
|
template<typename SAX, typename BasicJsonType>
|
||||||
|
bool check_container_size(SAX& sax, std::size_t len, const char* kind, BasicJsonType* ref)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref->max_size()))
|
||||||
|
{
|
||||||
|
return sax.parse_error(0, "", out_of_range::create(exception_id::container_too_large, concat("excessive ", kind, " size: ", std::to_string(len)), ref));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
/*!
|
/*!
|
||||||
@brief set the diagnostic positions of a value the DOM SAX parsers just stored
|
@brief set the diagnostic positions of a value the DOM SAX parsers just stored
|
||||||
@@ -187,6 +208,35 @@ befriends this struct, as the position members are private.
|
|||||||
*/
|
*/
|
||||||
struct diagnostic_positions
|
struct diagnostic_positions
|
||||||
{
|
{
|
||||||
|
/*!
|
||||||
|
@param[in,out] v the object or array whose opening brace or bracket was just read
|
||||||
|
@param[in] lexer the lexer that read it, or nullptr to leave @a v alone
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType, typename LexerType>
|
||||||
|
static void set_container_start(BasicJsonType& v, LexerType* lexer)
|
||||||
|
{
|
||||||
|
if (lexer)
|
||||||
|
{
|
||||||
|
// Lexer has read the first character of the container, so
|
||||||
|
// subtract 1 from the position to get the correct start position.
|
||||||
|
v.start_position = lexer->get_position() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in,out] v the object or array whose closing brace or bracket was just read
|
||||||
|
@param[in] lexer the lexer that read it, or nullptr to leave @a v alone
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType, typename LexerType>
|
||||||
|
static void set_container_end(BasicJsonType& v, LexerType* lexer)
|
||||||
|
{
|
||||||
|
if (lexer)
|
||||||
|
{
|
||||||
|
// Lexer's position is past the closing brace or bracket, so set that as the end position.
|
||||||
|
v.end_position = lexer->get_position();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@param[in,out] v the value that was just parsed
|
@param[in,out] v the value that was just parsed
|
||||||
@param[in] lexer the lexer that read it, or nullptr to leave @a v alone
|
@param[in] lexer the lexer that read it, or nullptr to leave @a v alone
|
||||||
@@ -354,22 +404,11 @@ class json_sax_dom_parser
|
|||||||
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
|
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Manually set the start position of the object here.
|
|
||||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||||
if (m_lexer_ref)
|
diagnostic_positions::set_container_start(*ref_stack.back(), m_lexer_ref);
|
||||||
{
|
|
||||||
// Lexer has read the first character of the object, so
|
|
||||||
// subtract 1 from the position to get the correct start position.
|
|
||||||
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
return check_container_size(*this, len, "object", ref_stack.back());
|
||||||
{
|
|
||||||
return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool key(string_t& val)
|
bool key(string_t& val)
|
||||||
@@ -388,11 +427,7 @@ class json_sax_dom_parser
|
|||||||
JSON_ASSERT(ref_stack.back()->is_object());
|
JSON_ASSERT(ref_stack.back()->is_object());
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
if (m_lexer_ref)
|
diagnostic_positions::set_container_end(*ref_stack.back(), m_lexer_ref);
|
||||||
{
|
|
||||||
// Lexer's position is past the closing brace, so set that as the end position.
|
|
||||||
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
@@ -405,17 +440,13 @@ class json_sax_dom_parser
|
|||||||
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
|
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Manually set the start position of the array here.
|
|
||||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||||
if (m_lexer_ref)
|
diagnostic_positions::set_container_start(*ref_stack.back(), m_lexer_ref);
|
||||||
{
|
|
||||||
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
if (JSON_HEDLEY_UNLIKELY(!check_container_size(*this, len, "array", ref_stack.back())))
|
||||||
{
|
{
|
||||||
return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len != detail::unknown_size())
|
if (len != detail::unknown_size())
|
||||||
@@ -432,11 +463,7 @@ class json_sax_dom_parser
|
|||||||
JSON_ASSERT(ref_stack.back()->is_array());
|
JSON_ASSERT(ref_stack.back()->is_array());
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
if (m_lexer_ref)
|
diagnostic_positions::set_container_end(*ref_stack.back(), m_lexer_ref);
|
||||||
{
|
|
||||||
// Lexer's position is past the closing bracket, so set that as the end position.
|
|
||||||
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
@@ -616,21 +643,11 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Manually set the start position of the object here.
|
|
||||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||||
if (m_lexer_ref)
|
diagnostic_positions::set_container_start(*ref_stack.back(), m_lexer_ref);
|
||||||
{
|
|
||||||
// Lexer has read the first character of the object, so
|
|
||||||
// subtract 1 from the position to get the correct start position.
|
|
||||||
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// check object limit
|
return check_container_size(*this, len, "object", ref_stack.back());
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
|
||||||
{
|
|
||||||
return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -700,11 +717,7 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
if (m_lexer_ref)
|
diagnostic_positions::set_container_end(*ref_stack.back(), m_lexer_ref);
|
||||||
{
|
|
||||||
// Lexer's position is past the closing brace, so set that as the end position.
|
|
||||||
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
@@ -715,13 +728,7 @@ class json_sax_dom_callback_parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_ASSERT(!ref_stack.empty());
|
const string_t object_key = pop_container();
|
||||||
JSON_ASSERT(!keep_stack.empty());
|
|
||||||
JSON_ASSERT(!container_key_stack.empty());
|
|
||||||
ref_stack.pop_back();
|
|
||||||
keep_stack.pop_back();
|
|
||||||
const string_t object_key = std::move(container_key_stack.back());
|
|
||||||
container_key_stack.pop_back();
|
|
||||||
|
|
||||||
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
|
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
|
||||||
{
|
{
|
||||||
@@ -747,20 +754,13 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Manually set the start position of the array here.
|
|
||||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||||
if (m_lexer_ref)
|
diagnostic_positions::set_container_start(*ref_stack.back(), m_lexer_ref);
|
||||||
{
|
|
||||||
// Lexer has read the first character of the array, so
|
|
||||||
// subtract 1 from the position to get the correct start position.
|
|
||||||
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// check array limit
|
if (JSON_HEDLEY_UNLIKELY(!check_container_size(*this, len, "array", ref_stack.back())))
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
|
||||||
{
|
{
|
||||||
return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len != detail::unknown_size())
|
if (len != detail::unknown_size())
|
||||||
@@ -784,11 +784,7 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
if (m_lexer_ref)
|
diagnostic_positions::set_container_end(*ref_stack.back(), m_lexer_ref);
|
||||||
{
|
|
||||||
// Lexer's position is past the closing bracket, so set that as the end position.
|
|
||||||
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
@@ -814,13 +810,7 @@ class json_sax_dom_callback_parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_ASSERT(!ref_stack.empty());
|
const string_t object_key = pop_container();
|
||||||
JSON_ASSERT(!keep_stack.empty());
|
|
||||||
JSON_ASSERT(!container_key_stack.empty());
|
|
||||||
ref_stack.pop_back();
|
|
||||||
keep_stack.pop_back();
|
|
||||||
const string_t object_key = std::move(container_key_stack.back());
|
|
||||||
container_key_stack.pop_back();
|
|
||||||
|
|
||||||
// remove discarded value
|
// remove discarded value
|
||||||
if (!ref_stack.empty() && ref_stack.back())
|
if (!ref_stack.empty() && ref_stack.back())
|
||||||
@@ -907,6 +897,23 @@ class json_sax_dom_callback_parser
|
|||||||
return string_t{};
|
return string_t{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief leave the object or array that end_object()/end_array() just closed
|
||||||
|
@return the key the container is stored under in its parent (see
|
||||||
|
container_key_stack)
|
||||||
|
*/
|
||||||
|
string_t pop_container()
|
||||||
|
{
|
||||||
|
JSON_ASSERT(!ref_stack.empty());
|
||||||
|
JSON_ASSERT(!keep_stack.empty());
|
||||||
|
JSON_ASSERT(!container_key_stack.empty());
|
||||||
|
ref_stack.pop_back();
|
||||||
|
keep_stack.pop_back();
|
||||||
|
string_t object_key = std::move(container_key_stack.back());
|
||||||
|
container_key_stack.pop_back();
|
||||||
|
return object_key;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief remove the discarded value the callback rejected from its parent,
|
@brief remove the discarded value the callback rejected from its parent,
|
||||||
unless it is a duplicate key's slot with a stashed previous value, in
|
unless it is a duplicate key's slot with a stashed previous value, in
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ class parser
|
|||||||
if (last_token != token_type::end_of_input && get_token() != token_type::end_of_input)
|
if (last_token != token_type::end_of_input && get_token() != token_type::end_of_input)
|
||||||
{
|
{
|
||||||
// the value is complete, so there is nothing to recover
|
// the value is complete, so there is nothing to recover
|
||||||
static_cast<void>(report_error(sax, parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr),
|
static_cast<void>(report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr),
|
||||||
std::integral_constant<bool, AllowRecovery> {}));
|
std::integral_constant<bool, AllowRecovery> {}));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -229,10 +229,7 @@ class parser
|
|||||||
// in strict mode, input must be completely read
|
// in strict mode, input must be completely read
|
||||||
if (get_token() != token_type::end_of_input)
|
if (get_token() != token_type::end_of_input)
|
||||||
{
|
{
|
||||||
sdp.parse_error(m_lexer.get_position(),
|
syntax_error(sdp, exception_message(token_type::end_of_input, "value"));
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(),
|
|
||||||
exception_message(token_type::end_of_input, "value"), nullptr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -424,7 +421,7 @@ class parser
|
|||||||
case token_type::parse_error:
|
case token_type::parse_error:
|
||||||
{
|
{
|
||||||
// using "uninitialized" to avoid an "expected" message
|
// using "uninitialized" to avoid an "expected" message
|
||||||
if (!report_error(sax, parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr), allow_recovery))
|
if (!report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr), allow_recovery))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -457,12 +454,12 @@ class parser
|
|||||||
if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
|
if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
|
||||||
{
|
{
|
||||||
// there is nothing to recover
|
// there is nothing to recover
|
||||||
static_cast<void>(report_error(sax, parse_error::create(101, m_lexer.get_position(),
|
static_cast<void>(report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(),
|
||||||
"attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr), allow_recovery));
|
"attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr), allow_recovery));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!report_error(sax, parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr), allow_recovery))
|
if (!report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr), allow_recovery))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -490,7 +487,7 @@ class parser
|
|||||||
case token_type::literal_or_value:
|
case token_type::literal_or_value:
|
||||||
default: // the last token was unexpected
|
default: // the last token was unexpected
|
||||||
{
|
{
|
||||||
if (!report_error(sax, parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr), allow_recovery))
|
if (!report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr), allow_recovery))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -569,7 +566,7 @@ class parser
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!report_error(sax, parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr), allow_recovery))
|
if (!report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr), allow_recovery))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -655,7 +652,7 @@ class parser
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!report_error(sax, parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr), allow_recovery))
|
if (!report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr), allow_recovery))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -759,7 +756,7 @@ class parser
|
|||||||
template<typename SAX>
|
template<typename SAX>
|
||||||
bool overflow_error(SAX* sax, const number_float_t value, std::true_type allow_recovery)
|
bool overflow_error(SAX* sax, const number_float_t value, std::true_type allow_recovery)
|
||||||
{
|
{
|
||||||
if (!report_error(sax, out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr), allow_recovery))
|
if (!report_error(sax, out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr), allow_recovery))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -771,7 +768,7 @@ class parser
|
|||||||
JSON_INTERNAL_ALWAYS_INLINE
|
JSON_INTERNAL_ALWAYS_INLINE
|
||||||
std::false_type overflow_error(SAX* sax, const number_float_t /*value*/, std::false_type allow_recovery)
|
std::false_type overflow_error(SAX* sax, const number_float_t /*value*/, std::false_type allow_recovery)
|
||||||
{
|
{
|
||||||
return report_error(sax, out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr), allow_recovery);
|
return report_error(sax, out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr), allow_recovery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -786,7 +783,7 @@ class parser
|
|||||||
JSON_INTERNAL_ALWAYS_INLINE
|
JSON_INTERNAL_ALWAYS_INLINE
|
||||||
std::false_type key_error(SAX* sax, std::false_type allow_recovery, const bool key_read)
|
std::false_type key_error(SAX* sax, std::false_type allow_recovery, const bool key_read)
|
||||||
{
|
{
|
||||||
return report_error(sax, parse_error::create(101, m_lexer.get_position(), key_read
|
return report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), key_read
|
||||||
? exception_message(token_type::name_separator, "object separator")
|
? exception_message(token_type::name_separator, "object separator")
|
||||||
: exception_message(token_type::value_string, "object key"), nullptr), allow_recovery);
|
: exception_message(token_type::value_string, "object key"), nullptr), allow_recovery);
|
||||||
}
|
}
|
||||||
@@ -803,14 +800,14 @@ class parser
|
|||||||
{
|
{
|
||||||
if (!key_read)
|
if (!key_read)
|
||||||
{
|
{
|
||||||
if (!report_error(sax, parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr), allow_recovery))
|
if (!report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr), allow_recovery))
|
||||||
{
|
{
|
||||||
return next_step::stop;
|
return next_step::stop;
|
||||||
}
|
}
|
||||||
return recover_key(sax);
|
return recover_key(sax);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!report_error(sax, parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr), allow_recovery))
|
if (!report_error(sax, parse_error::create(exception_id::syntax_error, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr), allow_recovery))
|
||||||
{
|
{
|
||||||
return next_step::stop;
|
return next_step::stop;
|
||||||
}
|
}
|
||||||
@@ -1208,6 +1205,21 @@ class parser
|
|||||||
return (last_token = m_lexer.scan_expecting(expected_type)) == expected_type;
|
return (last_token = m_lexer.scan_expecting(expected_type)) == expected_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief reports a syntax error at the current token (parse_error.101)
|
||||||
|
@param[in] sax the SAX parser to report the error to
|
||||||
|
@param[in] message the error message
|
||||||
|
@return the result of the SAX parser's parse_error()
|
||||||
|
*/
|
||||||
|
template<typename SAX>
|
||||||
|
bool syntax_error(SAX& sax, const std::string& message)
|
||||||
|
{
|
||||||
|
// MSVC 2015 reports C4100 (unreferenced parameter) when SAX::parse_error is static
|
||||||
|
static_cast<void>(sax);
|
||||||
|
return sax.parse_error(m_lexer.get_position(), m_lexer.get_token_string(),
|
||||||
|
parse_error::create(exception_id::syntax_error, m_lexer.get_position(), message, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
std::string exception_message(const token_type expected, const std::string& context)
|
std::string exception_message(const token_type expected, const std::string& context)
|
||||||
{
|
{
|
||||||
std::string error_msg = "syntax error ";
|
std::string error_msg = "syntax error ";
|
||||||
|
|||||||
@@ -279,6 +279,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @throw invalid_iterator.214 always
|
||||||
|
JSON_HEDLEY_NO_RETURN void throw_cannot_get_value() const
|
||||||
|
{
|
||||||
|
JSON_THROW(invalid_iterator::create(exception_id::iterator_value_unavailable, "cannot get value", m_object));
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*!
|
/*!
|
||||||
@brief return a reference to the value pointed to by the iterator
|
@brief return a reference to the value pointed to by the iterator
|
||||||
@@ -303,7 +309,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
}
|
}
|
||||||
|
|
||||||
case value_t::null:
|
case value_t::null:
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
throw_cannot_get_value();
|
||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
@@ -319,7 +325,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
return *m_object;
|
return *m_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
throw_cannot_get_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +367,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
return m_object;
|
return m_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
throw_cannot_get_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -478,7 +484,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
// if objects are not the same, the comparison is undefined
|
// if objects are not the same, the comparison is undefined
|
||||||
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
|
JSON_THROW(invalid_iterator::create(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
// value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
|
// value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
|
||||||
@@ -527,7 +533,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
// if objects are not the same, the comparison is undefined
|
// if objects are not the same, the comparison is undefined
|
||||||
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
|
JSON_THROW(invalid_iterator::create(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
// value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
|
// value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
|
||||||
@@ -540,7 +546,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
switch (m_object->m_data.m_type)
|
switch (m_object->m_data.m_type)
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(exception_id::iterator_order_on_object, "cannot compare order of object iterators", m_object));
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
return (m_it.array_iterator < other.m_it.array_iterator);
|
return (m_it.array_iterator < other.m_it.array_iterator);
|
||||||
@@ -596,7 +602,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
switch (m_object->m_data.m_type)
|
switch (m_object->m_data.m_type)
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object));
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
@@ -675,7 +681,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
switch (m_object->m_data.m_type)
|
switch (m_object->m_data.m_type)
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object));
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
return m_it.array_iterator - other.m_it.array_iterator;
|
return m_it.array_iterator - other.m_it.array_iterator;
|
||||||
@@ -704,13 +710,13 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
switch (m_object->m_data.m_type)
|
switch (m_object->m_data.m_type)
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(exception_id::iterator_subscript_on_object, "cannot use operator[] for object iterators", m_object));
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
return *std::next(m_it.array_iterator, n);
|
return *std::next(m_it.array_iterator, n);
|
||||||
|
|
||||||
case value_t::null:
|
case value_t::null:
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
throw_cannot_get_value();
|
||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
@@ -726,7 +732,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
return *m_object;
|
return *m_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
throw_cannot_get_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -744,7 +750,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
return m_it.object_iterator->first;
|
return m_it.object_iterator->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(exception_id::iterator_key_not_object, "cannot use key() for non-object iterators", m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
throw_no_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
reference_tokens.erase(reference_tokens.begin());
|
reference_tokens.erase(reference_tokens.begin());
|
||||||
@@ -178,7 +178,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
throw_no_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return reference_tokens.front();
|
return reference_tokens.front();
|
||||||
@@ -204,7 +204,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
throw_no_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
reference_tokens.pop_back();
|
reference_tokens.pop_back();
|
||||||
@@ -216,7 +216,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
throw_no_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return reference_tokens.back();
|
return reference_tokens.back();
|
||||||
@@ -244,6 +244,21 @@ class json_pointer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// @throw out_of_range.405 always
|
||||||
|
JSON_HEDLEY_NO_RETURN static void throw_no_parent()
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::out_of_range::create(detail::exception_id::patch_on_root, "JSON pointer has no parent", nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @throw out_of_range.404 always
|
||||||
|
template<typename BasicJsonContext>
|
||||||
|
JSON_HEDLEY_NO_RETURN static void throw_unresolved(const string_t& reference_token, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
static_cast<void>(reference_token); // unused when JSON_NOEXCEPTION is defined
|
||||||
|
static_cast<void>(context);
|
||||||
|
JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_unresolved, detail::concat("unresolved reference token '", reference_token, "'"), context));
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief result of @ref parse_array_index
|
@brief result of @ref parse_array_index
|
||||||
|
|
||||||
@@ -255,7 +270,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
ok, ///< @a s is a valid, representable array index
|
ok, ///< @a s is a valid, representable array index
|
||||||
leading_zero, ///< @a s begins with '0' but has more than one character
|
leading_zero, ///< @a s begins with '0' but has more than one character
|
||||||
not_a_number, ///< @a s does not begin with a digit
|
not_a_number, ///< @a s is neither empty nor "-" and does not begin with a digit
|
||||||
unresolved, ///< @a s could not be converted to an integer
|
unresolved, ///< @a s could not be converted to an integer
|
||||||
exceeds_size_type ///< @a s converts to an integer that exceeds size_type
|
exceeds_size_type ///< @a s converts to an integer that exceeds size_type
|
||||||
};
|
};
|
||||||
@@ -282,8 +297,10 @@ class json_pointer
|
|||||||
return array_index_status::leading_zero;
|
return array_index_status::leading_zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
// error condition (cf. RFC 6901, Sect. 4)
|
// error condition (cf. RFC 6901, Sect. 4); this also covers single-
|
||||||
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
|
// character tokens, so "/x" and "/xy" fail alike; "-" and the empty
|
||||||
|
// token are left to the conversion below and are reported as unresolved
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!s.empty() && s != "-" && !(s[0] >= '0' && s[0] <= '9')))
|
||||||
{
|
{
|
||||||
return array_index_status::not_a_number;
|
return array_index_status::not_a_number;
|
||||||
}
|
}
|
||||||
@@ -329,13 +346,13 @@ class json_pointer
|
|||||||
// the branches differ in their messages, not after JSON_THROW's expansion
|
// the branches differ in their messages, not after JSON_THROW's expansion
|
||||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||||
case array_index_status::leading_zero:
|
case array_index_status::leading_zero:
|
||||||
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
|
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_leading_zero, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
|
||||||
case array_index_status::not_a_number:
|
case array_index_status::not_a_number:
|
||||||
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
|
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_not_a_number, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
|
||||||
case array_index_status::unresolved:
|
case array_index_status::unresolved:
|
||||||
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
|
throw_unresolved(s, nullptr);
|
||||||
case array_index_status::exceeds_size_type:
|
case array_index_status::exceeds_size_type:
|
||||||
JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr));
|
JSON_THROW(detail::out_of_range::create(detail::exception_id::value_out_of_range, detail::concat("array index ", s, " exceeds size_type"), nullptr));
|
||||||
case array_index_status::ok:
|
case array_index_status::ok:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -349,7 +366,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
throw_no_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
json_pointer result = *this;
|
json_pointer result = *this;
|
||||||
@@ -486,7 +503,7 @@ class json_pointer
|
|||||||
case detail::value_t::binary:
|
case detail::value_t::binary:
|
||||||
case detail::value_t::discarded:
|
case detail::value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
|
JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_invalid_value, "invalid value to unflatten", &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
id = tree.find_child(id, reference_token);
|
id = tree.find_child(id, reference_token);
|
||||||
@@ -569,7 +586,7 @@ class json_pointer
|
|||||||
case detail::value_t::binary:
|
case detail::value_t::binary:
|
||||||
case detail::value_t::discarded:
|
case detail::value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
throw_unresolved(reference_token, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,7 +618,7 @@ class json_pointer
|
|||||||
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||||
{
|
{
|
||||||
// "-" always fails the range check
|
// "-" always fails the range check
|
||||||
JSON_THROW(detail::out_of_range::create(402, detail::concat(
|
JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_past_the_end_index, detail::concat(
|
||||||
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
|
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
|
||||||
") is out of range"), ptr));
|
") is out of range"), ptr));
|
||||||
}
|
}
|
||||||
@@ -610,7 +627,7 @@ class json_pointer
|
|||||||
// Bounds check before access to avoid exception with JSON_NOEXCEPTION
|
// Bounds check before access to avoid exception with JSON_NOEXCEPTION
|
||||||
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
|
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::out_of_range::create(401, detail::concat(
|
JSON_THROW(detail::out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat(
|
||||||
"array index ", std::to_string(idx), " is out of range"), ptr));
|
"array index ", std::to_string(idx), " is out of range"), ptr));
|
||||||
}
|
}
|
||||||
ptr = &ptr->operator[](idx);
|
ptr = &ptr->operator[](idx);
|
||||||
@@ -626,7 +643,7 @@ class json_pointer
|
|||||||
case detail::value_t::binary:
|
case detail::value_t::binary:
|
||||||
case detail::value_t::discarded:
|
case detail::value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
throw_unresolved(reference_token, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,7 +687,7 @@ class json_pointer
|
|||||||
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||||
{
|
{
|
||||||
// "-" cannot be used for const access
|
// "-" cannot be used for const access
|
||||||
JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
|
JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_past_the_end_index, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// use unchecked array access; the const operator[]
|
// use unchecked array access; the const operator[]
|
||||||
@@ -688,7 +705,7 @@ class json_pointer
|
|||||||
case detail::value_t::binary:
|
case detail::value_t::binary:
|
||||||
case detail::value_t::discarded:
|
case detail::value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
throw_unresolved(reference_token, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,9 +760,9 @@ class json_pointer
|
|||||||
// the branches differ in their messages, not after JSON_THROW's expansion
|
// the branches differ in their messages, not after JSON_THROW's expansion
|
||||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||||
case array_index_status::leading_zero:
|
case array_index_status::leading_zero:
|
||||||
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr));
|
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_leading_zero, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr));
|
||||||
case array_index_status::not_a_number:
|
case array_index_status::not_a_number:
|
||||||
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr));
|
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_not_a_number, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr));
|
||||||
case array_index_status::unresolved:
|
case array_index_status::unresolved:
|
||||||
case array_index_status::exceeds_size_type:
|
case array_index_status::exceeds_size_type:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -872,7 +889,7 @@ class json_pointer
|
|||||||
// check if a nonempty reference string begins with slash
|
// check if a nonempty reference string begins with slash
|
||||||
if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
|
if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
|
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_missing_slash, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the reference tokens:
|
// extract the reference tokens:
|
||||||
@@ -908,7 +925,7 @@ class json_pointer
|
|||||||
(reference_token[pos + 1] != '0' &&
|
(reference_token[pos + 1] != '0' &&
|
||||||
reference_token[pos + 1] != '1')))
|
reference_token[pos + 1] != '1')))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
|
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_invalid_escape, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1072,7 +1089,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
|
JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_not_object, "only objects can be unflattened", &value));
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicJsonType result;
|
BasicJsonType result;
|
||||||
@@ -1096,7 +1113,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
|
if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
|
JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_value_not_primitive, "values in object must be primitive", &element.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign the value to the reference pointed to by JSON pointer. Note
|
// Assign the value to the reference pointed to by JSON pointer. Note
|
||||||
|
|||||||
@@ -323,7 +323,7 @@
|
|||||||
return ej_pair.first == e; \
|
return ej_pair.first == e; \
|
||||||
}); \
|
}); \
|
||||||
if (it != std::end(m)) j = it->second; \
|
if (it != std::end(m)) j = it->second; \
|
||||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE, nullptr)); \
|
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range,"enum value out of range for " #ENUM_TYPE, nullptr)); \
|
||||||
} \
|
} \
|
||||||
template<typename BasicJsonType> \
|
template<typename BasicJsonType> \
|
||||||
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
||||||
@@ -338,7 +338,7 @@
|
|||||||
return ej_pair.second == j; \
|
return ej_pair.second == j; \
|
||||||
}); \
|
}); \
|
||||||
if (it != std::end(m)) e = it->first; \
|
if (it != std::end(m)) e = it->first; \
|
||||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
|
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
||||||
|
|||||||
@@ -172,6 +172,10 @@ struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using detect_key_compare = typename T::key_compare;
|
using detect_key_compare = typename T::key_compare;
|
||||||
|
|
||||||
|
// detects whether two values of type T can be compared with operator==
|
||||||
|
template<typename T>
|
||||||
|
using detect_equal_comparable = decltype(static_cast<bool>(std::declval<const T&>() == std::declval<const T&>()));
|
||||||
|
|
||||||
// obtains the actual object key comparator: object_t::key_compare if the
|
// obtains the actual object key comparator: object_t::key_compare if the
|
||||||
// object type defines it, and default_object_comparator_t otherwise
|
// object type defines it, and default_object_comparator_t otherwise
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ class binary_writer
|
|||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
|
JSON_THROW(type_error::create(exception_id::type_not_serializable, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,12 +313,6 @@ class binary_writer
|
|||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
static_assert(
|
|
||||||
std::is_convertible <
|
|
||||||
typename BasicJsonType::object_t::key_type,
|
|
||||||
string_t >::value,
|
|
||||||
"object_t::key_type must be implicitly convertible to string_t");
|
|
||||||
|
|
||||||
// step 1: write control byte and the object size
|
// step 1: write control byte and the object size
|
||||||
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
||||||
|
|
||||||
@@ -326,7 +320,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
// el.first is written directly (not via a temporary
|
// el.first is written directly (not via a temporary
|
||||||
// basic_json), with the object as diagnostics context
|
// basic_json), with the object as diagnostics context
|
||||||
write_cbor_string(el.first, j);
|
write_cbor_key(el.first, j);
|
||||||
write_cbor(el.second, depth + 1);
|
write_cbor(el.second, depth + 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -348,7 +342,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::uint32_t>(length)))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::uint32_t>(length)))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(412, concat("MessagePack length ", std::to_string(length), " exceeds maximum of ", std::to_string((std::numeric_limits<std::uint32_t>::max)())), &j));
|
JSON_THROW(out_of_range::create(exception_id::length_too_large, concat("MessagePack length ", std::to_string(length), " exceeds maximum of ", std::to_string((std::numeric_limits<std::uint32_t>::max)())), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
static_cast<void>(j);
|
static_cast<void>(j);
|
||||||
@@ -575,7 +569,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(j.m_data.m_value.binary->subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
if (JSON_HEDLEY_UNLIKELY(j.m_data.m_value.binary->subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(j.m_data.m_value.binary->subtype()), " is too large for the MessagePack ext type (max 255)"), &j));
|
JSON_THROW(out_of_range::create(exception_id::subtype_out_of_range, concat("subtype ", std::to_string(j.m_data.m_value.binary->subtype()), " is too large for the MessagePack ext type (max 255)"), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));
|
write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));
|
||||||
@@ -591,12 +585,6 @@ class binary_writer
|
|||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
static_assert(
|
|
||||||
std::is_convertible <
|
|
||||||
typename BasicJsonType::object_t::key_type,
|
|
||||||
string_t >::value,
|
|
||||||
"object_t::key_type must be implicitly convertible to string_t");
|
|
||||||
|
|
||||||
// step 1: write control byte and the object size
|
// step 1: write control byte and the object size
|
||||||
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
|
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
|
||||||
|
|
||||||
@@ -604,7 +592,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
// as in write_cbor, el.first is written directly with the
|
// as in write_cbor, el.first is written directly with the
|
||||||
// object as diagnostics context
|
// object as diagnostics context
|
||||||
write_msgpack_string(el.first, j);
|
write_msgpack_key(el.first, j);
|
||||||
write_msgpack(el.second, depth + 1);
|
write_msgpack(el.second, depth + 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -730,7 +718,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (!use_count)
|
if (!use_count)
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j));
|
||||||
}
|
}
|
||||||
oa.write_character(to_char_type('$'));
|
oa.write_character(to_char_type('$'));
|
||||||
oa.write_character(bjdata_draft3 ? 'B' : 'U');
|
oa.write_character(bjdata_draft3 ? 'B' : 'U');
|
||||||
@@ -809,6 +797,8 @@ class binary_writer
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
@param[in] j JSON value to serialize
|
@param[in] j JSON value to serialize
|
||||||
|
|
||||||
|
@throw type_error.321 if @a j or a value nested in it is discarded
|
||||||
*/
|
*/
|
||||||
void write_bon8(const BasicJsonType& j)
|
void write_bon8(const BasicJsonType& j)
|
||||||
{
|
{
|
||||||
@@ -831,7 +821,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
static_cast<void>(j); // unused when JSON_NOEXCEPTION is defined
|
static_cast<void>(j); // unused when JSON_NOEXCEPTION is defined
|
||||||
static_cast<void>(format_name);
|
static_cast<void>(format_name);
|
||||||
JSON_THROW(type_error::create(321, concat("cannot serialize discarded value to ", format_name), &j));
|
JSON_THROW(type_error::create(exception_id::discarded_value_used, concat("cannot serialize discarded value to ", format_name), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_msgpack_array_prefix(const std::size_t N, const BasicJsonType& j)
|
void write_msgpack_array_prefix(const std::size_t N, const BasicJsonType& j)
|
||||||
@@ -878,9 +868,9 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief a CBOR or MessagePack array or object whose elements
|
/// @brief a CBOR, MessagePack, or BON8 array or object whose elements
|
||||||
/// @ref write_cbor_iterative or @ref write_msgpack_iterative is
|
/// @ref write_cbor_iterative, @ref write_msgpack_iterative, or
|
||||||
/// still writing
|
/// @ref write_bon8_iterative is still writing
|
||||||
struct binary_container_frame
|
struct binary_container_frame
|
||||||
{
|
{
|
||||||
explicit binary_container_frame(const BasicJsonType* value_) noexcept
|
explicit binary_container_frame(const BasicJsonType* value_) noexcept
|
||||||
@@ -992,7 +982,7 @@ class binary_writer
|
|||||||
|
|
||||||
// the key is written directly (not via a temporary basic_json),
|
// the key is written directly (not via a temporary basic_json),
|
||||||
// with the object as diagnostics context, as in write_cbor
|
// with the object as diagnostics context, as in write_cbor
|
||||||
write_cbor_string(current.object_it->first, *current.value);
|
write_cbor_key(current.object_it->first, *current.value);
|
||||||
const BasicJsonType* child = &(current.object_it->second);
|
const BasicJsonType* child = &(current.object_it->second);
|
||||||
++stack.back().object_it;
|
++stack.back().object_it;
|
||||||
write_cbor_value_or_push(*child, stack);
|
write_cbor_value_or_push(*child, stack);
|
||||||
@@ -1069,7 +1059,7 @@ class binary_writer
|
|||||||
|
|
||||||
// as in write_cbor_iterative, the key is written directly with
|
// as in write_cbor_iterative, the key is written directly with
|
||||||
// the object as diagnostics context
|
// the object as diagnostics context
|
||||||
write_msgpack_string(current.object_it->first, *current.value);
|
write_msgpack_key(current.object_it->first, *current.value);
|
||||||
const BasicJsonType* child = &(current.object_it->second);
|
const BasicJsonType* child = &(current.object_it->second);
|
||||||
++stack.back().object_it;
|
++stack.back().object_it;
|
||||||
write_msgpack_value_or_push(*child, stack);
|
write_msgpack_value_or_push(*child, stack);
|
||||||
@@ -1091,7 +1081,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (!use_count)
|
if (!use_count)
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j));
|
||||||
}
|
}
|
||||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||||
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
||||||
@@ -1141,7 +1131,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (!use_count)
|
if (!use_count)
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j));
|
||||||
}
|
}
|
||||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||||
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
||||||
@@ -1358,7 +1348,7 @@ class binary_writer
|
|||||||
const auto it = name.find(static_cast<typename string_t::value_type>(0));
|
const auto it = name.find(static_cast<typename string_t::value_type>(0));
|
||||||
if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
|
if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
|
JSON_THROW(out_of_range::create(exception_id::bson_key_with_null, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t storage;
|
string_t storage;
|
||||||
@@ -1376,7 +1366,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(size)))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(size)))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(412, concat("BSON length ", std::to_string(size), " exceeds maximum of ", std::to_string((std::numeric_limits<std::int32_t>::max)())), nullptr));
|
JSON_THROW(out_of_range::create(exception_id::length_too_large, concat("BSON length ", std::to_string(size), " exceeds maximum of ", std::to_string((std::numeric_limits<std::int32_t>::max)())), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<std::int32_t>(size);
|
return static_cast<std::int32_t>(size);
|
||||||
@@ -1562,7 +1552,7 @@ class binary_writer
|
|||||||
|
|
||||||
if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j));
|
JSON_THROW(out_of_range::create(exception_id::subtype_out_of_range, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sizeof(std::int32_t) + value.size() + 1ul;
|
return sizeof(std::int32_t) + value.size() + 1ul;
|
||||||
@@ -1674,6 +1664,21 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief Writes the head of a BSON element with key @a name whose value is
|
||||||
|
the object or array @a j: its type, key, and @a size
|
||||||
|
|
||||||
|
Called while the key is in scope: an object key is a key_type, which
|
||||||
|
may only convert to a temporary string_t, so it cannot be kept by
|
||||||
|
pointer until after the loop over the entries.
|
||||||
|
*/
|
||||||
|
void write_bson_nested_head(const string_t& name, const BasicJsonType& j,
|
||||||
|
const std::size_t size)
|
||||||
|
{
|
||||||
|
write_bson_entry_header(name, j.is_object() ? 0x03 : 0x04);
|
||||||
|
write_number<std::int32_t>(to_bson_length(size), true);
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief an object or array of the BSON document being sized or written
|
/// @brief an object or array of the BSON document being sized or written
|
||||||
struct bson_frame
|
struct bson_frame
|
||||||
{
|
{
|
||||||
@@ -1838,7 +1843,6 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
// write entries until the current object or array is done, or an
|
// write entries until the current object or array is done, or an
|
||||||
// entry is an object or array itself
|
// entry is an object or array itself
|
||||||
const string_t* nested_name = nullptr;
|
|
||||||
const BasicJsonType* nested = nullptr;
|
const BasicJsonType* nested = nullptr;
|
||||||
if (current.value->is_object())
|
if (current.value->is_object())
|
||||||
{
|
{
|
||||||
@@ -1849,7 +1853,7 @@ class binary_writer
|
|||||||
++current.member;
|
++current.member;
|
||||||
if (el.second.is_structured())
|
if (el.second.is_structured())
|
||||||
{
|
{
|
||||||
nested_name = &el.first;
|
write_bson_nested_head(el.first, el.second, nested_sizes[next_size++]);
|
||||||
nested = &el.second;
|
nested = &el.second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1868,7 +1872,7 @@ class binary_writer
|
|||||||
++current.index;
|
++current.index;
|
||||||
if (el.is_structured())
|
if (el.is_structured())
|
||||||
{
|
{
|
||||||
nested_name = &index_name;
|
write_bson_nested_head(index_name, el, nested_sizes[next_size++]);
|
||||||
nested = ⪙
|
nested = ⪙
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1880,8 +1884,6 @@ class binary_writer
|
|||||||
|
|
||||||
if (nested != nullptr)
|
if (nested != nullptr)
|
||||||
{
|
{
|
||||||
write_bson_entry_header(*nested_name, nested->is_object() ? 0x03 : 0x04);
|
|
||||||
write_number<std::int32_t>(to_bson_length(nested_sizes[next_size++]), true);
|
|
||||||
parents.push_back(std::move(current));
|
parents.push_back(std::move(current));
|
||||||
current = bson_frame(nested);
|
current = bson_frame(nested);
|
||||||
continue;
|
continue;
|
||||||
@@ -1949,6 +1951,43 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief write an object key as a CBOR text string
|
||||||
|
|
||||||
|
A key convertible to string_t is written directly. Other key types (only
|
||||||
|
an explicit conversion, or only a to_json overload) go through a temporary
|
||||||
|
basic_json, as in version 3.12.0; the temporary is then the diagnostics
|
||||||
|
context for strict UTF-8 checks.
|
||||||
|
*/
|
||||||
|
template<typename Key = typename BasicJsonType::object_t::key_type,
|
||||||
|
enable_if_t<std::is_convertible<Key, string_t>::value, int> = 0>
|
||||||
|
void write_cbor_key(const typename BasicJsonType::object_t::key_type& key, const BasicJsonType& context)
|
||||||
|
{
|
||||||
|
write_cbor_string(key, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key = typename BasicJsonType::object_t::key_type,
|
||||||
|
enable_if_t < !std::is_convertible<Key, string_t>::value, int > = 0 >
|
||||||
|
void write_cbor_key(const typename BasicJsonType::object_t::key_type& key, const BasicJsonType& /*context*/)
|
||||||
|
{
|
||||||
|
write_cbor(BasicJsonType(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief write an object key as a MessagePack str, as in @ref write_cbor_key
|
||||||
|
template<typename Key = typename BasicJsonType::object_t::key_type,
|
||||||
|
enable_if_t<std::is_convertible<Key, string_t>::value, int> = 0>
|
||||||
|
void write_msgpack_key(const typename BasicJsonType::object_t::key_type& key, const BasicJsonType& context)
|
||||||
|
{
|
||||||
|
write_msgpack_string(key, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key = typename BasicJsonType::object_t::key_type,
|
||||||
|
enable_if_t < !std::is_convertible<Key, string_t>::value, int > = 0 >
|
||||||
|
void write_msgpack_key(const typename BasicJsonType::object_t::key_type& key, const BasicJsonType& /*context*/)
|
||||||
|
{
|
||||||
|
write_msgpack(BasicJsonType(key));
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief write a CBOR text string
|
@brief write a CBOR text string
|
||||||
|
|
||||||
@@ -2570,9 +2609,27 @@ class binary_writer
|
|||||||
@param[in] j JSON value to serialize
|
@param[in] j JSON value to serialize
|
||||||
@param[in,out] string_open whether the output ends with a non-empty
|
@param[in,out] string_open whether the output ends with a non-empty
|
||||||
string that has not been terminated with 0xFF
|
string that has not been terminated with 0xFF
|
||||||
|
@param[in] depth nesting level of @a j, counted from the
|
||||||
|
top-level value passed to @ref basic_json::to_bon8
|
||||||
|
@throw type_error.316 if a string value or an object key is not valid
|
||||||
|
UTF-8
|
||||||
|
@throw out_of_range.407 if an unsigned integer does not fit int64
|
||||||
|
@throw type_error.321 if @a j or a value nested in it is discarded
|
||||||
|
|
||||||
|
Values nested deeper than @ref recursion_depth_limit are written by
|
||||||
|
@ref write_bon8_iterative without the call stack.
|
||||||
|
|
||||||
|
@sa @ref write_cbor
|
||||||
|
@sa https://github.com/nlohmann/json/issues/5392
|
||||||
*/
|
*/
|
||||||
void write_bon8_value(const BasicJsonType& j, bool& string_open)
|
void write_bon8_value(const BasicJsonType& j, bool& string_open, const std::size_t depth = 0)
|
||||||
{
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(depth >= recursion_depth_limit()) && (j.is_array() || j.is_object()))
|
||||||
|
{
|
||||||
|
write_bon8_iterative(j, string_open);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (j.type())
|
switch (j.type())
|
||||||
{
|
{
|
||||||
case value_t::null:
|
case value_t::null:
|
||||||
@@ -2591,7 +2648,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (j.m_data.m_value.number_unsigned > static_cast<typename BasicJsonType::number_unsigned_t>((std::numeric_limits<std::int64_t>::max)()))
|
if (j.m_data.m_value.number_unsigned > static_cast<typename BasicJsonType::number_unsigned_t>((std::numeric_limits<std::int64_t>::max)()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BON8 as it does not fit int64"), &j));
|
JSON_THROW(out_of_range::create(exception_id::integer_too_large, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BON8 as it does not fit int64"), &j));
|
||||||
}
|
}
|
||||||
write_bon8_integer(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned));
|
write_bon8_integer(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned));
|
||||||
string_open = false;
|
string_open = false;
|
||||||
@@ -2626,7 +2683,7 @@ class binary_writer
|
|||||||
|
|
||||||
for (const auto& el : *j.m_data.m_value.array)
|
for (const auto& el : *j.m_data.m_value.array)
|
||||||
{
|
{
|
||||||
write_bon8_value(el, string_open);
|
write_bon8_value(el, string_open, depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (N > 4)
|
if (N > 4)
|
||||||
@@ -2645,7 +2702,7 @@ class binary_writer
|
|||||||
for (const auto& el : *j.m_data.m_value.object)
|
for (const auto& el : *j.m_data.m_value.object)
|
||||||
{
|
{
|
||||||
write_bon8_string(el.first, string_open, j);
|
write_bon8_string(el.first, string_open, j);
|
||||||
write_bon8_value(el.second, string_open);
|
write_bon8_value(el.second, string_open, depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (N > 4)
|
if (N > 4)
|
||||||
@@ -2678,7 +2735,84 @@ class binary_writer
|
|||||||
|
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
break;
|
throw_on_discarded(j, "BON8");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief write @a j with @ref write_bon8_value, or write its marker and push
|
||||||
|
a frame for @ref write_bon8_iterative to continue with its elements
|
||||||
|
|
||||||
|
A scalar, and an empty array or object, are written out in full and not
|
||||||
|
pushed.
|
||||||
|
|
||||||
|
@sa @ref write_cbor_value_or_push
|
||||||
|
*/
|
||||||
|
void write_bon8_value_or_push(const BasicJsonType& j, bool& string_open, std::vector<binary_container_frame>& stack)
|
||||||
|
{
|
||||||
|
if (j.is_array() || j.is_object())
|
||||||
|
{
|
||||||
|
// arrays use the markers 0x80..0x85, objects 0x86..0x8B; the last
|
||||||
|
// one stands for more than four elements, closed later with 0xFE
|
||||||
|
const auto N = j.size();
|
||||||
|
const std::size_t base = j.is_array() ? 0x80 : 0x86;
|
||||||
|
write_bon8_marker(static_cast<std::uint8_t>(base + (N <= 4 ? N : 5)), string_open);
|
||||||
|
if (N != 0)
|
||||||
|
{
|
||||||
|
stack.emplace_back(&j);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_bon8_value(j, string_open);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief write out @a root and everything below it without the call stack
|
||||||
|
|
||||||
|
A container with more than four elements is closed with 0xFE once its
|
||||||
|
last element is written, as in @ref write_bon8_value.
|
||||||
|
|
||||||
|
@sa @ref write_cbor_iterative
|
||||||
|
*/
|
||||||
|
void write_bon8_iterative(const BasicJsonType& root, bool& string_open)
|
||||||
|
{
|
||||||
|
// only a container with elements is ever pushed; see write_bon8_value_or_push
|
||||||
|
std::vector<binary_container_frame> stack;
|
||||||
|
write_bon8_value_or_push(root, string_open, stack);
|
||||||
|
|
||||||
|
while (!stack.empty())
|
||||||
|
{
|
||||||
|
const binary_container_frame current = stack.back();
|
||||||
|
const bool is_array = current.value->is_array();
|
||||||
|
const bool at_end = is_array
|
||||||
|
? current.array_it == current.value->m_data.m_value.array->cend()
|
||||||
|
: current.object_it == current.value->m_data.m_value.object->cend();
|
||||||
|
|
||||||
|
if (at_end)
|
||||||
|
{
|
||||||
|
if (current.value->size() > 4)
|
||||||
|
{
|
||||||
|
write_bon8_marker(0xFE, string_open);
|
||||||
|
}
|
||||||
|
stack.pop_back();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the child before pushing: entering it can move every frame
|
||||||
|
const BasicJsonType* child = nullptr;
|
||||||
|
if (is_array)
|
||||||
|
{
|
||||||
|
child = &(*current.array_it);
|
||||||
|
++stack.back().array_it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_bon8_string(current.object_it->first, string_open, *current.value);
|
||||||
|
child = &(current.object_it->second);
|
||||||
|
++stack.back().object_it;
|
||||||
|
}
|
||||||
|
write_bon8_value_or_push(*child, string_open, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2744,7 +2878,7 @@ class binary_writer
|
|||||||
const std::size_t valid = valid_utf8_prefix(data, s.size());
|
const std::size_t valid = valid_utf8_prefix(data, s.size());
|
||||||
if (JSON_HEDLEY_UNLIKELY(valid != s.size()))
|
if (JSON_HEDLEY_UNLIKELY(valid != s.size()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(valid), ": 0x", detail::hex_byte(data[valid])), &context));
|
JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("invalid UTF-8 byte at index ", std::to_string(valid), ": 0x", detail::hex_byte(data[valid])), &context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -888,7 +888,7 @@ class serializer
|
|||||||
{
|
{
|
||||||
case error_handler_t::strict:
|
case error_handler_t::strict:
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", detail::hex_byte(byte)), nullptr));
|
JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", detail::hex_byte(byte)), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::ignore:
|
case error_handler_t::ignore:
|
||||||
@@ -1021,7 +1021,7 @@ class serializer
|
|||||||
{
|
{
|
||||||
case error_handler_t::strict:
|
case error_handler_t::strict:
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", detail::hex_byte(static_cast<std::uint8_t>(s[s.size() - 1]))), nullptr));
|
JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("incomplete UTF-8 string; last byte: 0x", detail::hex_byte(static_cast<std::uint8_t>(s[s.size() - 1]))), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::ignore:
|
case error_handler_t::ignore:
|
||||||
|
|||||||
+116
-72
@@ -639,7 +639,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
object = nullptr; // silence warning, see #821
|
object = nullptr; // silence warning, see #821
|
||||||
if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
|
if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE
|
JSON_THROW(other_error::create(detail::exception_id::internal_error, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1421,6 +1421,24 @@ public:
|
|||||||
return create<object_t>(first, last);
|
return create<object_t>(first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief compare two object keys for equality, if the key type supports it
|
||||||
|
/// @note object_t only needs operator< for its keys (std::map), so operator==
|
||||||
|
/// may not exist; the keys are then reported as different, which makes
|
||||||
|
/// copy_object_level pair the values via object_t::find()
|
||||||
|
template<typename K = typename object_t::key_type,
|
||||||
|
detail::enable_if_t<detail::is_detected<detail::detect_equal_comparable, K>::value, int> = 0>
|
||||||
|
static bool copy_keys_equal(const K& a, const K& b)
|
||||||
|
{
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename K = typename object_t::key_type,
|
||||||
|
detail::enable_if_t < !detail::is_detected<detail::detect_equal_comparable, K>::value, int > = 0 >
|
||||||
|
static bool copy_keys_equal(const K& /*a*/, const K& /*b*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief create the copy of the object @a src in @a dst
|
/// @brief create the copy of the object @a src in @a dst
|
||||||
/// @note structured values are appended to @a worklist instead
|
/// @note structured values are appended to @a worklist instead
|
||||||
static void copy_object_level(const basic_json& src, basic_json& dst,
|
static void copy_object_level(const basic_json& src, basic_json& dst,
|
||||||
@@ -1453,7 +1471,7 @@ public:
|
|||||||
auto src_it = src_object.cbegin();
|
auto src_it = src_object.cbegin();
|
||||||
for (auto& element : *dst.m_data.m_value.object)
|
for (auto& element : *dst.m_data.m_value.object)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_LIKELY(src_it != src_object.cend() && src_it->first == element.first))
|
if (JSON_HEDLEY_LIKELY(src_it != src_object.cend() && copy_keys_equal(src_it->first, element.first)))
|
||||||
{
|
{
|
||||||
copy_shallow(src_it->second, element.second, worklist);
|
copy_shallow(src_it->second, element.second, worklist);
|
||||||
++src_it;
|
++src_it;
|
||||||
@@ -2287,7 +2305,7 @@ public:
|
|||||||
// if an object is wanted but impossible, throw an exception
|
// if an object is wanted but impossible, throw an exception
|
||||||
if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
|
if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
|
JSON_THROW(type_error::create(detail::exception_id::object_from_non_pairs, "cannot create object from initializer list", nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2407,7 +2425,7 @@ public:
|
|||||||
// make sure the iterator fits the current value
|
// make sure the iterator fits the current value
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterators_incompatible, "iterators are not compatible", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy type from the first iterator
|
// copy type from the first iterator
|
||||||
@@ -2426,7 +2444,7 @@ public:
|
|||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
|
if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
|
||||||
|| !last.m_it.primitive_iterator.is_end()))
|
|| !last.m_it.primitive_iterator.is_end()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_out_of_range, "iterators out of range", first.m_object));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2494,7 +2512,7 @@ public:
|
|||||||
case value_t::null:
|
case value_t::null:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_of_null, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
set_parents();
|
set_parents();
|
||||||
@@ -2882,7 +2900,7 @@ public:
|
|||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
|
JSON_THROW(type_error::create(detail::exception_id::incompatible_reference_type, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -3266,7 +3284,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!is_binary())
|
if (!is_binary())
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
|
detail::throw_type_must_be("binary", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *get_ptr<binary_t*>();
|
return *get_ptr<binary_t*>();
|
||||||
@@ -3278,7 +3296,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!is_binary())
|
if (!is_binary())
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
|
detail::throw_type_must_be("binary", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *get_ptr<const binary_t*>();
|
return *get_ptr<const binary_t*>();
|
||||||
@@ -3320,7 +3338,7 @@ public:
|
|||||||
// at only works for objects
|
// at only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", j.type_name()), &j));
|
detail::throw_cannot_use_with(detail::exception_id::at_wrong_type, "at()", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = object_lookup(j, std::forward<KeyType>(key));
|
auto it = object_lookup(j, std::forward<KeyType>(key));
|
||||||
@@ -3330,11 +3348,28 @@ public:
|
|||||||
// std::map or ordered_map) never moves from its argument, so key is still
|
// std::map or ordered_map) never moves from its argument, so key is still
|
||||||
// valid here regardless of whether KeyType was deduced as an rvalue reference
|
// valid here regardless of whether KeyType was deduced as an rvalue reference
|
||||||
// NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved)
|
// NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved)
|
||||||
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(key), "' not found"), &j));
|
JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", key_for_message(key), "' not found"), &j));
|
||||||
}
|
}
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief key as it is passed to detail::concat for an error message
|
||||||
|
/// @note keys with data() and size() (such as string_t itself or a string
|
||||||
|
/// view) are passed through unchanged, so a miss does not copy them;
|
||||||
|
/// other keys (such as string literals or key types that only convert
|
||||||
|
/// to string_t) are converted to string_t
|
||||||
|
template < typename KeyType, detail::enable_if_t < detail::detect_string_can_append_data<string_t, KeyType>::value, int > = 0 >
|
||||||
|
static const KeyType & key_for_message(const KeyType& key)
|
||||||
|
{
|
||||||
|
return key; // NOLINT(bugprone-return-const-ref-from-parameter): the result is only passed to concat() within the full-expression that holds key
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename KeyType, detail::enable_if_t < !detail::detect_string_can_append_data<string_t, KeyType>::value, int > = 0 >
|
||||||
|
static string_t key_for_message(const KeyType& key)
|
||||||
|
{
|
||||||
|
return string_t(key);
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief checked array element access used by the at() overloads taking an index
|
/// @brief checked array element access used by the at() overloads taking an index
|
||||||
/// @throw type_error.304 if @a j is not an array
|
/// @throw type_error.304 if @a j is not an array
|
||||||
/// @throw out_of_range.401 if @a idx is out of range
|
/// @throw out_of_range.401 if @a idx is out of range
|
||||||
@@ -3345,12 +3380,12 @@ public:
|
|||||||
// at only works for arrays
|
// at only works for arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", j.type_name()), &j));
|
detail::throw_cannot_use_with(detail::exception_id::at_wrong_type, "at()", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(idx >= j.m_data.m_value.array->size()))
|
if (JSON_HEDLEY_UNLIKELY(idx >= j.m_data.m_value.array->size()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &j));
|
JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (*j.m_data.m_value.array)[idx];
|
return (*j.m_data.m_value.array)[idx];
|
||||||
@@ -3383,6 +3418,15 @@ public:
|
|||||||
m_data.m_type = value_t::object;
|
m_data.m_type = value_t::object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief throws because operator[] is not supported for the type of this value
|
||||||
|
/// @param[in] argument the kind of the operator's argument, "numeric" or "string"
|
||||||
|
/// @throw type_error.305 always
|
||||||
|
JSON_HEDLEY_NO_RETURN void throw_subscript_wrong_type(const char* argument) const
|
||||||
|
{
|
||||||
|
detail::throw_cannot_use_with(detail::exception_id::subscript_wrong_type,
|
||||||
|
detail::concat("operator[] with a ", argument, " argument").c_str(), *this);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
////////////////////
|
////////////////////
|
||||||
// element access //
|
// element access //
|
||||||
@@ -3487,7 +3531,7 @@ public:
|
|||||||
return m_data.m_value.array->operator[](idx);
|
return m_data.m_value.array->operator[](idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
|
throw_subscript_wrong_type("numeric");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified array element
|
/// @brief access specified array element
|
||||||
@@ -3501,7 +3545,7 @@ public:
|
|||||||
return m_data.m_value.array->operator[](idx);
|
return m_data.m_value.array->operator[](idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
|
throw_subscript_wrong_type("numeric");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified object element
|
/// @brief access specified object element
|
||||||
@@ -3521,7 +3565,7 @@ public:
|
|||||||
return set_parent(result.first->second);
|
return set_parent(result.first->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
throw_subscript_wrong_type("string");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified object element
|
/// @brief access specified object element
|
||||||
@@ -3536,7 +3580,7 @@ public:
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
throw_subscript_wrong_type("string");
|
||||||
}
|
}
|
||||||
|
|
||||||
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
||||||
@@ -3572,7 +3616,7 @@ public:
|
|||||||
return set_parent(result.first->second);
|
return set_parent(result.first->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
throw_subscript_wrong_type("string");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified object element
|
/// @brief access specified object element
|
||||||
@@ -3589,7 +3633,7 @@ public:
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
throw_subscript_wrong_type("string");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -3613,7 +3657,7 @@ public:
|
|||||||
// value only works for objects
|
// value only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::value_wrong_type, "value()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto it = find(std::forward<KeyType>(key));
|
const auto it = find(std::forward<KeyType>(key));
|
||||||
@@ -3628,7 +3672,7 @@ public:
|
|||||||
// value only works for arrays and objects
|
// value only works for arrays and objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_structured()))
|
if (JSON_HEDLEY_UNLIKELY(!is_structured()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::value_wrong_type, "value()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptr.get_checked_or_null(this);
|
return ptr.get_checked_or_null(this);
|
||||||
@@ -3795,7 +3839,7 @@ public:
|
|||||||
// make sure the iterator fits the current value
|
// make sure the iterator fits the current value
|
||||||
if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
|
if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorType result = end();
|
IteratorType result = end();
|
||||||
@@ -3811,7 +3855,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
|
if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_out_of_range, "iterator out of range", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.m_value.destroy(m_data.m_type);
|
m_data.m_value.destroy(m_data.m_type);
|
||||||
@@ -3837,7 +3881,7 @@ public:
|
|||||||
case value_t::null:
|
case value_t::null:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -3853,7 +3897,7 @@ public:
|
|||||||
// make sure the iterator fits the current value
|
// make sure the iterator fits the current value
|
||||||
if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_from_other_value, "iterators do not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorType result = end();
|
IteratorType result = end();
|
||||||
@@ -3870,7 +3914,7 @@ public:
|
|||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
|
if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
|
||||||
|| !last.m_it.primitive_iterator.is_end()))
|
|| !last.m_it.primitive_iterator.is_end()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_out_of_range, "iterators out of range", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.m_value.destroy(m_data.m_type);
|
m_data.m_value.destroy(m_data.m_type);
|
||||||
@@ -3898,7 +3942,7 @@ public:
|
|||||||
case value_t::null:
|
case value_t::null:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -3912,7 +3956,7 @@ public:
|
|||||||
// this erase only works for objects
|
// this erase only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto erased = m_data.m_value.object->erase(std::forward<KeyType>(key));
|
const auto erased = m_data.m_value.object->erase(std::forward<KeyType>(key));
|
||||||
@@ -3927,7 +3971,7 @@ public:
|
|||||||
// this erase only works for objects
|
// this erase only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto it = object_lookup(*this, std::forward<KeyType>(key));
|
const auto it = object_lookup(*this, std::forward<KeyType>(key));
|
||||||
@@ -3969,14 +4013,14 @@ public:
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(idx >= size()))
|
if (JSON_HEDLEY_UNLIKELY(idx >= size()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
|
JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
|
m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4465,7 +4509,7 @@ public:
|
|||||||
// push_back only works for null objects or arrays
|
// push_back only works for null objects or arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
@@ -4496,7 +4540,7 @@ public:
|
|||||||
// push_back only works for null objects or arrays
|
// push_back only works for null objects or arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
@@ -4526,7 +4570,7 @@ public:
|
|||||||
// push_back only works for null objects or objects
|
// push_back only works for null objects or objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an object
|
// transform a null object into an object
|
||||||
@@ -4580,7 +4624,7 @@ public:
|
|||||||
// emplace_back only works for null objects or arrays
|
// emplace_back only works for null objects or arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::emplace_wrong_type, "emplace_back()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
@@ -4603,7 +4647,7 @@ public:
|
|||||||
// emplace only works for null objects or arrays
|
// emplace only works for null objects or arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::emplace_wrong_type, "emplace()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an object
|
// transform a null object into an object
|
||||||
@@ -4655,14 +4699,14 @@ public:
|
|||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert to array and return iterator
|
// insert to array and return iterator
|
||||||
return insert_iterator(pos, val);
|
return insert_iterator(pos, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief inserts element into array
|
/// @brief inserts element into array
|
||||||
@@ -4675,7 +4719,7 @@ public:
|
|||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// moving into a local first keeps this safe even if val aliases
|
// moving into a local first keeps this safe even if val aliases
|
||||||
@@ -4684,7 +4728,7 @@ public:
|
|||||||
return insert_iterator(pos, std::move(tmp));
|
return insert_iterator(pos, std::move(tmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief inserts copies of element into array
|
/// @brief inserts copies of element into array
|
||||||
@@ -4697,14 +4741,14 @@ public:
|
|||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert to array and return iterator
|
// insert to array and return iterator
|
||||||
return insert_iterator(pos, cnt, val);
|
return insert_iterator(pos, cnt, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief inserts range of elements into array
|
/// @brief inserts range of elements into array
|
||||||
@@ -4714,30 +4758,30 @@ public:
|
|||||||
// insert only works for arrays
|
// insert only works for arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if range iterators belong to the same JSON object
|
// check if range iterators belong to the same JSON object
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_into_itself, "passed iterators may not belong to container", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed iterators must belong to arrays
|
// passed iterators must belong to arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to arrays", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterators first and last must point to arrays", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert to array and return iterator
|
// insert to array and return iterator
|
||||||
@@ -4751,13 +4795,13 @@ public:
|
|||||||
// insert only works for arrays
|
// insert only works for arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy the values first: ilist may refer to elements of this array
|
// copy the values first: ilist may refer to elements of this array
|
||||||
@@ -4779,19 +4823,19 @@ public:
|
|||||||
// insert only works for objects
|
// insert only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if range iterators belong to the same JSON object
|
// check if range iterators belong to the same JSON object
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed iterators must belong to objects
|
// passed iterators must belong to objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!first.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(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterators first and last must point to objects", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
|
m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
|
||||||
@@ -4808,7 +4852,7 @@ public:
|
|||||||
// j, not the copy made below)
|
// j, not the copy made below)
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", j.type_name()), &j));
|
detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy first: j may be *this or one of its descendants, and is
|
// copy first: j may be *this or one of its descendants, and is
|
||||||
@@ -4826,13 +4870,13 @@ public:
|
|||||||
// check if range iterators belong to the same JSON object
|
// check if range iterators belong to the same JSON object
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
|
JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed iterators must belong to objects
|
// passed iterators must belong to objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
|
detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", *first.m_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy first: the range may belong to *this or one of its
|
// copy first: the range may belong to *this or one of its
|
||||||
@@ -4868,7 +4912,7 @@ public:
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5031,7 +5075,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(array_t&)", *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5048,7 +5092,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(object_t&)", *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5064,7 +5108,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(string_t&)", *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5080,7 +5124,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(binary_t&)", *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5096,7 +5140,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
|
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(binary_t::container_type&)", *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6558,7 +6602,7 @@ public:
|
|||||||
if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
|
if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
|
||||||
{
|
{
|
||||||
// avoid undefined behavior
|
// avoid undefined behavior
|
||||||
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
|
JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
// default case: insert add offset
|
// default case: insert add offset
|
||||||
@@ -6577,7 +6621,7 @@ public:
|
|||||||
case value_t::binary:
|
case value_t::binary:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(out_of_range::create(411, detail::concat("cannot add value: the JSON Patch 'add' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
JSON_THROW(out_of_range::create(detail::exception_id::patch_add_parent_not_container, detail::concat("cannot add value: the JSON Patch 'add' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -6600,7 +6644,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
|
JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", last_path, "' not found"), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parent.is_array())
|
else if (parent.is_array())
|
||||||
@@ -6612,7 +6656,7 @@ public:
|
|||||||
{
|
{
|
||||||
// the parent of a "remove" target must be an object or array
|
// the parent of a "remove" target must be an object or array
|
||||||
// (see #5396)
|
// (see #5396)
|
||||||
JSON_THROW(out_of_range::create(413, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
JSON_THROW(out_of_range::create(detail::exception_id::patch_remove_parent_not_container, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -6643,7 +6687,7 @@ public:
|
|||||||
// type check: top level value must be an array
|
// type check: top level value must be an array
|
||||||
if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
|
JSON_THROW(parse_error::create(detail::exception_id::patch_not_an_array, 0, "JSON patch must be an array of objects", &json_patch));
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate and apply the operations
|
// iterate and apply the operations
|
||||||
@@ -6664,14 +6708,14 @@ public:
|
|||||||
if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
|
if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
||||||
JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
|
JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the result is of type string
|
// check if the result is of type string
|
||||||
if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
||||||
JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
|
JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// no error: return value
|
// no error: return value
|
||||||
@@ -6681,7 +6725,7 @@ public:
|
|||||||
// type check: every element of the array must be an object
|
// type check: every element of the array must be an object
|
||||||
if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
|
JSON_THROW(parse_error::create(detail::exception_id::patch_not_an_array, 0, "JSON patch must be an array of objects", &val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect mandatory members
|
// collect mandatory members
|
||||||
@@ -6717,7 +6761,7 @@ public:
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr)))
|
if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr)))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(414, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result));
|
JSON_THROW(out_of_range::create(detail::exception_id::patch_move_into_child, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result));
|
||||||
}
|
}
|
||||||
|
|
||||||
// the "from" location must exist - use at()
|
// the "from" location must exist - use at()
|
||||||
@@ -6764,7 +6808,7 @@ public:
|
|||||||
// throw an exception if the test fails
|
// throw an exception if the test fails
|
||||||
if (JSON_HEDLEY_UNLIKELY(!success))
|
if (JSON_HEDLEY_UNLIKELY(!success))
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
|
JSON_THROW(other_error::create(detail::exception_id::patch_test_failed, detail::concat("unsuccessful: ", val.dump()), &val));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -6775,7 +6819,7 @@ public:
|
|||||||
{
|
{
|
||||||
// op must be "add", "remove", "replace", "move", "copy", or
|
// op must be "add", "remove", "replace", "move", "copy", or
|
||||||
// "test"
|
// "test"
|
||||||
JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
|
JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat("operation value '", op, "' is invalid"), &val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,19 @@ private:
|
|||||||
return self.end();
|
return self.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief shared implementation of the const and non-const at() overloads
|
||||||
|
/// @throw std::out_of_range if @a key is not found
|
||||||
|
template<typename Self, typename KeyType>
|
||||||
|
static auto at_impl(Self& self, const KeyType& key) -> decltype((self.begin()->second))
|
||||||
|
{
|
||||||
|
const auto it = find_impl(self, key);
|
||||||
|
if (it == self.end())
|
||||||
|
{
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief remove the entry @a it points to, preserving order
|
/// @brief remove the entry @a it points to, preserving order
|
||||||
/// @note keys are not movable, so the tail is destroyed and re-constructed in place
|
/// @note keys are not movable, so the tail is destroyed and re-constructed in place
|
||||||
void erase_at(iterator it)
|
void erase_at(iterator it)
|
||||||
@@ -156,46 +169,26 @@ public:
|
|||||||
|
|
||||||
T& at(const key_type& key)
|
T& at(const key_type& key)
|
||||||
{
|
{
|
||||||
const auto it = find_impl(*this, key);
|
return at_impl(*this, key);
|
||||||
if (it == this->end())
|
|
||||||
{
|
|
||||||
JSON_THROW(std::out_of_range("key not found"));
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
{
|
{
|
||||||
const auto it = find_impl(*this, key);
|
return at_impl(*this, key);
|
||||||
if (it == this->end())
|
|
||||||
{
|
|
||||||
JSON_THROW(std::out_of_range("key not found"));
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& at(const key_type& key) const
|
const T& at(const key_type& key) const
|
||||||
{
|
{
|
||||||
const auto it = find_impl(*this, key);
|
return at_impl(*this, key);
|
||||||
if (it == this->end())
|
|
||||||
{
|
|
||||||
JSON_THROW(std::out_of_range("key not found"));
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
{
|
{
|
||||||
const auto it = find_impl(*this, key);
|
return at_impl(*this, key);
|
||||||
if (it == this->end())
|
|
||||||
{
|
|
||||||
JSON_THROW(std::out_of_range("key not found"));
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type erase(const key_type& key)
|
size_type erase(const key_type& key)
|
||||||
@@ -247,6 +240,14 @@ public:
|
|||||||
// ^ ^
|
// ^ ^
|
||||||
// first last
|
// first last
|
||||||
|
|
||||||
|
// Note on conformance: before C++20, [basic.life]/8 did not allow an
|
||||||
|
// object of a type with a const member (like value_type's const Key)
|
||||||
|
// to transparently replace the destroyed one, so strictly, accessing
|
||||||
|
// it through the vector's existing pointers would have required
|
||||||
|
// std::launder (which does not exist before C++17). C++20 dropped that
|
||||||
|
// condition (P1971R0, NB comment US 041). Compilers have always treated
|
||||||
|
// this pattern as intended, so it is kept deliberately.
|
||||||
|
|
||||||
// Since we cannot move const Keys, we re-construct them in place.
|
// Since we cannot move const Keys, we re-construct them in place.
|
||||||
// We start at first and re-construct (viz. copy) the elements from
|
// We start at first and re-construct (viz. copy) the elements from
|
||||||
// the back of the vector. Example for the first iteration:
|
// the back of the vector. Example for the first iteration:
|
||||||
|
|||||||
Generated
+748
-434
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,519 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||||
|
// | | |__ | | | | | | version 3.12.0
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Object types with a user-defined key type. The key types differ in what they
|
||||||
|
// offer to the library: a conversion to std::string (implicit or explicit), a
|
||||||
|
// comparison with ==, a to_json overload, or a c_str() member.
|
||||||
|
|
||||||
|
namespace custom_key_test
|
||||||
|
{
|
||||||
|
class key_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
key_base() = default;
|
||||||
|
|
||||||
|
key_base(const char* value)
|
||||||
|
: m_value(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
key_base(std::string value)
|
||||||
|
: m_value(std::move(value))
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Required by JSON_DIAGNOSTICS, which reads object keys through data()
|
||||||
|
// when building the path of an exception.
|
||||||
|
const char* data() const noexcept
|
||||||
|
{
|
||||||
|
return m_value.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<(const key_base& lhs, const key_base& rhs)
|
||||||
|
{
|
||||||
|
return lhs.m_value < rhs.m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const std::string& str() const noexcept
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// implicit conversion to std::string and operator==
|
||||||
|
class key_full : public key_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
key_full() = default;
|
||||||
|
using key_base::key_base;
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
return str();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const key_full& lhs, const key_full& rhs)
|
||||||
|
{
|
||||||
|
return lhs.str() == rhs.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// implicit conversion to std::string, but no operator==
|
||||||
|
class key_no_eq : public key_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
key_no_eq() = default;
|
||||||
|
using key_base::key_base;
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
return str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// explicit conversion to std::string, no operator==
|
||||||
|
class key_explicit : public key_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
key_explicit() = default;
|
||||||
|
using key_base::key_base;
|
||||||
|
|
||||||
|
explicit operator std::string() const
|
||||||
|
{
|
||||||
|
return str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// no conversion at all, only a to_json overload, no operator==
|
||||||
|
class key_to_json : public key_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
key_to_json() = default;
|
||||||
|
using key_base::key_base;
|
||||||
|
|
||||||
|
const std::string& value() const
|
||||||
|
{
|
||||||
|
return str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
void to_json(BasicJsonType& j, const key_to_json& k)
|
||||||
|
{
|
||||||
|
j = k.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// like key_to_json, but with size() and c_str()
|
||||||
|
class key_c_str : public key_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
key_c_str() = default;
|
||||||
|
using key_base::key_base;
|
||||||
|
|
||||||
|
const std::string& value() const
|
||||||
|
{
|
||||||
|
return str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size() const
|
||||||
|
{
|
||||||
|
return str().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* c_str() const
|
||||||
|
{
|
||||||
|
return str().c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
void to_json(BasicJsonType& j, const key_c_str& k)
|
||||||
|
{
|
||||||
|
j = k.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::map with key type K, ignoring the key type basic_json passes
|
||||||
|
template<class K>
|
||||||
|
struct object_for
|
||||||
|
{
|
||||||
|
template<class Key, class Value, class Compare, class Allocator>
|
||||||
|
using pair_allocator = typename std::allocator_traits<Allocator>::template rebind_alloc<std::pair<const K, Value>>;
|
||||||
|
|
||||||
|
template<class Key, class Value, class Compare, class Allocator>
|
||||||
|
using type = std::map<K, Value, std::less<K>, pair_allocator<Key, Value, Compare, Allocator>>; // NOLINT(modernize-use-transparent-functors)
|
||||||
|
};
|
||||||
|
|
||||||
|
using json_full = nlohmann::json::with_object_t<object_for<key_full>::type>;
|
||||||
|
using json_no_eq = nlohmann::json::with_object_t<object_for<key_no_eq>::type>;
|
||||||
|
using json_explicit = nlohmann::json::with_object_t<object_for<key_explicit>::type>;
|
||||||
|
using json_to_json = nlohmann::json::with_object_t<object_for<key_to_json>::type>;
|
||||||
|
using json_c_str = nlohmann::json::with_object_t<object_for<key_c_str>::type>;
|
||||||
|
|
||||||
|
// a key that is long enough to need a length byte in CBOR and MessagePack
|
||||||
|
inline const char* long_key_name(std::size_t i, std::string& storage)
|
||||||
|
{
|
||||||
|
storage = "a key longer than thirty-one characters " + std::to_string(i);
|
||||||
|
return storage.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// name of the key at nesting level i of a deep value
|
||||||
|
inline std::string deep_name(std::size_t i, bool long_keys)
|
||||||
|
{
|
||||||
|
std::string storage;
|
||||||
|
return (long_keys && i % 2 == 1) ? std::string(long_key_name(i, storage)) : "k" + std::to_string(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// {"a": 1, "b": [true, null, "x"], "c": {"d": 2.5}, <keys of 23, 36, and 300 characters>}
|
||||||
|
// 23 is the longest CBOR length stored in the initial byte; 36 needs one
|
||||||
|
// length byte in CBOR and MessagePack, 300 needs two
|
||||||
|
template<class J>
|
||||||
|
J make_shallow()
|
||||||
|
{
|
||||||
|
using key_t = typename J::object_t::key_type;
|
||||||
|
|
||||||
|
J array = J::array();
|
||||||
|
array.push_back(J(true));
|
||||||
|
array.push_back(J(nullptr));
|
||||||
|
array.push_back(J("x"));
|
||||||
|
|
||||||
|
typename J::object_t inner;
|
||||||
|
inner.emplace(key_t("d"), J(2.5));
|
||||||
|
|
||||||
|
typename J::object_t object;
|
||||||
|
object.emplace(key_t("a"), J(1));
|
||||||
|
object.emplace(key_t("b"), std::move(array));
|
||||||
|
object.emplace(key_t("c"), J(std::move(inner)));
|
||||||
|
object.emplace(key_t(std::string(23, 'x')), J(2));
|
||||||
|
object.emplace(key_t(std::string(36, 'y')), J(3));
|
||||||
|
object.emplace(key_t(std::string(300, 'z')), J(4));
|
||||||
|
return J(std::move(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
// {"k0": {"k1": {... {"k<depth-1>": 1} ...}}}
|
||||||
|
template<class J>
|
||||||
|
J make_deep(std::size_t depth, bool long_keys)
|
||||||
|
{
|
||||||
|
using key_t = typename J::object_t::key_type;
|
||||||
|
|
||||||
|
J value = 1;
|
||||||
|
for (std::size_t i = depth; i > 0; --i)
|
||||||
|
{
|
||||||
|
typename J::object_t object;
|
||||||
|
object.emplace(key_t(deep_name(i - 1, long_keys)), std::move(value));
|
||||||
|
value = J(std::move(object));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t deep_depth()
|
||||||
|
{
|
||||||
|
return nlohmann::detail::recursion_depth_limit() + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk down the nesting levels without recursion and check the leaf
|
||||||
|
template<class J>
|
||||||
|
bool check_deep(const J& value, std::size_t depth, bool long_keys)
|
||||||
|
{
|
||||||
|
using key_t = typename J::object_t::key_type;
|
||||||
|
|
||||||
|
const J* current = &value;
|
||||||
|
for (std::size_t i = 0; i < depth; ++i)
|
||||||
|
{
|
||||||
|
if (!current->is_object() || current->size() != 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto it = current->find(key_t(deep_name(i, long_keys)));
|
||||||
|
if (it == current->end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
current = &it.value();
|
||||||
|
}
|
||||||
|
return current->is_number_integer() && current->template get<int>() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class J>
|
||||||
|
bool check_shallow(const J& value)
|
||||||
|
{
|
||||||
|
using key_t = typename J::object_t::key_type;
|
||||||
|
|
||||||
|
if (!value.is_object() || value.size() != 6)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto a = value.find(key_t("a"));
|
||||||
|
const auto b = value.find(key_t("b"));
|
||||||
|
const auto c = value.find(key_t("c"));
|
||||||
|
if (a == value.end() || b == value.end() || c == value.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto d = c->find(key_t("d"));
|
||||||
|
// basic_json::operator== needs operator== on the keys, which most of the
|
||||||
|
// key types do not have, so the values are checked through get<>()
|
||||||
|
return a->template get<int>() == 1
|
||||||
|
&& b->is_array() && b->size() == 3 && (*b)[0].template get<bool>() && (*b)[1].is_null()
|
||||||
|
&& (*b)[2].template get<std::string>() == "x"
|
||||||
|
&& d != c->end() && std::abs(d->template get<double>() - 2.5) < 1e-9
|
||||||
|
&& value.find(key_t(std::string(23, 'x')))->template get<int>() == 2
|
||||||
|
&& value.find(key_t(std::string(36, 'y')))->template get<int>() == 3
|
||||||
|
&& value.find(key_t(std::string(300, 'z')))->template get<int>() == 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class J>
|
||||||
|
bool is_missing(const J& value, const char* name)
|
||||||
|
{
|
||||||
|
return value.find(typename J::object_t::key_type(name)) == value.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// member access through find(): at() does not compile for key types without
|
||||||
|
// size() or a conversion to string_t (key_to_json), as in version 3.12.0
|
||||||
|
template<class J>
|
||||||
|
const J& member(const J& value, const char* name)
|
||||||
|
{
|
||||||
|
const auto it = value.find(typename J::object_t::key_type(name));
|
||||||
|
REQUIRE(it != value.end());
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The test cases, as function templates: each unit-custom-key-type-*.cpp file
|
||||||
|
// runs them for one object type only. The MinGW linker fails on objects with
|
||||||
|
// more than 65535 sections, and every basic_json specialization adds many
|
||||||
|
// (see .github/workflows/windows.yml).
|
||||||
|
|
||||||
|
// copy
|
||||||
|
template<class J>
|
||||||
|
void test_copy()
|
||||||
|
{
|
||||||
|
SECTION("shallow")
|
||||||
|
{
|
||||||
|
const J original = custom_key_test::make_shallow<J>();
|
||||||
|
REQUIRE(custom_key_test::check_shallow(original));
|
||||||
|
|
||||||
|
const J copy(original); // NOLINT(performance-unnecessary-copy-initialization)
|
||||||
|
CHECK(custom_key_test::check_shallow(copy));
|
||||||
|
|
||||||
|
J assigned;
|
||||||
|
assigned = original;
|
||||||
|
CHECK(custom_key_test::check_shallow(assigned));
|
||||||
|
|
||||||
|
// the original is unchanged
|
||||||
|
CHECK(custom_key_test::check_shallow(original));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("deep")
|
||||||
|
{
|
||||||
|
const std::size_t depth = custom_key_test::deep_depth();
|
||||||
|
|
||||||
|
const J original = custom_key_test::make_deep<J>(depth, false);
|
||||||
|
REQUIRE(custom_key_test::check_deep(original, depth, false));
|
||||||
|
|
||||||
|
const J copy(original); // NOLINT(performance-unnecessary-copy-initialization)
|
||||||
|
CHECK(custom_key_test::check_deep(copy, depth, false));
|
||||||
|
|
||||||
|
J assigned;
|
||||||
|
assigned = original;
|
||||||
|
CHECK(custom_key_test::check_deep(assigned, depth, false));
|
||||||
|
|
||||||
|
CHECK(custom_key_test::check_deep(original, depth, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse
|
||||||
|
template<class J>
|
||||||
|
void test_parse()
|
||||||
|
{
|
||||||
|
const J j = J::parse(R"({"a":1,"b":{"c":[1,2]}})");
|
||||||
|
|
||||||
|
CHECK(j.size() == 2);
|
||||||
|
CHECK(custom_key_test::member(j, "a").template get<int>() == 1);
|
||||||
|
CHECK(custom_key_test::member(custom_key_test::member(j, "b"), "c").size() == 2);
|
||||||
|
CHECK(custom_key_test::member(custom_key_test::member(j, "b"), "c")[1].template get<int>() == 2);
|
||||||
|
|
||||||
|
// a deeply nested document
|
||||||
|
const std::size_t depth = custom_key_test::deep_depth();
|
||||||
|
std::string text;
|
||||||
|
for (std::size_t i = 0; i < depth; ++i)
|
||||||
|
{
|
||||||
|
text += "{\"k" + std::to_string(i) + "\":";
|
||||||
|
}
|
||||||
|
text += '1';
|
||||||
|
text.append(depth, '}');
|
||||||
|
CHECK(custom_key_test::check_deep(J::parse(text), depth, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge_patch, update, and insert
|
||||||
|
template<class J>
|
||||||
|
void test_patch()
|
||||||
|
{
|
||||||
|
SECTION("merge_patch")
|
||||||
|
{
|
||||||
|
J j = J::parse(R"({"a":1,"b":2,"n":{"x":1,"y":2}})");
|
||||||
|
j.merge_patch(J::parse(R"({"b":null,"c":3,"n":{"y":null,"z":3}})"));
|
||||||
|
|
||||||
|
CHECK(j.size() == 3);
|
||||||
|
CHECK(custom_key_test::member(j, "a").template get<int>() == 1);
|
||||||
|
CHECK(custom_key_test::is_missing(j, "b"));
|
||||||
|
CHECK(custom_key_test::member(j, "c").template get<int>() == 3);
|
||||||
|
CHECK(custom_key_test::member(j, "n").size() == 2);
|
||||||
|
CHECK(custom_key_test::member(custom_key_test::member(j, "n"), "x").template get<int>() == 1);
|
||||||
|
CHECK(custom_key_test::member(custom_key_test::member(j, "n"), "z").template get<int>() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("update")
|
||||||
|
{
|
||||||
|
J j = J::parse(R"({"a":1,"b":2,"n":{"x":1}})");
|
||||||
|
const J other = J::parse(R"({"b":3,"c":4,"n":{"y":2}})");
|
||||||
|
|
||||||
|
J replaced = j;
|
||||||
|
replaced.update(other);
|
||||||
|
CHECK(replaced.size() == 4);
|
||||||
|
CHECK(custom_key_test::member(replaced, "a").template get<int>() == 1);
|
||||||
|
CHECK(custom_key_test::member(replaced, "b").template get<int>() == 3);
|
||||||
|
CHECK(custom_key_test::member(replaced, "c").template get<int>() == 4);
|
||||||
|
CHECK(custom_key_test::member(replaced, "n").size() == 1);
|
||||||
|
CHECK(custom_key_test::member(custom_key_test::member(replaced, "n"), "y").template get<int>() == 2);
|
||||||
|
|
||||||
|
j.update(other, true);
|
||||||
|
CHECK(j.size() == 4);
|
||||||
|
CHECK(custom_key_test::member(j, "n").size() == 2);
|
||||||
|
CHECK(custom_key_test::member(custom_key_test::member(j, "n"), "x").template get<int>() == 1);
|
||||||
|
CHECK(custom_key_test::member(custom_key_test::member(j, "n"), "y").template get<int>() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("insert")
|
||||||
|
{
|
||||||
|
J j = J::parse(R"({"a":1,"b":2})");
|
||||||
|
const J other = J::parse(R"({"b":3,"c":4})");
|
||||||
|
j.insert(other.begin(), other.end());
|
||||||
|
|
||||||
|
CHECK(j.size() == 3);
|
||||||
|
CHECK(custom_key_test::member(j, "b").template get<int>() == 2);
|
||||||
|
CHECK(custom_key_test::member(j, "c").template get<int>() == 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// at() reports a missing key
|
||||||
|
template<class J>
|
||||||
|
void test_at()
|
||||||
|
{
|
||||||
|
// not for key_to_json: at() needs the key's size() or a conversion to
|
||||||
|
// string_t for its error message, which also was the case in version 3.12.0
|
||||||
|
J j = J::parse(R"({"a":1})");
|
||||||
|
const J& j_const = j;
|
||||||
|
|
||||||
|
CHECK(j.at("a").template get<int>() == 1);
|
||||||
|
CHECK(j_const.at("a").template get<int>() == 1);
|
||||||
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
CHECK_THROWS_WITH_AS(j.at("missing"), "[json.exception.out_of_range.403] (bytes 0-7) key 'missing' not found", typename J::out_of_range&);
|
||||||
|
CHECK_THROWS_WITH_AS(j_const.at("missing"), "[json.exception.out_of_range.403] (bytes 0-7) key 'missing' not found", typename J::out_of_range&);
|
||||||
|
#else
|
||||||
|
CHECK_THROWS_WITH_AS(j.at("missing"), "[json.exception.out_of_range.403] key 'missing' not found", typename J::out_of_range&);
|
||||||
|
CHECK_THROWS_WITH_AS(j_const.at("missing"), "[json.exception.out_of_range.403] key 'missing' not found", typename J::out_of_range&);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSON
|
||||||
|
template<class J>
|
||||||
|
void test_bson()
|
||||||
|
{
|
||||||
|
SECTION("shallow")
|
||||||
|
{
|
||||||
|
const J value = custom_key_test::make_shallow<J>();
|
||||||
|
const nlohmann::json expected = custom_key_test::make_shallow<nlohmann::json>();
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> encoded = J::to_bson(value);
|
||||||
|
CHECK(encoded == nlohmann::json::to_bson(expected));
|
||||||
|
CHECK(nlohmann::json::from_bson(encoded) == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("deep")
|
||||||
|
{
|
||||||
|
const std::size_t depth = custom_key_test::deep_depth();
|
||||||
|
const J value = custom_key_test::make_deep<J>(depth, false);
|
||||||
|
const nlohmann::json expected = custom_key_test::make_deep<nlohmann::json>(depth, false);
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> encoded = J::to_bson(value);
|
||||||
|
CHECK(encoded == nlohmann::json::to_bson(expected));
|
||||||
|
CHECK(nlohmann::json::from_bson(encoded) == expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CBOR
|
||||||
|
template<class J>
|
||||||
|
void test_cbor()
|
||||||
|
{
|
||||||
|
SECTION("shallow")
|
||||||
|
{
|
||||||
|
const J value = custom_key_test::make_shallow<J>();
|
||||||
|
const nlohmann::json expected = custom_key_test::make_shallow<nlohmann::json>();
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> encoded = J::to_cbor(value);
|
||||||
|
CHECK(encoded == nlohmann::json::to_cbor(expected));
|
||||||
|
CHECK(nlohmann::json::from_cbor(encoded) == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("deeper than the recursion depth limit")
|
||||||
|
{
|
||||||
|
const std::size_t depth = custom_key_test::deep_depth();
|
||||||
|
const J value = custom_key_test::make_deep<J>(depth, true);
|
||||||
|
const nlohmann::json expected = custom_key_test::make_deep<nlohmann::json>(depth, true);
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> encoded = J::to_cbor(value);
|
||||||
|
CHECK(encoded == nlohmann::json::to_cbor(expected));
|
||||||
|
CHECK(nlohmann::json::from_cbor(encoded) == expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessagePack
|
||||||
|
template<class J>
|
||||||
|
void test_msgpack()
|
||||||
|
{
|
||||||
|
SECTION("shallow")
|
||||||
|
{
|
||||||
|
const J value = custom_key_test::make_shallow<J>();
|
||||||
|
const nlohmann::json expected = custom_key_test::make_shallow<nlohmann::json>();
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> encoded = J::to_msgpack(value);
|
||||||
|
CHECK(encoded == nlohmann::json::to_msgpack(expected));
|
||||||
|
CHECK(nlohmann::json::from_msgpack(encoded) == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("deeper than the recursion depth limit")
|
||||||
|
{
|
||||||
|
const std::size_t depth = custom_key_test::deep_depth();
|
||||||
|
const J value = custom_key_test::make_deep<J>(depth, true);
|
||||||
|
const nlohmann::json expected = custom_key_test::make_deep<nlohmann::json>(depth, true);
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> encoded = J::to_msgpack(value);
|
||||||
|
CHECK(encoded == nlohmann::json::to_msgpack(expected));
|
||||||
|
CHECK(nlohmann::json::from_msgpack(encoded) == expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace custom_key_test
|
||||||
@@ -71,5 +71,5 @@ class object
|
|||||||
using base_type::base_type;
|
using base_type::base_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
using json = nlohmann::basic_json<object>;
|
using json = nlohmann::json::with_object_t<object>;
|
||||||
} // namespace custom_object_key_test
|
} // namespace custom_object_key_test
|
||||||
@@ -55,25 +55,9 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include "fuzzer_common.hpp"
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
// the round-trip checks below are assertions; NDEBUG would compile them away
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "the fuzzer drivers must be built without NDEBUG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuzzer-recovering_checker.hpp"
|
#include "fuzzer-recovering_checker.hpp"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
|
||||||
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
|
||||||
static bool same_value(const json& lhs, const json& rhs)
|
|
||||||
{
|
|
||||||
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
}
|
|
||||||
|
|
||||||
// value-stable comparison for the round-trip checks below; see the note
|
// value-stable comparison for the round-trip checks below; see the note
|
||||||
// above on why this compares dump()s rather than the json values directly
|
// above on why this compares dump()s rather than the json values directly
|
||||||
static bool is_value_stable(const json& lhs, const json& rhs)
|
static bool is_value_stable(const json& lhs, const json& rhs)
|
||||||
@@ -89,23 +73,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
|
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions; a parse error must then be
|
// step 0: parse input without exceptions
|
||||||
// reported as a discarded value, never thrown
|
|
||||||
json j_noexcept;
|
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
try
|
json const j_noexcept = parse_without_exceptions([&] { return json::from_bjdata(vec1, true, false); }, noexcept_threw);
|
||||||
{
|
|
||||||
j_noexcept = json::from_bjdata(vec1, true, false);
|
|
||||||
}
|
|
||||||
catch (const json::parse_error&)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch (const json::exception&)
|
|
||||||
{
|
|
||||||
// type and out-of-range errors are not parse errors and still throw
|
|
||||||
noexcept_threw = true;
|
|
||||||
}
|
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -29,26 +29,10 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <nlohmann/json.hpp>
|
#include "fuzzer_common.hpp"
|
||||||
|
|
||||||
// the round-trip checks below are assertions; NDEBUG would compile them away
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "the fuzzer drivers must be built without NDEBUG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuzzer-recovering_checker.hpp"
|
#include "fuzzer-recovering_checker.hpp"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
|
||||||
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
|
||||||
static bool same_value(const json& lhs, const json& rhs)
|
|
||||||
{
|
|
||||||
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// the serialization of the value read from @a input, or the error message
|
// the serialization of the value read from @a input, or the error message
|
||||||
@@ -81,23 +65,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
|
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions; a parse error must then be
|
// step 0: parse input without exceptions
|
||||||
// reported as a discarded value, never thrown
|
|
||||||
json j_noexcept;
|
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
try
|
json const j_noexcept = parse_without_exceptions([&] { return json::from_bon8(vec1, true, false); }, noexcept_threw);
|
||||||
{
|
|
||||||
j_noexcept = json::from_bon8(vec1, true, false);
|
|
||||||
}
|
|
||||||
catch (const json::parse_error&)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch (const json::exception&)
|
|
||||||
{
|
|
||||||
// type and out-of-range errors are not parse errors and still throw
|
|
||||||
noexcept_threw = true;
|
|
||||||
}
|
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -25,25 +25,9 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include "fuzzer_common.hpp"
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
// the round-trip checks below are assertions; NDEBUG would compile them away
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "the fuzzer drivers must be built without NDEBUG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuzzer-recovering_checker.hpp"
|
#include "fuzzer-recovering_checker.hpp"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
|
||||||
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
|
||||||
static bool same_value(const json& lhs, const json& rhs)
|
|
||||||
{
|
|
||||||
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
}
|
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
@@ -52,23 +36,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
|
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions; a parse error must then be
|
// step 0: parse input without exceptions
|
||||||
// reported as a discarded value, never thrown
|
|
||||||
json j_noexcept;
|
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
try
|
json const j_noexcept = parse_without_exceptions([&] { return json::from_bson(vec1, true, false); }, noexcept_threw);
|
||||||
{
|
|
||||||
j_noexcept = json::from_bson(vec1, true, false);
|
|
||||||
}
|
|
||||||
catch (const json::parse_error&)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch (const json::exception&)
|
|
||||||
{
|
|
||||||
// type and out-of-range errors are not parse errors and still throw
|
|
||||||
noexcept_threw = true;
|
|
||||||
}
|
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -25,25 +25,9 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include "fuzzer_common.hpp"
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
// the round-trip checks below are assertions; NDEBUG would compile them away
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "the fuzzer drivers must be built without NDEBUG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuzzer-recovering_checker.hpp"
|
#include "fuzzer-recovering_checker.hpp"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
|
||||||
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
|
||||||
static bool same_value(const json& lhs, const json& rhs)
|
|
||||||
{
|
|
||||||
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
}
|
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
@@ -52,23 +36,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
|
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions; a parse error must then be
|
// step 0: parse input without exceptions
|
||||||
// reported as a discarded value, never thrown
|
|
||||||
json j_noexcept;
|
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
try
|
json const j_noexcept = parse_without_exceptions([&] { return json::from_cbor(vec1, true, false); }, noexcept_threw);
|
||||||
{
|
|
||||||
j_noexcept = json::from_cbor(vec1, true, false);
|
|
||||||
}
|
|
||||||
catch (const json::parse_error&)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch (const json::exception&)
|
|
||||||
{
|
|
||||||
// type and out-of-range errors are not parse errors and still throw
|
|
||||||
noexcept_threw = true;
|
|
||||||
}
|
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -26,25 +26,9 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include "fuzzer_common.hpp"
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
// the round-trip checks below are assertions; NDEBUG would compile them away
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "the fuzzer drivers must be built without NDEBUG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuzzer-recovering_checker.hpp"
|
#include "fuzzer-recovering_checker.hpp"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
|
||||||
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
|
||||||
static bool same_value(const json& lhs, const json& rhs)
|
|
||||||
{
|
|
||||||
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
}
|
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
@@ -55,23 +39,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
assert((checker.errors == 0) == json::accept(data, data + size));
|
assert((checker.errors == 0) == json::accept(data, data + size));
|
||||||
}
|
}
|
||||||
|
|
||||||
// step 0: parse input without exceptions; a parse error must then be
|
// step 0: parse input without exceptions
|
||||||
// reported as a discarded value, never thrown
|
|
||||||
json j_noexcept;
|
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
try
|
json const j_noexcept = parse_without_exceptions([&] { return json::parse(data, data + size, nullptr, false); }, noexcept_threw);
|
||||||
{
|
|
||||||
j_noexcept = json::parse(data, data + size, nullptr, false);
|
|
||||||
}
|
|
||||||
catch (const json::parse_error&)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch (const json::exception&)
|
|
||||||
{
|
|
||||||
// type and out-of-range errors are not parse errors and still throw
|
|
||||||
noexcept_threw = true;
|
|
||||||
}
|
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -25,25 +25,9 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include "fuzzer_common.hpp"
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
// the round-trip checks below are assertions; NDEBUG would compile them away
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "the fuzzer drivers must be built without NDEBUG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuzzer-recovering_checker.hpp"
|
#include "fuzzer-recovering_checker.hpp"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
|
||||||
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
|
||||||
static bool same_value(const json& lhs, const json& rhs)
|
|
||||||
{
|
|
||||||
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
}
|
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
@@ -52,23 +36,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
|
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions; a parse error must then be
|
// step 0: parse input without exceptions
|
||||||
// reported as a discarded value, never thrown
|
|
||||||
json j_noexcept;
|
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
try
|
json const j_noexcept = parse_without_exceptions([&] { return json::from_msgpack(vec1, true, false); }, noexcept_threw);
|
||||||
{
|
|
||||||
j_noexcept = json::from_msgpack(vec1, true, false);
|
|
||||||
}
|
|
||||||
catch (const json::parse_error&)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch (const json::exception&)
|
|
||||||
{
|
|
||||||
// type and out-of-range errors are not parse errors and still throw
|
|
||||||
noexcept_threw = true;
|
|
||||||
}
|
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -34,25 +34,9 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include "fuzzer_common.hpp"
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
// the round-trip checks below are assertions; NDEBUG would compile them away
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "the fuzzer drivers must be built without NDEBUG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuzzer-recovering_checker.hpp"
|
#include "fuzzer-recovering_checker.hpp"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
|
||||||
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
|
||||||
static bool same_value(const json& lhs, const json& rhs)
|
|
||||||
{
|
|
||||||
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
}
|
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
@@ -61,23 +45,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
|
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions; a parse error must then be
|
// step 0: parse input without exceptions
|
||||||
// reported as a discarded value, never thrown
|
|
||||||
json j_noexcept;
|
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
try
|
json const j_noexcept = parse_without_exceptions([&] { return json::from_ubjson(vec1, true, false); }, noexcept_threw);
|
||||||
{
|
|
||||||
j_noexcept = json::from_ubjson(vec1, true, false);
|
|
||||||
}
|
|
||||||
catch (const json::parse_error&)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch (const json::exception&)
|
|
||||||
{
|
|
||||||
// type and out-of-range errors are not parse errors and still throw
|
|
||||||
noexcept_threw = true;
|
|
||||||
}
|
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
Loaded 100 of 116 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user