Compare commits
109
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa01cf20dc | ||
|
|
4de0133cfc | ||
|
|
d547e3bfec | ||
|
|
8af1dc4ef4 | ||
|
|
5331e1ad6f | ||
|
|
e3423b2a0a | ||
|
|
fea6e8dd4b | ||
|
|
d61e61baa1 | ||
|
|
26b37690e9 | ||
|
|
dd4773e8c0 | ||
|
|
bad66b8707 | ||
|
|
0c9aab60c9 | ||
|
|
84367f79d1 | ||
|
|
b12ddeee94 | ||
|
|
540db5c385 | ||
|
|
ab7f9a2027 | ||
|
|
ebf991636d | ||
|
|
ed79a4b1aa | ||
|
|
6dd4b03202 | ||
|
|
df22c17c9b | ||
|
|
4a4501f3ea | ||
|
|
93a69864c6 | ||
|
|
efe02e0741 | ||
|
|
a6efb9335a | ||
|
|
f274a1b70d | ||
|
|
12610c5664 | ||
|
|
7e9b99635a | ||
|
|
71e4c84e91 | ||
|
|
949df24b1a | ||
|
|
2a3293079d | ||
|
|
fb39dc807e | ||
|
|
e86cd18fca | ||
|
|
f33fdebb27 | ||
|
|
2135653299 | ||
|
|
bd54e27937 | ||
|
|
736639bb39 | ||
|
|
5c7e407f51 | ||
|
|
b861264127 | ||
|
|
5e25168741 | ||
|
|
6da03bd6a3 | ||
|
|
c9691f2d61 | ||
|
|
70fd3d891a | ||
|
|
dddc9be9b8 | ||
|
|
87345f71da | ||
|
|
68196aa445 | ||
|
|
f2bf9b7bf7 | ||
|
|
1d29b01d84 | ||
|
|
6d72dad8fd | ||
|
|
489a1a120a | ||
|
|
934655fc88 | ||
|
|
327832c968 | ||
|
|
d1dcc11adc | ||
|
|
5b256af6f6 | ||
|
|
c562bbb5c8 | ||
|
|
ccca948c23 | ||
|
|
f7a9f9bd69 | ||
|
|
22e7a3c27a | ||
|
|
d5fd35ec95 | ||
|
|
c50d10be76 | ||
|
|
40d518f2d7 | ||
|
|
4a70524e9b | ||
|
|
d09643e3e3 | ||
|
|
890918a310 | ||
|
|
ad89113e82 | ||
|
|
30fc666df7 | ||
|
|
913bdc26ec | ||
|
|
9178d1c40c | ||
|
|
9e05cb7942 | ||
|
|
47f24b64f3 | ||
|
|
5bc15dd9ec | ||
|
|
0a4fa95d37 | ||
|
|
58510535b8 | ||
|
|
6a4adb908d | ||
|
|
29b3c0c133 | ||
|
|
4fe127d2f9 | ||
|
|
9105130cd6 | ||
|
|
26820493c7 | ||
|
|
5ed7ac57bc | ||
|
|
45fb3ee7e2 | ||
|
|
0460fc997b | ||
|
|
ff3cb67362 | ||
|
|
246d8527db | ||
|
|
b7bd190efa | ||
|
|
ca9db1910b | ||
|
|
c71fe8da35 | ||
|
|
e9e97f1d3e | ||
|
|
42ab1fa573 | ||
|
|
624f4b030d | ||
|
|
758b6a76fe | ||
|
|
6052e793c0 | ||
|
|
0c3caee646 | ||
|
|
624660b04e | ||
|
|
d7f97d140d | ||
|
|
e587d3e5fd | ||
|
|
bed7ff801e | ||
|
|
cd787fb0f7 | ||
|
|
88dc1e6ae2 | ||
|
|
18c4935d99 | ||
|
|
f0fc46fa03 | ||
|
|
4dcba03757 | ||
|
|
402cb4f835 | ||
|
|
32d4f7fa33 | ||
|
|
f4aceabef3 | ||
|
|
6952ff6363 | ||
|
|
f5f864298c | ||
|
|
40dbea3de2 | ||
|
|
80e2aae3e2 | ||
|
|
f56f36c188 | ||
|
|
0f6c4dda11 |
No files matched your search
+3
-10
@@ -108,16 +108,9 @@ The tests are located in [`tests/src/unit-*.cpp`](https://github.com/nlohmann/js
|
||||
are structured along the features of the library or the nature of the tests. Usually, it should be clear from the
|
||||
context which existing file needs to be extended, and only very few cases require creating new test files.
|
||||
|
||||
When fixing a bug, edit `unit-regression3.cpp` and add a section referencing the fixed issue. Tests that need C++17 or
|
||||
C++20 go into `unit-regression3-cpp17.cpp` or `unit-regression3-cpp20.cpp` instead, so the large file is not rebuilt
|
||||
for every C++ standard. `unit-regression2.cpp` holds the older tests; the two files exist because a single one grew
|
||||
large enough for the MinGW linker to fail relocating it, so please keep adding to the smaller file rather than growing
|
||||
the larger one.
|
||||
|
||||
To keep compile times down, several test files are compiled together as one translation unit. This sets a few rules
|
||||
for test files, such as giving file-scope helpers file-specific names. See the README in the
|
||||
[`tests`](https://github.com/nlohmann/json/tree/develop/tests) folder for how the tests are built and what to keep in
|
||||
mind when adding them.
|
||||
When fixing a bug, edit `unit-regression3.cpp` and add a section referencing the fixed issue.
|
||||
`unit-regression2.cpp` holds the older tests; the two files exist because a single one grew large enough for the
|
||||
MinGW linker to fail relocating it, so please keep adding to the smaller file rather than growing the larger one.
|
||||
|
||||
#### Exceptions
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -31,13 +31,13 @@ jobs:
|
||||
mkdir -p ./pr
|
||||
echo ${{ github.event.number }} > ./pr/number
|
||||
echo ${{ github.event.pull_request.user.login }} > ./pr/author
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: pr
|
||||
path: pr/
|
||||
|
||||
check:
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
MAIN_DIR: ${{ github.workspace }}/main
|
||||
INCLUDE_DIR: ${{ github.workspace }}/main/single_include/nlohmann
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -77,12 +77,13 @@ jobs:
|
||||
cd $MAIN_DIR
|
||||
|
||||
# Built from this PR's own tools/macro_builder/main.cpp, not a
|
||||
# develop checkout: unlike amalgamate.py, this tool has no other
|
||||
# source of truth to check against (its own README documents that
|
||||
# it must reproduce macro_scope.hpp 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 that adds support for a new
|
||||
# dispatch table until that PR itself merges to develop.
|
||||
# develop checkout: unlike amalgamate.py and generate_natvis.py,
|
||||
# this tool has no other source of truth to check against (its
|
||||
# own README documents that it must reproduce macro_scope.hpp
|
||||
# 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
|
||||
# that adds support for a new dispatch table until that PR itself
|
||||
# merges to develop.
|
||||
TMPDIR=$(mktemp -d ./macro_builder_check.XXXXXX)
|
||||
c++ -std=c++11 tools/macro_builder/main.cpp -o "$TMPDIR/macro_builder"
|
||||
"$TMPDIR/macro_builder" > "$TMPDIR/paste.hpp"
|
||||
@@ -145,14 +146,14 @@ jobs:
|
||||
- name: Regenerate nlohmann_json.natvis
|
||||
run: |
|
||||
cd $MAIN_DIR
|
||||
# The generator and its template are what this check verifies the
|
||||
# committed natvis file against (which namespaces it lists, and
|
||||
# what each entry looks like), so run this PR's copy rather than
|
||||
# the develop checkout's: with develop's, a PR that changes either
|
||||
# could never pass. generate_natvis.py loads the template from its
|
||||
# own directory. Like the macro_builder step above, this only runs
|
||||
# PR content in a job without credentials.
|
||||
python3 tools/generate_natvis/generate_natvis.py $MAIN_DIR
|
||||
# The template is what this check verifies the committed natvis
|
||||
# file against, so take it from this PR rather than from the
|
||||
# develop checkout: generate_natvis.py loads the template from its
|
||||
# own directory, and with develop's copy a PR that changes the
|
||||
# template could never pass. Like the macro_builder step above,
|
||||
# this only renders PR content in a job without credentials.
|
||||
cp tools/generate_natvis/nlohmann_json.natvis.j2 $NATVIS_TOOL_DIR/
|
||||
python3 $NATVIS_TOOL_DIR/generate_natvis.py $MAIN_DIR
|
||||
|
||||
- name: Build patch and check for differences
|
||||
id: diff
|
||||
@@ -172,7 +173,7 @@ jobs:
|
||||
# instead of installing the pinned astyle version locally.
|
||||
- name: Upload patch
|
||||
if: steps.diff.outputs.has_diff == 'true'
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: amalgamation-patch
|
||||
path: patch/amalgamation.patch
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
dry-run: false
|
||||
language: c++
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
|
||||
@@ -21,13 +21,13 @@ permissions:
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -38,14 +38,14 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
with:
|
||||
languages: c-cpp
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -47,6 +47,6 @@ jobs:
|
||||
output: 'flawfinder_results.sarif'
|
||||
|
||||
- name: Upload analysis results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
with:
|
||||
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0
|
||||
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -80,6 +80,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -33,10 +33,10 @@ jobs:
|
||||
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
||||
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
|
||||
name: Scan
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
|
||||
# Upload SARIF file generated in previous step
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
with:
|
||||
sarif_file: semgrep.sarif
|
||||
if: always()
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -25,20 +25,20 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
run: cmake --build build --target ci_test_gcc
|
||||
|
||||
ci_meson_install:
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Check that Meson and pkg-config offer the CMake options
|
||||
run: make check_build_options
|
||||
- name: Install Meson
|
||||
@@ -77,10 +77,10 @@ jobs:
|
||||
cmake --build build-import-split
|
||||
|
||||
ci_infer:
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -92,27 +92,27 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
run: cmake --build build --target ci_infer
|
||||
- name: Archive Infer report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: infer-report
|
||||
path: ${{ github.workspace }}/build/build_infer/infer-out/report.txt
|
||||
if-no-files-found: ignore
|
||||
|
||||
ci_static_analysis_ubuntu:
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
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:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -123,7 +123,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -142,7 +142,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -168,17 +168,17 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
run: cmake --build build --target ${{ matrix.target }}
|
||||
|
||||
ci_test_coverage:
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
- name: Build
|
||||
run: cmake --build build --target ci_test_coverage
|
||||
- name: Archive coverage report
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: code-coverage-report
|
||||
path: ${{ github.workspace }}/build/html
|
||||
@@ -244,7 +244,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: CXX=g++-${{ matrix.compiler }} cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -262,7 +262,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -279,7 +279,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- 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"
|
||||
if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }}
|
||||
@@ -299,7 +299,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -319,7 +319,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build with libc++
|
||||
@@ -346,7 +346,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -366,7 +366,7 @@ jobs:
|
||||
# import-std support. Its opt-in token is CMake-version-specific, so pin
|
||||
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
|
||||
- name: Get pinned CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
with:
|
||||
cmakeVersion: 4.3.4
|
||||
# Clang: the std library module is provided by libc++ (the image's libstdc++
|
||||
@@ -392,7 +392,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -409,7 +409,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -423,17 +423,17 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
run: cmake --build build --target ci_nvhpc
|
||||
|
||||
ci_emscripten:
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -443,20 +443,20 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -GNinja
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
ci_test_documentation:
|
||||
runs-on: ubuntu-26.04
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_test_examples, ci_test_build_documentation, ci_test_documentation_mermaid]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
uses: step-security/harden-runner@351661ca32ac09a36dc5ee2d536e3128f2a3c8ed # v2.22.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -465,7 +465,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
# the git-revision-date-localized plugin needs the history; a shallow clone makes the strict build fail
|
||||
fetch-depth: ${{ matrix.target == 'ci_test_build_documentation' && '0' || '1' }}
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
if: matrix.target == 'ci_test_documentation_mermaid'
|
||||
with:
|
||||
node-version: 24
|
||||
@@ -484,7 +484,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Check that the job runs natively on arm64
|
||||
run: uname -m && test "$(uname -m)" = aarch64
|
||||
- name: Run CMake
|
||||
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Set extra CXX_FLAGS for latest std_version
|
||||
# /wd5285 silences C5285 emitted by the bundled third-party doctest.h, which
|
||||
# specializes std::tuple (newly diagnosed by the VS2026 v145 toolset)
|
||||
@@ -166,21 +166,19 @@ jobs:
|
||||
# link, but the binaries clang 11.0.1 and clang 18.1.8 then produce crash
|
||||
# before doctest prints its first line - 39 of 102 tests on clang 18.
|
||||
# Keep the objects small by splitting the test files instead.
|
||||
# The tests link with LLD: GNU ld fails on objects with more than 32767
|
||||
# sections with "relocation truncated to fit: IMAGE_REL_AMD64_REL32
|
||||
# against `.rdata'", as it stores the section an associative COMDAT
|
||||
# section belongs to in 16 bits (x_associated in binutils'
|
||||
# include/coff/internal.h) and so discards the jump tables of inline
|
||||
# functions together with the wrong function. Each basic_json
|
||||
# specialization and input type a test file instantiates adds many
|
||||
# sections, so unit-msgpack.cpp and unit-regression2.cpp kept crossing
|
||||
# that limit as the library grew.
|
||||
# Objects with more than 65535 sections fail to link with "relocation
|
||||
# truncated to fit: IMAGE_REL_AMD64_REL32 against `.rdata'": the MinGW
|
||||
# linker stores the section an associative COMDAT section belongs to in
|
||||
# 16 bits (x_associated in binutils' include/coff/internal.h), so it
|
||||
# discards the jump tables of inline functions together with the wrong
|
||||
# function. Each basic_json specialization a test file instantiates adds
|
||||
# many sections, so test a second one in a file of its own.
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build ^
|
||||
-DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" ^
|
||||
-DCMAKE_CXX_FLAGS="--target=x86_64-w64-mingw32 -stdlib=libstdc++ -pthread" ^
|
||||
-DCMAKE_CXX_FLAGS_DEBUG="-g0" ^
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld -lwinpthread" ^
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-lwinpthread" ^
|
||||
-G"MinGW Makefiles" ^
|
||||
-DCMAKE_BUILD_TYPE=Debug ^
|
||||
-DJSON_BuildTests=On
|
||||
@@ -216,7 +214,7 @@ jobs:
|
||||
# import-std support. Its opt-in token is CMake-version-specific, so pin
|
||||
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
|
||||
- name: Get pinned CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
with:
|
||||
cmakeVersion: 4.3.4
|
||||
# CMAKE_CXX_FLAGS replaces CMake's MSVC defaults (which include /EHsc), and
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"_comment": "Used by the ci_infer CMake target (#5715 item 4b). fail-on-issue makes CI fail on Infer findings; disable-issue-type is a type-level baseline for the ~174 pre-existing findings (all PULSE_UNNECESSARY_COPY*/PULSE_RESOURCE_LEAK/PULSE_CONST_REFABLE, mostly in test code) triaged in run https://github.com/nlohmann/json/actions/runs/35829411620 on commit 1054b2097, so CI fails only on a NEW issue type. Remove an entry here once its findings have been fixed or explicitly accepted.",
|
||||
"_comment_pulse": "Pulse stops exploring paths after pulse-max-disjuncts (default 20). With the default, basic_json::replace_value() (destroy + assert_invariant) exceeds the limit, Pulse loses the stored type, and reports false NULLPTR_DEREFERENCE findings for get_ptr() results in tests/src/unit-pointer_access.cpp.",
|
||||
"_comment_view": "Infer's model of std::unique_ptr mixes up values that are returned by value and own one: basic_json_document (parse() results) and the `built` values of the build() helper in tests/src/unit-json_view_builder.cpp. It reports USE_AFTER_DELETE for one of them after the destructor of an unrelated object (e.g. ~built() on line 345 invalidating `shallow` on line 350 of that file, or two documents parsed in one lambda in tests/src/unit-json_view_dump.cpp). AddressSanitizer and Valgrind are clean on the same tests, so reports for the json_view test files are excluded; findings reported in the library headers are still reported.",
|
||||
"pulse-max-disjuncts": 40,
|
||||
"fail-on-issue": true,
|
||||
"disable-issue-type": [
|
||||
@@ -11,8 +10,5 @@
|
||||
"PULSE_UNNECESSARY_COPY_OPTIONAL",
|
||||
"PULSE_RESOURCE_LEAK",
|
||||
"PULSE_CONST_REFABLE"
|
||||
],
|
||||
"report-block-list-path-regex": [
|
||||
"tests/src/unit-json_view.*\\.cpp"
|
||||
]
|
||||
}
|
||||
+7
-14
@@ -361,10 +361,10 @@ add_custom_target(ci_test_coverage
|
||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_coverage32
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_coverage32 && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
|
||||
|
||||
COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 --ignore-errors mismatch --ignore-errors unused --ignore-errors inconsistent
|
||||
COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc branch_coverage=1 --ignore-errors unused --ignore-errors inconsistent
|
||||
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 ${CMAKE_SOURCE_DIR}/tests/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept
|
||||
COMMAND ${GENHTML_TOOL} --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage --ignore-errors inconsistent 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"
|
||||
)
|
||||
@@ -488,13 +488,6 @@ add_custom_target(ci_clang_analyze
|
||||
# Check code with Cppcheck.
|
||||
###############################################################################
|
||||
|
||||
# default_defines.hpp expands the Hedley macros to the compiler's feature-test operators, which Cppcheck does not know.
|
||||
# Since Cppcheck 2.20, it rejects their invocations in #if conditions instead of evaluating them as 0.
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/cppcheck_feature_tests.hpp "")
|
||||
foreach(OPERATOR __has_attribute __has_builtin __has_cpp_attribute __has_declspec_attribute __has_extension __has_feature __has_include __has_warning)
|
||||
file(APPEND ${CMAKE_BINARY_DIR}/cppcheck_feature_tests.hpp "#define ${OPERATOR}(x) 0\n")
|
||||
endforeach()
|
||||
|
||||
add_custom_target(ci_cppcheck
|
||||
COMMAND mkdir -p cppcheck
|
||||
COMMAND clang -dM -E -x c++ -std=c++11 ${CMAKE_SOURCE_DIR}/include/nlohmann/thirdparty/hedley/hedley.hpp > default_defines.hpp 2> /dev/null
|
||||
@@ -503,7 +496,7 @@ add_custom_target(ci_cppcheck
|
||||
COMMAND venv_cppcheck/bin/cppcheck --enable=warning --check-level=exhaustive --inline-suppr --inconclusive --force
|
||||
--std=c++11 ${PROJECT_SOURCE_DIR}/include/nlohmann/json.hpp -I ${CMAKE_SOURCE_DIR}/include
|
||||
--error-exitcode=1 --relative-paths=${PROJECT_SOURCE_DIR} -j ${N} --include=default_defines.hpp
|
||||
--include=${CMAKE_BINARY_DIR}/cppcheck_feature_tests.hpp --cppcheck-build-dir=cppcheck
|
||||
--cppcheck-build-dir=cppcheck
|
||||
-UJSON_CATCH_USER -UJSON_TRY_USER -UJSON_ASSERT -UJSON_INTERNAL_CATCH -UJSON_THROW
|
||||
-DJSON_HAS_CPP_11 -UJSON_HAS_CPP_14 -UJSON_HAS_CPP_17 -UJSON_HAS_CPP_20 -UJSON_HAS_THREE_WAY_COMPARISON
|
||||
COMMENT "Check code with Cppcheck"
|
||||
@@ -890,11 +883,11 @@ add_custom_target(ci_icpx
|
||||
# The following tests are excluded as they trigger known nvc++ 25.5 defects (not
|
||||
# library bugs); see https://github.com/nlohmann/json for tracking. Only the
|
||||
# affected language-standard variants are excluded so coverage is otherwise kept:
|
||||
# - test-comparison-cpp20_cpp20, test-comparison_legacy-cpp20_cpp20
|
||||
# - test-comparison_cpp20, test-comparison_legacy_cpp20
|
||||
# miscompiles cross-type/<=> comparison (e.g. `-17 <= null`)
|
||||
# - test-constructor1_cpp11
|
||||
# std::initializer_list lifetime bug -> SIGSEGV
|
||||
# - test-deserialization-cpp20_cpp20
|
||||
# - test-deserialization_cpp20
|
||||
# mangles the UTF-8 u8"" string literal in the char8_t (C++20) section
|
||||
add_custom_target(ci_nvhpc
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
@@ -906,7 +899,7 @@ add_custom_target(ci_nvhpc
|
||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_nvhpc
|
||||
# the pipes are escaped so the surrounding shell passes them to ctest verbatim
|
||||
# instead of treating them as shell pipe operators
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_nvhpc && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-comparison-cpp20_cpp20\\|test-comparison_legacy-cpp20_cpp20\\|test-constructor1_cpp11\\|test-deserialization-cpp20_cpp20" --output-on-failure
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_nvhpc && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-comparison_cpp20\\|test-comparison_legacy_cpp20\\|test-constructor1_cpp11\\|test-deserialization_cpp20" --output-on-failure
|
||||
COMMENT "Compile and test with NVIDIA HPC SDK (nvc++)"
|
||||
)
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
cppcheck==1.5.3
|
||||
cppcheck==1.5.1
|
||||
+39
-366
@@ -109,55 +109,6 @@ function(_json_test_apply_test_properties test_target properties_target)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# for internal use by _json_test_add_test() and _json_test_add_unity_batch():
|
||||
# registers the CTest test <test_name>_cpp<cxx_standard> (plus its Valgrind
|
||||
# variant), which runs the executable target <test_target> with the arguments
|
||||
# in ARGN, and applies the test properties of the test- and standard-specific
|
||||
# interface targets
|
||||
function(_json_test_register_test test_name test_target cxx_standard)
|
||||
set(ctest_name ${test_name}_cpp${cxx_standard})
|
||||
|
||||
if (JSON_FastTests)
|
||||
add_test(NAME ${ctest_name}
|
||||
COMMAND ${test_target} ${DOCTEST_TEST_FILTER} ${ARGN}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
else()
|
||||
add_test(NAME ${ctest_name}
|
||||
COMMAND ${test_target} ${DOCTEST_TEST_FILTER} ${ARGN} --no-skip
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
set_tests_properties(${ctest_name} PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA)
|
||||
|
||||
# apply standard-specific test properties
|
||||
if(TARGET _json_test_interface__cpp_${cxx_standard})
|
||||
_json_test_apply_test_properties(${ctest_name} _json_test_interface__cpp_${cxx_standard})
|
||||
endif()
|
||||
|
||||
# apply test-specific test properties
|
||||
if(TARGET _json_test_interface_${test_name})
|
||||
_json_test_apply_test_properties(${ctest_name} _json_test_interface_${test_name})
|
||||
endif()
|
||||
|
||||
# apply test- and standard-specific test properties
|
||||
if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard})
|
||||
_json_test_apply_test_properties(${ctest_name}
|
||||
_json_test_interface_${test_name}_cpp_${cxx_standard}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(JSON_Valgrind)
|
||||
add_test(NAME ${ctest_name}_valgrind
|
||||
COMMAND ${memcheck_command} $<TARGET_FILE:${test_target}> ${DOCTEST_TEST_FILTER} ${ARGN}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
set_tests_properties(${ctest_name}_valgrind PROPERTIES
|
||||
LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# for internal use by json_test_add_test_for()
|
||||
function(_json_test_add_test test_name file main cxx_standard)
|
||||
set(test_target ${test_name}_cpp${cxx_standard})
|
||||
@@ -192,7 +143,45 @@ function(_json_test_add_test test_name file main cxx_standard)
|
||||
)
|
||||
endif()
|
||||
|
||||
_json_test_register_test(${test_name} ${test_target} ${cxx_standard})
|
||||
if (JSON_FastTests)
|
||||
add_test(NAME ${test_target}
|
||||
COMMAND ${test_target} ${DOCTEST_TEST_FILTER}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
else()
|
||||
add_test(NAME ${test_target}
|
||||
COMMAND ${test_target} ${DOCTEST_TEST_FILTER} --no-skip
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
set_tests_properties(${test_target} PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA)
|
||||
|
||||
# apply standard-specific test properties
|
||||
if(TARGET _json_test_interface__cpp_${cxx_standard})
|
||||
_json_test_apply_test_properties(${test_target} _json_test_interface__cpp_${cxx_standard})
|
||||
endif()
|
||||
|
||||
# apply test-specific test properties
|
||||
if(TARGET _json_test_interface_${test_name})
|
||||
_json_test_apply_test_properties(${test_target} _json_test_interface_${test_name})
|
||||
endif()
|
||||
|
||||
# apply test- and standard-specific test properties
|
||||
if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard})
|
||||
_json_test_apply_test_properties(${test_target}
|
||||
_json_test_interface_${test_name}_cpp_${cxx_standard}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(JSON_Valgrind)
|
||||
add_test(NAME ${test_target}_valgrind
|
||||
COMMAND ${memcheck_command} $<TARGET_FILE:${test_target}> ${DOCTEST_TEST_FILTER}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
set_tests_properties(${test_target}_valgrind PROPERTIES
|
||||
LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
#############################################################################
|
||||
@@ -211,14 +200,6 @@ endfunction()
|
||||
# Use NAME <name> to override the filename-derived test name.
|
||||
# Use FORCE to create the test regardless of the file containing
|
||||
# JSON_HAS_CPP_<version_number>.
|
||||
#
|
||||
# Tests that depend on the C++ standard (e.g., because they use the macros
|
||||
# JSON_HAS_FILESYSTEM, JSON_HAS_RANGES, or JSON_HAS_THREE_WAY_COMPARISON)
|
||||
# should not make the whole of a large unit-foo.cpp be rebuilt for every
|
||||
# standard. Put them into a separate file unit-foo-cpp<NN>.cpp (see, e.g.,
|
||||
# unit-items-cpp17.cpp) which wraps its content in #ifdef JSON_HAS_CPP_<NN>.
|
||||
# Then, unit-foo.cpp itself contains no JSON_HAS_CPP_<NN> and is only built for
|
||||
# C++11.
|
||||
# Test targets are linked against <main>.
|
||||
# CXX_STANDARDS defaults to "11".
|
||||
#############################################################################
|
||||
@@ -262,314 +243,6 @@ function(json_test_add_test_for file)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# for internal use by json_test_add_unity_tests(): sets <result> to whether the
|
||||
# (absolute) <file> is built for <cxx_standard>; same rule as in
|
||||
# json_test_add_test_for(): C++11 always, others only if the file contains
|
||||
# JSON_HAS_CPP_<cxx_standard> or <force> is set
|
||||
function(_json_test_unity_applies file cxx_standard force result)
|
||||
set(${result} TRUE PARENT_SCOPE)
|
||||
if(NOT ("${cxx_standard}" STREQUAL 11 OR force))
|
||||
file(READ ${file} file_content)
|
||||
string(FIND "${file_content}" JSON_HAS_CPP_${cxx_standard} has_cpp_found)
|
||||
if(${has_cpp_found} EQUAL -1)
|
||||
set(${result} FALSE PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# for internal use by json_test_add_unity_tests(): creates the executable
|
||||
# test-unity-<batch_name>_cpp<cxx_standard> from the (absolute) source files
|
||||
# in ARGN, which are #include-d by a generated source file, and registers one
|
||||
# CTest test per source file that runs only the test cases of that file; if
|
||||
# <private> is true, the generated file defines JSON_TESTS_PRIVATE first
|
||||
function(_json_test_add_unity_batch batch_name cxx_standard main private)
|
||||
set(batch_target test-unity-${batch_name}_cpp${cxx_standard})
|
||||
set(batch_source ${PROJECT_BINARY_DIR}/tests/unity/${batch_target}.cpp)
|
||||
|
||||
set(batch_content "// generated by cmake/test.cmake; do not edit\n")
|
||||
if(private)
|
||||
string(APPEND batch_content "// at least one file of this batch needs access to private members of the library\n")
|
||||
string(APPEND batch_content "#define JSON_TESTS_PRIVATE\n")
|
||||
# the files define the macro again; mark this definition as used, as
|
||||
# -Wunused-macros reports an unused definition when it is redefined
|
||||
string(APPEND batch_content "#ifdef JSON_TESTS_PRIVATE\n#endif\n")
|
||||
endif()
|
||||
foreach(file ${ARGN})
|
||||
string(APPEND batch_content "#include \"${file}\" // NOLINT(bugprone-suspicious-include)\n")
|
||||
endforeach()
|
||||
|
||||
# only touch the generated file if it changed to keep incremental builds incremental
|
||||
set(old_content "")
|
||||
if(EXISTS ${batch_source})
|
||||
file(READ ${batch_source} old_content)
|
||||
endif()
|
||||
if(NOT "${old_content}" STREQUAL "${batch_content}")
|
||||
file(WRITE ${batch_source} "${batch_content}")
|
||||
endif()
|
||||
|
||||
add_executable(${batch_target} ${batch_source})
|
||||
target_link_libraries(${batch_target} PRIVATE ${main})
|
||||
set_target_properties(${batch_target} PROPERTIES
|
||||
CXX_STANDARD ${cxx_standard}
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
if(TARGET _json_test_interface__cpp_${cxx_standard})
|
||||
target_link_libraries(${batch_target} PRIVATE _json_test_interface__cpp_${cxx_standard})
|
||||
endif()
|
||||
|
||||
# rebuild the batch when one of its files changes, and show the files in IDEs;
|
||||
# files that are also built standalone (VARIANT_FILES) are left out, as
|
||||
# HEADER_FILE_ONLY is a per-file property and would also affect those targets
|
||||
set_source_files_properties(${batch_source} PROPERTIES OBJECT_DEPENDS "${ARGN}")
|
||||
foreach(file ${ARGN})
|
||||
if(NOT file IN_LIST _json_test_unity_variant_files)
|
||||
set_source_files_properties(${file} PROPERTIES HEADER_FILE_ONLY ON)
|
||||
target_sources(${batch_target} PRIVATE ${file})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(file ${ARGN})
|
||||
get_filename_component(file_basename ${file} NAME_WE)
|
||||
string(REGEX REPLACE "unit-(.+)" "test-\\1" test_name ${file_basename})
|
||||
|
||||
# run only the test cases defined in this file (and in the shared
|
||||
# make_test_data_available.hpp if the file uses it)
|
||||
file(READ ${file} file_content)
|
||||
set(source_filter "--source-file=*${file_basename}.cpp")
|
||||
string(FIND "${file_content}" make_test_data_available.hpp uses_test_data)
|
||||
if(NOT ${uses_test_data} EQUAL -1)
|
||||
string(APPEND source_filter ",*make_test_data_available.hpp")
|
||||
endif()
|
||||
|
||||
_json_test_register_test(${test_name} ${batch_target} ${cxx_standard} "${source_filter}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
#############################################################################
|
||||
# json_test_add_unity_tests(
|
||||
# FILES <files>...
|
||||
# MAIN <main>
|
||||
# [CXX_STANDARDS <version_number>...] [FORCE]
|
||||
# [BATCH_SIZE <size>]
|
||||
# [GROUPS <group>...]
|
||||
# [VARIANT_FILES <files>...])
|
||||
#
|
||||
# Like calling json_test_add_test_for(<file> MAIN <main> ...) for each of the
|
||||
# <files>, but compiles several files together to speed up the build: for each
|
||||
# C++ standard, the files are split into batches of <size> files (default: 8)
|
||||
# and each batch is built as a single executable
|
||||
#
|
||||
# test-unity-<pool><index>_cpp<version_number>
|
||||
#
|
||||
# whose generated source file #include-s the files of the batch (so they share
|
||||
# the template instantiations of the library). The tests are still named
|
||||
# test-foo_cpp<version_number>, one per file, but run the batch executable with
|
||||
# a doctest filter that selects the test cases of that file only.
|
||||
#
|
||||
# Files are only batched with files that agree on the macros defined before
|
||||
# the library is included: files that define at most JSON_TESTS_PRIVATE (or
|
||||
# macros derived from global compile definitions) form the pools "plain" and
|
||||
# "private". All other files are added with json_test_add_test_for() as usual,
|
||||
# as are files with test-specific build settings (see
|
||||
# json_test_set_test_options()) and the files listed in the explicit
|
||||
# exclusion list below.
|
||||
# Each <group> names a list variable json_test_unity_group_<group> of test file
|
||||
# stems (file names without "unit-" and ".cpp"). The batchable files of a group
|
||||
# are compiled together (regardless of BATCH_SIZE) as one executable
|
||||
#
|
||||
# test-unity-<group>_cpp<version_number>
|
||||
#
|
||||
# so that related tests, which instantiate the same templates, share one
|
||||
# translation unit. A group may mix the pools "plain" and "private"; if any of
|
||||
# its files needs JSON_TESTS_PRIVATE, the whole group is built with it. Files
|
||||
# that cannot be batched stay standalone even if they are listed in a group.
|
||||
# Files in no group are batched by BATCH_SIZE as described above.
|
||||
# <files> in VARIANT_FILES are also built standalone with other settings, so
|
||||
# they are not marked as header-only sources of the batch.
|
||||
#############################################################################
|
||||
|
||||
function(json_test_add_unity_tests)
|
||||
cmake_parse_arguments(args "FORCE" "MAIN;BATCH_SIZE" "FILES;CXX_STANDARDS;VARIANT_FILES;GROUPS" ${ARGN})
|
||||
|
||||
if("${args_MAIN}" STREQUAL "")
|
||||
message(FATAL_ERROR "Required argument MAIN <main> missing.")
|
||||
endif()
|
||||
|
||||
if("${args_BATCH_SIZE}" STREQUAL "")
|
||||
set(args_BATCH_SIZE 8)
|
||||
endif()
|
||||
|
||||
if("${args_CXX_STANDARDS}" STREQUAL "")
|
||||
set(args_CXX_STANDARDS 11)
|
||||
endif()
|
||||
|
||||
if(args_FORCE)
|
||||
set(force FORCE)
|
||||
else()
|
||||
set(force "")
|
||||
endif()
|
||||
|
||||
set(_json_test_unity_variant_files "")
|
||||
foreach(file ${args_VARIANT_FILES})
|
||||
get_filename_component(file ${file} ABSOLUTE)
|
||||
list(APPEND _json_test_unity_variant_files ${file})
|
||||
endforeach()
|
||||
|
||||
# files that must not be merged into a batch: unit-32bit.cpp is only built
|
||||
# for 32bit targets, and unit-no-macro-leak.cpp checks that including the
|
||||
# library defines no unprefixed macro, which any other file would disturb
|
||||
set(standalone_files unit-32bit.cpp unit-no-macro-leak.cpp)
|
||||
|
||||
set(harmless_macros "^(DOCTEST_.*|SKIP_TESTS_FOR_.*|JSON_TEST_DEPRECATED_FUNCTIONS_DELETED|JSON_TEST_STRICT_NUL_HANDLING_ENABLED|JSON_TEST_STRINGIZE)$")
|
||||
|
||||
# classify the files
|
||||
set(plain_files "")
|
||||
set(private_files "")
|
||||
set(standalone_abs_files "")
|
||||
foreach(file ${args_FILES})
|
||||
get_filename_component(file_name ${file} NAME)
|
||||
get_filename_component(file_basename ${file} NAME_WE)
|
||||
string(REGEX REPLACE "unit-(.+)" "test-\\1" test_name ${file_basename})
|
||||
|
||||
set(batchable TRUE)
|
||||
if(file_name IN_LIST standalone_files)
|
||||
set(batchable FALSE)
|
||||
endif()
|
||||
if(TARGET _json_test_interface_${test_name})
|
||||
set(batchable FALSE)
|
||||
endif()
|
||||
foreach(cxx_standard ${args_CXX_STANDARDS})
|
||||
if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard})
|
||||
set(batchable FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# files that suppress GCC's -Wnoexcept around their include of the
|
||||
# library: the suppression has no effect once another file of the
|
||||
# batch included the library first
|
||||
if(batchable)
|
||||
file(READ ${file} file_content)
|
||||
string(FIND "${file_content}" "SUPPRESS_WARNING(\"-Wnoexcept\")" suppresses_noexcept)
|
||||
if(NOT ${suppresses_noexcept} EQUAL -1)
|
||||
set(batchable FALSE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(pool plain)
|
||||
if(batchable)
|
||||
# collect the macros (un)defined before the library is included
|
||||
file(READ ${file} file_content)
|
||||
string(FIND "${file_content}" "#include <nlohmann/" include_position)
|
||||
if(NOT ${include_position} EQUAL -1)
|
||||
string(SUBSTRING "${file_content}" 0 ${include_position} file_content)
|
||||
endif()
|
||||
string(REGEX MATCHALL "(^|\n)[ \t]*#[ \t]*(define|undef)[ \t]+[A-Za-z_0-9]+" directives "${file_content}")
|
||||
foreach(directive ${directives})
|
||||
string(REGEX REPLACE "^.*[ \t]([A-Za-z_0-9]+)$" "\\1" macro "${directive}")
|
||||
if(macro MATCHES "${harmless_macros}")
|
||||
continue()
|
||||
elseif("${macro}" STREQUAL JSON_TESTS_PRIVATE)
|
||||
set(pool private)
|
||||
else()
|
||||
set(batchable FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
get_filename_component(file_abs ${file} ABSOLUTE)
|
||||
if(NOT batchable)
|
||||
list(APPEND standalone_abs_files ${file_abs})
|
||||
json_test_add_test_for(${file} MAIN ${args_MAIN} CXX_STANDARDS ${args_CXX_STANDARDS} ${force})
|
||||
continue()
|
||||
endif()
|
||||
get_filename_component(file ${file} ABSOLUTE)
|
||||
list(APPEND ${pool}_files ${file})
|
||||
endforeach()
|
||||
|
||||
# resolve the explicit groups: group_<name>_files are the (absolute) files
|
||||
# of the group, group_<name>_private tells whether one of them is private
|
||||
set(grouped_files "")
|
||||
foreach(group ${args_GROUPS})
|
||||
if(NOT DEFINED json_test_unity_group_${group})
|
||||
message(FATAL_ERROR "Unity test group '${group}' is not defined (json_test_unity_group_${group}).")
|
||||
endif()
|
||||
set(group_${group}_files "")
|
||||
set(group_${group}_private FALSE)
|
||||
foreach(stem ${json_test_unity_group_${group}})
|
||||
# check against the source directory, because FILES may be filtered (JSON_TestShard)
|
||||
get_filename_component(file ${CMAKE_CURRENT_SOURCE_DIR}/src/unit-${stem}.cpp ABSOLUTE)
|
||||
if(NOT EXISTS ${file})
|
||||
message(FATAL_ERROR "Unity test group '${group}' lists '${stem}', but ${file} does not exist.")
|
||||
endif()
|
||||
if(file IN_LIST grouped_files)
|
||||
message(FATAL_ERROR "Unity test file unit-${stem}.cpp is listed in more than one group (second: '${group}').")
|
||||
endif()
|
||||
list(APPEND grouped_files ${file})
|
||||
|
||||
if(file IN_LIST standalone_abs_files)
|
||||
message(STATUS "Unity test group '${group}': unit-${stem}.cpp cannot be batched and stays standalone")
|
||||
elseif(file IN_LIST plain_files)
|
||||
list(APPEND group_${group}_files ${file})
|
||||
list(REMOVE_ITEM plain_files ${file})
|
||||
elseif(file IN_LIST private_files)
|
||||
list(APPEND group_${group}_files ${file})
|
||||
list(REMOVE_ITEM private_files ${file})
|
||||
set(group_${group}_private TRUE)
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
foreach(cxx_standard ${args_CXX_STANDARDS})
|
||||
if(NOT compiler_supports_cpp_${cxx_standard})
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# explicit groups: one batch per group
|
||||
foreach(group ${args_GROUPS})
|
||||
set(batch_files "")
|
||||
foreach(file ${group_${group}_files})
|
||||
_json_test_unity_applies(${file} ${cxx_standard} "${force}" applies)
|
||||
if(applies)
|
||||
list(APPEND batch_files ${file})
|
||||
endif()
|
||||
endforeach()
|
||||
if(batch_files)
|
||||
_json_test_add_unity_batch(${group} ${cxx_standard} ${args_MAIN} ${group_${group}_private} ${batch_files})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# remaining files: batches of BATCH_SIZE files per pool
|
||||
foreach(pool plain private)
|
||||
set(is_private FALSE)
|
||||
if(pool STREQUAL private)
|
||||
set(is_private TRUE)
|
||||
endif()
|
||||
|
||||
set(batch_files "")
|
||||
set(batch_count 0)
|
||||
set(batch_index 0)
|
||||
foreach(file ${${pool}_files})
|
||||
_json_test_unity_applies(${file} ${cxx_standard} "${force}" applies)
|
||||
if(NOT applies)
|
||||
continue()
|
||||
endif()
|
||||
|
||||
list(APPEND batch_files ${file})
|
||||
math(EXPR batch_count "${batch_count} + 1")
|
||||
if(batch_count EQUAL args_BATCH_SIZE)
|
||||
_json_test_add_unity_batch(${pool}${batch_index} ${cxx_standard} ${args_MAIN} ${is_private} ${batch_files})
|
||||
set(batch_files "")
|
||||
set(batch_count 0)
|
||||
math(EXPR batch_index "${batch_index} + 1")
|
||||
endif()
|
||||
endforeach()
|
||||
if(batch_files)
|
||||
_json_test_add_unity_batch(${pool}${batch_index} ${cxx_standard} ${args_MAIN} ${is_private} ${batch_files})
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
#############################################################################
|
||||
# json_test_should_build_32bit_test(
|
||||
# <build_32bit_var> <build_32bit_only_var> <input>)
|
||||
|
||||
@@ -132,10 +132,6 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by
|
||||
- [operator>>](../operator_gtgt.md) - deserialize from stream
|
||||
- [`JSON_STRICT_NUL_HANDLING`](../macros/json_strict_nul_handling.md) - opt in to rejecting a NUL byte in the input
|
||||
instead of treating it as end of input
|
||||
- [`JSON_DISABLE_STREAM_BULK_SCAN`](../macros/json_disable_stream_bulk_scan.md) - read a `std::istream` one character
|
||||
at a time
|
||||
- [`JSON_DISABLE_UNLOCKED_FILE_IO`](../macros/json_disable_unlocked_file_io.md) - read a `FILE*` with the locking stdio
|
||||
functions
|
||||
|
||||
## Version history
|
||||
|
||||
@@ -147,10 +143,6 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
- `JSON_STRICT_NUL_HANDLING` added in version 3.13.0 to optionally reject a NUL byte in the input instead of treating
|
||||
it as end of input; planned to become the default in version 4.0.0.
|
||||
- Parsing from an `std::istream` scans the characters in its stream buffer in bulk in version 3.13.0
|
||||
([`JSON_DISABLE_STREAM_BULK_SCAN`](../macros/json_disable_stream_bulk_scan.md)).
|
||||
- Parsing from a `FILE*` locks the file once instead of once per character in version 3.13.0
|
||||
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../macros/json_disable_unlocked_file_io.md)).
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ To store objects in C++, a type is defined by the template parameters explained
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for `ArrayType` (`std::vector`) and `AllocatorType` (`std::allocator`), the default type for
|
||||
With the default values for `ArrayType` (`std::vector`) and `AllocatorType` (`std::allocator`), the default value for
|
||||
`array_t` is:
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -68,14 +68,6 @@ basic_json(basic_json&& other) noexcept;
|
||||
`std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with a `key_type` compatible to `string_t`
|
||||
and a `value_type` from which a `basic_json` value can be constructed.
|
||||
- **strings**: `string_t`, string literals, and all compatible string containers can be used.
|
||||
|
||||
!!! note "Rvalue containers are moved from"
|
||||
|
||||
If `val` is an rvalue of a compatible array-like or object-like container other than `array_t`/`object_t`
|
||||
(e.g., `json j = std::move(vec);` or `json j(std::vector<std::string>{...});`), the elements are moved into
|
||||
the JSON value instead of copied. Afterwards, the elements of the source container are in a valid but
|
||||
unspecified state (**moved-from**). Keys of associative containers are `const` and therefore still copied.
|
||||
Lvalues and `const` rvalues are copied, and the source is left unchanged.
|
||||
- **numbers**: [`number_integer_t`](number_integer_t.md), [`number_unsigned_t`](number_unsigned_t.md),
|
||||
[`number_float_t`](number_float_t.md), and all convertible number types such as `int`, `size_t`, `int64_t`, `float`
|
||||
or `double` can be used.
|
||||
@@ -244,9 +236,7 @@ basic_json(basic_json&& other) noexcept;
|
||||
2. No-throw guarantee: this constructor never throws exceptions.
|
||||
3. Depends on the called constructor. For types directly supported by the library (i.e., all types for which no
|
||||
`to_json()` function was provided), a strong guarantee holds: if an exception is thrown, there are no changes to any
|
||||
JSON value. **Exception:** when `val` is an rvalue array-like or object-like container, its elements are moved one
|
||||
by one; if an exception is thrown in the middle of the conversion (e.g., an allocation failure), the JSON value is
|
||||
unchanged, but the source container may be left partially moved-from.
|
||||
JSON value.
|
||||
4. Depends on the called constructor. For types directly supported by the library (i.e., all types for which no
|
||||
`to_json()` function was provided), a strong guarantee holds: if an exception is thrown, there are no changes to any
|
||||
JSON value.
|
||||
|
||||
@@ -23,7 +23,7 @@ To store boolean values in C++, a type is defined by the template parameter `Bo
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for `BooleanType` (`#!cpp bool`), the default type for `boolean_t` is `#!cpp bool`.
|
||||
With the default values for `BooleanType` (`#!cpp bool`), the default value for `boolean_t` is `#!cpp bool`.
|
||||
|
||||
### Storage
|
||||
|
||||
|
||||
@@ -93,8 +93,7 @@ Logarithmic in the size of the JSON object.
|
||||
|
||||
- [count](count.md) returns the number of occurrences of a key
|
||||
- [contains](contains.md) checks whether a key exists
|
||||
- [basic_json_view::find](../basic_json_view/find.md) - the same lookup on a zero-copy view (a duplicate key resolves
|
||||
to the first member, whereas `parse()` keeps the last)
|
||||
- [basic_json_view::find](../basic_json_view/find.md) - the same lookup on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -51,8 +51,7 @@ Constant.
|
||||
## See also
|
||||
|
||||
- [back](back.md) to access the last element
|
||||
- [basic_json_view::front](../basic_json_view/front.md) - the same access on a zero-copy view (document order, not
|
||||
sorted; duplicate keys are visited)
|
||||
- [basic_json_view::front](../basic_json_view/front.md) - the same access on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -6,9 +6,6 @@ constexpr bool is_number_unsigned() const noexcept;
|
||||
|
||||
This function returns `#!cpp true` if and only if the JSON value is an unsigned integer number. This excludes
|
||||
floating-point and signed integer values.
|
||||
|
||||
If [`number_unsigned_t`](number_unsigned_t.md) is the same type as [`number_integer_t`](number_integer_t.md), every
|
||||
integer is stored as `number_integer_t`, and this function always returns `#!cpp false`.
|
||||
|
||||
## Return value
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ When iterating over an array, `key()` will return the index of the element as st
|
||||
- [begin](begin.md) returns an iterator to the first element
|
||||
- [end](end.md) returns an iterator to one past the last element
|
||||
- [basic_json_view::items](../basic_json_view/items.md) - the same range on a zero-copy view (`#!cpp const auto`,
|
||||
not `#!cpp const auto&`: items are produced on the fly; document order, not sorted; duplicate keys are visited)
|
||||
not `#!cpp const auto&`: items are produced on the fly)
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ type to use.
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for `NumberFloatType` (`double`), the default type for `number_float_t` is `#!cpp double`.
|
||||
With the default values for `NumberFloatType` (`double`), the default value for `number_float_t` is `#!cpp double`.
|
||||
|
||||
### Default behavior
|
||||
|
||||
@@ -52,9 +52,8 @@ With the default values for `NumberFloatType` (`double`), the default type for `
|
||||
> interoperability can be achieved by implementations that expect no more precision or range than these provide, in the
|
||||
> sense that implementations will approximate JSON numbers within the expected precision.
|
||||
|
||||
This implementation does exactly follow this approach, as it uses double precision floating-point numbers by default.
|
||||
Note that with the default `double`, numbers smaller than `-1.79769313486232e+308` or greater than
|
||||
`1.79769313486232e+308` are rejected during parsing with
|
||||
This implementation does exactly follow this approach, as it uses double precision floating-point numbers. Note that
|
||||
numbers smaller than `-1.79769313486232e+308` or greater than `1.79769313486232e+308` are rejected during parsing with
|
||||
[`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406). Non-finite values (NaN and infinity) can
|
||||
only be stored by assigning them directly and are serialized to `null`.
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ to use.
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for `NumberIntegerType` (`std::int64_t`), the default type for `number_integer_t` is
|
||||
With the default values for `NumberIntegerType` (`std::int64_t`), the default value for `number_integer_t` is
|
||||
`#!cpp std::int64_t`.
|
||||
|
||||
### Default behavior
|
||||
|
||||
@@ -25,15 +25,14 @@ the type to use.
|
||||
`NumberUnsignedType`
|
||||
: the type to store unsigned integers. It must be an **unsigned integral** type (`#!cpp std::is_integral`) with a
|
||||
`#!cpp std::numeric_limits` specialization, and it must be able to represent the absolute value of every
|
||||
[`number_integer_t`](number_integer_t.md) value. Alternatively, it can be the same type as
|
||||
[`number_integer_t`](number_integer_t.md); then every integer is stored as `number_integer_t`. See
|
||||
[`number_integer_t`](number_integer_t.md) value. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#numberintegertype-and-numberunsignedtype).
|
||||
|
||||
## Notes
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for `NumberUnsignedType` (`std::uint64_t`), the default type for `number_unsigned_t` is
|
||||
With the default values for `NumberUnsignedType` (`std::uint64_t`), the default value for `number_unsigned_t` is
|
||||
`#!cpp std::uint64_t`.
|
||||
|
||||
### Default behavior
|
||||
@@ -90,4 +89,3 @@ Integer number values are stored directly inside a `basic_json` type.
|
||||
## Version history
|
||||
|
||||
- Added in version 2.0.0.
|
||||
- Can be the same type as `number_integer_t` since version 3.13.0.
|
||||
@@ -36,7 +36,7 @@ To store objects in C++, a type is defined by the template parameters described
|
||||
### Default type
|
||||
|
||||
With the default values for `ObjectType` (`std::map`), `StringType` (`std::string`), and `AllocatorType`
|
||||
(`std::allocator`), the default type for `object_t` is:
|
||||
(`std::allocator`), the default value for `object_t` is:
|
||||
|
||||
```cpp
|
||||
// until C++14
|
||||
|
||||
@@ -275,9 +275,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
- documentation on [runtime assertions](../../features/assertions.md)
|
||||
- see [`at`](at.md) for access by reference with range checking
|
||||
- see [`value`](value.md) for access with default value
|
||||
- [basic_json_view::operator[]](../basic_json_view/operator%5B%5D.md) - the same access on a zero-copy view (a duplicate
|
||||
key resolves to the first member, whereas `parse()` keeps the last; a missing key gives a discarded view instead of
|
||||
undefined behavior)
|
||||
- [basic_json_view::operator[]](../basic_json_view/operator%5B%5D.md) - the same access on a zero-copy view (always
|
||||
returns a discarded view instead of assuming undefined behavior)
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -112,16 +112,6 @@ By default, a `'\0'` (NUL) byte anywhere in the input is treated as end of input
|
||||
outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-bytes-in-the-input) for details and the
|
||||
[`JSON_STRICT_NUL_HANDLING`](../macros/json_strict_nul_handling.md) macro to opt into rejecting it instead.
|
||||
|
||||
!!! tip "Performance"
|
||||
|
||||
Contiguous inputs (strings, string views, vectors, arrays, pointer ranges) are the fastest to parse. A
|
||||
`#!cpp std::istream` comes close: the parser scans the characters its stream buffer holds in bulk, without reading
|
||||
ahead, so the stream is left exactly where it would be after reading one character at a time. A `#!cpp FILE*` is
|
||||
read one character at a time, but the file is locked only once, so other threads that use the same `FILE` object
|
||||
wait until parsing is done. See [input sources and performance](../../features/parsing/index.md#input-sources-and-performance),
|
||||
[`JSON_DISABLE_STREAM_BULK_SCAN`](../macros/json_disable_stream_bulk_scan.md), and
|
||||
[`JSON_DISABLE_UNLOCKED_FILE_IO`](../macros/json_disable_unlocked_file_io.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: (1) parse from a character array"
|
||||
@@ -257,10 +247,6 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by
|
||||
- [operator>>](../operator_gtgt.md) - deserialize from stream
|
||||
- [`JSON_STRICT_NUL_HANDLING`](../macros/json_strict_nul_handling.md) - opt in to rejecting a NUL byte in the input
|
||||
instead of treating it as end of input
|
||||
- [`JSON_DISABLE_STREAM_BULK_SCAN`](../macros/json_disable_stream_bulk_scan.md) - read a `std::istream` one character
|
||||
at a time
|
||||
- [`JSON_DISABLE_UNLOCKED_FILE_IO`](../macros/json_disable_unlocked_file_io.md) - read a `FILE*` with the locking stdio
|
||||
functions
|
||||
|
||||
## Version history
|
||||
|
||||
@@ -275,11 +261,6 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by
|
||||
it as end of input; planned to become the default in version 4.0.0.
|
||||
- Extended empty-input detection to also cover an `std::istream` without a stream buffer, and fixed a crash
|
||||
(`std::terminate`) when parsing from an `std::istream` with `eofbit` in its exception mask, in version 3.13.0.
|
||||
- Parsing from an `std::istream` scans the characters in its stream buffer in bulk in version 3.13.0
|
||||
([`JSON_DISABLE_STREAM_BULK_SCAN`](../macros/json_disable_stream_bulk_scan.md) restores reading one character at a
|
||||
time).
|
||||
- Parsing from a `FILE*` locks the file once instead of once per character in version 3.13.0
|
||||
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../macros/json_disable_unlocked_file_io.md) restores `std::fgetc`).
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -116,10 +116,6 @@ consumer `sax` has a super-linear complexity.
|
||||
|
||||
A UTF-8 byte order mark is silently ignored.
|
||||
|
||||
When reading from a `#!c FILE*`, the file is locked while it is parsed. The lock is recursive, so the SAX handler may
|
||||
use the same file with stdio functions, but it must not wait for another thread that uses the same `FILE` object; see
|
||||
[`JSON_DISABLE_UNLOCKED_FILE_IO`](../macros/json_disable_unlocked_file_io.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@@ -141,10 +137,6 @@ use the same file with stdio functions, but it must not wait for another thread
|
||||
|
||||
- [parse](parse.md) - deserialize from a compatible input
|
||||
- [accept](accept.md) - check if the input is valid JSON
|
||||
- [`JSON_DISABLE_STREAM_BULK_SCAN`](../macros/json_disable_stream_bulk_scan.md) - read a `std::istream` one character
|
||||
at a time
|
||||
- [`JSON_DISABLE_UNLOCKED_FILE_IO`](../macros/json_disable_unlocked_file_io.md) - read a `FILE*` with the locking stdio
|
||||
functions
|
||||
|
||||
## Version history
|
||||
|
||||
@@ -156,10 +148,6 @@ use the same file with stdio functions, but it must not wait for another thread
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
- `JSON_PRECISE_STREAM_POSITION` added in version 3.13.0 to optionally leave a `#!cpp std::istream` positioned right
|
||||
after the parsed value when `strict` is `#!cpp false`.
|
||||
- Parsing from an `std::istream` scans the characters in its stream buffer in bulk in version 3.13.0
|
||||
([`JSON_DISABLE_STREAM_BULK_SCAN`](../macros/json_disable_stream_bulk_scan.md)).
|
||||
- Parsing from a `FILE*` locks the file once instead of once per character in version 3.13.0
|
||||
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../macros/json_disable_unlocked_file_io.md)).
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ JSON class into byte-sized characters during deserialization.
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for `StringType` (`std::string`), the default type for `string_t` is `#!cpp std::string`.
|
||||
With the default values for `StringType` (`std::string`), the default value for `string_t` is `#!cpp std::string`.
|
||||
|
||||
### Encoding
|
||||
|
||||
|
||||
@@ -123,6 +123,4 @@ Linear in the size of the JSON value `j`.
|
||||
that is not valid UTF-8 unchanged, as before; `strict` (the default if
|
||||
[`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316`.
|
||||
- Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an
|
||||
array or object was silently skipped, producing invalid BJData.
|
||||
- Writes unsigned integers wider than 64 bits as high-precision numbers since version 3.13.0; previously, they were
|
||||
silently truncated to 64 bits.
|
||||
array or object was silently skipped, producing invalid BJData.
|
||||
@@ -37,9 +37,8 @@ With (2), the bytes written before the exception remain in the output adapter.
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Throws [out_of_range.407](../../home/exceptions.md#jsonexceptionout_of_range407) if `j` contains an integer outside
|
||||
the range of int64 (an unsigned integer above 9223372036854775807, or, with a number type wider than 64 bits, any
|
||||
integer beyond int64), which BON8 cannot represent
|
||||
- Throws [out_of_range.407](../../home/exceptions.md#jsonexceptionout_of_range407) if `j` contains an unsigned integer
|
||||
above 9223372036854775807, which BON8 cannot represent
|
||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if `j` contains a string that is not
|
||||
valid UTF-8
|
||||
- Throws [type_error.321](../../home/exceptions.md#jsonexceptiontype_error321) if `j` or a value nested in it is
|
||||
|
||||
@@ -47,10 +47,6 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
|
||||
- Throws [`type_error.317`](../../home/exceptions.md#jsonexceptiontype_error317) if the top-level type of the JSON value
|
||||
is not an object; example: `"to serialize to BSON, top-level type must be object, but is string"`
|
||||
- Throws [`out_of_range.407`](../../home/exceptions.md#jsonexceptionout_of_range407) if `j` contains a signed integer
|
||||
outside the range of int64 or an unsigned integer outside the range of uint64, which is only possible with a number
|
||||
type wider than 64 bits; example:
|
||||
`"integer number 9223372036854775808 cannot be represented by BSON as it does not fit int64"`
|
||||
- Throws [`out_of_range.409`](../../home/exceptions.md#jsonexceptionout_of_range409) if a key in the JSON object contains
|
||||
a null byte (code point U+0000); example: `"BSON key cannot contain code point U+0000 (at byte 2)"`
|
||||
- Throws [`out_of_range.412`](../../home/exceptions.md#jsonexceptionout_of_range412) if the length of a document, array,
|
||||
@@ -123,5 +119,3 @@ pass before anything is written.
|
||||
that is not valid UTF-8 unchanged, as before; `strict` (the default if
|
||||
[`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316` before anything
|
||||
is written.
|
||||
- Throws `out_of_range.407` for integers that do not fit 64 bits since version 3.13.0; previously, integers of a
|
||||
number type wider than 64 bits were silently truncated.
|
||||
@@ -46,9 +46,6 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Throws [`out_of_range.407`](../../home/exceptions.md#jsonexceptionout_of_range407) if `j` contains an integer
|
||||
outside [-2^64, 2^64-1], which is only possible with a number type wider than 64 bits; example:
|
||||
`"integer number 18446744073709551616 cannot be represented by CBOR as it does not fit [-2^64, 2^64-1]"`
|
||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is
|
||||
not valid UTF-8 and `error_handler` is `strict` (the default only if
|
||||
[`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled)
|
||||
@@ -93,5 +90,3 @@ Linear in the size of the JSON value `j`.
|
||||
[`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316`.
|
||||
- Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an
|
||||
array or object was silently skipped, producing invalid CBOR.
|
||||
- Throws `out_of_range.407` for integers that do not fit 64 bits since version 3.13.0; previously, integers of a
|
||||
number type wider than 64 bits were silently truncated.
|
||||
@@ -46,9 +46,6 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Throws [`out_of_range.407`](../../home/exceptions.md#jsonexceptionout_of_range407) if `j` contains an integer
|
||||
outside [-2^63, 2^64-1], which is only possible with a number type wider than 64 bits; example:
|
||||
`"integer number 18446744073709551616 cannot be represented by MessagePack as it does not fit [-2^63, 2^64-1]"`
|
||||
- Throws [`out_of_range.412`](../../home/exceptions.md#jsonexceptionout_of_range412) if the length of a string, binary
|
||||
value, array, or object exceeds 4294967295, the maximum MessagePack can store; example:
|
||||
`"MessagePack length 4294967296 exceeds maximum of 4294967295"`
|
||||
@@ -115,5 +112,3 @@ Linear in the size of the JSON value `j`.
|
||||
`number_unsigned_t`.
|
||||
- Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an
|
||||
array or object was silently skipped, producing invalid MessagePack.
|
||||
- Throws `out_of_range.407` for integers that do not fit 64 bits since version 3.13.0; previously, integers of a
|
||||
number type wider than 64 bits were silently truncated.
|
||||
@@ -12,11 +12,6 @@ Checks whether the input is valid JSON, accepting and rejecting exactly what
|
||||
function never throws an exception for invalid input, and the returned `#!cpp bool` is the only result -- no document
|
||||
is returned.
|
||||
|
||||
The result is the same as that of `BasicJsonType::accept()` by design; the difference is how the check is made. This
|
||||
function runs the document's index builder (and discards the index), while `BasicJsonType::accept()` runs the SAX
|
||||
parser with a handler that ignores every event. Use this one if you go on to parse the same input with
|
||||
[`parse()`](parse.md) anyway, so that both use the same code; either is fine for a plain yes/no answer.
|
||||
|
||||
## Template parameters
|
||||
|
||||
`InputType`
|
||||
|
||||
@@ -16,8 +16,8 @@ basic_json_document(const basic_json_document&) = delete;
|
||||
2. Move constructor. Takes over `other`'s index and, if owned, its text; `other` is left as an empty document. Views
|
||||
taken from `other` before the move remain valid, because the index is heap-allocated independently of the
|
||||
`basic_json_document` object.
|
||||
3. `basic_json_document` is move-only. Copying is disabled because of its cost: a copy would duplicate the whole
|
||||
index, the decoded-string buffer, and the owned text, while a move is enough in every use we know of.
|
||||
3. `basic_json_document` is move-only. Copying is disabled because it would either duplicate a potentially large index
|
||||
and text, or leave two documents claiming to borrow the same buffer.
|
||||
|
||||
## Parameters
|
||||
|
||||
@@ -30,7 +30,7 @@ No-throw guarantee: the default and move constructors never throw exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
Constant.
|
||||
Constant, for the default and move constructors.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ has `erase`; calling it on a read-only `basic_json_document` fails to compile (`
|
||||
1. Removes every member of `object` whose key is `key` (see [Notes](#notes) on duplicate keys) and returns how many
|
||||
were removed; `#!cpp 0` if `object` has no member with this key.
|
||||
2. Removes the element at index `idx` of `array`, which must already exist (`#!cpp idx < array.size()`).
|
||||
3. Removes the value the JSON pointer `ptr` refers to, relative to [`root()`](root.md). `ptr` must not be empty
|
||||
([`root()`](root.md) itself cannot be erased), and the *parent* of the target must already exist. The target is
|
||||
removed as in 1. if the parent is an object (returns the number of removed members, `#!cpp 0` or more) and as in 2.
|
||||
if it is an array (always returns `#!cpp 1`).
|
||||
3. Removes the value the JSON pointer `ptr` refers to, relative to [`root()`](root.md), and returns how many values
|
||||
were removed: the *parent* of the target must already exist, and the target itself is removed as in 1. (an object
|
||||
member; `#!cpp 0` or more) or 2. (an array element; always `#!cpp 1`). `ptr` must not be empty -- [`root()`](root.md)
|
||||
itself cannot be erased.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@@ -69,10 +69,10 @@ has `erase`; calling it on a read-only `basic_json_document` fails to compile (`
|
||||
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) (an empty token); otherwise (an
|
||||
object, or a primitive value the pointer's parent resolves to) throws what 1. throws.
|
||||
|
||||
Overloads 1. and 2. also throw [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202)
|
||||
("view does not belong to this document") if `object`/`array` is a [discarded](../basic_json_view/is_discarded.md)
|
||||
view or a view of a *different* document. Overload 3. never throws `invalid_iterator.202`: it takes no view, and it
|
||||
always starts from this document's own [`root()`](root.md).
|
||||
Every overload also throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view
|
||||
does not belong to this document") if `object`/`array` is a [discarded](../basic_json_view/is_discarded.md) view or a
|
||||
view of a *different* document (overloads 1-2 only; overload 3 always starts from this document's own
|
||||
[`root()`](root.md)).
|
||||
|
||||
## Complexity
|
||||
|
||||
@@ -92,10 +92,9 @@ always starts from this document's own [`root()`](root.md).
|
||||
|
||||
Like [`set`](set.md) and [`push_back`](push_back.md), `erase` never moves an element's *value*: a view still
|
||||
referring to a removed member or element keeps showing what it last held (see [Edits](index.md#edits)) -- it just no
|
||||
longer appears when `array`/`object` is read, dumped, or iterated. What does change is the container's sequence of
|
||||
*links* to its elements: removing an element of `array` (2.) shifts the links to the elements after it by one, as
|
||||
[`insert`](insert.md) does in the other direction. *Every* iterator already taken over `array`/`object` is invalidated
|
||||
by an erase, not only those at or after the removed element, since the container may now use a different sequence.
|
||||
longer appears when `array`/`object` is read, dumped, or iterated. Removing an element of `array` (2.) does shift the
|
||||
*links* to the elements after it, the same way `insert`, `set`, or `push_back` on the same array would; any iterator
|
||||
already taken over `array`/`object` is invalidated by an erase, since it was walking the old layout.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -11,14 +11,13 @@ A parsed JSON text, held as a flat index of its values
|
||||
([16 bytes per value](../../home/architecture.md#node-index-of-json-views)) instead of a tree of `BasicJsonType` values.
|
||||
Strings and numbers stay in the source text; only strings that contain escapes are decoded, into one buffer owned by
|
||||
the document. [`basic_json_view`](../basic_json_view/index.md) is a read-only handle to one value of a
|
||||
`basic_json_document`; [`materialize()`](../basic_json_view/materialize.md) turns a subtree into the
|
||||
`basic_json_document`; [`materialize()`](../basic_json_view/materialize.md) turns a subtree back into the
|
||||
`BasicJsonType` value that [`BasicJsonType::parse()`](../basic_json/parse.md) would have produced for it.
|
||||
|
||||
A document may **borrow** the text it was parsed from (the caller's buffer must then outlive the document) or **own**
|
||||
it (a copy, or an rvalue `#!cpp std::string` that was moved in); see [`owns_source`](owns_source.md). `basic_json_document`
|
||||
is move-only: a copy would duplicate the whole index, the decoded-string buffer, and the owned text, and a move is
|
||||
enough in every use we know of. The index, the decoded strings, and the owned text live in one heap block that the
|
||||
document holds through a `#!cpp std::unique_ptr`; this is also why views survive a move of the document.
|
||||
is move-only: copying a document would either duplicate a potentially large index and text, or leave two documents
|
||||
claiming to borrow the same buffer, so it is disabled.
|
||||
|
||||
With `#!cpp Editable == true`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
|
||||
[`insert`](insert.md), and [`erase`](erase.md) to change values in place, see [Edits](#edits) below. The source text
|
||||
|
||||
@@ -110,30 +110,17 @@ enum class image_check
|
||||
|
||||
How thoroughly `load()` validates `image` before trusting it.
|
||||
|
||||
`full` (the default)
|
||||
: Checks everything the parser itself guarantees: structure and bounds; that every string is valid UTF-8 (and, for a
|
||||
string still in the source text, that it contains no quote, backslash, or control character); and that every number
|
||||
token is well-formed and matches the value stored for it. Strings and float tokens may share a range only if the
|
||||
ranges are identical (as nodes that share a value do), and never overlap otherwise. Reading and serializing a
|
||||
checked image is safe and always produces valid JSON, exactly as for a parsed document. This is the right choice for
|
||||
an image from anything you do not fully control -- a file, a cache shared with other processes, a peer on the
|
||||
network.
|
||||
| value | checks | guarantees |
|
||||
|----------|--------------------------------------------------------------------------------------------------------------|------------|
|
||||
| `full` | everything the parser itself guarantees: structure and bounds; that every string is valid UTF-8 (and, for a string still in the source text, that it contains no quote, backslash, or control character); and that every number token is well-formed and matches the value stored for it; strings and float tokens may share a range only if the ranges are identical (as nodes that share a value do), and never overlap otherwise | reading and serializing a checked image is safe and always produces valid JSON, exactly as for a parsed document |
|
||||
| `bounds` | structure and bounds only -- that every offset and count in the node index stays inside the image | reading and serializing stay memory-safe, but a crafted image can hold strings that are not valid UTF-8 or that serialize to invalid JSON ([`dump()`](../basic_json_view/dump.md) writes them unchanged or throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316)), and numbers whose values differ from their text |
|
||||
| `none` | nothing | images from a trusted source only -- reading a damaged image is undefined behavior |
|
||||
|
||||
`bounds`
|
||||
: Checks structure and bounds only: that every offset and count in the node index stays inside the image. So
|
||||
`load()`, [`root()`](root.md), element access, and [`materialize()`](../basic_json_view/materialize.md) can never
|
||||
read outside the image, even on a damaged one. It does *not* guarantee that the image describes valid JSON: a
|
||||
string that a `full` check would have rejected can make [`dump()`](../basic_json_view/dump.md) write invalid UTF-8
|
||||
or invalid JSON, or throw [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316), and a number can
|
||||
read back with a value that does not match how it is spelled. An [editable document](../json_editable_document.md)
|
||||
does not take such a string over: [`set`](set.md), [`push_back`](push_back.md) and [`insert`](insert.md) throw
|
||||
`type_error.316` when they copy it from a view of the loaded document, and leave the editable document unchanged.
|
||||
`bounds` skips scanning the text and the decoded strings, so it fits a cache your own process just wrote and reads
|
||||
straight back, where damage would mean a bug or a hardware fault rather than adversarial input.
|
||||
|
||||
`none`
|
||||
: Checks nothing. Reading a damaged image is undefined behavior, so use it only for an image you trust as much as
|
||||
your own memory.
|
||||
`full` is the default and the right choice for an image from anything you do not fully control -- a file, a cache
|
||||
shared with other processes, a peer on the network. `bounds` skips scanning the text and the decoded strings, so it
|
||||
fits a cache your own process just wrote and reads straight back, where damage would mean a bug or a hardware fault
|
||||
rather than adversarial input; it still cannot crash or read out of bounds. `none` skips validation entirely and
|
||||
should only be used for an image you trust as much as your own memory.
|
||||
|
||||
**Lifetime.** Overloads 1 and 2 borrow `image`: it must stay alive and byte-for-byte unchanged for as long as the
|
||||
returned document, and any [view](../basic_json_view/index.md) taken from it, is used -- exactly like a document
|
||||
@@ -147,6 +134,16 @@ returned document, and any [view](../basic_json_view/index.md) taken from it, is
|
||||
("unknown format"). Use images to cache a document within one build of the library, or to hand one to another
|
||||
process running the *same* build on the *same* (little-endian) machine -- not as a long-term storage format.
|
||||
|
||||
**What `image_check::bounds` does not guarantee.** A bounds-checked image can never make `load()`,
|
||||
[`root()`](root.md), element access, or [`materialize()`](../basic_json_view/materialize.md) read outside the image,
|
||||
so those stay safe on a damaged one. It does *not* guarantee that the image describes valid JSON: a string
|
||||
that a `full` check would have rejected can make [`dump()`](../basic_json_view/dump.md) write invalid UTF-8 or invalid
|
||||
JSON, or throw `type_error.316`, and a number can read back with a value that does not match how it is spelled.
|
||||
Reserve `bounds` for images you already trust to be well-formed, and use it only to skip the extra scan.
|
||||
An [editable document](../json_editable_document.md) does not take such a string over either:
|
||||
[`set`](set.md), [`push_back`](push_back.md) and [`insert`](insert.md) throw `type_error.316` when they copy it from
|
||||
a view of the loaded document, and leave the editable document unchanged.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Caching a document, ownership, and a rejected image"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
bool owns_source() const noexcept;
|
||||
```
|
||||
|
||||
Returns whether the document holds its own copy of the parsed text or is borrowing the caller's buffer.
|
||||
Returns whether the document holds its own copy of the parsed text, as opposed to borrowing the caller's buffer.
|
||||
|
||||
## Return value
|
||||
|
||||
|
||||
@@ -21,15 +21,13 @@ static basic_json_document parse(IteratorType first, IteratorType last,
|
||||
|
||||
Both overloads accept the same JSON text as [`BasicJsonType::parse()`](../basic_json/parse.md), with the same
|
||||
`ignore_comments`/`ignore_trailing_commas` options, but build a [`basic_json_document`](index.md) (a flat index into
|
||||
the input) instead of a tree of `BasicJsonType` values. They take the same inputs as `BasicJsonType::parse()`. Byte
|
||||
inputs that stay alive can be borrowed; all others (streams, `#!cpp FILE*`, wide characters, non-contiguous
|
||||
iterators) are read into a copy that the document owns -- see the Notes. Use [`parse_copy()`](parse_copy.md) to get an
|
||||
owned copy of a borrowable input as well.
|
||||
the input) instead of a tree of `BasicJsonType` values. The input must be byte-oriented (see the template parameters
|
||||
below): not every input type of `BasicJsonType::parse()` is supported.
|
||||
|
||||
## Template parameters
|
||||
|
||||
`InputType`
|
||||
: A compatible input, for instance:
|
||||
: A byte-oriented input, one of:
|
||||
|
||||
- a `#!cpp std::string`, `#!cpp std::string_view`, or a C-style array of single-byte characters
|
||||
- a pointer to a null-terminated string of single-byte characters (`#!cpp char`, `#!cpp signed char`,
|
||||
@@ -37,10 +35,12 @@ owned copy of a borrowable input as well.
|
||||
- a container for which `#!cpp obj.data()` and `#!cpp obj.size()` give contiguous single-byte access, e.g.
|
||||
`#!cpp std::vector<char>` or `#!cpp std::vector<std::uint8_t>`
|
||||
- an `#!cpp std::istream` object
|
||||
- a `#!cpp FILE*` pointer
|
||||
- wide characters (`#!cpp wchar_t`, `#!cpp char16_t`, `#!cpp char32_t`), which are converted to UTF-8: a wide
|
||||
string object (`#!cpp std::wstring`, `#!cpp std::u16string`, `#!cpp std::u32string`), an array (e.g. a wide
|
||||
string literal), or a pointer to a null-terminated wide string
|
||||
- a wide string object (`#!cpp std::wstring`, `#!cpp std::u16string`, `#!cpp std::u32string`), which is converted
|
||||
to UTF-8
|
||||
|
||||
Other inputs are not supported: a `#!cpp FILE*`, and pointers to or arrays of wide characters (`#!cpp wchar_t`,
|
||||
`#!cpp char16_t`, `#!cpp char32_t`) are rejected at compile time by a `#!cpp static_assert`. (Use
|
||||
[`BasicJsonType::parse()`](../basic_json/parse.md) for these.)
|
||||
|
||||
`IteratorType`
|
||||
: an input iterator type, for instance a pair of pointers such as `ptr` and `ptr + len`, or a pair of
|
||||
@@ -78,9 +78,7 @@ discarded; see [`is_discarded`](is_discarded.md).
|
||||
|
||||
Throws the same exception [`BasicJsonType::parse()`](../basic_json/parse.md) throws for the same input and options --
|
||||
the same exception id, message, and position -- because on a failing input the library's own parser is run on the
|
||||
same bytes to produce the diagnostic. This replay runs only for a failing input, and costs about a lexing pass up to
|
||||
the error (its SAX handler builds no values); with `allow_exceptions` set to `#!cpp false`, it is skipped and a
|
||||
discarded document is returned instead. Additionally throws
|
||||
same bytes to produce the diagnostic. Additionally throws
|
||||
[`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the input is 4294967280 bytes (4 GiB
|
||||
minus 16 bytes) or larger, a size [`BasicJsonType::parse()`](../basic_json/parse.md) does not reject.
|
||||
|
||||
@@ -97,7 +95,7 @@ Linear in the length of the input.
|
||||
| lvalue byte container (`std::string`, `std::vector<char>`, ...), `std::string_view`, C string, character array | **borrowed** -- `input` must outlive the document |
|
||||
| non-const rvalue `#!cpp std::string` | **owned**, moved in without a copy |
|
||||
| other rvalue byte container (including a `#!cpp const` rvalue `#!cpp std::string`) | **owned**, copied |
|
||||
| stream, `#!cpp FILE*`, wide characters, or anything else read through the general input adapter | **owned**, read into a buffer (a stream is read to its end) |
|
||||
| stream, wide string, or anything else read through the general input adapter | **owned**, read into a buffer (a stream is read to its end) |
|
||||
|
||||
For overload (2), a pair of pointers to single-byte integers (e.g. `#!cpp const char*`, `#!cpp std::uint8_t*`) is
|
||||
borrowed. From C++20 on, so is any other contiguous iterator over single bytes, such as
|
||||
|
||||
@@ -47,9 +47,7 @@ Every view taken from `#!cpp *this` before the call -- including the previous [`
|
||||
whether or not the new parse succeeds; take fresh views from [`root()`](root.md) afterward.
|
||||
|
||||
`input` is borrowed or owned by the same rules as [`parse()`](parse.md#notes); a document can borrow on one call and
|
||||
own on the next, since ownership is decided freshly each time. An input that is copied (see the table in
|
||||
[`parse()`](parse.md#notes)) is written into the document's previous owned copy, reusing its memory; a moved-in
|
||||
`#!cpp std::string` replaces it.
|
||||
own on the next, since ownership is decided freshly each time.
|
||||
|
||||
Reusing a document matters most for large inputs: the operating system provides the memory of a fresh node index one
|
||||
page at a time, and every page costs a page fault the first time it is written. On x86-64 Linux (4 KiB pages), parsing
|
||||
|
||||
@@ -39,8 +39,7 @@ auto v = doc.root();
|
||||
`root()` is a cheap handle into the document's index, not a copy of anything; call it as often as needed. The
|
||||
returned view is valid under the same conditions as any other view of the document -- see
|
||||
[Object inspection](../basic_json_view/index.md) -- in particular, it is invalidated by the next
|
||||
[`read()`](read.md) or [`shrink_to_fit()`](shrink_to_fit.md) on this document. A view can dangle, like a
|
||||
`#!cpp std::string_view`; see [Ownership and lifetime](../../features/json_view.md#ownership-and-lifetime).
|
||||
[`read()`](read.md) or [`shrink_to_fit()`](shrink_to_fit.md) on this document.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ basic_json_view at(const json_pointer& ptr) const;
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -77,8 +77,8 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
|
||||
on average.
|
||||
2. Linear in `idx`: elements are skipped one at a time from the first one, since they are not a fixed size in the
|
||||
index (unlike `BasicJsonType`'s array, which is random-access).
|
||||
3. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
|
||||
@@ -13,7 +13,7 @@ The last element or member value. For a primitive value (number, string, boolean
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -33,7 +33,8 @@ index.
|
||||
## Notes
|
||||
|
||||
Unlike [`BasicJsonType::back()`](../basic_json/back.md), which has undefined behavior for an empty array or object,
|
||||
`back()` throws `invalid_iterator.214` for an empty array, an empty object, a null value, or a discarded view.
|
||||
`back()` throws `invalid_iterator.214` in that case -- the same way it already does for `#!json null` and for a
|
||||
discarded view, where `BasicJsonType::back()` also throws.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ iterator begin() const noexcept;
|
||||
|
||||
Returns an iterator to the first element of an array, or the first member value of an object, in **document order**
|
||||
-- the order the values appear in the source text, not sorted by key. A primitive value iterates as a range of one
|
||||
element (itself), and a `#!json null` value or a [discarded](is_discarded.md) view iterates as an empty range.
|
||||
element (itself); `#!json null` and a [discarded](is_discarded.md) view iterate as an empty range.
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -23,7 +23,7 @@ Constant.
|
||||
## Notes
|
||||
|
||||
For an object, iteration visits **every** member, including all occurrences of a duplicate key -- unlike
|
||||
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), and [`contains`](contains.md),
|
||||
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), [`contains`](contains.md), and [`count`](count.md),
|
||||
which all resolve to the *first* member with a given key. See the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]`.
|
||||
|
||||
@@ -31,10 +31,6 @@ Because objects are iterated in document order rather than sorted by key, the or
|
||||
iterating the [`materialize()`](materialize.md)d `BasicJsonType` value would produce: a `#!cpp basic_json` object
|
||||
(`std::map`-backed by default) sorts its keys, while a view does not.
|
||||
|
||||
An `ordered_json` value also keeps document order, but it keeps only one entry per key: as `parse()` does, it keeps the
|
||||
*last* value, at the position of the key's *first* occurrence. The view, in contrast, visits every member, including
|
||||
the duplicates.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
@@ -35,8 +35,8 @@ No-throw guarantee: this function never throws exceptions.
|
||||
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
|
||||
on average.
|
||||
2. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
that level or the index into the array -- as for [`operator[]`](operator[].md#complexity) and
|
||||
[`at`](at.md#complexity) with a JSON pointer.
|
||||
@@ -55,8 +55,7 @@ view.
|
||||
|
||||
!!! info "Postconditions"
|
||||
|
||||
If `#!cpp v.contains(key)` returns `#!cpp true`, then `#!cpp v[key]` is not [discarded](is_discarded.md) and
|
||||
`#!cpp v.at(key)` does not throw. If
|
||||
If `#!cpp v.contains(key)` returns `#!cpp true`, then `#!cpp v[key]` is not [discarded](is_discarded.md). If
|
||||
`#!cpp v.contains(ptr)` returns `#!cpp true`, then `#!cpp v[ptr]` is not discarded and `#!cpp v.at(ptr)` does not
|
||||
throw.
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@ size_type count(const char* key) const;
|
||||
size_type count(const string_t& key) const;
|
||||
```
|
||||
|
||||
Returns the number of members with key `key` if the value is an object, `#!cpp 0` otherwise. Members with a repeated
|
||||
key are all counted.
|
||||
Returns `#!cpp 1` if the value is an object with a member with key `key`, `#!cpp 0` otherwise.
|
||||
|
||||
## Parameters
|
||||
|
||||
@@ -16,8 +15,7 @@ key are all counted.
|
||||
|
||||
## Return value
|
||||
|
||||
the number of members of the object with key `key` (duplicates included), or `#!cpp 0` if the value is not an object
|
||||
or has no such member.
|
||||
`#!cpp 1` if the value is an object and has a member with key `key`, `#!cpp 0` otherwise.
|
||||
|
||||
## Exception safety
|
||||
|
||||
@@ -25,30 +23,36 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear in the number of members: unlike the lookup functions, `count()` does not stop at the first match, because it
|
||||
has to count every member with the key. Members are compared one after another, in document order. Each comparison
|
||||
first checks the key's length -- already known from the index, without reading the key bytes -- before comparing its
|
||||
content. The hash index of the keys of objects with 128 or more members does not help here, since every member
|
||||
is visited.
|
||||
Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after another,
|
||||
in document order, stopping at the first match. Each comparison first checks the key's length
|
||||
-- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time on
|
||||
average.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! warning "Duplicate keys: the first member wins"
|
||||
|
||||
If the source text repeats a key, this resolves to the *first* member with it, not to the last one that
|
||||
[`materialize()`](materialize.md) and `parse()` keep. See the [Notes on duplicate keys](operator[].md#notes) of
|
||||
`operator[]` and [Duplicate keys](../../features/json_view.md#duplicate-keys) for the reasons and for how to get
|
||||
the last value.
|
||||
|
||||
This method always returns `#!cpp 0` when the value is not an object -- including a [discarded](is_discarded.md)
|
||||
view.
|
||||
|
||||
If the source text repeats a key, `count()` returns more than `#!cpp 1` for it, even though the
|
||||
[materialized](materialize.md) value (like the result of `parse()`) would have only one member with that key. Hence
|
||||
`#!cpp count(key) > 1` detects duplicate keys. This is unlike the lookup functions
|
||||
([`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), [`contains`](contains.md)), which resolve to the
|
||||
*first* member; see the [Notes on duplicate keys](operator[].md#notes) of `operator[]`.
|
||||
Unlike [`BasicJsonType::count()`](../basic_json/count.md), whose return value can in principle exceed `#!cpp 1` for
|
||||
an `ObjectType` that allows multiple entries per key, `count()` here never does: it is exactly
|
||||
[`contains()`](contains.md) as `#!cpp 0`/`#!cpp 1`. This holds even if the source text has a duplicate key -- see the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]` -- because a `#!cpp count() > 1` result would require
|
||||
counting every member with a matching key (the lookup functions resolve to the *first* one).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below validates that every transaction of a batch carries exactly one `amount` field, using
|
||||
`count()` before deciding whether to materialize a transaction at all. It reports a transaction with no `amount`
|
||||
field and one with a duplicated `amount` field.
|
||||
The example below validates that every transaction of a batch carries a mandatory `amount` field, using
|
||||
`count()` before deciding whether to materialize a transaction at all.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__count.cpp"
|
||||
|
||||
@@ -60,13 +60,11 @@ Linear in the size of the output text.
|
||||
The walk over the subtree is iterative, so the nesting depth it can write is limited by available memory only, not by
|
||||
the call stack -- as for [`materialize()`](materialize.md).
|
||||
|
||||
Strings are escaped by the same rules as [`BasicJsonType::dump`](../basic_json/dump.md).
|
||||
|
||||
With `#!cpp numbers == number_format::shortest`, floats are written with the library's shortest round-trip conversion,
|
||||
Strings are escaped by the same rules as [`BasicJsonType::dump`](../basic_json/dump.md). With
|
||||
`#!cpp numbers == number_format::shortest`, floats are written with the library's shortest round-trip conversion,
|
||||
exactly as [`BasicJsonType::dump`](../basic_json/dump.md) would (e.g. `#!cpp 1.5`, `#!cpp 100.0`, `#!cpp 1e+100`), and
|
||||
integers are copied from the source text -- already canonical in JSON, so this matches their shortest form too --
|
||||
except that `#!cpp -0` is written as `#!cpp 0`, the way [`BasicJsonType::parse()`](../basic_json/parse.md) reads it.
|
||||
|
||||
`#!cpp number_format::source` copies every number exactly as written in the source text instead, with no exception
|
||||
for `#!cpp -0` -- `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0.0`, `#!cpp -0`, or all digits of an integer literal with more
|
||||
digits than any number type holds (such a literal is itself classified as a float, see
|
||||
|
||||
@@ -5,8 +5,9 @@ iterator end() const noexcept;
|
||||
```
|
||||
|
||||
Returns an iterator to one past the last element of an array, one past the last member value of an object, in
|
||||
**document order** -- see [`begin()`](begin.md). A primitive value iterates as a range of one element (itself), and a
|
||||
`#!json null` value or a [discarded](is_discarded.md) view iterates as an empty range (`#!cpp begin() == end()`).
|
||||
**document order** -- see [`begin()`](begin.md). A primitive value iterates as a range of one element (itself);
|
||||
`#!json null` and a [discarded](is_discarded.md) view iterate as an empty range, so `#!cpp begin() == end()` for
|
||||
them.
|
||||
|
||||
## Return value
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ No-throw guarantee: this function never throws exceptions.
|
||||
Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after another,
|
||||
in document order, stopping at the first match. Each comparison first checks the key's length
|
||||
-- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time on
|
||||
average.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ The first element or member value. For a primitive value (number, string, boolea
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -31,8 +31,8 @@ Constant.
|
||||
## Notes
|
||||
|
||||
Unlike [`BasicJsonType::front()`](../basic_json/front.md), which has undefined behavior for an empty array or
|
||||
object, `front()` throws `invalid_iterator.214` for an empty array, an empty object, a null value, or a discarded
|
||||
view.
|
||||
object, `front()` throws `invalid_iterator.214` in that case -- the same way it already does for `#!json null` and
|
||||
for a discarded view, where `BasicJsonType::front()` also throws.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ Converts the value to `T`.
|
||||
For the types below, the conversion works directly on the flat index -- no `BasicJsonType` value is built for it:
|
||||
|
||||
- `#!cpp bool`
|
||||
- arithmetic types other than `#!cpp bool` (for a boolean, `#!cpp 0`/`#!cpp 1`, exactly as for
|
||||
[`BasicJsonType::get<T>()`](../basic_json/get.md))
|
||||
- arithmetic types other than `#!cpp bool` (from a number; from a boolean, as `#!cpp 0`/`#!cpp 1`, exactly as
|
||||
[`BasicJsonType::get<T>()`](../basic_json/get.md) converts a boolean)
|
||||
- `#!cpp std::nullptr_t`
|
||||
- `#!cpp std::basic_string<char, Traits, Alloc>` (including `string_t`) -- a copy of the string
|
||||
- [`string_view_t`](index.md#member-types) -- **no copy**: the returned view points into the document's
|
||||
@@ -19,10 +19,10 @@ For the types below, the conversion works directly on the flat index -- no `Basi
|
||||
document's own buffer of decoded strings (see [`get_string()`](get_string.md))
|
||||
- `BasicJsonType` -- equivalent to [`materialize()`](materialize.md)
|
||||
- `basic_json_view` -- returns `#!cpp *this`
|
||||
- `#!cpp std::vector<U, A>` -- from an array, element by element, each converted with `#!cpp get<U>()`; `#!cpp
|
||||
- `#!cpp std::vector<U, A>` -- element by element, each converted with `#!cpp get<U>()`; `#!cpp
|
||||
std::vector<basic_json_view>` keeps a view of every element instead of a value
|
||||
- `#!cpp std::map<K, V, C, A>` and `#!cpp std::unordered_map<K, V, H, E, A>`, if `K` is constructible from a `#!cpp
|
||||
(const char*, std::size_t)` pair -- from an object, member by member, each value converted with `#!cpp get<V>()`; with a repeated
|
||||
(const char*, std::size_t)` pair -- member by member, each value converted with `#!cpp get<V>()`; with a repeated
|
||||
key, the *last* value is kept, as [`BasicJsonType::parse()`](../basic_json/parse.md) (and
|
||||
[`materialize()`](materialize.md)) does; `#!cpp std::map<std::string, basic_json_view>` keeps views of the members
|
||||
instead of values
|
||||
@@ -43,7 +43,7 @@ the value, converted to `T`
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -62,9 +62,6 @@ None of the exceptions thrown directly by this function (the first three bullets
|
||||
[`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no `BasicJsonType` value to point at. An
|
||||
exception thrown while converting through `materialize()` (the last bullet) is different: it is thrown by a real
|
||||
`BasicJsonType` value, so it **does** carry a `JSON_DIAGNOSTICS` path if `BasicJsonType` was built with it enabled.
|
||||
That path is relative to the root of the view's subtree, because `materialize()` builds only the subtree (with parent
|
||||
pointers): it is empty if the failing value is the subtree's root itself, and it never is the path within the whole
|
||||
document.
|
||||
|
||||
## Complexity
|
||||
|
||||
@@ -76,8 +73,8 @@ document.
|
||||
- `#!cpp std::map`/`#!cpp std::unordered_map`: linear in the number of members for walking them, plus the container's
|
||||
own insertion cost per member (logarithmic for `#!cpp std::map`, amortized constant for `#!cpp
|
||||
std::unordered_map`), times the complexity of converting one member to the mapped type.
|
||||
- every other `T`: the cost of [`materialize()`](materialize.md) and of destroying the `BasicJsonType` value
|
||||
afterwards, plus that of [`BasicJsonType::get<T>()`](../basic_json/get.md).
|
||||
- every other `T`: linear in the size of the subtree (building the `BasicJsonType` value), plus the complexity of
|
||||
[`BasicJsonType::get<T>()`](../basic_json/get.md) on it.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ had to be decoded once when the document was parsed).
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -37,14 +37,9 @@ hand out a reference to a stored `string_t`. `get_string()` (equivalently, [`get
|
||||
zero-copy alternative: [`BasicJsonType::get_ref<const string_t&>()`](../basic_json/get_ref.md) is its closest
|
||||
counterpart, except that it returns a view instead of a reference to a value that must already exist.
|
||||
|
||||
`get_string()` borrows the string: nothing is copied, whereas [`get<std::string>()`](get.md) copies it. For a borrowed
|
||||
document, the returned [`string_view_t`](index.md#member-types) is valid as long as the caller's buffer; for an owned
|
||||
one, as long as the document.
|
||||
|
||||
The returned [`string_view_t`](index.md#member-types) is valid exactly as long as the view that produced it -- see the
|
||||
[validity rules](index.md) of `basic_json_view` -- and, for a string with no escapes, for as long as the document's
|
||||
source text, which for a borrowed document must remain valid **and unmodified** for as long as the document exists,
|
||||
since floating-point values and unescaped strings are read from the source lazily.
|
||||
source text.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -5,15 +5,12 @@ template<typename T>
|
||||
T& get_to(T& v) const;
|
||||
```
|
||||
|
||||
Converts the value to `T` and stores it in `v`, in one of two ways:
|
||||
Converts the value to `T` and assigns it to `v`. Equivalent to
|
||||
|
||||
- For the types that [`get<T>()`](get.md) converts directly -- arithmetic types, `#!cpp bool`,
|
||||
`#!cpp std::nullptr_t`, [`string_view_t`](index.md#member-types), `#!cpp std::basic_string`, `BasicJsonType`,
|
||||
`basic_json_view`, `#!cpp std::vector`, and `#!cpp std::map`/`#!cpp std::unordered_map` with string keys -- `v` is
|
||||
assigned: `#!cpp v = get<T>()`.
|
||||
- For every other type, the subtree is built into a `BasicJsonType` value and `#!cpp materialize().get_to(v)` is
|
||||
called, i.e. `from_json()` is invoked with the existing `v`, exactly as
|
||||
[`BasicJsonType::get_to()`](../basic_json/get_to.md) does.
|
||||
```cpp
|
||||
v = get<T>();
|
||||
return v;
|
||||
```
|
||||
|
||||
## Template parameters
|
||||
|
||||
@@ -31,27 +28,15 @@ Converts the value to `T` and stores it in `v`, in one of two ways:
|
||||
|
||||
## Exception safety
|
||||
|
||||
- For the directly converted types: strong exception safety. If an exception is thrown, `v` is not modified.
|
||||
- For every other type: as for [`BasicJsonType::get_to()`](../basic_json/get_to.md). `materialize()` throws before `v`
|
||||
is touched, but a `from_json()` that throws may leave `v` partly modified.
|
||||
Strong exception safety: if an exception is thrown, `v` is not modified.
|
||||
|
||||
## Exceptions
|
||||
|
||||
- For the directly converted types: whatever [`get<T>()`](get.md) throws for the same value and `T`.
|
||||
- For every other type: whatever [`materialize()`](materialize.md) and
|
||||
[`BasicJsonType::get_to()`](../basic_json/get_to.md) throw.
|
||||
Whatever [`get<T>()`](get.md) throws for the same value and `T`.
|
||||
|
||||
## Complexity
|
||||
|
||||
- For the directly converted types: whatever [`get<T>()`](get.md) has for the same `T`.
|
||||
- For every other type: that of [`materialize()`](materialize.md), plus that of
|
||||
[`BasicJsonType::get_to()`](../basic_json/get_to.md).
|
||||
|
||||
## Notes
|
||||
|
||||
The difference between the two ways matters for a `from_json()` that sets only the fields present in the JSON: since
|
||||
it runs on the existing `v`, the other fields of `v` keep their values, whereas assigning `get<T>()` would replace
|
||||
them with those of a default-constructed `T`.
|
||||
Whatever [`get<T>()`](get.md) has for the same `T`.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -14,27 +14,18 @@ to the document and a pointer into its index), trivially copyable. A view is val
|
||||
- the document has not been re-parsed with [`read()`](../basic_json_document/read.md) (or
|
||||
[`parse()`](../basic_json_document/parse.md) into it) or shrunk with
|
||||
[`shrink_to_fit()`](../basic_json_document/shrink_to_fit.md) since the view was taken, and
|
||||
- if the document borrows its source text, that text is still alive and unmodified (floating-point values and
|
||||
unescaped strings are read from it lazily).
|
||||
- if the document borrows its source text, that text is still alive.
|
||||
|
||||
Moving the document itself does not invalidate its views: the index is heap-allocated independently of the
|
||||
`basic_json_document` object.
|
||||
|
||||
`basic_json_view` provides the read-only part of the `BasicJsonType` interface:
|
||||
|
||||
- the type-inspection functions
|
||||
- element access
|
||||
- lookup
|
||||
- iteration
|
||||
- conversion: [`get<T>()`](get.md), [`get_string()`](get_string.md), [`number_token()`](number_token.md), and
|
||||
[`materialize()`](materialize.md) to build the `BasicJsonType` value of a subtree on demand
|
||||
- comparison: [`operator==`](operator_eq.md) and [`operator!=`](operator_ne.md) compare two views, or a view and a
|
||||
`BasicJsonType` value, without ever building a `BasicJsonType` value for a view; no ordering comparison
|
||||
(`#!cpp operator<`) is provided
|
||||
|
||||
[`operator[]`](operator%5B%5D.md), [`at`](at.md), [`contains`](contains.md), and [`value`](value.md) also accept a
|
||||
[`json_pointer`](../json_pointer/index.md). Unlike `basic_json`, there are no implicit conversion operators (no
|
||||
`#!cpp operator ValueType()`), and no `#!cpp get_ptr()` or `#!cpp get_ref()`; see [`get`](get.md).
|
||||
`basic_json_view` provides the read-only part of the `BasicJsonType` interface: the type-inspection functions, element
|
||||
access, lookup, iteration, conversion, and comparison -- [`get<T>()`](get.md), [`get_string()`](get_string.md),
|
||||
[`number_token()`](number_token.md), and [`materialize()`](materialize.md) to build the `BasicJsonType` value of a
|
||||
subtree on demand. [`operator[]`](operator%5B%5D.md), [`at`](at.md), [`contains`](contains.md), and
|
||||
[`value`](value.md) also accept a [`json_pointer`](../json_pointer/index.md). [`operator==`](operator_eq.md) and
|
||||
[`operator!=`](operator_ne.md) compare two views, or a view and a `BasicJsonType` value, without ever building a
|
||||
`BasicJsonType` value for a view; no ordering comparison (`#!cpp operator<`) is provided.
|
||||
|
||||
`basic_json_view` itself is always read-only -- it never has a `set` or `push_back` of its own. A view of an
|
||||
**editable** document (`#!cpp Editable == true`) sees every edit made through
|
||||
@@ -70,6 +61,7 @@ still refers to it -- including ones taken before the change -- reads the new va
|
||||
- **string_view_t** - `#!cpp std::string_view` on C++17 and newer, a minimal internal substitute otherwise
|
||||
- **iterator**, **const_iterator** - a forward iterator over the elements of an array or the member values of an
|
||||
object, in document order; both names refer to the same type, since a view is always read-only
|
||||
- **item** - a (key, value) pair produced by [`items()`](items.md)
|
||||
- [**number_format**](number_format.md) - how [`dump()`](dump.md) writes numbers
|
||||
|
||||
## Member functions
|
||||
|
||||
@@ -38,8 +38,7 @@ Constant.
|
||||
## See also
|
||||
|
||||
- [is_structured](is_structured.md) - return whether the type is structured
|
||||
- [size](size.md) - the number of elements
|
||||
- [empty](empty.md) - whether there are no elements
|
||||
- [size](size.md), [empty](empty.md) - the number of elements, and whether there are none
|
||||
- [`BasicJsonType::is_array`](../basic_json/is_array.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
bool is_binary() const noexcept;
|
||||
```
|
||||
|
||||
This function always returns `#!cpp false`: a document is only ever parsed from JSON text, never from CBOR or the other
|
||||
binary formats, and a JSON text has no binary values, so a view can never refer to one. The function exists for
|
||||
interface parity with [`BasicJsonType::is_binary`](../basic_json/is_binary.md).
|
||||
This function always returns `#!cpp false`: a JSON text has no binary values, so a view can never refer to one. The
|
||||
function exists for interface parity with [`BasicJsonType::is_binary`](../basic_json/is_binary.md).
|
||||
|
||||
## Return value
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ JSON pointer that cannot be resolved, and for any access on a view that is itsel
|
||||
|
||||
## Return value
|
||||
|
||||
`#!cpp true` if the view or its document is discarded, `#!cpp false` otherwise.
|
||||
`#!cpp true` if the view is discarded, `#!cpp false` otherwise.
|
||||
|
||||
## Exception safety
|
||||
|
||||
|
||||
@@ -38,8 +38,7 @@ Constant.
|
||||
## See also
|
||||
|
||||
- [is_structured](is_structured.md) - return whether the type is structured
|
||||
- [size](size.md) - the number of elements
|
||||
- [empty](empty.md) - whether there are no elements
|
||||
- [size](size.md), [empty](empty.md) - the number of elements, and whether there are none
|
||||
- [`BasicJsonType::is_object`](../basic_json/is_object.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
@@ -37,8 +37,7 @@ Constant.
|
||||
|
||||
## See also
|
||||
|
||||
- [source_offset](source_offset.md) - byte offset of this value in the source text, which differs for strings: an
|
||||
escaped string has none
|
||||
- [source_offset](source_offset.md) - byte offset of this value in the document's source text
|
||||
- [`BasicJsonType::is_string`](../basic_json/is_string.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
/* unspecified */ items() const noexcept;
|
||||
```
|
||||
|
||||
Returns a range of items -- (key, value) pairs -- for use in range-based for loops. An item's `#!cpp key()` is a
|
||||
`#!cpp string_view_t` (for an array element, its index converted to a string, as for
|
||||
[`BasicJsonType::items()`](../basic_json/items.md)), and its `#!cpp value()` is a `basic_json_view` of the element.
|
||||
Returns a range of [`item`](index.md#member-types) values -- (key, value) pairs -- for use in range-based for loops.
|
||||
The key of an array element is its index, converted to a string, as for
|
||||
[`BasicJsonType::items()`](../basic_json/items.md).
|
||||
|
||||
The returned type is not part of the public API and may change between versions; use a range-based for loop (see the
|
||||
example), or `#!cpp decltype(v.items())` if you need to name it.
|
||||
@@ -33,8 +33,8 @@ is nothing for a reference to bind to.
|
||||
|
||||
## Return value
|
||||
|
||||
A range whose iterators dereference to an item (with `#!cpp key()` and `#!cpp value()`, see above) and whose
|
||||
`#!cpp begin()`/`#!cpp end()` are equivalent to [`basic_json_view::begin()`](begin.md)/[`end()`](end.md), in document order.
|
||||
A range whose iterators dereference to [`item`](index.md#member-types) and whose `#!cpp begin()`/`#!cpp end()` are
|
||||
equivalent to [`basic_json_view::begin()`](begin.md)/[`end()`](end.md), in document order.
|
||||
|
||||
## Exception safety
|
||||
|
||||
@@ -48,14 +48,14 @@ Constant.
|
||||
|
||||
As for [`begin()`](begin.md)/[`end()`](end.md), `items()` visits **every** member of an object, including all
|
||||
occurrences of a duplicate key -- unlike [`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md),
|
||||
and [`contains`](contains.md), which resolve to the *first* member with a given key. See the
|
||||
[`contains`](contains.md), and [`count`](count.md), which resolve to the *first* member with a given key. See the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]`.
|
||||
|
||||
!!! danger "Lifetime issues"
|
||||
|
||||
Unlike `BasicJsonType::items()` (see [#2040](https://github.com/nlohmann/json/issues/2040)), calling `items()` on
|
||||
a temporary view is safe, for instance `#!cpp for (auto item : v["a"].items())`: the returned range holds a copy
|
||||
of the view. What must outlive the loop is the document and, for a borrowed document, the source buffer.
|
||||
As for `BasicJsonType::items()`, calling `items()` on a temporary view (or a temporary document) is dangerous:
|
||||
the range refers back to the document, so the document must outlive the loop. See
|
||||
[#2040](https://github.com/nlohmann/json/issues/2040) for the `BasicJsonType` background.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ if the view is [discarded](is_discarded.md).
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to (nothing about either is mutated by
|
||||
this function).
|
||||
Strong guarantee: if an exception is thrown, there are no changes to the view or the document it refers to (nothing
|
||||
about either is mutated by this function).
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -28,13 +28,12 @@ Linear in the size of the subtree.
|
||||
## Notes
|
||||
|
||||
`materialize()` replays the subtree through the same SAX builder [`BasicJsonType::parse()`](../basic_json/parse.md)
|
||||
uses, so the result matches it exactly -- including, for an object, that a repeated key keeps only its
|
||||
uses internally, so the result matches it exactly -- including, for an object, that a repeated key keeps only its
|
||||
last value. The replay is iterative, so it is not limited by the call stack the way a naive recursive conversion
|
||||
would be; the JSON nesting depth is limited only by available memory, as for `BasicJsonType::parse()` itself.
|
||||
|
||||
Unlike parsing with [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) enabled, the values
|
||||
produced by `materialize()` do not carry source positions. The index has the start offset of every value, but not the
|
||||
end of arrays, objects, and escaped strings, which the positions also need.
|
||||
produced by `materialize()` do not carry source positions: there is no lexer run during the replay to record them.
|
||||
|
||||
Calling `materialize()` on the same view repeatedly builds a new, independent `BasicJsonType` value each time; it
|
||||
never caches the result.
|
||||
|
||||
@@ -15,7 +15,7 @@ and [`materialize()`](materialize.md) can only represent approximately, as a `nu
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ basic_json_view operator[](const json_pointer& ptr) const;
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -83,8 +83,8 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content, so a
|
||||
key of a different length than `key` is rejected without touching the source text.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
|
||||
on average.
|
||||
2. Linear in `idx`: elements are skipped one at a time from the first one, since they are not a fixed size in the
|
||||
index (unlike `BasicJsonType`'s array, which is random-access).
|
||||
3. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
@@ -110,13 +110,13 @@ document.
|
||||
!!! warning "Duplicate keys: the first member wins"
|
||||
|
||||
If the source text has an object with a duplicate key, `#!cpp operator[]` (and [`at`](at.md), [`find`](find.md),
|
||||
[`contains`](contains.md), [`value`](value.md), and JSON pointer resolution) all resolve to
|
||||
[`contains`](contains.md), [`count`](count.md), [`value`](value.md), and JSON pointer resolution) all resolve to
|
||||
the *first* member with that key, because a lookup can stop as soon as it finds a match. This is different from
|
||||
[`materialize()`](materialize.md) (and [`BasicJsonType::parse()`](../basic_json/parse.md)), which replay every
|
||||
member in order and so keep the *last* value for a repeated key, so `#!cpp v["a"]` and
|
||||
`#!cpp v.materialize()["a"]` can differ. To get the value `parse()` would give, use
|
||||
[`materialize()`](materialize.md) or iterate the members with [`items()`](items.md) and keep the last match.
|
||||
The key hash index of a larger object (128 members or more) leads to the first member of a key as well.
|
||||
The hash index of a larger object (128 members or more) leads to the first member of a key as well.
|
||||
[`begin()`](begin.md)/[`end()`](end.md) and [`items()`](items.md) iterate over *all* members, including
|
||||
duplicates, in document order. See [Duplicate keys](../../features/json_view.md#duplicate-keys) and
|
||||
[`size()`](size.md#notes).
|
||||
|
||||
@@ -10,15 +10,15 @@ Returns the number of elements, as [`BasicJsonType::size()`](../basic_json/size.
|
||||
|
||||
The return value depends on the type and is defined as follows:
|
||||
|
||||
| Value type | return value |
|
||||
|------------|---------------------------|
|
||||
| null | `0` |
|
||||
| discarded | `0` |
|
||||
| boolean | `1` |
|
||||
| string | `1` |
|
||||
| number | `1` |
|
||||
| object | number of key/value pairs |
|
||||
| array | number of elements |
|
||||
| Value type | return value |
|
||||
|----------------------|-----------------------------|
|
||||
| null | `0` |
|
||||
| discarded | `0` |
|
||||
| boolean | `1` |
|
||||
| string | `1` |
|
||||
| number | `1` |
|
||||
| object | number of key/value pairs |
|
||||
| array | number of elements |
|
||||
|
||||
## Exception safety
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ same string for a discarded `BasicJsonType` value).
|
||||
a string representation of the type ([`value_t`](../basic_json/value_t.md)):
|
||||
|
||||
| Value type | return value |
|
||||
|----------------------------------------------------|---------------|
|
||||
| `#!json null` | `"null"` |
|
||||
| boolean | `"boolean"` |
|
||||
| string | `"string"` |
|
||||
| number (integer, unsigned integer, floating-point) | `"number"` |
|
||||
| object | `"object"` |
|
||||
| array | `"array"` |
|
||||
| discarded | `"discarded"` |
|
||||
|-----------------------------------------------------|---------------|
|
||||
| `#!json null` | `"null"` |
|
||||
| boolean | `"boolean"` |
|
||||
| string | `"string"` |
|
||||
| number (integer, unsigned integer, floating-point) | `"number"` |
|
||||
| object | `"object"` |
|
||||
| array | `"array"` |
|
||||
| discarded | `"discarded"` |
|
||||
|
||||
`type_name()` never returns `#!cpp "binary"`, since a JSON text has no binary values (see
|
||||
[`is_binary()`](is_binary.md)); it also never returns `#!cpp "invalid"`, since a view's `#!cpp kind` always comes
|
||||
|
||||
@@ -44,7 +44,7 @@ equivalent) deduce `string_t`, not `const char*`, for their return type and for
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -70,8 +70,8 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
1. Linear in the number of members: as for [`operator[]`](operator[].md#complexity), members are compared one after
|
||||
another, in document order, stopping at the first match. Plus the complexity of converting
|
||||
the found member to `T` (see [`get`](get.md)).
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
|
||||
on average.
|
||||
2. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
that level or the index into the array -- as for the [`operator[]`](operator[].md#complexity) and
|
||||
[`at`](at.md#complexity) overloads that take a JSON pointer. Plus the complexity of converting the resolved value
|
||||
|
||||
@@ -16,10 +16,6 @@ header. See also the [macro overview page](../../features/macros.md).
|
||||
|
||||
## Parsing
|
||||
|
||||
- [**JSON_DISABLE_STREAM_BULK_SCAN**](json_disable_stream_bulk_scan.md) - read a `std::istream` one character at a time
|
||||
instead of scanning its stream buffer in bulk
|
||||
- [**JSON_DISABLE_UNLOCKED_FILE_IO**](json_disable_unlocked_file_io.md) - read a `FILE*` with `std::fgetc` instead of
|
||||
locking it once and using the unlocked stdio functions
|
||||
- [**JSON_PRECISE_STREAM_POSITION**](json_precise_stream_position.md) - opt in to leaving an input stream positioned
|
||||
right after a parsed number
|
||||
- [**JSON_STRICT_BINARY_UTF8**](json_strict_binary_utf8.md) - opt in to checking strings for valid UTF-8 in the CBOR,
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
# JSON_DISABLE_STREAM_BULK_SCAN
|
||||
|
||||
```cpp
|
||||
#define JSON_DISABLE_STREAM_BULK_SCAN /* value */
|
||||
```
|
||||
|
||||
When defined to `1`, parsing from a `#!cpp std::istream` reads the input one character at a time through the stream
|
||||
buffer, as in version 3.12.0 and earlier, instead of scanning the characters that the stream buffer already holds in
|
||||
bulk.
|
||||
|
||||
The macro is an escape hatch for stream buffers that do not follow the usual contract of `std::basic_streambuf` (see
|
||||
the requirements on the stream buffer in the notes below). It does not change any result: values, exceptions, and the
|
||||
position of the stream after parsing are the same either way. Only the speed differs.
|
||||
|
||||
## Default definition
|
||||
|
||||
The default value is `0`: streams are scanned in bulk.
|
||||
|
||||
```cpp
|
||||
#define JSON_DISABLE_STREAM_BULK_SCAN 0
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "How streams are scanned"
|
||||
|
||||
A `std::streambuf` keeps the part of the input it has read but not yet handed out in its *get area*, the range
|
||||
from `gptr()` to `egptr()`. A `std::filebuf`, for instance, reads the file in blocks of a few kilobytes into its get
|
||||
area, and a `std::stringbuf` exposes its whole string as one get area.
|
||||
|
||||
When parsing from a `std::istream`, the parser scans this get area directly, with the same fast paths that it uses
|
||||
for a `std::string`: runs of ordinary string characters, numbers, and indentation are recognized several bytes at a
|
||||
time instead of being requested from the stream buffer one character at a time. When the parser reaches the end of
|
||||
the get area, it asks the stream buffer for the next character as before, which makes the stream buffer refill its
|
||||
get area.
|
||||
|
||||
The parser only reads characters that it would also have read one at a time, and it advances the stream buffer
|
||||
exactly over the characters it consumes. Nothing is read ahead, buffered elsewhere, or put back. Therefore, the
|
||||
stream is left exactly where it was left before:
|
||||
|
||||
- [`operator>>`](../operator_gtgt.md) and [`sax_parse`](../basic_json/sax_parse.md) with `strict = false` can still
|
||||
read several values from one stream, and the stream can still be used with other `std::istream` functions after a
|
||||
value has been read.
|
||||
- With [`JSON_PRECISE_STREAM_POSITION`](json_precise_stream_position.md), the stream is still positioned right after
|
||||
a parsed number.
|
||||
- Exception messages, including the line, the column, and the last read token, are unchanged.
|
||||
|
||||
!!! note "Performance"
|
||||
|
||||
Parsing from a `std::ifstream` or `std::istringstream` is typically 1.5 to 2 times as fast as before, and reading
|
||||
many small values from one stream with `operator>>` 1.4 to 4 times as fast. Parsing from a stream is then within
|
||||
about 10 to 20 % of first reading the whole file into a `std::string` and parsing that.
|
||||
|
||||
A stream buffer without a get area (one that only overrides `underflow()` and `uflow()` and hands out every
|
||||
character from there) offers nothing to scan in bulk, so it is read one character at a time as before.
|
||||
|
||||
!!! note "Requirements on the stream buffer"
|
||||
|
||||
The bulk scan relies on the following behavior, which every stream buffer of the standard library and every stream
|
||||
buffer that keeps its input in its get area has:
|
||||
|
||||
- When `sgetc()` returns a character while `gptr() < egptr()`, that character is `*gptr()`; when `sbumpc()` returns
|
||||
one, it was at `gptr()` before the call.
|
||||
- Characters in the get area are not changed while they are in the get area.
|
||||
- `underflow()` or `uflow()` either sets up a get area that holds the returned character at `gptr()` (or at
|
||||
`gptr() - 1` after `uflow()`), or leaves the get area empty.
|
||||
|
||||
A stream buffer that returns characters from `uflow()` while leaving unrelated characters in its get area, or that
|
||||
changes the characters in its get area in place, does not meet these requirements. Define the macro to `1` for
|
||||
such stream buffers.
|
||||
|
||||
!!! note "ABI compatibility"
|
||||
|
||||
The value of this macro is encoded in the [namespace](../../features/namespace.md) (tag `_dsbs`), resulting in
|
||||
distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program
|
||||
without One Definition Rule (ODR) violations, but they cannot exchange instances of library types.
|
||||
|
||||
!!! note "Other inputs"
|
||||
|
||||
Strings, string views, vectors, arrays, and pointer or iterator ranges over contiguous memory are scanned in bulk
|
||||
anyway. Reading from a `#!cpp FILE*` is not affected by this macro; see
|
||||
[`JSON_DISABLE_UNLOCKED_FILE_IO`](json_disable_unlocked_file_io.md) for that input.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: reading values from a stream (default)"
|
||||
|
||||
The stream is scanned in bulk, and the values are read one after the other:
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::istringstream input(R"({"id": 1} {"id": 2} 42 rest)");
|
||||
json j1, j2, j3;
|
||||
input >> j1 >> j2 >> j3; // {"id":1}, {"id":2}, 42
|
||||
|
||||
std::string word;
|
||||
input >> word; // "rest"
|
||||
}
|
||||
```
|
||||
|
||||
??? example "Example: reading one character at a time (macro defined to 1)"
|
||||
|
||||
With the macro, the same program reads the stream one character at a time, with the same results:
|
||||
|
||||
```cpp
|
||||
#define JSON_DISABLE_STREAM_BULK_SCAN 1
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::istringstream input(R"({"id": 1} {"id": 2} 42 rest)");
|
||||
json j1, j2, j3;
|
||||
input >> j1 >> j2 >> j3; // {"id":1}, {"id":2}, 42
|
||||
|
||||
std::string word;
|
||||
input >> word; // "rest"
|
||||
}
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [**parse**](../basic_json/parse.md) - deserialize from a compatible input
|
||||
- [**operator>>**](../operator_gtgt.md) - deserialize from stream
|
||||
- [**sax_parse**](../basic_json/sax_parse.md) - generate SAX events
|
||||
- [**JSON_PRECISE_STREAM_POSITION**](json_precise_stream_position.md) - leave an input stream positioned right after a
|
||||
parsed number
|
||||
- [**JSON_DISABLE_UNLOCKED_FILE_IO**](json_disable_unlocked_file_io.md) - read a `FILE*` with the locking stdio
|
||||
functions
|
||||
- [Parsing: input sources and performance](../../features/parsing/index.md#input-sources-and-performance)
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -1,115 +0,0 @@
|
||||
# JSON_DISABLE_UNLOCKED_FILE_IO
|
||||
|
||||
```cpp
|
||||
#define JSON_DISABLE_UNLOCKED_FILE_IO /* value */
|
||||
```
|
||||
|
||||
When defined to `1`, parsing from a `#!cpp FILE*` reads every character with `std::fgetc`, as in version 3.12.0 and
|
||||
earlier, instead of locking the file once and reading it with the unlocked stdio functions.
|
||||
|
||||
It does not change any result: values, exceptions, and the position of the file after parsing are the same either way.
|
||||
Only the speed and the locking of the file differ (see the notes on locking below).
|
||||
|
||||
Builds with MemorySanitizer use `std::fgetc` automatically, because the inline `getc_unlocked` of glibc reads the stdio
|
||||
buffer directly, which glibc (not instrumented) filled, and MemorySanitizer would report it as uninitialized.
|
||||
|
||||
## Default definition
|
||||
|
||||
The default value is `0`: the file is locked once and read with the unlocked stdio functions where they are available.
|
||||
|
||||
```cpp
|
||||
#define JSON_DISABLE_UNLOCKED_FILE_IO 0
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "Background"
|
||||
|
||||
The C standard library makes every `std::fgetc` call thread-safe by locking and unlocking the `FILE` object. When
|
||||
parsing from a `FILE*`, the parser reads one character at a time, so this happens for every character of the input.
|
||||
|
||||
Instead, the parser locks the file once when parsing starts and unlocks it when parsing ends - also when an
|
||||
exception is thrown - and reads the characters in between without locking:
|
||||
|
||||
| C library | functions |
|
||||
|------------------------------------------------------------|----------------------------------------------------|
|
||||
| glibc (Linux), Apple (macOS, iOS), Android, FreeBSD, NetBSD, OpenBSD, DragonFly BSD | `flockfile`, `getc_unlocked`, `funlockfile` (POSIX) |
|
||||
| Microsoft (MSVC, clang-cl) | `_lock_file`, `_fgetc_nolock`, `_unlock_file` |
|
||||
| others (e.g., musl, MinGW, newlib) | `std::fgetc`, as before |
|
||||
|
||||
This makes parsing from a `FILE*` 3 to 4 times as fast with the Apple C library and 1.1 to 1.3 times as fast with
|
||||
glibc, whose locking is cheaper. The binary formats ([`from_cbor`](../basic_json/from_cbor.md),
|
||||
[`from_msgpack`](../basic_json/from_msgpack.md), ...) read from a `FILE*` the same way.
|
||||
|
||||
!!! note "Locking"
|
||||
|
||||
While a value is parsed from a `FILE*`, the parsing thread holds the file's lock. The lock is recursive, so the
|
||||
parsing thread itself - for instance, a [SAX](../json_sax/index.md) handler or a
|
||||
[parser callback](../basic_json/parser_callback_t.md) - can keep using the file with stdio functions such as
|
||||
`std::ftell`. Other threads that use the same `FILE` object wait until the parser is done. Before, they could
|
||||
interleave their reads with the parser's, which made the parsed input unpredictable anyway.
|
||||
|
||||
A program in which a SAX handler or parser callback waits for **another** thread that uses the **same** `FILE`
|
||||
object would deadlock. Define the macro to `1` for such programs.
|
||||
|
||||
!!! note "ABI compatibility"
|
||||
|
||||
The value of this macro is encoded in the [namespace](../../features/namespace.md) (tag `_dufio`), resulting in
|
||||
distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program
|
||||
without One Definition Rule (ODR) violations, but they cannot exchange instances of library types.
|
||||
|
||||
!!! note "Other inputs"
|
||||
|
||||
Reading from a `#!cpp std::istream` is not affected by this macro; see
|
||||
[`JSON_DISABLE_STREAM_BULK_SCAN`](json_disable_stream_bulk_scan.md) for that input.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: parsing from a `FILE*` (default)"
|
||||
|
||||
The file is locked once while it is parsed:
|
||||
|
||||
```cpp
|
||||
#include <cstdio>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::FILE* f = std::fopen("example.json", "rb");
|
||||
json j = json::parse(f); // f is locked until parse() returns
|
||||
std::fclose(f);
|
||||
}
|
||||
```
|
||||
|
||||
??? example "Example: locking for every character (macro defined to 1)"
|
||||
|
||||
With the macro, every character is read with `std::fgetc`, with the same result:
|
||||
|
||||
```cpp
|
||||
#define JSON_DISABLE_UNLOCKED_FILE_IO 1
|
||||
#include <cstdio>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::FILE* f = std::fopen("example.json", "rb");
|
||||
json j = json::parse(f); // std::fgetc for every character
|
||||
std::fclose(f);
|
||||
}
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [**parse**](../basic_json/parse.md) - deserialize from a compatible input
|
||||
- [**sax_parse**](../basic_json/sax_parse.md) - generate SAX events
|
||||
- [**JSON_DISABLE_STREAM_BULK_SCAN**](json_disable_stream_bulk_scan.md) - read a `std::istream` one character at a
|
||||
time
|
||||
- [Parsing: input sources and performance](../../features/parsing/index.md#input-sources-and-performance)
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -72,12 +72,6 @@ The default value is `0` (disabled — existing behavior is preserved).
|
||||
distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program
|
||||
without One Definition Rule (ODR) violations, but they cannot exchange instances of library types.
|
||||
|
||||
!!! note "Bulk scanning"
|
||||
|
||||
The parser scans the characters in the stream buffer in bulk (see
|
||||
[`JSON_DISABLE_STREAM_BULK_SCAN`](json_disable_stream_bulk_scan.md)), but it never reads ahead. The stream is left
|
||||
at the same position with and without bulk scanning, in both modes of this macro.
|
||||
|
||||
!!! tip "Workaround without the macro"
|
||||
|
||||
Separate the values in the stream with whitespace. The character consumed after a number is then the separator,
|
||||
|
||||
@@ -12,9 +12,8 @@ non-ASCII characters (e.g. CJK or emoji) this can validate several times faster.
|
||||
This is an **opt-in external dependency**. The library itself remains header-only and its behavior is unchanged: the
|
||||
same input is accepted or rejected either way, and every parse error is reported at the same position with the same
|
||||
message (simdutf is only used to fast-path *valid* runs; anything it flags falls back to the scalar path so the exact
|
||||
diagnostic is preserved). A `std::istream` uses simdutf for the characters its stream buffer holds (see
|
||||
[`JSON_DISABLE_STREAM_BULK_SCAN`](json_disable_stream_bulk_scan.md)); other streaming inputs (`FILE*`, wide strings,
|
||||
user-defined adapters) always use the scalar path.
|
||||
diagnostic is preserved). Streaming inputs (files, `std::istream`, wide strings, user-defined adapters) always use the
|
||||
scalar path.
|
||||
|
||||
When `JSON_USE_SIMDUTF` is defined you must make the `simdutf.h` header available on the include path and link the
|
||||
simdutf library. When it is not defined, no simdutf header is included and there is no dependency.
|
||||
|
||||
@@ -14,12 +14,10 @@ The same input is accepted or rejected either way, with the same values, and err
|
||||
the speed differs. The macro exists for platforms whose compilers lack the intrinsics headers, and to test the portable
|
||||
code.
|
||||
|
||||
!!! note "ABI compatibility"
|
||||
!!! warning "Define consistently"
|
||||
|
||||
The macro selects between two definitions of the same inline functions. Whether it is defined is encoded in the
|
||||
[namespace](../../features/namespace.md) (tag `_vns`), resulting in distinct symbol names. Translation units
|
||||
compiled with and without it can therefore be linked into the same program without One Definition Rule (ODR)
|
||||
violations, but they cannot exchange instances of library types.
|
||||
The macro selects between two definitions of the same inline functions. It must therefore be defined identically for
|
||||
**every** translation unit that includes `<nlohmann/json_view.hpp>`; prefer a compile definition on the target.
|
||||
|
||||
## Default definition
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ Define the macro only together with a compiler option that enables SSSE3 (e.g. `
|
||||
has it), and only for programs that run on such CPUs. It saves the check of the CPU, which costs little. The same
|
||||
input is accepted or rejected either way; only the speed of non-ASCII text differs.
|
||||
|
||||
!!! note "ABI compatibility"
|
||||
!!! warning "Define consistently"
|
||||
|
||||
The macro selects between two definitions of the same inline functions. Whether it is defined is encoded in the
|
||||
[namespace](../../features/namespace.md) (tag `_vssse3`, on every architecture), resulting in distinct symbol
|
||||
names. Translation units compiled with and without it can therefore be linked into the same program without One
|
||||
Definition Rule (ODR) violations, but they cannot exchange instances of library types.
|
||||
The macro selects between two definitions of the same inline functions. It must therefore be defined identically,
|
||||
with the same compiler options, for **every** translation unit that includes `<nlohmann/json_view.hpp>`; mixing
|
||||
translation units that define it with ones that do not is an ODR violation. Prefer a compile definition on the
|
||||
target.
|
||||
|
||||
## Default definition
|
||||
|
||||
|
||||
@@ -39,6 +39,5 @@ the library.
|
||||
## Version history
|
||||
|
||||
- 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`, `_ekmo`, `_dsbs`, `_dufio`, `_vns`, and
|
||||
`_vssse3` in version 3.13.0; see
|
||||
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).
|
||||
@@ -121,7 +121,6 @@ being read.
|
||||
- [`JSON_STRICT_NUL_HANDLING`](macros/json_strict_nul_handling.md) - opt in to rejecting a NUL byte in the input
|
||||
instead of treating it as end of input
|
||||
- [`JSON_PRECISE_STREAM_POSITION`](macros/json_precise_stream_position.md) - opt in to leaving the stream positioned right after a number
|
||||
- [`JSON_DISABLE_STREAM_BULK_SCAN`](macros/json_disable_stream_bulk_scan.md) - read the stream one character at a time
|
||||
|
||||
## Version history
|
||||
|
||||
@@ -134,6 +133,3 @@ being read.
|
||||
crash (`std::terminate`) when `i` has `eofbit` in its exception mask, in version 3.13.0.
|
||||
- Changed to the strong exception safety guarantee in version 3.13.0: `j` is no longer left with a partially parsed
|
||||
value if parsing throws.
|
||||
- Scans the characters in the stream buffer of `i` in bulk in version 3.13.0; the position of `i` after the call is
|
||||
unchanged ([`JSON_DISABLE_STREAM_BULK_SCAN`](macros/json_disable_stream_bulk_scan.md) restores reading one character
|
||||
at a time).
|
||||
@@ -135,9 +135,6 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa
|
||||
headers are included.
|
||||
- [x] On Windows, the library is compiled with `<Windows.h>` being included to detect and avoid common bugs (see
|
||||
[`unit-windows_h.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-windows_h.cpp)).
|
||||
- [x] The library is compiled with Qt's keyword macros (`slots`, `signals`, `emit`, `foreach`, `forever`) being defined
|
||||
to make sure it does not use them as identifiers (see
|
||||
[`unit-qt_keywords.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-qt_keywords.cpp)).
|
||||
- [x] The library is compiled with exceptions disabled to support alternative means of error handling.
|
||||
|
||||
## Stable public API
|
||||
|
||||
@@ -5,14 +5,13 @@ using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// validate that every transaction of a batch carries exactly one
|
||||
// validate that every transaction of a batch carries a mandatory
|
||||
// "amount" field before materializing any of them into a nlohmann::json
|
||||
// value -- count() counts every member with the key
|
||||
// value -- count() returns 0 or 1 for an object
|
||||
json_document batch = json_document::parse(R"(
|
||||
[
|
||||
{"id": 1, "amount": 9.99},
|
||||
{"id": 2},
|
||||
{"id": 3, "amount": 5.00, "amount": 500.00}
|
||||
{"id": 2}
|
||||
]
|
||||
)");
|
||||
|
||||
@@ -20,10 +19,9 @@ int main()
|
||||
for (std::size_t i = 0; i < transactions.size(); ++i)
|
||||
{
|
||||
const auto transaction = transactions[i];
|
||||
const auto amounts = transaction.count("amount");
|
||||
if (amounts != 1)
|
||||
if (transaction.count("amount") == 0)
|
||||
{
|
||||
std::cout << "transaction " << i << " has " << amounts << " \"amount\" fields\n";
|
||||
std::cout << "transaction " << i << " is missing \"amount\"\n";
|
||||
continue;
|
||||
}
|
||||
std::cout << "transaction " << i << ": " << transaction["amount"].materialize().dump() << '\n';
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
transaction 0: 9.99
|
||||
transaction 1 has 0 "amount" fields
|
||||
transaction 2 has 2 "amount" fields
|
||||
transaction 1 is missing "amount"
|
||||
@@ -14,8 +14,8 @@ C++ types, and finally serialize it again.
|
||||
[parsing untrusted input](parsing/untrusted_input.md).
|
||||
- [Zero-copy JSON views](json_view.md) — read a JSON text through a flat index instead of building a `json` tree;
|
||||
strings and numbers stay in the input and are only decoded when needed.
|
||||
- [Editable documents](json_view.md#editing-a-document) — modify a parsed document without building a `json` tree.
|
||||
- [Images](json_view.md#images) — save a parsed document and load it again without parsing it.
|
||||
[Editable documents](json_view.md#editing-a-document) can also be modified, and [images](json_view.md#images) load a
|
||||
parsed document again without parsing it.
|
||||
- [Comments](comments.md) and [trailing commas](trailing_commas.md) — opt-in relaxations of the JSON grammar.
|
||||
|
||||
## Accessing and modifying values
|
||||
|
||||
@@ -16,9 +16,8 @@ most of the resulting tree is thrown away almost immediately.
|
||||
[`basic_json_document::parse()`](../api/basic_json_document/parse.md) parses the same JSON grammar, with the same
|
||||
options, but instead of a tree it builds a flat index of the values it found: one
|
||||
[16-byte entry](../home/architecture.md#node-index-of-json-views) per value (and one per object key), in document
|
||||
order. Integers are converted while parsing and stored in their entry. Floating-point numbers and strings are
|
||||
referenced in place in the source text: a float is converted when it is read, and only strings that contain escape
|
||||
sequences are decoded, into one shared buffer owned by the document.
|
||||
order. Strings and numbers are not copied out of the input; they stay in the source text, and are only decoded when
|
||||
actually needed (for a string, only if it contains escape sequences, into one shared buffer owned by the document).
|
||||
|
||||
[`basic_json_view`](../api/basic_json_view/index.md) is a small, trivially copyable handle (two pointers) into that
|
||||
index. It gives you the read-only, type-inspection part of the `basic_json` interface --
|
||||
@@ -37,8 +36,7 @@ one [`parse()`](../api/basic_json/parse.md) would have produced for it.
|
||||
|
||||
Include `<nlohmann/json_view.hpp>` in addition to (or instead of) `<nlohmann/json.hpp>`. Parse into a
|
||||
[`json_document`](../api/json_document.md), inspect its [`root()`](../api/basic_json_document/root.md), and
|
||||
`materialize()` when you need a real value. `materialize()` works on any view, not just the root, so you can turn just
|
||||
the subtree you need into a value:
|
||||
`materialize()` when you need a real value:
|
||||
|
||||
??? example "Example: parse a document, inspect its root, and materialize it"
|
||||
|
||||
@@ -67,28 +65,23 @@ table). [`parse_copy()`](../api/basic_json_document/parse_copy.md) always owns a
|
||||
|
||||
!!! warning "A borrowed document depends on your buffer"
|
||||
|
||||
If a document borrows its text, that text **must outlive the document** (and every view taken from it) and must
|
||||
stay **unmodified** for as long as the document exists, since floating-point values and unescaped strings are
|
||||
read from it lazily. Reading or writing through a view after the underlying buffer is gone is undefined behavior,
|
||||
exactly as it would be for a dangling `#!cpp std::string_view`.
|
||||
If a document borrows its text, that text **must outlive the document** (and every view taken from it). Reading
|
||||
or writing through a view after the underlying buffer is gone is undefined behavior, exactly as it would be for
|
||||
a dangling `#!cpp std::string_view`.
|
||||
|
||||
A view is valid only while all of the following hold:
|
||||
|
||||
- the document is alive,
|
||||
- the document has not been re-parsed since the view was taken (with [`read()`](../api/basic_json_document/read.md)
|
||||
or [`parse()`](../api/basic_json_document/parse.md) into it),
|
||||
- the document has not had [`shrink_to_fit()`](../api/basic_json_document/shrink_to_fit.md) called on it since, and
|
||||
- if the document borrows its source text, that text is still alive and unmodified.
|
||||
or [`parse()`](../api/basic_json_document/parse.md) into it), and has not had
|
||||
[`shrink_to_fit()`](../api/basic_json_document/shrink_to_fit.md) called on it since, and
|
||||
- if the document borrows its source text, that text is still alive.
|
||||
|
||||
Moving the `basic_json_document<>` itself is fine and does **not** invalidate its views: the index is a separate heap
|
||||
allocation that keeps its address across the move. Take a fresh view from [`root()`](../api/basic_json_document/root.md)
|
||||
Moving the document itself is fine and does **not** invalidate its views: the index is a separate heap allocation
|
||||
that keeps its address across the move. Take a fresh view from [`root()`](../api/basic_json_document/root.md)
|
||||
whenever any of the other conditions above was not met.
|
||||
|
||||
A view can dangle, exactly like a `#!cpp std::string_view`: nothing stops you from using it after its document is
|
||||
gone. This is deliberate. A view is two pointers and trivially copyable; making it safe (a `#!cpp std::shared_ptr` in
|
||||
the document and a `#!cpp std::weak_ptr` in each view) would make it larger, add reference counting to every copy,
|
||||
and a `lock()` to every access -- exactly the costs the view exists to avoid. What is caught is the obvious case:
|
||||
because a view dies with its document, [`root()`](../api/basic_json_document/root.md) is not callable on a temporary
|
||||
Because a view dies with its document, [`root()`](../api/basic_json_document/root.md) is not callable on a temporary
|
||||
document: `#!cpp auto v = json_document::parse(text).root();` does not compile. Give the document a name first.
|
||||
|
||||
??? example "Example: borrowed and owned documents, and when views become invalid"
|
||||
@@ -110,19 +103,14 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
||||
[`basic_json::accept()`](../api/basic_json/accept.md)/[`basic_json::parse()`](../api/basic_json/parse.md), with the
|
||||
same `ignore_comments` and `ignore_trailing_commas` options.
|
||||
- **Errors.** A failing parse throws the same exception -- the same id, message, and position -- because on failure
|
||||
the library's own parser is run on the same bytes to produce the diagnostic. Valid input never pays for this, and
|
||||
the replay builds no values: it costs about a lexing pass up to the error.
|
||||
`#!cpp allow_exceptions == false` skips the replay and gives a
|
||||
[discarded](../api/basic_json_document/is_discarded.md) document instead of throwing, just as it gives a discarded
|
||||
value for `#!cpp basic_json::parse()`.
|
||||
the library's own parser is run on the same bytes to produce the diagnostic.
|
||||
`#!cpp allow_exceptions == false` gives a [discarded](../api/basic_json_document/is_discarded.md) document instead
|
||||
of throwing, just as it gives a discarded value for `#!cpp basic_json::parse()`.
|
||||
- **Number classification.** An integer literal that does not fit into the 64-bit integer type becomes a
|
||||
floating-point value, exactly as it does for `#!cpp basic_json::parse()`.
|
||||
- **Macros.** [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) and
|
||||
[`JSON_NOEXCEPTION`](../api/macros/json_noexception.md)/[`JSON_THROW_USER`](../api/macros/json_throw_user.md)
|
||||
behave the same way they do for `<nlohmann/json.hpp>`. These are the macros that change what the parser accepts or
|
||||
how it reports errors. The others either do not apply ([`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md)
|
||||
needs parent pointers in `basic_json` values) or only affect the values `materialize()` produces, through
|
||||
`BasicJsonType`.
|
||||
behave the same way they do for `<nlohmann/json.hpp>`.
|
||||
|
||||
## What is different
|
||||
|
||||
@@ -130,15 +118,12 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
||||
`number_unsigned_t` to both be 64 bits wide; this is a compile-time `#!cpp static_assert`.
|
||||
- **A 4 GiB input limit.** An input of 4294967280 bytes (4 GiB minus 16 bytes) or more throws
|
||||
[`out_of_range.416`](../home/exceptions.md#jsonexceptionout_of_range416), a limit
|
||||
`#!cpp basic_json::parse()` does not have. It keeps an index entry at 16 bytes: offsets and counts are 32 bits
|
||||
wide. The limit is 16 bytes below 2^32, because the parser reads in 16-byte steps, and a position one step past the
|
||||
end must still fit.
|
||||
- **A stream is always read to its end.** There is no partial/streaming read of an `#!cpp std::istream`: the stream
|
||||
is read to its end into a buffer the document owns, and parsing starts after that.
|
||||
`#!cpp basic_json::parse()` does not have.
|
||||
- **A stream is always read to its end.** There is no partial/streaming read of an `#!cpp std::istream`.
|
||||
- **No source positions on `materialize()`.** Even with
|
||||
[`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md) enabled,
|
||||
[`materialize()`](../api/basic_json_view/materialize.md) does not set them. The index has the start offset of every
|
||||
value, but not the end of arrays, objects, and escaped strings, which the positions also need.
|
||||
[`materialize()`](../api/basic_json_view/materialize.md) does not set them: there is no lexer run during the
|
||||
replay to record them.
|
||||
- **Objects iterate in document order.** [`begin()`](../api/basic_json_view/begin.md)/
|
||||
[`end()`](../api/basic_json_view/end.md) and [`items()`](../api/basic_json_view/items.md) visit an object's
|
||||
members in the order they appear in the source text. `basic_json`'s default `object_t` is a `std::map`, which
|
||||
@@ -168,10 +153,10 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
||||
|
||||
If an object in the source text repeats a key, [`operator[]`](../api/basic_json_view/operator%5B%5D.md),
|
||||
[`at`](../api/basic_json_view/at.md), [`find`](../api/basic_json_view/find.md),
|
||||
[`value`](../api/basic_json_view/value.md), [`contains`](../api/basic_json_view/contains.md), and JSON pointer
|
||||
resolution all return the **first** member with that key. `basic_json::parse()` instead keeps the **last** value
|
||||
of a repeated key, so for `#!cpp {"a":1,"a":2}`, `#!cpp view["a"]` is `#!cpp 1` while `#!cpp parse(text)["a"]` is
|
||||
`#!cpp 2`. [`count`](../api/basic_json_view/count.md) counts every member with the key, so it is `#!cpp 2` here.
|
||||
[`value`](../api/basic_json_view/value.md), [`contains`](../api/basic_json_view/contains.md),
|
||||
[`count`](../api/basic_json_view/count.md), and JSON pointer resolution all return the **first** member with that
|
||||
key. `basic_json::parse()` instead keeps the **last** value of a repeated key, so for `#!cpp {"a":1,"a":2}`,
|
||||
`#!cpp view["a"]` is `#!cpp 1` while `#!cpp parse(text)["a"]` is `#!cpp 2`.
|
||||
|
||||
[`begin()`](../api/basic_json_view/begin.md)/[`end()`](../api/basic_json_view/end.md) and
|
||||
[`items()`](../api/basic_json_view/items.md) visit *every* occurrence, in document order, and
|
||||
@@ -180,7 +165,7 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
||||
|
||||
**Why the first?** A lookup can stop as soon as it finds a match. Returning the last member would force every lookup
|
||||
to scan all members of the object, even when the key is found at the very first one: this made lookups in small
|
||||
objects 1.6 to 3.4 times slower. The hash index of the keys of objects with 128 members or more leads to the first member of a
|
||||
objects 1.6 to 3.4 times slower. The hash index of objects with 128 members or more leads to the first member of a
|
||||
key as well. Other zero-copy parsers that index the source text, such as yyjson and simdjson, also return the first
|
||||
member. RFC 8259 only says that names within an object SHOULD be unique and that the behavior of a receiver that sees
|
||||
duplicates is unpredictable, so neither choice is wrong.
|
||||
|
||||
@@ -133,14 +133,6 @@ When defined, default parse and serialize functions for enums are excluded and h
|
||||
|
||||
See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md).
|
||||
|
||||
## `JSON_DISABLE_STREAM_BULK_SCAN`
|
||||
|
||||
When defined to `1`, parsing from a `#!cpp std::istream` reads one character at a time instead of scanning the
|
||||
characters that the stream buffer holds in bulk. Results are the same either way; the macro is an escape hatch for
|
||||
stream buffers that do not follow the usual `std::streambuf` contract. The default value is `0`.
|
||||
|
||||
See [full documentation of `JSON_DISABLE_STREAM_BULK_SCAN`](../api/macros/json_disable_stream_bulk_scan.md).
|
||||
|
||||
## `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`
|
||||
|
||||
When defined to `1`, a JSON value can no longer be created from a one-element `std::tuple` holding a reference to a JSON
|
||||
@@ -149,14 +141,6 @@ is planned to become the default in version 4.0.0.
|
||||
|
||||
See [full documentation of `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md).
|
||||
|
||||
## `JSON_DISABLE_UNLOCKED_FILE_IO`
|
||||
|
||||
When defined to `1`, parsing from a `#!cpp FILE*` reads every character with `std::fgetc`, which locks the file each
|
||||
time, instead of locking the file once and reading it with the unlocked stdio functions. Results are the same either
|
||||
way. The default value is `0`.
|
||||
|
||||
See [full documentation of `JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md).
|
||||
|
||||
## `JSON_NO_AUTOMATIC_UDLS`
|
||||
|
||||
When defined, `<nlohmann/json.hpp>` does not include `<nlohmann/json_literals.hpp>` with the user-defined string literals
|
||||
|
||||
@@ -23,12 +23,6 @@ The complete default namespace name is derived as follows:
|
||||
- [`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md) defined non-zero appends `_sbu8`.
|
||||
- [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md) defined non-zero
|
||||
appends `_ekmo`.
|
||||
- [`JSON_DISABLE_STREAM_BULK_SCAN`](../api/macros/json_disable_stream_bulk_scan.md) defined non-zero appends
|
||||
`_dsbs`.
|
||||
- [`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md) defined non-zero appends
|
||||
`_dufio`.
|
||||
- [`JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md) defined appends `_vns`.
|
||||
- [`JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md) defined appends `_vssse3`.
|
||||
- The inline namespace ends with the suffix `_v` followed by the 3 components of the version number separated by
|
||||
underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component)
|
||||
below.
|
||||
@@ -111,9 +105,5 @@ follows:
|
||||
- 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)), `_ekmo`
|
||||
([`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md)), `_dsbs`
|
||||
([`JSON_DISABLE_STREAM_BULK_SCAN`](../api/macros/json_disable_stream_bulk_scan.md)), `_dufio`
|
||||
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md)), `_vns`
|
||||
([`JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md)), and `_vssse3`
|
||||
([`JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md)) in version 3.13.0.
|
||||
([`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.
|
||||
@@ -55,30 +55,6 @@ whitespace, because `operator>>` consumes the character that terminates a number
|
||||
[`JSON_PRECISE_STREAM_POSITION`](../../api/macros/json_precise_stream_position.md) is defined to `1` — see the
|
||||
[`operator>>` notes](../../api/operator_gtgt.md#notes) for details and examples.
|
||||
|
||||
## Input sources and performance
|
||||
|
||||
All inputs produce the same values and the same exceptions, but they are read in different ways, which makes some of
|
||||
them faster than others:
|
||||
|
||||
| input | how it is read |
|
||||
|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------|
|
||||
| strings, string views, string literals, contiguous containers, pointer or iterator ranges over contiguous memory | the whole input is scanned in bulk: runs of string characters, numbers, and indentation are recognized several bytes at a time |
|
||||
| `#!cpp std::istream` (`#!cpp std::ifstream`, `#!cpp std::istringstream`, ...) | the characters the stream buffer holds are scanned in bulk like a string; the stream buffer is asked for more when they are used up |
|
||||
| `#!cpp FILE*` | one character at a time, with the file locked once for the whole parse |
|
||||
| other iterator ranges (e.g., `#!cpp std::list<char>`, `#!cpp std::istreambuf_iterator<char>`), wide strings | one character at a time |
|
||||
|
||||
Parsing a file from a `#!cpp std::ifstream` is therefore only about 10 to 20 % slower than reading the whole file into a
|
||||
`#!cpp std::string` first and parsing that, and it needs no memory for a copy of the file. The stream is never read
|
||||
ahead: after parsing, it is positioned exactly as if every character had been read one at a time, so
|
||||
[`operator>>`](../../api/operator_gtgt.md) can still read several values from one stream (see also
|
||||
[JSON Lines](json_lines.md)).
|
||||
|
||||
Two macros switch these optimizations off without changing any result:
|
||||
[`JSON_DISABLE_STREAM_BULK_SCAN`](../../api/macros/json_disable_stream_bulk_scan.md) for stream buffers that do not
|
||||
follow the usual `std::streambuf` contract, and
|
||||
[`JSON_DISABLE_UNLOCKED_FILE_IO`](../../api/macros/json_disable_unlocked_file_io.md) for programs in which another
|
||||
thread must use the same `#!cpp FILE` object while it is parsed.
|
||||
|
||||
## SAX vs. DOM parsing
|
||||
|
||||
The library offers two parsing models:
|
||||
|
||||
@@ -65,8 +65,8 @@ a DOM, three alternatives avoid building it:
|
||||
unparsed remainder of the input) instead of the whole document -- see the [recipe for streaming a large homogeneous
|
||||
array](parsing/parser_callbacks.md#recipe-streaming-a-large-homogeneous-array).
|
||||
- Parse into a [`json_document`](json_view.md) (`#!cpp <nlohmann/json_view.hpp>`) instead of a `basic_json`. It keeps
|
||||
the input text and builds a flat index of 16 bytes per value; strings and floating-point numbers are not copied, but
|
||||
read from the text when needed. Read-only [views](../api/basic_json_view/index.md) give the familiar element access, and only the
|
||||
the input text and builds a flat index of 16 bytes per value; strings and numbers are not copied, but read from the
|
||||
text when needed. Read-only [views](../api/basic_json_view/index.md) give the familiar element access, and only the
|
||||
parts you [`materialize()`](../api/basic_json_view/materialize.md) become `basic_json` values. A document that
|
||||
borrows the text instead of owning a copy needs the text to outlive it; see
|
||||
[choosing between `json`, the SAX interface, and `json_view`](json_view.md#choosing-between-json-ordered_json-the-sax-interface-and-json_view).
|
||||
|
||||
@@ -120,7 +120,7 @@ requirements are collected in [Template Parameter Requirements](template_paramet
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for *ObjectType* (`std::map`), *StringType* (`std::string`), and *AllocatorType* (`std::allocator`), the default type for `object_t` is:
|
||||
With the default values for *ObjectType* (`std::map`), *StringType* (`std::string`), and *AllocatorType* (`std::allocator`), the default value for `object_t` is:
|
||||
|
||||
```cpp
|
||||
std::map<
|
||||
@@ -177,7 +177,7 @@ json j = m;
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for *ArrayType* (`std::vector`) and *AllocatorType* (`std::allocator`), the default type for `array_t` is:
|
||||
With the default values for *ArrayType* (`std::vector`) and *AllocatorType* (`std::allocator`), the default value for `array_t` is:
|
||||
|
||||
```cpp
|
||||
std::vector<
|
||||
@@ -209,7 +209,7 @@ Unicode values are split by the JSON class into byte-sized characters during des
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for *StringType* (`std::string`), the default type for `string_t` is `#!cpp std::string`.
|
||||
With the default values for *StringType* (`std::string`), the default value for `string_t` is `#!cpp std::string`.
|
||||
|
||||
### Encoding
|
||||
|
||||
@@ -234,7 +234,7 @@ String values are stored as pointers in a `basic_json` type. That is, for any ac
|
||||
|
||||
### Default type
|
||||
|
||||
With the default values for *BooleanType* (`#!cpp bool`), the default type for `boolean_t` is `#!cpp bool`.
|
||||
With the default values for *BooleanType* (`#!cpp bool`), the default value for `boolean_t` is `#!cpp bool`.
|
||||
|
||||
### Storage
|
||||
|
||||
@@ -252,9 +252,9 @@ This description includes both integer and floating-point numbers. However, C++
|
||||
|
||||
### Default types
|
||||
|
||||
With the default values for *NumberIntegerType* (`std::int64_t`), the default type for `number_integer_t` is `std::int64_t`.
|
||||
With the default values for *NumberUnsignedType* (`std::uint64_t`), the default type for `number_unsigned_t` is `std::uint64_t`.
|
||||
With the default values for *NumberFloatType* (`#!cpp double`), the default type for `number_float_t` is `#!cpp double`.
|
||||
With the default values for *NumberIntegerType* (`std::int64_t`), the default value for `number_integer_t` is `std::int64_t`.
|
||||
With the default values for *NumberUnsignedType* (`std::uint64_t`), the default value for `number_unsigned_t` is `std::uint64_t`.
|
||||
With the default values for *NumberFloatType* (`#!cpp double`), the default value for `number_float_t` is `#!cpp double`.
|
||||
|
||||
### Default behavior
|
||||
|
||||
@@ -281,7 +281,7 @@ As this range is a subrange of the exactly supported range [`INT64_MIN`, `INT64_
|
||||
|
||||
> This specification allows implementations to set limits on the range and precision of numbers accepted. Since software that implements IEEE 754-2008 binary64 (double precision) numbers is generally available and widely used, good interoperability can be achieved by implementations that expect no more precision or range than these provide, in the sense that implementations will approximate JSON numbers within the expected precision.
|
||||
|
||||
This implementation does exactly follow this approach, as it uses double precision floating-point numbers by default (see *NumberFloatType* above). Note that with the default `#!cpp double`, numbers smaller than `#!c -1.79769313486232e+308` or greater than `#!c 1.79769313486232e+308` are rejected during parsing with [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406). Non-finite values (NaN and infinity) can only be stored by assigning them directly and are serialized to `#!json null`.
|
||||
This implementation does exactly follow this approach, as it uses double precision floating-point numbers. Note that numbers smaller than `#!c -1.79769313486232e+308` or greater than `#!c 1.79769313486232e+308` are rejected during parsing with [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406). Non-finite values (NaN and infinity) can only be stored by assigning them directly and are serialized to `#!json null`.
|
||||
|
||||
### Storage
|
||||
|
||||
|
||||
@@ -345,11 +345,8 @@ The number types can be changed with template parameters.
|
||||
in case of overflow.
|
||||
- The type for unsigned integers must be convertible from `#!c unsigned long long`. The type for floating-point
|
||||
numbers is used in case of overflow.
|
||||
- The type for unsigned integers can also be the same signed type as the type for signed integers (e.g.,
|
||||
`#!c std::int64_t` for both). Then every integer is stored as a signed integer, and
|
||||
[`is_number_unsigned()`](../../api/basic_json/is_number_unsigned.md) is always `#!c false`, see
|
||||
[Template Parameter Requirements](template_parameters.md#same-type-for-both).
|
||||
- The type for floating-point numbers must be distinct from the integer types.
|
||||
- The types for signed and unsigned integers must be distinct, see
|
||||
[#2573](https://github.com/nlohmann/json/issues/2573).
|
||||
- Only `#!c double`, `#!c float`, and `#!c long double` are supported for floating-point numbers.
|
||||
|
||||
!!! example
|
||||
|
||||
@@ -40,19 +40,19 @@ Requirements are split into two groups:
|
||||
|
||||
## Overview
|
||||
|
||||
| Template parameter | Default | Notable substitutes |
|
||||
|-------------------------------------------------------------------|-----------------------------------|--------------------------------------------------------------------------------------------------|
|
||||
| [`ObjectType`](#objecttype) | `std::map` | [`nlohmann::ordered_map`](../../api/ordered_map.md), Abseil hash maps |
|
||||
| [`ArrayType`](#arraytype) | `std::vector` | `#!cpp std::deque` |
|
||||
| [`StringType`](#stringtype) | `std::string` | `std::string`-like types over `char` |
|
||||
| [`BooleanType`](#booleantype) | `bool` | none worth using |
|
||||
| [`NumberIntegerType`](#numberintegertype-and-numberunsignedtype) | `std::int64_t` | any signed integer type |
|
||||
| [`NumberUnsignedType`](#numberintegertype-and-numberunsignedtype) | `std::uint64_t` | any unsigned integer type at least as wide as `NumberIntegerType`, or `NumberIntegerType` itself |
|
||||
| [`NumberFloatType`](#numberfloattype) | `double` | `float` (`long double`: no binary formats) |
|
||||
| [`AllocatorType`](#allocatortype) | `std::allocator` | stateless allocators |
|
||||
| [`JSONSerializer`](#jsonserializer) | `adl_serializer` | serializers with the same interface |
|
||||
| [`BinaryType`](#binarytype) | `#!cpp std::vector<std::uint8_t>` | `#!cpp std::vector<char>` |
|
||||
| [`CustomBaseClass`](#custombaseclass) | `void` | any default-constructible class |
|
||||
| Template parameter | Default | Notable substitutes |
|
||||
|-------------------------------------------------------------------|-----------------------------------|-----------------------------------------------------------------------|
|
||||
| [`ObjectType`](#objecttype) | `std::map` | [`nlohmann::ordered_map`](../../api/ordered_map.md), Abseil hash maps |
|
||||
| [`ArrayType`](#arraytype) | `std::vector` | `#!cpp std::deque` |
|
||||
| [`StringType`](#stringtype) | `std::string` | `std::string`-like types over `char` |
|
||||
| [`BooleanType`](#booleantype) | `bool` | none worth using |
|
||||
| [`NumberIntegerType`](#numberintegertype-and-numberunsignedtype) | `std::int64_t` | any signed integer type |
|
||||
| [`NumberUnsignedType`](#numberintegertype-and-numberunsignedtype) | `std::uint64_t` | any unsigned integer type at least as wide as `NumberIntegerType` |
|
||||
| [`NumberFloatType`](#numberfloattype) | `double` | `float` (`long double`: no binary formats) |
|
||||
| [`AllocatorType`](#allocatortype) | `std::allocator` | stateless allocators |
|
||||
| [`JSONSerializer`](#jsonserializer) | `adl_serializer` | serializers with the same interface |
|
||||
| [`BinaryType`](#binarytype) | `#!cpp std::vector<std::uint8_t>` | `#!cpp std::vector<char>` |
|
||||
| [`CustomBaseClass`](#custombaseclass) | `void` | any default-constructible class |
|
||||
|
||||
!!! warning "Third-party containers and incomplete types"
|
||||
|
||||
@@ -504,14 +504,13 @@ Both types are stored **directly** inside `basic_json`'s union.
|
||||
### Always required
|
||||
|
||||
- `#!cpp std::is_integral` must be satisfied: `NumberIntegerType` must be a **signed** integer type,
|
||||
`NumberUnsignedType` an **unsigned** integer type or the same type as `NumberIntegerType` (see
|
||||
[below](#same-type-for-both)). Class types are not supported -- among others, the constructors taking integer values
|
||||
are constrained on `#!cpp std::is_integral`.
|
||||
`NumberUnsignedType` an **unsigned** integer type. Class types are not supported -- among others, the constructors
|
||||
taking integer values are constrained on `#!cpp std::is_integral`.
|
||||
- Trivially default-constructible, trivially copyable, and trivially destructible (union member).
|
||||
- `#!cpp std::numeric_limits` must be specialized for both types.
|
||||
- An unsigned `NumberUnsignedType` must be able to represent the absolute value of every `NumberIntegerType` value;
|
||||
serialization of negative numbers converts the value to `NumberUnsignedType`. A `#!cpp static_assert` requires it to
|
||||
be at least as wide as `NumberIntegerType`, which is what that amounts to for the standard integer types.
|
||||
- `NumberUnsignedType` must be able to represent the absolute value of every `NumberIntegerType` value; serialization
|
||||
of negative numbers converts the value to `NumberUnsignedType`. A `#!cpp static_assert` requires it to be at least as
|
||||
wide as `NumberIntegerType`, which is what that amounts to for the standard integer types.
|
||||
- Both types must fit into the internal 64-character number buffer used by
|
||||
[`dump`](../../api/basic_json/dump.md), which is the case for all standard integer types.
|
||||
- [`std::hash<basic_json>`](../../api/basic_json/std_hash.md) additionally requires `#!cpp std::hash` specializations.
|
||||
@@ -523,23 +522,6 @@ is stored as [`number_float_t`](../../api/basic_json/number_float_t.md) instead.
|
||||
therefore silently changes parse results rather than raising an error. See
|
||||
[Number Handling](number_handling.md) for details.
|
||||
|
||||
#### Same type for both
|
||||
|
||||
`NumberUnsignedType` may be the same type as `NumberIntegerType`, e.g.
|
||||
`#!cpp nlohmann::json::with_integers_t<std::int64_t, std::int64_t>` (see
|
||||
[`with_integers_t`](../../api/basic_json/with_t.md)), for code that only wants to handle one integer type. Such a `basic_json` stores every integer as
|
||||
[`number_integer_t`](../../api/basic_json/number_integer_t.md):
|
||||
|
||||
- [`is_number_unsigned()`](../../api/basic_json/is_number_unsigned.md) is always `#!cpp false`, and
|
||||
[`type()`](../../api/basic_json/type.md) never returns `value_t::number_unsigned`. Constructing a value from
|
||||
`value_t::number_unsigned` gives a `value_t::number_integer` value.
|
||||
- Values of unsigned C++ types (e.g., `#!cpp 5u`) are converted to `NumberIntegerType`, so values above its maximum
|
||||
wrap around, as values outside the range of a narrower `NumberIntegerType` already do.
|
||||
- The parsers store a non-negative integer above the maximum of `NumberIntegerType` (e.g., `18446744073709551615` for
|
||||
`#!cpp std::int64_t`) as [`number_float_t`](../../api/basic_json/number_float_t.md), like any other integer that does
|
||||
not fit.
|
||||
- Converting from a `basic_json` with distinct types turns its unsigned values into `number_integer_t` values.
|
||||
|
||||
### Compatible types
|
||||
|
||||
| Type pair | Support |
|
||||
@@ -547,9 +529,8 @@ therefore silently changes parse results rather than raising an error. See
|
||||
| `#!cpp std::int64_t` / `#!cpp std::uint64_t` (default) | full |
|
||||
| `#!cpp std::int32_t` / `#!cpp std::uint32_t`, `#!cpp long long` / `#!cpp unsigned long long` | full; narrower types change which literals the parser can represent |
|
||||
| any other pair of standard signed/unsigned integer types | full |
|
||||
| the same signed integer type for both, e.g. `#!cpp std::int64_t` / `#!cpp std::int64_t` | full; every integer is stored as `number_integer_t`, see [above](#same-type-for-both) |
|
||||
| class types, enumerations | not usable; `#!cpp std::is_integral` must hold |
|
||||
| `#!cpp bool`, `number_float_t`, or the type of another member of the union | not usable; `#!cpp std::is_integral<bool>` is in fact `#!cpp true`, but the `get_impl_ptr` overloads for `boolean_t`, `number_integer_t`, `number_unsigned_t` and `number_float_t` would collide |
|
||||
| `#!cpp bool`, or a type already used for another member of the union | not usable; `#!cpp std::is_integral<bool>` is in fact `#!cpp true`, but the `get_impl_ptr` overloads for `boolean_t`, `number_integer_t`, `number_unsigned_t` and `number_float_t` would collide |
|
||||
|
||||
## `NumberFloatType`
|
||||
|
||||
|
||||
@@ -194,9 +194,9 @@ packet-beta
|
||||
|
||||
| Bytes | Field | Type | Contents |
|
||||
|-------|---------|------------|-------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0 | `kind` | `uint8_t` | the type, numbered as [`value_t`](../api/basic_json/value_t.md): 0 null, 1 object, 2 array, 3 string, 4 boolean, 5 signed integer, 6 unsigned integer, 7 float; 10 for a link (see below). There is no node for a discarded value: a [discarded](../api/basic_json_view/is_discarded.md) view has none |
|
||||
| 1 | `flags` | `uint8_t` | bits 0-1: where a string's bytes (or a number's token) are (0: the source text, 1: the buffer of decoded strings, for strings with escapes, 2: the edit buffer); bit 2: the value of a boolean; bit 3: moved, bit 4: new, bit 5: linked (see below) |
|
||||
| 2-3 | `extra` | `uint16_t` | numbers: the number of integer digits (low byte) and fraction digits (high byte), 255 for more; objects: the number of their key hash index (1-based), or 0; otherwise 0 |
|
||||
| 0 | `kind` | `uint8_t` | the type, numbered as [`value_t`](../api/basic_json/value_t.md): 0 null, 1 object, 2 array, 3 string, 4 boolean, 5 signed integer, 6 unsigned integer, 7 float; 10 for a link (see below) |
|
||||
| 1 | `flags` | `uint8_t` | bits 0-1: where a string's bytes (or a number's token) are (0: the source text, 1: the buffer of decoded strings, for strings with escapes, 2: the edit buffer); bit 2: the value of a boolean; bits 3 and 4: moved and new (see below) |
|
||||
| 2-3 | `extra` | `uint16_t` | numbers: the number of integer digits (low byte) and fraction digits (high byte), 255 for more; objects: the number of their hash index (1-based), or 0; otherwise 0 |
|
||||
| 4-7 | `off` | `uint32_t` | where the value starts: the first byte after a string's opening quote (or its position in the buffer of decoded strings), the first byte of a number or literal, the bracket of an array or object |
|
||||
| 8-11 | `len` | `uint32_t` | strings: the length after decoding; floats and literals: the length of the token; arrays and objects: the number of elements |
|
||||
| 12-15 | `next` | `uint32_t` | arrays and objects: the number of nodes of the subtree, including the node itself |
|
||||
@@ -212,7 +212,7 @@ packet-beta
|
||||
step from element to element this way and skip whole subtrees in constant time.
|
||||
- **Offsets** are 32 bits wide, so a document is limited to 4294967279 bytes, 4 GiB minus 16 bytes (a margin below
|
||||
2^32 for positions one scanner step past the end of the text; `out_of_range.416`).
|
||||
- **Large objects** (128 members or more) get a hash index for their keys after parsing
|
||||
- **Large objects** (128 members or more) get a hash index after parsing
|
||||
([`detail/view/object_index.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/view/object_index.hpp)):
|
||||
an open-addressing table whose slots hold the distance from the object's node to a key's node, so that a lookup does
|
||||
not compare every key. Of duplicate keys the table leads to the first, as a linear search does. The object's `extra`
|
||||
@@ -257,8 +257,6 @@ edited:
|
||||
sequence (a header node, then the entries), whose number is in `off`. The entries are links (`kind` 10), whose bytes
|
||||
8-15 hold the address of the value's node, so values never move.
|
||||
- A node written by an edit gets the flag *new* (bit 4): it has no position in the source text.
|
||||
- A value that an entry of such a sequence links to gets the flag *linked* (bit 5): its extent in the parsed layout
|
||||
(`next`) no longer matters, so a scalar can replace an array or object there in place.
|
||||
- Views of read-only documents compile without any of this: how views walk the index is a template parameter
|
||||
(`navigation<Editable>`).
|
||||
|
||||
|
||||
@@ -972,19 +972,9 @@ double-precision number when `number_float_t` is `#!cpp float`.
|
||||
|
||||
### json.exception.out_of_range.407
|
||||
|
||||
An integer number cannot be represented by the binary format it is serialized to:
|
||||
|
||||
- [BON8](../features/binary_formats/bon8.md) only stores integers that fit into int64, so
|
||||
[`to_bon8`](../api/basic_json/to_bon8.md) throws for unsigned integers greater than 9223372036854775807.
|
||||
- [CBOR](../features/binary_formats/cbor.md), [MessagePack](../features/binary_formats/messagepack.md), and
|
||||
[BSON](../features/binary_formats/bson.md) store integers in at most 64 bits. With the default number types, every
|
||||
integer fits, but a [`number_integer_t`](../api/basic_json/number_integer_t.md) or
|
||||
[`number_unsigned_t`](../api/basic_json/number_unsigned_t.md) wider than 64 bits (e.g., `__int128`) can hold values
|
||||
outside the range of the format: [-2^64, 2^64-1] for CBOR, [-2^63, 2^64-1] for MessagePack, and the range of int64
|
||||
(signed integers) or uint64 (unsigned integers) for BSON.
|
||||
|
||||
[UBJSON](../features/binary_formats/ubjson.md) and [BJData](../features/binary_formats/bjdata.md) never throw this
|
||||
exception, because they serialize integers beyond 64 bits as high-precision numbers.
|
||||
An unsigned integer number greater than 9223372036854775807 cannot be represented in the binary format. This exception
|
||||
is only thrown by [`to_bon8`](../api/basic_json/to_bon8.md), as [BON8](../features/binary_formats/bon8.md) has no
|
||||
unsigned 64-bit integer type.
|
||||
|
||||
!!! note "Former occurrences"
|
||||
|
||||
@@ -993,17 +983,11 @@ exception, because they serialize integers beyond 64 bits as high-precision numb
|
||||
- Since version 3.9.0, integer numbers beyond int64 are serialized as high-precision UBJSON numbers.
|
||||
- Since version 3.12.0, integer numbers beyond int64 are serialized as uint64 BSON numbers.
|
||||
|
||||
Before version 3.13.0, CBOR, MessagePack, and BSON silently truncated integers wider than 64 bits, and BJData
|
||||
truncated unsigned integers wider than 64 bits.
|
||||
|
||||
!!! failure "Example messages"
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
integer number 18446744073709551615 cannot be represented by BON8 as it does not fit int64
|
||||
```
|
||||
```
|
||||
integer number 1267650600228229401496703205376 cannot be represented by CBOR as it does not fit [-2^64, 2^64-1]
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.408
|
||||
|
||||
|
||||
@@ -9,15 +9,6 @@ published on the [GitHub releases page](https://github.com/nlohmann/json/release
|
||||
This documentation is built from the `develop` branch and may describe changes that are not part of a release
|
||||
yet. Their version numbers are followed by an <span class="unreleased-version">unreleased</span> badge.
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Converting an rvalue container to JSON (`json j = std::move(vec);`, `json j = std::map<std::string, std::string>{...};`)
|
||||
now **moves** the elements instead of copying them (e.g., `std::vector<std::string>` with 100,000 strings: 4.7 ms to
|
||||
2.3 ms). Two consequences: the source container is left in a valid but unspecified (moved-from) state, and if an
|
||||
exception is thrown during the conversion, the source may be partially moved-from, so the strong exception guarantee
|
||||
no longer holds for the source of an rvalue conversion (the JSON value itself is unaffected). Lvalues and `const`
|
||||
objects are still copied. See [`basic_json`](../api/basic_json/basic_json.md).
|
||||
|
||||
## v3.12.0 (2025-04-11)
|
||||
|
||||
Fixes bugs found in 3.11.3 and adds several features. All changes are backward-compatible.
|
||||
|
||||
@@ -235,17 +235,6 @@ Build the unit tests against the [simdutf](https://github.com/simdutf/simdutf) U
|
||||
its version is set by the cache variable `JSON_SIMDUTF_VERSION`. This option is `OFF` by default. Depends on
|
||||
`JSON_BuildTests`.
|
||||
|
||||
### `JSON_TestUnityBuild`
|
||||
|
||||
Build the unit tests in batches of several test files per executable to speed up compilation: the files of a batch are
|
||||
compiled as one translation unit, so the template instantiations of the library are shared. Every test file still gets
|
||||
its own CTest test (e.g., `test-foo_cpp11`), which runs only the test cases of that file from the shared executable.
|
||||
This option is `ON` by default (and `OFF` with MinGW). Set it to `OFF` to get one executable per test file, e.g., when
|
||||
debugging a single file. The number of files per executable is set by the cache variable `JSON_TestUnityBatchSize`
|
||||
(default: `8`). Related test files (e.g., all binary formats) are grouped explicitly in `tests/CMakeLists.txt`; each
|
||||
group is compiled as one executable per C++ standard regardless of the batch size, and only the remaining files are
|
||||
batched by size. Depends on `JSON_BuildTests`.
|
||||
|
||||
### `JSON_Valgrind`
|
||||
|
||||
Execute the test suite with [Valgrind](https://valgrind.org). This option is `OFF` by default. Depends on `JSON_BuildTests`.
|
||||
|
||||
Loaded 100 of 233 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user