mirror of
https://github.com/nlohmann/json.git
synced 2026-08-28 20:07:32 +00:00
Compare commits
108
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0da083744a | ||
|
|
5a2b8a274d | ||
|
|
8ce64b9c16 | ||
|
|
3b28316ee4 | ||
|
|
22c8a9554f | ||
|
|
43afb5bebc | ||
|
|
110cd31e8f | ||
|
|
0e4ad2e8da | ||
|
|
ccb290facf | ||
|
|
26b10a7b18 | ||
|
|
690c3be01d | ||
|
|
ca47dd539d | ||
|
|
681fb07eb2 | ||
|
|
a02741fd28 | ||
|
|
b8482ed7f4 | ||
|
|
d386e0aa52 | ||
|
|
5d93f35463 | ||
|
|
96806af2dc | ||
|
|
7a37a27a67 | ||
|
|
06feaa8d04 | ||
|
|
b1c9a68b9b | ||
|
|
599bb1b68c | ||
|
|
35705d79d8 | ||
|
|
892be68ca4 | ||
|
|
1ac268d409 | ||
|
|
3fa93dac65 | ||
|
|
1876493f87 | ||
|
|
01853ed6bc | ||
|
|
2f025f401e | ||
|
|
734fd305a1 | ||
|
|
36187cacfb | ||
|
|
b5378e8deb | ||
|
|
ce87157d4e | ||
|
|
cdf52ae9be | ||
|
|
146ba55453 | ||
|
|
e6978ba50c | ||
|
|
6285225fd0 | ||
|
|
21af527e75 | ||
|
|
23518f54fe | ||
|
|
1c136a66c4 | ||
|
|
c1c19a7bcd | ||
|
|
bacdabd176 | ||
|
|
d5647e6a3b | ||
|
|
9a091d2b82 | ||
|
|
b890b4cba3 | ||
|
|
dca9d49a33 | ||
|
|
acd87e2336 | ||
|
|
ad94fb01cc | ||
|
|
c2e1cc50e0 | ||
|
|
173f2a7407 | ||
|
|
1c63a120b6 | ||
|
|
85889e8843 | ||
|
|
3c0a9a99fd | ||
|
|
e82724d87f | ||
|
|
78821cd9c2 | ||
|
|
68f0722a19 | ||
|
|
5f121d8c50 | ||
|
|
585929bff9 | ||
|
|
31ba5208c8 | ||
|
|
2222d386c9 | ||
|
|
eaedec859a | ||
|
|
d94cbd99dc | ||
|
|
bc48951128 | ||
|
|
fd72ecfc8c | ||
|
|
de8a099ba5 | ||
|
|
dd24e2dffd | ||
|
|
868506dcc0 | ||
|
|
58ce09dcfd | ||
|
|
8dacb98041 | ||
|
|
2e23687092 | ||
|
|
227c5cdfb1 | ||
|
|
0832fd1cb4 | ||
|
|
8ec98e2c9e | ||
|
|
88b28ac43c | ||
|
|
e0c3c819e1 | ||
|
|
06ac77f4fd | ||
|
|
dfa51af692 | ||
|
|
d0d29039da | ||
|
|
9a3ebb9456 | ||
|
|
3296a3ad8c | ||
|
|
3565f40229 | ||
|
|
1c5a953de5 | ||
|
|
a03e65420c | ||
|
|
d6ede37088 | ||
|
|
722c03495f | ||
|
|
c197feff81 | ||
|
|
b2b47c69b1 | ||
|
|
6a406ee141 | ||
|
|
ca76c37650 | ||
|
|
fe2bcc080f | ||
|
|
c60217e801 | ||
|
|
6ba332c7df | ||
|
|
e9c3985f0a | ||
|
|
b630f5e9c7 | ||
|
|
4d8e7a7210 | ||
|
|
75e8fbac32 | ||
|
|
631e667fe5 | ||
|
|
d0a43141ea | ||
|
|
ecff144b3a | ||
|
|
855f511db4 | ||
|
|
d0de6a9111 | ||
|
|
f8e99e856c | ||
|
|
521a084827 | ||
|
|
ca91678af1 | ||
|
|
ff34a3fd2f | ||
|
|
fe0299545a | ||
|
|
366f3d26e5 | ||
|
|
7c9208bfb3 |
@@ -15,6 +15,14 @@ guidance.
|
||||
|
||||
For vulnerabilities in third-party dependencies or modules, please report them directly to the respective maintainers.
|
||||
|
||||
## Unofficial packages
|
||||
|
||||
This project does not publish an official npm package. The npm package
|
||||
[`nlohmann-json`](https://www.npmjs.com/package/nlohmann-json) (or similarly named packages) is not maintained or
|
||||
endorsed by this project. See the
|
||||
[package managers documentation](https://json.nlohmann.me/integration/package_managers/#npm) for supported
|
||||
integration options.
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- Explore security-related topics and contribute to tools and projects through
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -34,19 +34,19 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout pull request
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
path: main
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Checkout tools
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
path: tools
|
||||
ref: develop
|
||||
@@ -67,8 +67,18 @@ jobs:
|
||||
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
|
||||
$INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp
|
||||
|
||||
# fail loudly if a directory is renamed or removed: find would only warn
|
||||
# about the missing path and silently drop its files from the check
|
||||
SOURCE_DIRS="docs/mkdocs/docs/examples include tests"
|
||||
for DIR in $SOURCE_DIRS; do
|
||||
if [ ! -d "$DIR" ]; then
|
||||
echo "::error::source directory '$DIR' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
|
||||
$(find docs/examples include tests -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort)
|
||||
$(find $SOURCE_DIRS -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort)
|
||||
|
||||
- name: Build patch and check for differences
|
||||
id: diff
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -27,25 +27,25 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
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@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
uses: github/codeql-action/autobuild@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: 'Dependency Review'
|
||||
|
||||
@@ -27,12 +27,12 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -43,6 +43,6 @@ jobs:
|
||||
output: 'flawfinder_results.sarif'
|
||||
|
||||
- name: Upload analysis results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
with:
|
||||
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run CMake
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run CMake
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
standard: [11, 14, 17, 20, 23, 26]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run CMake
|
||||
|
||||
@@ -7,7 +7,6 @@ on:
|
||||
- develop
|
||||
paths:
|
||||
- docs/mkdocs/**
|
||||
- docs/examples/**
|
||||
workflow_dispatch:
|
||||
|
||||
# we don't want to have concurrent jobs, and we don't want to cancel running jobs to avoid broken publications
|
||||
@@ -27,11 +26,11 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Install virtual environment
|
||||
run: make install_venv -C docs/mkdocs
|
||||
|
||||
@@ -36,17 +36,17 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
||||
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -76,6 +76,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -32,12 +32,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
# Checkout project source
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
|
||||
# Upload SARIF file generated in previous step
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
with:
|
||||
sarif_file: semgrep.sarif
|
||||
if: always()
|
||||
|
||||
@@ -16,11 +16,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
|
||||
- uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
|
||||
with:
|
||||
stale-issue-label: 'state: stale'
|
||||
stale-pr-label: 'state: stale'
|
||||
|
||||
@@ -21,11 +21,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: gcc:latest
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -33,11 +33,21 @@ jobs:
|
||||
|
||||
ci_infer:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v2.4.0
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Install Infer
|
||||
run: |
|
||||
wget -q -O - "https://github.com/facebook/infer/releases/download/v1.3.0/infer-linux-x86_64-v1.3.0.tar.xz" | sudo tar -C /opt -xJ
|
||||
sudo ln -s /opt/infer-linux-x86_64-v1.3.0/bin/infer /usr/local/bin/infer
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -50,17 +60,17 @@ jobs:
|
||||
target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Install Valgrind
|
||||
run: sudo apt-get update ; sudo apt-get install -y valgrind
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -75,11 +85,11 @@ jobs:
|
||||
steps:
|
||||
- name: Install git, clang-tools, iwyu (ci_single_binaries), and unzip
|
||||
run: apt-get update ; apt-get install -y git clang-tools iwyu unzip
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -94,11 +104,11 @@ jobs:
|
||||
steps:
|
||||
- name: Install build-essential
|
||||
run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -108,11 +118,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install dependencies and de_DE locale
|
||||
@@ -132,7 +142,7 @@ jobs:
|
||||
name: code-coverage-report
|
||||
path: ${{ github.workspace }}/build/html
|
||||
- name: Publish report to Coveralls
|
||||
uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
|
||||
uses: coverallsapp/github-action@8d6379e14d29928660c4ba802d8e85393440b329 # v2.3.8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: ${{ github.workspace }}/build/json.info.filtered.noexcept
|
||||
@@ -143,11 +153,38 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ['4.8', '4.9', '5', '6']
|
||||
container: ghcr.io/nlohmann/json-ci:v2.4.0
|
||||
# official gcc:4.8/4.9/5/6 images fail to check out code (too old for
|
||||
# actions/checkout); install the old compilers on top of official ubuntu:20.04
|
||||
# instead, mirroring what the (now retired) custom json-ci image did.
|
||||
container: ubuntu:20.04
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Install g++-${{ matrix.compiler }}
|
||||
run: |
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends software-properties-common ca-certificates gnupg make git
|
||||
# add-apt-repository resolves the PPA through the Launchpad API,
|
||||
# which intermittently times out or fails the team lookup (the plain
|
||||
# "deb ..." sources below never hit Launchpad and never flake).
|
||||
# Retry with backoff so a transient Launchpad blip does not fail CI.
|
||||
for attempt in 1 2 3 4 5; do
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test && break
|
||||
echo "::warning::add-apt-repository ppa:ubuntu-toolchain-r/test failed (attempt ${attempt}/5); retrying"
|
||||
sleep $((attempt * 10))
|
||||
done
|
||||
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ bionic main"
|
||||
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ bionic universe"
|
||||
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial main"
|
||||
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial universe"
|
||||
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial-updates main"
|
||||
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial-updates universe"
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends g++-${{ matrix.compiler }}
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
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
|
||||
@@ -161,11 +198,11 @@ jobs:
|
||||
compiler: ['7', '8', '9', '10', '11', '12', '13', '14', '15', 'latest']
|
||||
container: gcc:${{ matrix.compiler }}
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -175,14 +212,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', 'latest']
|
||||
compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', '21', '22', 'latest']
|
||||
container: silkeh/clang:${{ matrix.compiler }}
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Set env FORCE_STDCPPFS_FLAG 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' }}
|
||||
@@ -198,11 +235,11 @@ jobs:
|
||||
matrix:
|
||||
standard: [11, 14, 17, 20, 23, 26]
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -218,11 +255,11 @@ jobs:
|
||||
steps:
|
||||
- name: Install git and unzip
|
||||
run: apt-get update ; apt-get install -y git unzip
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build with libc++
|
||||
@@ -245,11 +282,11 @@ jobs:
|
||||
cuda: ['11.8.0', '12.1.1', '12.6.3']
|
||||
container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu22.04
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -262,14 +299,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{ matrix.container }}
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
# The module test uses `import std;`, which needs CMake's experimental
|
||||
# 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@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.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++
|
||||
@@ -287,25 +324,30 @@ jobs:
|
||||
|
||||
ci_icpc:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/nlohmann/json-ci:v2.2.0
|
||||
# Intel discontinued the classic icc/icpc compiler in oneAPI 2024.0; this is
|
||||
# Intel's own last officially published image that still includes it.
|
||||
container: intel/oneapi-hpckit:2023.2.1-devel-ubuntu22.04
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
run: |
|
||||
. /opt/intel/oneapi/setvars.sh
|
||||
cmake --build build --target ci_icpc
|
||||
# No need to source setvars.sh here: unlike the old custom image, this
|
||||
# official image already has the oneAPI environment (icc/icpc on PATH)
|
||||
# baked in, and re-sourcing it fails with "already been run" (exit 3).
|
||||
run: cmake --build build --target ci_icpc
|
||||
|
||||
ci_icpx:
|
||||
runs-on: ubuntu-latest
|
||||
container: intel/oneapi-hpckit:latest
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -315,9 +357,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: nvcr.io/nvidia/nvhpc:25.5-devel-cuda12.9-ubuntu22.04
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -327,17 +369,17 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Install emscripten
|
||||
uses: mymindstorm/setup-emsdk@4528d102f7230f0e7b276855c01ea1159be0e984 # v16
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.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
|
||||
@@ -350,11 +392,11 @@ jobs:
|
||||
target: [ci_test_examples, ci_test_build_documentation]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run CMake
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
architecture: [x64, x86]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up MinGW
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
runs-on: windows-2022
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set extra CXX_FLAGS for latest std_version
|
||||
@@ -86,9 +86,9 @@ jobs:
|
||||
runs-on: windows-2025
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.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)
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
runs-on: windows-11-arm
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Run CMake (Release)
|
||||
run: cmake -S . -B build -G "Visual Studio 17 2022" -A ARM64 -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX"
|
||||
if: matrix.build_type == 'Release'
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
version: [11.0.1, 12.0.1, 13.0.1, 14.0.6, 15.0.7, 16.0.6, 18.1.8, 19.1.7, 20.1.8]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Clang
|
||||
@@ -153,10 +153,16 @@ jobs:
|
||||
with:
|
||||
platform: x64
|
||||
version: 12.2.0 # https://github.com/egor-tensin/setup-mingw/issues/14
|
||||
# CMAKE_CXX_FLAGS_DEBUG is overridden to drop the default -g: linking
|
||||
# test-regression2_cpp20 intermittently fails with "relocation truncated
|
||||
# to fit: IMAGE_REL_AMD64_SECREL against `.debug_line'" because the
|
||||
# MinGW linker cannot relocate the debug sections this test produces.
|
||||
# The tests are only built and run here, so the debug info is not used.
|
||||
- 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="-lwinpthread" ^
|
||||
-G"MinGW Makefiles" ^
|
||||
-DCMAKE_BUILD_TYPE=Debug ^
|
||||
@@ -173,7 +179,7 @@ jobs:
|
||||
architecture: [Win32, x64]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run CMake
|
||||
@@ -186,14 +192,14 @@ jobs:
|
||||
ci_module_cpp20:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
# The module test uses `import std;`, which needs CMake's experimental
|
||||
# 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@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
with:
|
||||
cmakeVersion: 4.3.4
|
||||
- name: Run CMake (Debug)
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
- [Specializing enum conversion](#specializing-enum-conversion)
|
||||
- [Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData)](#binary-formats-bson-cbor-messagepack-ubjson-and-bjdata)
|
||||
- [Customers](#customers)
|
||||
- [Ecosystem](#ecosystem)
|
||||
- [Supported compilers](#supported-compilers)
|
||||
- [Integration](#integration)
|
||||
- [CMake](#cmake)
|
||||
@@ -90,7 +91,6 @@ You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nl
|
||||
- [Steve Sperandeo](https://github.com/homer6)
|
||||
- [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe)
|
||||
- [Steve Wagner](https://github.com/ciroque)
|
||||
- [Lion Yang](https://github.com/LionNatsu)
|
||||
|
||||
### Further support
|
||||
|
||||
@@ -1187,6 +1187,11 @@ The library is used in multiple projects, applications, operating systems, etc.
|
||||
|
||||
[](https://json.nlohmann.me/home/customers/)
|
||||
|
||||
## Ecosystem
|
||||
|
||||
Beyond projects that use the library, there are third-party projects that build on top of it - schema validators,
|
||||
language bindings, format converters, and the like. See the curated [Ecosystem](https://json.nlohmann.me/community/ecosystem/) page.
|
||||
|
||||
## Supported compilers
|
||||
|
||||
Though it's 2026 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
|
||||
@@ -1802,13 +1807,13 @@ The library itself consists of a single header file licensed under the MIT licen
|
||||
- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file
|
||||
- [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) for fuzz testing
|
||||
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
|
||||
- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation
|
||||
- [**Artistic Style**](https://astyle.sourceforge.net) for automatic source code indentation
|
||||
- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers
|
||||
- [**CMake**](https://cmake.org) for build automation
|
||||
- [**Codacy**](https://www.codacy.com) for further [code analysis](https://app.codacy.com/gh/nlohmann/json/dashboard)
|
||||
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
|
||||
- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)
|
||||
- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis
|
||||
- [**cppcheck**](https://cppcheck.sourceforge.io) for static analysis
|
||||
- [**doctest**](https://github.com/onqtam/doctest) for the unit tests
|
||||
- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)
|
||||
- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks
|
||||
@@ -1823,6 +1828,15 @@ The library itself consists of a single header file licensed under the MIT licen
|
||||
|
||||
## Notes
|
||||
|
||||
### Standards compliance
|
||||
|
||||
The library targets strict conformance with [RFC 8259](https://tools.ietf.org/html/rfc8259.html). Both the original [JSONTestSuite](https://github.com/nst/JSONTestSuite) and its updated revision are exercised in CI; their test data is downloaded from [`nlohmann/json_test_data`](https://github.com/nlohmann/json_test_data) at configure time rather than committed to this repository (see [`tests/src/unit-testsuites.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-testsuites.cpp)):
|
||||
|
||||
- The updated revision runs all mandatory `y_` (must-accept) and `n_` (must-reject) cases through the strict [`parse()`](https://json.nlohmann.me/api/basic_json/parse/) entry point; the original suite runs its `n_` cases through `parse()` and its `y_` cases through [`operator>>`](https://json.nlohmann.me/api/operator_gtgt/).
|
||||
- The `i_` (implementation-defined) cases are, by RFC 8259, free to be accepted *or* rejected, so "passing all `i_` cases" is not a meaningful conformance metric. The library makes deliberate, documented choices there: nesting depth is not artificially limited, a leading UTF-8 byte order mark is silently ignored, [Unicode noncharacters](https://www.unicode.org/faq/private_use.html#nonchar1) are forwarded unchanged, invalid UTF-8 and lone/unpaired UTF-16 surrogates are rejected (stricter than required), and a number that cannot be stored without becoming `NaN`/`INF` raises [`out_of_range.406`](https://json.nlohmann.me/home/exceptions/#jsonexceptionout_of_range406).
|
||||
|
||||
One behavioral nuance is worth calling out, because a superficial test often misreads it as non-compliance: [`parse()`](https://json.nlohmann.me/api/basic_json/parse/) is strict and rejects trailing data after a value, whereas [`operator>>`](https://json.nlohmann.me/api/operator_gtgt/) follows relaxed iostream semantics — it parses a single value and leaves the stream positioned right after it. Feeding "a valid document followed by trailing bytes" through `operator>>` reports success; the same input through `parse()` is rejected. This is a documented two-API design, not a conformance gap. See [**parsing**](https://json.nlohmann.me/features/parsing/) for details.
|
||||
|
||||
### Character encoding
|
||||
|
||||
The library supports **Unicode input** as follows:
|
||||
|
||||
+7
-2
@@ -294,7 +294,7 @@ file(GLOB_RECURSE INDENT_FILES
|
||||
${PROJECT_SOURCE_DIR}/tests/src/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/tests/src/*.hpp
|
||||
${PROJECT_SOURCE_DIR}/tests/benchmarks/src/benchmarks.cpp
|
||||
${PROJECT_SOURCE_DIR}/docs/examples/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cpp
|
||||
)
|
||||
|
||||
set(include_dir ${PROJECT_SOURCE_DIR}/single_include/nlohmann)
|
||||
@@ -719,6 +719,11 @@ add_custom_target(ci_icpx
|
||||
# to zero and does not honor NaN ordering; -Kieee restores strict IEEE 754 behavior
|
||||
# (needed for the dtoa/grisu and NaN-comparison code paths).
|
||||
#
|
||||
# -tp=px pins the target processor to the generic x86-64 baseline (SSE2-only) to avoid
|
||||
# a nvc++ 25.5 / LLVM issue: when nvc++ auto-detects -tp from the runner's CPU (e.g. -tp znver4),
|
||||
# certain attribute combinations trigger an llc instruction-selection crash on std::ldexp<unsigned>.
|
||||
# Pinning to px removes this variability and is robust to future llc/nvc++ updates.
|
||||
#
|
||||
# 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:
|
||||
@@ -732,7 +737,7 @@ add_custom_target(ci_nvhpc
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
||||
-DCMAKE_C_COMPILER=nvc -DCMAKE_CXX_COMPILER=nvc++
|
||||
-DCMAKE_CXX_FLAGS=-Kieee
|
||||
-DCMAKE_CXX_FLAGS="-Kieee;-tp=px"
|
||||
-DJSON_BuildTests=ON -DJSON_FastTests=ON
|
||||
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_nvhpc
|
||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_nvhpc
|
||||
|
||||
@@ -5,8 +5,14 @@
|
||||
# -Wno-extra-semi-stmt The library uses assert which triggers this warning.
|
||||
# -Wno-padded We do not care about padding warnings.
|
||||
# -Wno-covered-switch-default All switches list all cases and a default case.
|
||||
# -Wno-unsafe-buffer-usage Otherwise Doctest would not compile.
|
||||
# -Wno-missing-noreturn We found no way to silence this warning otherwise, see PR #4871
|
||||
# -Wno-c2y-extensions Clang 22.1 diagnoses __COUNTER__ as a C2y extension, also in
|
||||
# C++ mode. The library does not use __COUNTER__; the warnings
|
||||
# all come from vendored Doctest (SECTION/TEST_CASE macros).
|
||||
# -Wno-unsafe-buffer-usage Pervasive: the library's own low-level numeric/buffer code
|
||||
# (to_chars, serializer, lexer, binary reader/writer, input
|
||||
# adapters, json_pointer) plus vendored Doctest itself (~208
|
||||
# distinct sites measured 2026-07-08 on clang trunk) all use
|
||||
# raw pointer arithmetic / libc string calls by necessity.
|
||||
|
||||
set(CLANG_CXXFLAGS
|
||||
-Werror
|
||||
@@ -17,6 +23,6 @@ set(CLANG_CXXFLAGS
|
||||
-Wno-extra-semi-stmt
|
||||
-Wno-padded
|
||||
-Wno-covered-switch-default
|
||||
-Wno-c2y-extensions
|
||||
-Wno-unsafe-buffer-usage
|
||||
-Wno-missing-noreturn
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"archive": "JSON_for_Modern_C++.tgz",
|
||||
"author": {
|
||||
"name": "Niels Lohmann",
|
||||
"link": "https://twitter.com/nlohmann"
|
||||
"link": "https://nlohmann.me"
|
||||
},
|
||||
"aliases": ["nlohmann/json"]
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ static bool accept(InputType&& i,
|
||||
const bool ignore_trailing_commas = false);
|
||||
|
||||
// (2)
|
||||
template<typename IteratorType>
|
||||
static bool accept(IteratorType first, IteratorType last,
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
static bool accept(IteratorType first, SentinelType last,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false);
|
||||
```
|
||||
@@ -17,10 +17,11 @@ static bool accept(IteratorType first, IteratorType last,
|
||||
Checks whether the input is valid JSON.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from a pair of character iterators
|
||||
2. Reads from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support)
|
||||
|
||||
The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted
|
||||
respectively as UTF-8, UTF-16, and UTF-32.
|
||||
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to
|
||||
the iterator type with `operator!=`.
|
||||
|
||||
Unlike the [`parse()`](parse.md) function, this function neither throws an exception in case of invalid JSON input
|
||||
(i.e., a parse error) nor creates diagnostic information.
|
||||
@@ -35,7 +36,8 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters (throws if null)
|
||||
- a `std::string`
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type, for instance.
|
||||
@@ -43,6 +45,12 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
|
||||
- a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator`
|
||||
- a pair of pointers such as `ptr` and `ptr + len`
|
||||
|
||||
`SentinelType`
|
||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -60,7 +68,7 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
|
||||
: iterator to the start of the character range
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the character range
|
||||
: iterator to the end of the character range, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -109,7 +117,9 @@ A UTF-8 byte order mark is silently ignored.
|
||||
- Added in version 3.0.0.
|
||||
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
||||
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
|
||||
- Added `ignore_trailing_commas` in version 3.12.x.
|
||||
- Added `ignore_trailing_commas` in version 3.13.0.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -14,7 +14,11 @@ To store objects in C++, a type is defined by the template parameters explained
|
||||
## Template parameters
|
||||
|
||||
`ArrayType`
|
||||
: container type to store arrays (e.g., `std::vector` or `std::list`)
|
||||
: container type to store arrays. It must be a vector-like container: the library uses `operator[]`, `at()`, and
|
||||
`resize()`, and requires random-access iterators. `#!cpp std::vector` and `#!cpp std::deque` qualify;
|
||||
`#!cpp std::list` does not. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#arraytype) for the full list of
|
||||
requirements.
|
||||
|
||||
`AllocatorType`
|
||||
: the allocator to use for objects (e.g., `std::allocator`)
|
||||
@@ -66,3 +70,4 @@ Arrays are stored as pointers in a `basic_json` type. That is, for any access to
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
- Made `capacity()` optional, so that array types such as `#!cpp std::deque` can be used, in version 3.13.0.
|
||||
|
||||
@@ -82,7 +82,13 @@ basic_json(basic_json&& other) noexcept;
|
||||
4. This is a constructor for existing `basic_json` types. It does not hijack copy/move constructors, since the parameter
|
||||
has different template arguments than the current ones.
|
||||
|
||||
The constructor tries to convert the internal `m_value` of the parameter.
|
||||
The constructor tries to convert the internal `m_value` of the parameter. Each member value (object, array, string,
|
||||
etc.) is serialized via the corresponding `to_json()` overload. For objects and strings, the conversion requires
|
||||
that the *target* `basic_json` type's `object_t::key_type` (or `string_t`) be directly constructible from the
|
||||
*source* type's corresponding member type via `is_constructible`. If this requirement is not met, the conversion
|
||||
does not fail to compile; instead, it silently falls back to the array-conversion path, which represents objects
|
||||
as arrays of `[key, value]` pairs and strings as arrays of character codes. This is a known limitation tracked in
|
||||
[issue #3425](https://github.com/nlohmann/json/issues/3425).
|
||||
|
||||
5. Creates a JSON value of type array or object from the passed initializer list `init`. In case `type_deduction` is
|
||||
`#!cpp true` (default), the type of the JSON value to be created is deducted from the initializer list `init`
|
||||
@@ -109,7 +115,22 @@ basic_json(basic_json&& other) noexcept;
|
||||
|
||||
Function [`array()`](array.md) and [`object()`](object.md) force array and object creation from initializer lists,
|
||||
respectively.
|
||||
|
||||
|
||||
!!! warning "Brace initialization yields arrays"
|
||||
|
||||
Because this constructor takes an `initializer_list_t`, brace-initializing a `json`/`ordered_json` from
|
||||
another `json` value wraps it in a single-element array rather than copying it:
|
||||
|
||||
```cpp
|
||||
json j1 = "hello";
|
||||
json j2{j1}; // [!] j2 is ["hello"], NOT a copy of j1
|
||||
json j3(j1); // j3 is "hello" -- parentheses copy as expected
|
||||
```
|
||||
|
||||
See the FAQ entry on [brace initialization](../../home/faq.md#brace-initialization-yields-arrays) for the
|
||||
full explanation, an opt-in macro to change this behavior, and how to explicitly create a single-element
|
||||
array (`json::array({value})`) if that is what you want.
|
||||
|
||||
6. Constructs a JSON array value by creating `cnt` copies of a passed value. In case `cnt` is `0`, an empty array is
|
||||
created.
|
||||
|
||||
@@ -146,6 +167,11 @@ basic_json(basic_json&& other) noexcept;
|
||||
|
||||
- `BasicJsonType` is a `basic_json` type.
|
||||
- `BasicJsonType` has different template arguments than `basic_json_t`.
|
||||
|
||||
**Note:** For cross-`basic_json` conversions to produce correct results, the target `basic_json`'s
|
||||
`object_t::key_type` and `string_t` must be directly constructible from the source `basic_json`'s
|
||||
corresponding types. See the description of overload (4) above for details on what happens when
|
||||
this requirement is not met.
|
||||
|
||||
`U`:
|
||||
: `uncvref_t<CompatibleType>`
|
||||
|
||||
@@ -13,9 +13,8 @@ is compatible with both of the binary data formats that use binary subtyping, (t
|
||||
incompatible with each other, and it is up to the user to translate between them). The subtype is added to `BinaryType`
|
||||
via the helper type [byte_container_with_subtype](../byte_container_with_subtype/index.md).
|
||||
|
||||
[CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as:
|
||||
> Major type 2: a byte string. The string's length in bytes is represented following the rules for positive integers
|
||||
> (major type 0).
|
||||
[CBOR's RFC 8949](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.1) describes this type as:
|
||||
> Major type 2: A byte string. The number of bytes in the string is equal to the argument.
|
||||
|
||||
[MessagePack's documentation on the bin type
|
||||
family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family) describes this type as:
|
||||
@@ -37,12 +36,59 @@ represent a byte array in modern C++.
|
||||
`BinaryType`
|
||||
: container type to store arrays
|
||||
|
||||
Although not formally expressed as a C++ concept, `BinaryType` must be default-constructible,
|
||||
copy/move-constructible, and support `push_back()`, `.data()`, and `.size()`, because
|
||||
[`byte_container_with_subtype`](../byte_container_with_subtype/index.md) derives directly from it. Its
|
||||
`value_type` must additionally be exactly one byte wide (e.g., `std::uint8_t`/`char`/`std::byte`): the binary
|
||||
serializers (CBOR, MessagePack, BSON, UBJSON) read and write the container's raw bytes via
|
||||
`reinterpret_cast`, which is only correct for byte-sized elements -- a container like
|
||||
`#!cpp std::vector<std::intptr_t>` will not work as `BinaryType`. The elements must be stored contiguously, and
|
||||
the binary readers additionally require `resize()` and `operator[]`. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#binarytype) for the full list.
|
||||
|
||||
## Notes
|
||||
|
||||
#### Default type
|
||||
|
||||
The default values for `BinaryType` is `#!cpp std::vector<std::uint8_t>`.
|
||||
|
||||
#### Supported byte types
|
||||
|
||||
`#!cpp std::vector<std::uint8_t>`, `#!cpp std::vector<char>`, and `#!cpp std::vector<std::byte>` are supported.
|
||||
Regardless of which of them is configured, [`dump`](dump.md) writes the bytes as the numbers 0..255.
|
||||
|
||||
#### Custom BinaryType behavior
|
||||
|
||||
When a custom `BinaryType` is configured (other than the default `#!cpp std::vector<std::uint8_t>`), you can assign
|
||||
values of that type directly to a `basic_json` instance, and they will automatically be recognized as binary values
|
||||
rather than arrays:
|
||||
|
||||
```cpp
|
||||
using custom_json = nlohmann::basic_json<
|
||||
nlohmann::ordered_map, // ObjectType
|
||||
std::vector, // ArrayType
|
||||
std::string, // StringType
|
||||
bool, // BooleanType
|
||||
std::int64_t, // NumberIntegerType
|
||||
std::uint64_t, // NumberUnsignedType
|
||||
double, // NumberFloatType
|
||||
std::allocator, // AllocatorType
|
||||
nlohmann::adl_serializer,
|
||||
std::vector<std::byte> // Custom BinaryType
|
||||
>;
|
||||
|
||||
std::vector<std::byte> data{std::byte{1}, std::byte{2}, std::byte{3}};
|
||||
custom_json j = data; // Creates a binary value, not an array
|
||||
assert(j.is_binary());
|
||||
|
||||
// Round-tripping works seamlessly
|
||||
auto extracted = j.get<std::vector<std::byte>>();
|
||||
assert(extracted == data);
|
||||
```
|
||||
|
||||
This automatic type detection is a convenience feature that only applies to custom (non-default) `BinaryType` configurations.
|
||||
The default `nlohmann::json` continues to treat `#!cpp std::vector<std::uint8_t>` as arrays for backward compatibility.
|
||||
|
||||
#### Storage
|
||||
|
||||
Binary Arrays are stored as pointers in a `basic_json` type. That is, for any access to array values, a pointer of the
|
||||
@@ -87,3 +133,6 @@ type `#!cpp binary_t*` must be dereferenced.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.8.0. Changed the type of subtype to `std::uint64_t` in version 3.10.0.
|
||||
- Fixed [`dump`](dump.md), [`std::hash`](std_hash.md), and [`to_ubjson`](to_ubjson.md) for byte types that are not
|
||||
integers (e.g., `#!cpp std::byte`) in version 3.13.0. `dump` now writes the bytes of a signed byte type (e.g.,
|
||||
`#!cpp char`) as 0..255 rather than as negative numbers.
|
||||
|
||||
@@ -11,6 +11,14 @@ literals `#!json true` and `#!json false`.
|
||||
|
||||
To store boolean values in C++, a type is defined by the template parameter `BooleanType` which chooses the type to use.
|
||||
|
||||
## Template parameters
|
||||
|
||||
`BooleanType`
|
||||
: the type to store booleans. As it is stored directly inside a `basic_json` value (in a union), it must be a
|
||||
trivially default-constructible, trivially copyable, and trivially destructible type that is convertible to and
|
||||
from `#!cpp bool`. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#booleantype).
|
||||
|
||||
## Notes
|
||||
|
||||
#### Default type
|
||||
|
||||
@@ -43,6 +43,17 @@ Strong guarantee: if an exception is thrown, there are no changes to any JSON va
|
||||
Throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if a string stored inside the JSON value
|
||||
is not UTF-8 encoded and `error_handler` is set to `strict`
|
||||
|
||||
!!! warning "Serializing untrusted input"
|
||||
|
||||
When serializing values that may contain invalid or untrusted UTF-8 (e.g., bytes taken directly from network
|
||||
input), `dump()` throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) in the default
|
||||
`strict` mode. To serialize such data without throwing, pass
|
||||
[`error_handler_t::replace`](error_handler_t.md) (substitutes U+FFFD) or
|
||||
[`error_handler_t::ignore`](error_handler_t.md). Callers that serialize untrusted input on a crash-sensitive path
|
||||
should either choose a non-strict error handler or wrap `dump()` in a `#!cpp try`/`#!cpp catch`.
|
||||
|
||||
See the [FAQ](../../home/faq.md#serializing-untrusted-or-invalid-utf-8) for details.
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear.
|
||||
|
||||
@@ -92,4 +92,4 @@ std::string format_as(const BasicJsonType& j)
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.12.x.
|
||||
- Added in version 3.13.0.
|
||||
|
||||
@@ -7,8 +7,8 @@ static basic_json from_bjdata(InputType&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
// (2)
|
||||
template<typename IteratorType>
|
||||
static basic_json from_bjdata(IteratorType first, IteratorType last,
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
static basic_json from_bjdata(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
```
|
||||
@@ -16,7 +16,7 @@ static basic_json from_bjdata(IteratorType first, IteratorType last,
|
||||
Deserializes a given input to a JSON value using the BJData (Binary JData) serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bjdata.md).
|
||||
|
||||
@@ -29,11 +29,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
- a `FILE` pointer
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -43,7 +50,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -101,3 +108,5 @@ Linear in the size of the input.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.11.0.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
@@ -7,8 +7,8 @@ static basic_json from_bson(InputType&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
// (2)
|
||||
template<typename IteratorType>
|
||||
static basic_json from_bson(IteratorType first, IteratorType last,
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
static basic_json from_bson(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
```
|
||||
@@ -16,7 +16,7 @@ static basic_json from_bson(IteratorType first, IteratorType last,
|
||||
Deserializes a given input to a JSON value using the BSON (Binary JSON) serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bson.md).
|
||||
|
||||
@@ -29,11 +29,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
- a `FILE` pointer
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -43,7 +50,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -101,6 +108,8 @@ Linear in the size of the input.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.4.0.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ static basic_json from_cbor(InputType&& i,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
|
||||
|
||||
// (2)
|
||||
template<typename IteratorType>
|
||||
static basic_json from_cbor(IteratorType first, IteratorType last,
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
static basic_json from_cbor(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
|
||||
@@ -19,7 +19,7 @@ static basic_json from_cbor(IteratorType first, IteratorType last,
|
||||
Deserializes a given input to a JSON value using the CBOR (Concise Binary Object Representation) serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/cbor.md).
|
||||
|
||||
@@ -32,11 +32,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
- a `FILE` pointer
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -46,7 +53,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -111,6 +118,8 @@ Linear in the size of the input.
|
||||
- Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0.
|
||||
- Added `allow_exceptions` parameter in version 3.2.0.
|
||||
- Added `tag_handler` parameter in version 3.9.0.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ static basic_json from_msgpack(InputType&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
// (2)
|
||||
template<typename IteratorType>
|
||||
static basic_json from_msgpack(IteratorType first, IteratorType last,
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
static basic_json from_msgpack(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
```
|
||||
@@ -16,7 +16,7 @@ static basic_json from_msgpack(IteratorType first, IteratorType last,
|
||||
Deserializes a given input to a JSON value using the MessagePack serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/messagepack.md).
|
||||
|
||||
@@ -29,11 +29,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
- a `FILE` pointer
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -43,7 +50,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -103,6 +110,8 @@ Linear in the size of the input.
|
||||
- Parameter `start_index` since version 2.1.1.
|
||||
- Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0.
|
||||
- Added `allow_exceptions` parameter in version 3.2.0.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ static basic_json from_ubjson(InputType&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
// (2)
|
||||
template<typename IteratorType>
|
||||
static basic_json from_ubjson(IteratorType first, IteratorType last,
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
static basic_json from_ubjson(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
```
|
||||
@@ -16,7 +16,7 @@ static basic_json from_ubjson(IteratorType first, IteratorType last,
|
||||
Deserializes a given input to a JSON value using the UBJSON (Universal Binary JSON) serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/ubjson.md).
|
||||
|
||||
@@ -29,11 +29,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
- a `FILE` pointer
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -43,7 +50,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -102,6 +109,8 @@ Linear in the size of the input.
|
||||
|
||||
- Added in version 3.1.0.
|
||||
- Added `allow_exceptions` parameter in version 3.2.0.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -114,6 +114,13 @@ overload (3).
|
||||
See [Number conversion](../../features/types/number_handling.md#number-conversion)
|
||||
for more information.
|
||||
|
||||
!!! note "`std::optional` conversions"
|
||||
|
||||
Prior to version 3.13.0, `#!cpp get<std::optional<T>>()` (and other conversions to `std::optional<T>`) failed to
|
||||
compile in every configuration, due to an internal implementation bug that made the `from_json` overload for
|
||||
`std::optional` unreachable regardless of the [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md)
|
||||
setting. This has been fixed.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
@@ -35,6 +35,10 @@ class basic_json;
|
||||
| `BinaryType` | type for binary arrays | [`binary_t`](binary_t.md) |
|
||||
| `CustomBaseClass` | extension point for user code | [`json_base_class_t`](json_base_class_t.md) |
|
||||
|
||||
The library imposes a number of requirements on these types that are not expressed as C++ concepts, such as the
|
||||
container operations `object_t` and `array_t` must provide, or the fact that `StringType` must be `char`-based. They
|
||||
are collected in [Template Parameter Requirements](../../features/types/template_parameters.md).
|
||||
|
||||
## Specializations
|
||||
|
||||
- [**json**](../json.md) - default specialization
|
||||
|
||||
@@ -46,6 +46,17 @@ for (auto& [key, val] : j_object.items())
|
||||
}
|
||||
```
|
||||
|
||||
If you need to name the type of the dereferenced element explicitly (e.g., to write a standalone function that
|
||||
takes it as a parameter, or to use `items()` with `std::for_each`), use `decltype`:
|
||||
|
||||
```cpp
|
||||
using element_type = decltype(*j_object.items().begin());
|
||||
```
|
||||
|
||||
The per-element type (`iteration_proxy_value`) lives in the library's internal `detail` namespace and is
|
||||
intentionally unspecified as a stable, named type -- `decltype` is the supported way to obtain it, but its exact
|
||||
name/definition may change between versions.
|
||||
|
||||
## Return value
|
||||
|
||||
iteration proxy object wrapping the current value with an interface to use in range-based for loops
|
||||
|
||||
@@ -21,8 +21,11 @@ The default value for `CustomBaseClass` is `void`. In this case, an
|
||||
|
||||
#### Limitations
|
||||
|
||||
The type `CustomBaseClass` has to be a default-constructible class.
|
||||
The type `CustomBaseClass` has to be a default-constructible, non-`final` class.
|
||||
`basic_json` only supports copy/move construction/assignment if `CustomBaseClass` does so as well.
|
||||
A `CustomBaseClass` with non-static data members forfeits `basic_json`'s
|
||||
[standard layout](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType) guarantee. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#custombaseclass).
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -19,6 +19,12 @@ using json_serializer = JSONSerializer<T, SFINAE>;
|
||||
|
||||
The default values for `json_serializer` is [`adl_serializer`](../adl_serializer/index.md).
|
||||
|
||||
#### Requirements
|
||||
|
||||
A custom serializer must provide `#!cpp static void to_json(basic_json&, T)` for every type it serializes, and either
|
||||
`#!cpp static void from_json(const basic_json&, T&)` or `#!cpp static T from_json(const basic_json&)` for every type it
|
||||
deserializes. See [Template Parameter Requirements](../../features/types/template_parameters.md#jsonserializer).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
@@ -20,6 +20,16 @@ used.
|
||||
To store floating-point numbers in C++, a type is defined by the template parameter `NumberFloatType` which chooses the
|
||||
type to use.
|
||||
|
||||
## Template parameters
|
||||
|
||||
`NumberFloatType`
|
||||
: the type to store floating-point numbers. Parsing and serialization are implemented in terms of
|
||||
`#!cpp std::strtof`/`#!cpp std::strtod`/`#!cpp std::strtold` and `#!cpp std::snprintf`, so the type must be
|
||||
`#!cpp float`, `#!cpp double`, or `#!cpp long double`. The
|
||||
[binary formats](../../features/binary_formats/index.md) additionally require `#!cpp float` or `#!cpp double`,
|
||||
because they have no encoding for `#!cpp long double`. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#numberfloattype).
|
||||
|
||||
## Notes
|
||||
|
||||
#### Default type
|
||||
|
||||
@@ -20,6 +20,13 @@ used.
|
||||
To store integer numbers in C++, a type is defined by the template parameter `NumberIntegerType` which chooses the type
|
||||
to use.
|
||||
|
||||
## Template parameters
|
||||
|
||||
`NumberIntegerType`
|
||||
: the type to store signed integers. It must be a **signed integral** type (`#!cpp std::is_integral`) with a
|
||||
`#!cpp std::numeric_limits` specialization, and it is stored directly inside a `basic_json` value. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#numberintegertype-and-numberunsignedtype).
|
||||
|
||||
## Notes
|
||||
|
||||
#### Default type
|
||||
|
||||
@@ -20,6 +20,14 @@ used.
|
||||
To store unsigned integer numbers in C++, a type is defined by the template parameter `NumberUnsignedType` which chooses
|
||||
the type to use.
|
||||
|
||||
## Template parameters
|
||||
|
||||
`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. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#numberintegertype-and-numberunsignedtype).
|
||||
|
||||
## Notes
|
||||
|
||||
#### Default type
|
||||
|
||||
@@ -30,3 +30,5 @@ and [`default_object_comparator_t`](default_object_comparator_t.md) otherwise.
|
||||
- Added in version 3.0.0.
|
||||
- Changed to be conditionally defined as `#!cpp typename object_t::key_compare` or `default_object_comparator_t` in
|
||||
version 3.11.0.
|
||||
- Fixed the fallback to `default_object_comparator_t`, which previously failed to compile for object types without a
|
||||
`key_compare` member type, in version 3.13.0.
|
||||
|
||||
@@ -18,7 +18,11 @@ To store objects in C++, a type is defined by the template parameters described
|
||||
## Template parameters
|
||||
|
||||
`ObjectType`
|
||||
: the container to store objects (e.g., `std::map` or `std::unordered_map`)
|
||||
: the container to store objects. Its template parameters must have the same order and meaning as those of
|
||||
`std::map`; in particular, the third parameter is a comparator. `#!cpp std::unordered_map`, whose third parameter
|
||||
is a hash function, therefore needs an adapter -- see
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#objecttype) for the full list of
|
||||
requirements, an adapter example, and the containers that are known to work.
|
||||
|
||||
`StringType`
|
||||
: the type of the keys or names (e.g., `std::string`). The comparison function `std::less<StringType>` is used to
|
||||
@@ -63,7 +67,8 @@ behavior:
|
||||
object will agree on the name-value mappings.
|
||||
- When the names within an object are not unique, it is unspecified which one of the values for a given key will be
|
||||
chosen. For instance, `#!json {"key": 2, "key": 1}` could be equal to either `#!json {"key": 1}` or
|
||||
`#!json {"key": 2}`.
|
||||
`#!json {"key": 2}`. To reject duplicate keys instead of silently resolving them one way or another, see
|
||||
[this parsing recipe](../../features/parsing/parser_callbacks.md#recipe-rejecting-duplicate-object-keys).
|
||||
- Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see
|
||||
[`dump`](dump.md)) in this order. For instance, `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be stored
|
||||
and serialized as `#!json {"a": 2, "b": 1}`.
|
||||
@@ -93,6 +98,15 @@ alphabetical order as `std::map` with `std::less` is used by default. Please not
|
||||
[RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON
|
||||
objects.
|
||||
|
||||
#### Cross-`basic_json` conversion requirements
|
||||
|
||||
When converting an object from one `basic_json` specialization to another via the
|
||||
[converting constructor](basic_json.md#overload-4), the target `object_t`'s `key_type` must be
|
||||
directly constructible from the source `basic_json`'s `string_t` type (or more generally, from the
|
||||
source object's key type). If this requirement is not met, the conversion does not fail; instead,
|
||||
the object is silently converted as an array of key-value pairs, which is incorrect. See
|
||||
[issue #3425](https://github.com/nlohmann/json/issues/3425) for details and an example.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@@ -112,3 +126,4 @@ objects.
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
- Allowed object types whose `erase(iterator)` returns `#!cpp void` in version 3.13.0.
|
||||
|
||||
@@ -124,6 +124,15 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
filled with `#!json null`.
|
||||
- The special value `-` is treated as a synonym for the index past the end.
|
||||
|
||||
!!! note "Creating intermediate levels that don't exist yet"
|
||||
|
||||
When the JSON pointer traverses intermediate levels that don't exist at all yet (not just a missing
|
||||
leaf), each missing level is created as an array or an object depending on whether the corresponding
|
||||
pointer token parses as a non-negative integer: a numeric token creates an array, a non-numeric token
|
||||
creates an object. For example, on an initially `#!json null` value, `/foo/0/0/0` creates nested arrays,
|
||||
while `/foo/one/one/one` creates nested objects. This is not specified by the JSON Pointer RFC; it is
|
||||
this library's own, intentional disambiguation rule. See also [JSON Pointer](../../features/json_pointer.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: (1) access specified array element"
|
||||
@@ -251,5 +260,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
1. Added in version 1.0.0.
|
||||
2. Added in version 1.0.0. Added overloads for `T* key` in version 1.1.0. Removed overloads for `T* key` (replaced by 3)
|
||||
in version 3.11.0.
|
||||
3. Added in version 3.11.0.
|
||||
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
|
||||
already supported by [`at`](at.md), [`value`](value.md), [`find`](find.md), and other lookup functions.
|
||||
4. Added in version 2.0.0.
|
||||
|
||||
@@ -19,10 +19,8 @@ class basic_json {
|
||||
};
|
||||
```
|
||||
|
||||
1. Compares two JSON values for inequality according to the following rules:
|
||||
- The comparison always yields `#!cpp false` if (1) either operand is discarded, or (2) either operand is `NaN` and
|
||||
the other operand is either `NaN` or any other number.
|
||||
- Otherwise, returns the result of `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20).
|
||||
1. Compares two JSON values for inequality. Returns `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20).
|
||||
- This means the comparison is simply the logical negation of `operator==`, including for special values like `NaN` and `discarded`.
|
||||
|
||||
2. Compares a JSON value and a scalar or a scalar and a JSON value for inequality by converting the scalar to a JSON
|
||||
value and comparing both JSON values according to 1.
|
||||
@@ -54,13 +52,12 @@ Linear.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "Comparing `NaN`"
|
||||
!!! note "Comparing `NaN` and `discarded`"
|
||||
|
||||
`NaN` values are unordered within the domain of numbers.
|
||||
The following comparisons all yield `#!cpp false`:
|
||||
1. Comparing a `NaN` with itself.
|
||||
2. Comparing a `NaN` with another `NaN`.
|
||||
3. Comparing a `NaN` and any other number.
|
||||
Since `operator!=` is defined as `!(a == b)`, the behavior for special values follows that of `operator==`:
|
||||
|
||||
- For `NaN` values: `NaN == NaN` yields `#!cpp false`, so `NaN != NaN` yields `#!cpp true`.
|
||||
- For `discarded` values: `discarded == x` yields `#!cpp false` for any `x`, so `discarded != x` yields `#!cpp true`.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -94,5 +91,7 @@ Linear.
|
||||
|
||||
## Version history
|
||||
|
||||
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
|
||||
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
|
||||
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.13.0 to remove
|
||||
special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`.
|
||||
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.13.0 to remove
|
||||
special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`.
|
||||
|
||||
@@ -10,8 +10,8 @@ static basic_json parse(InputType&& i,
|
||||
const bool ignore_trailing_commas = false);
|
||||
|
||||
// (2)
|
||||
template<typename IteratorType>
|
||||
static basic_json parse(IteratorType first, IteratorType last,
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
static basic_json parse(IteratorType first, SentinelType last,
|
||||
const parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
@@ -19,10 +19,11 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
```
|
||||
|
||||
1. Deserialize from a compatible input.
|
||||
2. Deserialize from a pair of character iterators
|
||||
2. Deserialize from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support)
|
||||
|
||||
The `value_type` of the iterator must be an integral type with size of 1, 2, or 4 bytes, which will be interpreted
|
||||
respectively as UTF-8, UTF-16, and UTF-32.
|
||||
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to
|
||||
the iterator type with `operator!=`.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@@ -34,7 +35,8 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters (throws if null)
|
||||
- a `std::string`
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type, for instance.
|
||||
@@ -42,6 +44,12 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
- a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator`
|
||||
- a pair of pointers such as `ptr` and `ptr + len`
|
||||
|
||||
`SentinelType`
|
||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -66,7 +74,7 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
: iterator to the start of a character range
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of a character range
|
||||
: iterator to the end of a character range, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -235,7 +243,9 @@ Invalid Unicode escapes and unpaired surrogates in the input are reported as
|
||||
- Overload for contiguous containers (1) added in version 2.0.3.
|
||||
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
||||
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
|
||||
- Added `ignore_trailing_commas` in version 3.12.x.
|
||||
- Added `ignore_trailing_commas` in version 3.13.0.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -29,7 +29,14 @@ Discarding a value (i.e., returning `#!cpp false`) has different effects dependi
|
||||
called:
|
||||
|
||||
- Discarded values in structured types are skipped. That is, the parser will behave as if the discarded value was never
|
||||
read.
|
||||
read. This holds for every value type and for both kinds of parent: a discarded element is removed from the
|
||||
surrounding array, and a discarded member is removed from the surrounding object together with its key.
|
||||
- Arrays and objects can be discarded either at their `parse_event_t::array_start`/`parse_event_t::object_start` event
|
||||
or at their `parse_event_t::array_end`/`parse_event_t::object_end` event, and both remove the whole value. Discarding
|
||||
it at the start event also means the callback is called neither for the content of the value nor for its matching end
|
||||
event.
|
||||
- Discarding a `parse_event_t::key` event discards the whole object member. The callback is still called for the
|
||||
associated value, but its return value has no further effect.
|
||||
- In case a value outside a structured type is skipped, it is replaced with `null`. This case happens if the top-level
|
||||
element is skipped.
|
||||
|
||||
@@ -49,7 +56,7 @@ called:
|
||||
## Return value
|
||||
|
||||
Whether the JSON value which called the function during parsing should be kept (`#!cpp true`) or not (`#!cpp false`). In
|
||||
the latter case, it is either skipped completely or replaced by an empty discarded object.
|
||||
the latter case, it is skipped completely, or replaced by `null` if it is the top-level value.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -68,6 +75,21 @@ the latter case, it is either skipped completely or replaced by an empty discard
|
||||
--8<-- "examples/parse__string__parser_callback_t.output"
|
||||
```
|
||||
|
||||
??? example
|
||||
|
||||
The example below shows where discarded values are removed. The array and the number are discarded in different
|
||||
ways, but in each case the parse result contains neither the value nor its key.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/parser_callback_t.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/parser_callback_t.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [parse](parse.md) deserialize from a compatible input
|
||||
@@ -76,3 +98,5 @@ the latter case, it is either skipped completely or replaced by an empty discard
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
- Fixed in version 3.13.0 to also remove discarded values from a parent object; before, discarding an array or a value
|
||||
stored under an object key left a discarded member behind, which made the parse result serialize to invalid JSON.
|
||||
|
||||
@@ -74,4 +74,4 @@ is thrown. In any case, the original value is not changed: the patch is applied
|
||||
|
||||
- Added in version 2.0.0.
|
||||
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
|
||||
target location has a non-object/non-array parent in version 3.12.x.
|
||||
target location has a non-object/non-array parent in version 3.13.0.
|
||||
|
||||
@@ -71,4 +71,4 @@ function throws an exception.
|
||||
|
||||
- Added in version 3.11.0.
|
||||
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
|
||||
target location has a non-object/non-array parent in version 3.12.x.
|
||||
target location has a non-object/non-array parent in version 3.13.0.
|
||||
|
||||
@@ -11,8 +11,8 @@ static bool sax_parse(InputType&& i,
|
||||
const bool ignore_trailing_commas = false);
|
||||
|
||||
// (2)
|
||||
template<class IteratorType, class SAX>
|
||||
static bool sax_parse(IteratorType first, IteratorType last,
|
||||
template<class IteratorType, class SAX, class SentinelType = IteratorType>
|
||||
static bool sax_parse(IteratorType first, SentinelType last,
|
||||
SAX* sax,
|
||||
input_format_t format = input_format_t::json,
|
||||
const bool strict = true,
|
||||
@@ -23,10 +23,11 @@ static bool sax_parse(IteratorType first, IteratorType last,
|
||||
Read from input and generate SAX events
|
||||
|
||||
1. Read from a compatible input.
|
||||
2. Read from a pair of character iterators
|
||||
2. Read from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support)
|
||||
|
||||
The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted
|
||||
respectively as UTF-8, UTF-16, and UTF-32.
|
||||
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to
|
||||
the iterator type with `operator!=`.
|
||||
|
||||
The SAX event lister must follow the interface of [`json_sax`](../json_sax/index.md).
|
||||
|
||||
@@ -39,13 +40,19 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
|
||||
- a `FILE` pointer
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters
|
||||
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of
|
||||
iterators.
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type for overload (2); a pair of character iterators whose `value_type` is an integral type
|
||||
with a size of 1, 2, or 4 bytes (interpreted respectively as UTF-8, UTF-16, and UTF-32)
|
||||
|
||||
`SentinelType`
|
||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for overload (2), for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||
|
||||
`SAX`
|
||||
: a class fulfilling the SAX event listener interface; see [`json_sax`](../json_sax/index.md)
|
||||
|
||||
@@ -76,7 +83,7 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
|
||||
: iterator to the start of a character range
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of a character range
|
||||
: iterator to the end of a character range, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -126,7 +133,9 @@ A UTF-8 byte order mark is silently ignored.
|
||||
|
||||
- Added in version 3.2.0.
|
||||
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
||||
- Added `ignore_trailing_commas` in version 3.12.x.
|
||||
- Added `ignore_trailing_commas` in version 3.13.0.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -54,4 +54,4 @@ provides `<format>`, controlled by the [`JSON_HAS_STD_FORMAT`](../macros/json_ha
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.12.x.
|
||||
- Added in version 3.13.0.
|
||||
|
||||
@@ -18,6 +18,16 @@ JSON class into byte-sized characters during deserialization.
|
||||
: the container to store strings (e.g., `std::string`). Note this container is used for keys/names in objects, see
|
||||
[object_t](object_t.md).
|
||||
|
||||
`StringType` must have a `char`-compatible `value_type`: the library relies on UTF-8/`char`-based storage and
|
||||
processing internally, so `std::wstring`, `std::u16string`, and `std::u32string` are **not** valid choices for
|
||||
`StringType`. To work with wide-character data, convert it to/from UTF-8 at the boundary instead -- see the
|
||||
FAQ's [wide string handling](../../home/faq.md#wide-string-handling) section for a conversion recipe.
|
||||
|
||||
Beyond the character type, the library expects a substantial part of the `#!cpp std::string` interface (contiguous
|
||||
null-terminated `data()`, `substr()`, `find()`, `append()`, ...). See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#stringtype) for the full list and
|
||||
for the string types that are known to work.
|
||||
|
||||
## Notes
|
||||
|
||||
#### Default type
|
||||
@@ -45,6 +55,15 @@ This implementation is interoperable as it does compare strings code unit by cod
|
||||
String values are stored as pointers in a `basic_json` type. That is, for any access to string values, a pointer of type
|
||||
`string_t*` must be dereferenced.
|
||||
|
||||
#### Cross-`basic_json` conversion requirements
|
||||
|
||||
When converting a string value from one `basic_json` specialization to another via the
|
||||
[converting constructor](basic_json.md#overload-4), the target `string_t` must be directly
|
||||
constructible from the source `basic_json`'s `string_t` type. If this requirement is not met, the
|
||||
conversion does not fail; instead, the string is silently converted as an array of character codes,
|
||||
which is incorrect. See [issue #3425](https://github.com/nlohmann/json/issues/3425) for details
|
||||
and an example.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@@ -64,3 +83,5 @@ String values are stored as pointers in a `basic_json` type. That is, for any ac
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
- Removed the requirement that `string_t` be implicitly convertible from `#!cpp std::string`, which the BSON writer and
|
||||
the UBJSON reader relied on, in version 3.13.0.
|
||||
|
||||
@@ -52,6 +52,11 @@ optional, `#!cpp bjdata_version_t::draft2` by default.
|
||||
|
||||
Strong guarantee: if an exception is thrown, there are no changes in the JSON value.
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size`
|
||||
is false.
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear in the size of the JSON value `j`.
|
||||
|
||||
@@ -40,10 +40,15 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
is not an object; example: `"to serialize to BSON, top-level type must be object, but is string"`
|
||||
- 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,
|
||||
string, or binary value exceeds the range of the 32-bit BSON length field; example:
|
||||
`"BSON length 2147483661 exceeds maximum of 2147483647"`
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear in the size of the JSON value `j`.
|
||||
Proportional to the size of the JSON value `j` multiplied by its maximum nesting
|
||||
depth, `O(n × d)`. BSON length prefixes are computed recursively before nested
|
||||
values are written.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -45,6 +45,11 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
|
||||
Strong guarantee: if an exception is thrown, there are no changes in the JSON value.
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size`
|
||||
is false.
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear in the size of the JSON value `j`.
|
||||
|
||||
@@ -21,6 +21,12 @@ a string representation of the type ([`value_t`](value_t.md)):
|
||||
| array | `"array"` |
|
||||
| binary | `"binary"` |
|
||||
| discarded | `"discarded"` |
|
||||
| invalid (corrupted value) | `"invalid"` |
|
||||
|
||||
!!! note "The \"invalid\" type"
|
||||
|
||||
The `"invalid"` return value indicates a corrupted JSON value — this can occur if an enum value falls outside the
|
||||
range of valid `value_t` values. This is useful for diagnosing data corruption or internal errors.
|
||||
|
||||
## Exception safety
|
||||
|
||||
@@ -52,3 +58,4 @@ Constant.
|
||||
- Part of the public API version since 2.1.0.
|
||||
- Changed return value to `const char*` and added `noexcept` in version 3.0.0.
|
||||
- Added support for binary type in version 3.8.0.
|
||||
- Added `"invalid"` return value for corrupted JSON values in version 3.13.0.
|
||||
|
||||
@@ -37,7 +37,14 @@ Linear in the size of the JSON value.
|
||||
## Notes
|
||||
|
||||
Empty objects and arrays are flattened by [`flatten()`](flatten.md) to `#!json null` values and cannot unflattened to
|
||||
their original type. Apart from this example, for a JSON value `j`, the following is always true:
|
||||
their original type.
|
||||
|
||||
A flattened array and a flattened object whose keys are array indices are indistinguishable, because both are
|
||||
described by the same JSON pointers. A value is therefore restored as an array if and only if one of its keys is the
|
||||
reference token `0`, and as an object otherwise: `#!json {"2": 1}` is restored unchanged, whereas `#!json {"0": 1}` is
|
||||
restored as `#!json [1]`. This decision does not depend on the order in which the flattened object is iterated.
|
||||
|
||||
Apart from these two cases, for a JSON value `j`, the following is always true:
|
||||
`#!cpp j == j.flatten().unflatten()`.
|
||||
|
||||
## Examples
|
||||
@@ -63,3 +70,4 @@ their original type. Apart from this example, for a JSON value `j`, the followin
|
||||
## Version history
|
||||
|
||||
- Added in version 2.0.0.
|
||||
- Made the array/object decision independent of the object's iteration order in version 3.13.0.
|
||||
|
||||
@@ -17,6 +17,8 @@ ValueType value(const json_pointer& ptr,
|
||||
const ValueType& default_value) const;
|
||||
```
|
||||
|
||||
This is equivalent to Python's `dict.get(key, default)`.
|
||||
|
||||
1. Returns either a copy of an object's element at the specified key `key` or a given default value if no element with
|
||||
key `key` exists.
|
||||
|
||||
@@ -184,4 +186,6 @@ changes to any JSON value.
|
||||
|
||||
1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version 3.11.0.
|
||||
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2.
|
||||
3. Added in version 2.0.2. Extended to work with arrays in version 3.12.x.
|
||||
3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0, including fixing an issue where resolving
|
||||
`ptr` through an array unexpectedly threw `out_of_range` instead of returning the resolved element (or
|
||||
`default_value`, as documented).
|
||||
|
||||
@@ -36,4 +36,4 @@ Constant.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.12.x.
|
||||
- Added in version 3.13.0.
|
||||
|
||||
@@ -32,4 +32,4 @@ Linear in the number of reference tokens in the `json_pointer`.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.12.x.
|
||||
- Added in version 3.13.0.
|
||||
|
||||
@@ -35,4 +35,4 @@ Linear in the number of reference tokens in the `json_pointer`.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.12.x.
|
||||
- Added in version 3.13.0.
|
||||
|
||||
@@ -92,4 +92,4 @@ The default value is `0` (disabled — existing behavior is preserved).
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.12.x.
|
||||
- Added in version 3.13.0.
|
||||
|
||||
@@ -38,7 +38,8 @@ When the macro is not defined, the library will define it to its default value.
|
||||
|
||||
Diagnostic messages can also be controlled with the CMake option
|
||||
[`JSON_Diagnostics`](../../integration/cmake.md#json_diagnostics) (`OFF` by default)
|
||||
which defines `JSON_DIAGNOSTICS` accordingly.
|
||||
which defines `JSON_DIAGNOSTICS` accordingly. Note this only applies when building the
|
||||
library from source — see the pre-installed-package caveat on that page.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -44,4 +44,4 @@ The default value is detected based on preprocessor macros such as `#!cpp __cplu
|
||||
|
||||
- Added in version 3.10.5.
|
||||
- Added `JSON_HAS_CPP_23` in version 3.12.0.
|
||||
- Added `JSON_HAS_CPP_26` in version 3.12.x.
|
||||
- Added `JSON_HAS_CPP_26` in version 3.13.0.
|
||||
|
||||
@@ -19,6 +19,20 @@ The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_
|
||||
`#!cpp __cpp_lib_experimental_filesystem`, `#!cpp __has_include(<filesystem>)`, or
|
||||
`#!cpp __has_include(<experimental/filesystem>)`.
|
||||
|
||||
!!! info "Known compiler/stdlib exclusions"
|
||||
|
||||
Even when the feature-test macro indicates filesystem support is available, the library disables it on the following broken toolchains:
|
||||
|
||||
- **MinGW + GCC 8** — disabled entirely (broken `std::filesystem` implementation; [MinGW-w64 bug 737](https://sourceforge.net/p/mingw-w64/bugs/737/))
|
||||
- **GCC (non-Clang) < 8** — disabled (no filesystem support)
|
||||
- **Clang < 7** — disabled (no filesystem support)
|
||||
- **MSVC < 19.14** — disabled (no filesystem support)
|
||||
- **iOS < 13** — disabled (no filesystem support)
|
||||
- **macOS < Catalina (10.15)** — disabled (no filesystem support)
|
||||
|
||||
If `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERIMENTAL_FILESYSTEM` is `0` despite `__cpp_lib_filesystem` being defined, one
|
||||
of the exclusions above likely applies to your toolchain.
|
||||
|
||||
## Notes
|
||||
|
||||
- Note that older compilers or older versions of libstdc++ also require the library `stdc++fs` to be linked to for
|
||||
|
||||
@@ -13,6 +13,20 @@ The default value is detected based on the preprocessor macro `#!cpp __cpp_lib_r
|
||||
|
||||
When the macro is not defined, the library will define it to its default value.
|
||||
|
||||
!!! info "Known compiler/stdlib exclusions"
|
||||
|
||||
Even when the feature-test macro `__cpp_lib_ranges` indicates ranges support is available, the library disables it on
|
||||
the following incomplete or broken toolchains:
|
||||
|
||||
- **GCC 11.1.0** — disabled (the shipped `<ranges>` header has a syntax error; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
||||
- **libstdc++ < 11** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
||||
- **Clang < 16 with libstdc++** — disabled (incomplete ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
||||
- **libc++ < 160000** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
|
||||
- **nvcc (CUDA) 12.0.x and 12.1.x** — disabled (the `enable_borrowed_range` variable-template syntax triggers a parse error
|
||||
under these two toolkit versions; fixed in CUDA 12.2; [issue #3907](https://github.com/nlohmann/json/issues/3907))
|
||||
|
||||
If `JSON_HAS_RANGES` is `0` despite `__cpp_lib_ranges` being defined, one of the exclusions above likely applies to your toolchain.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
@@ -38,4 +38,4 @@ When the macro is not defined, the library will define it to its default value.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.12.x.
|
||||
- Added in version 3.13.0.
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
Controls how exceptions are handled by the library.
|
||||
|
||||
1. This macro overrides [`#!cpp catch`](https://en.cppreference.com/w/cpp/language/try_catch) calls inside the library.
|
||||
The argument is the type of the exception to catch. As of version 3.8.0, the library only catches `std::out_of_range`
|
||||
exceptions internally to rethrow them as [`json::out_of_range`](../../home/exceptions.md#out-of-range) exceptions.
|
||||
The macro is always followed by a scope.
|
||||
The argument is the type of the exception to catch. The library uses it in a single place: to swallow any exception
|
||||
escaping the parent-pointer check that [`JSON_DIAGNOSTICS`](json_diagnostics.md) adds to the class invariant. The
|
||||
places where the library catches its own [`json::out_of_range`](../../home/exceptions.md#out-of-range) exceptions
|
||||
use `JSON_INTERNAL_CATCH` instead, which `JSON_CATCH_USER` also overrides unless `JSON_INTERNAL_CATCH_USER` is
|
||||
defined. The macro is always followed by a scope.
|
||||
2. This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown. Note that
|
||||
`JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield
|
||||
undefined behavior.
|
||||
|
||||
@@ -62,6 +62,9 @@ See the examples below for the concrete generated code.
|
||||
|
||||
- The current implementation is limited to at most 63 member variables. If you want to serialize/deserialize types
|
||||
with more than 63 member variables, you need to define the `to_json`/`from_json` functions manually.
|
||||
- These macros always produce object-style (named-key) JSON, one key per member. There is no macro variant
|
||||
that serializes a struct's members positionally into a JSON array; for that, write `to_json`/`from_json` by
|
||||
hand, building/reading a `json::array()` of the members in order.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ See the examples below for the concrete generated code.
|
||||
|
||||
- The current implementation is limited to at most 63 member variables. If you want to serialize/deserialize types
|
||||
with more than 63 member variables, you need to define the `to_json`/`from_json` functions manually.
|
||||
- These macros always produce object-style (named-key) JSON, one key per member. There is no macro variant
|
||||
that serializes a struct's members positionally into a JSON array; for that, write `to_json`/`from_json` by
|
||||
hand, building/reading a `json::array()` of the members in order.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -75,4 +75,4 @@ For further information please refer to the corresponding macros without `WITH_N
|
||||
|
||||
## Version history
|
||||
|
||||
1. Added in version 3.12.x.
|
||||
1. Added in version 3.13.0.
|
||||
|
||||
@@ -102,4 +102,4 @@ inline void from_json(const BasicJsonType& j, type& e);
|
||||
|
||||
## Version history
|
||||
|
||||
Added in version 3.12.x.
|
||||
Added in version 3.13.0.
|
||||
|
||||
@@ -33,6 +33,45 @@ A UTF-8 byte order mark is silently ignored.
|
||||
Invalid Unicode escapes and unpaired surrogates in the input are reported as
|
||||
[`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) with a detailed message.
|
||||
|
||||
`operator>>` parses exactly one JSON value, so it can be called repeatedly to read a sequence of concatenated JSON
|
||||
values from the same stream:
|
||||
|
||||
```cpp
|
||||
json j1, j2;
|
||||
input >> j1; // parses the first value
|
||||
input >> j2; // parses the next value
|
||||
```
|
||||
|
||||
!!! warning "A number must be followed by whitespace"
|
||||
|
||||
A number is only terminated by the character that follows it. That character is read from the stream to detect the
|
||||
end of the number, and it is **not** put back. When a value that is a number is immediately followed by the next
|
||||
value, the first character of that next value is lost:
|
||||
|
||||
```cpp
|
||||
std::istringstream input("1true");
|
||||
json j1, j2;
|
||||
input >> j1; // j1 == 1
|
||||
input >> j2; // throws parse_error.101: the stream now starts at "rue"
|
||||
```
|
||||
|
||||
Separating the values with whitespace avoids this, because the character that is eaten is then the separator:
|
||||
|
||||
```cpp
|
||||
std::istringstream input("1 true");
|
||||
json j1, j2;
|
||||
input >> j1; // j1 == 1
|
||||
input >> j2; // j2 == true
|
||||
```
|
||||
|
||||
Only numbers are affected. Values ending in a self-delimiting character do not read past themselves, so
|
||||
`truefalse`, `[1][2]`, `{"a":1}{"b":2}`, and `"a""b"` can be read back to back without a separator.
|
||||
|
||||
This is tracked in [#5340](https://github.com/nlohmann/json/issues/5340).
|
||||
|
||||
Note that reading concatenated values does **not** work for [JSON Lines](../features/parsing/json_lines.md)
|
||||
(newline-delimited JSON) input -- see that page for why and for the recommended alternative.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
This function replaces function `#!cpp std::istream& operator<<(basic_json& j, std::istream& i)` which has
|
||||
|
||||
@@ -64,4 +64,4 @@ Linear.
|
||||
|
||||
- Added in version 1.0.0.
|
||||
- Moved to namespace `nlohmann::literals::json_literals` in 3.11.0.
|
||||
- Added `char8_t*` overload in 3.12.x.
|
||||
- Added `char8_t*` overload in 3.13.0.
|
||||
|
||||
@@ -63,4 +63,4 @@ Linear.
|
||||
|
||||
- Added in version 2.0.0.
|
||||
- Moved to namespace `nlohmann::literals::json_literals` in 3.11.0.
|
||||
- Added `char8_t*` overload in 3.12.x.
|
||||
- Added `char8_t*` overload in 3.13.0.
|
||||
|
||||
@@ -13,6 +13,12 @@ Therefore, adding object elements can yield a reallocation in which case all ite
|
||||
[`end()`](basic_json/end.md) iterator) and all references to the elements are invalidated. Also, any iterator or
|
||||
reference after the insertion point will point to the same index, which is now a different value.
|
||||
|
||||
## Complexity
|
||||
|
||||
[`ordered_map`](ordered_map.md) has no lookup index: every key-based object operation is a linear scan, so building or
|
||||
parsing an object of `n` keys costs O(n²) rather than O(n log n). See
|
||||
[`ordered_map` complexity](ordered_map.md#complexity) for the per-operation table and for measured numbers.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
@@ -56,6 +56,48 @@ std::equal_to<> // since C++14
|
||||
- **find**
|
||||
- **insert**
|
||||
|
||||
## Complexity
|
||||
|
||||
Because the elements are stored in a `std::vector` in insertion order, there is no index to look a key up by. Every
|
||||
key-based operation performs a **linear scan** over the stored elements. With `n` denoting the number of elements in the
|
||||
container:
|
||||
|
||||
| Operation | Complexity | Note |
|
||||
|----------------------------------------|----------------|----------------------------------------------------------|
|
||||
| **emplace** | O(n) | scans for an existing key, then appends (amortized O(1)) |
|
||||
| **operator\[\]** | O(n) | delegates to **emplace** (non-const) or **at** (const) |
|
||||
| **at** | O(n) | throws `#!cpp std::out_of_range` if the key is not found |
|
||||
| **find** | O(n) | |
|
||||
| **count** | O(n) | the result is always 0 or 1 |
|
||||
| **erase(key)** | O(n) | scan, then move the remaining elements one position down |
|
||||
| **erase(pos)**, **erase(first, last)** | O(n) | moves all elements after the erased range |
|
||||
| **insert(value)** | O(n) | equivalent to **emplace** |
|
||||
| **insert(first, last)** | O((n + m) * m) | for `m` inserted elements |
|
||||
|
||||
This differs from `#!cpp std::map`, where the same operations are O(log n).
|
||||
|
||||
!!! warning "Quadratic cost of building large objects"
|
||||
|
||||
Because every insertion scans all elements inserted so far, building an object of `n` distinct keys costs
|
||||
**O(n²)** in total. This applies to filling an [`ordered_json`](ordered_json.md) object key by key as well as to
|
||||
parsing one, since the parser inserts each key as it is read.
|
||||
|
||||
The cost is negligible for the object sizes typically found in configuration files or API payloads, but it grows
|
||||
steeply for machine-generated objects with many thousands of keys. Measured with `-O2 -DNDEBUG` for parsing a flat
|
||||
object of `n` keys, relative to `#!cpp nlohmann::json` (which uses `#!cpp std::map`):
|
||||
|
||||
| `n` | `json` | `ordered_json` | factor |
|
||||
|--------|--------|----------------|--------|
|
||||
| 2000 | 0.7 ms | 3.6 ms | 5× |
|
||||
| 4000 | 0.8 ms | 14.0 ms | 19× |
|
||||
| 8000 | 1.6 ms | 67.8 ms | 43× |
|
||||
| 16 000 | 3.3 ms | 181.6 ms | 54× |
|
||||
|
||||
If key order matters for objects of that size, consider a container with a lookup index, such as
|
||||
[`tsl::ordered_map`](https://github.com/Tessil/ordered-map)
|
||||
([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)), as the object type -- see
|
||||
[object order](../features/object_order.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Ecosystem
|
||||
|
||||
The projects below build on top of `nlohmann::json` rather than merely using it - schema validators, language
|
||||
bindings, format converters, and similar building blocks. The list is not exhaustive, and is curated rather than
|
||||
automatically generated. If you maintain or know of a project that belongs here,
|
||||
[please let me know](mailto:mail@nlohmann.me).
|
||||
|
||||
For products, applications, and organizations that use the library, see [Customers](../home/customers.md) instead.
|
||||
|
||||
## Schema validation
|
||||
|
||||
- [**json-schema-validator**](https://github.com/pboettch/json-schema-validator), a JSON Schema (draft 7) validator
|
||||
with human-readable error messages
|
||||
|
||||
## Serialization and reflection
|
||||
|
||||
- [**nlohmann_json_reflect**](https://github.com/1261385937/nlohmann_json_reflect), a reflection extension for
|
||||
(de)serializing nested containers-in-structs-in-containers
|
||||
|
||||
## Encodings
|
||||
|
||||
- [**base-encode-decode**](https://github.com/saxonnicholls/base-encode-decode), a header-only Base64/32/16/8/4/2
|
||||
(and DNA/RNA) encoding library, with an adapter that serializes binary data through `nlohmann::json`
|
||||
|
||||
## Language bindings and interop
|
||||
|
||||
- [**pybind11_json**](https://github.com/pybind/pybind11_json), a bidirectional type caster between
|
||||
`nlohmann::json` and Python objects for [pybind11](https://github.com/pybind/pybind11) bindings
|
||||
- [**nanobind_json**](https://github.com/ianhbell/nanobind_json), the same idea for
|
||||
[nanobind](https://github.com/wjakob/nanobind) bindings
|
||||
- [**nlohmann_json_qt**](https://github.com/dpurgin/nlohmann_json_qt), deserialization helpers for Qt types
|
||||
(`QString`, `QUrl`, `QDateTime`, `QVector`, ...) from `nlohmann::json`
|
||||
- [**vulkan2json**](https://github.com/Fadis/vulkan2json), serialization and deserialization of Vulkan API structs
|
||||
|
||||
## Format converters
|
||||
|
||||
- [**tojson**](https://github.com/mircodz/tojson), a header-only converter between YAML/XML documents and
|
||||
`nlohmann::json`
|
||||
- [**json2xml**](https://github.com/testillano/json2xml), a header-only converter from `nlohmann::json` to XML for
|
||||
simple configuration documents
|
||||
@@ -1,5 +1,6 @@
|
||||
# Community
|
||||
|
||||
- [Ecosystem](ecosystem.md) - third-party projects built on top of this library
|
||||
- [Code of Conduct](code_of_conduct.md) - the rules and norms of this project
|
||||
- [Contribution Guidelines](contribution_guidelines.md) - guidelines how to contribute to this project
|
||||
- [Governance](governance.md) - the governance model of this project
|
||||
|
||||
@@ -10,6 +10,10 @@ violations will result in a failed build.
|
||||
|
||||
Any compiler with complete C++11 support can compile the library without warnings.
|
||||
|
||||
Note: C++20 modules support may hit compiler-specific issues not covered by the general compiler matrix below. See [Modules](../features/modules.md#known-issues) for known issues and workarounds.
|
||||
|
||||
Note: Some modern features (like C++20 ranges or filesystem support) may be disabled on specific broken or incomplete toolchains even when standard feature-test macros indicate support. See [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) and [`JSON_HAS_FILESYSTEM`](../api/macros/json_has_filesystem.md) for details on known exclusions.
|
||||
|
||||
- [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms,
|
||||
including the oldest versions known to compile the library.
|
||||
|
||||
@@ -62,14 +66,15 @@ violations will result in a failed build.
|
||||
| Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub |
|
||||
| Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| Clang 22.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| CUDA 11.8.0 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
||||
| CUDA 12.1.1 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
||||
| CUDA 12.6.3 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
||||
| Emscripten 4.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 4.8.5 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 4.9.3 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 5.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 6.4.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 4.8.5 | x86_64 | Ubuntu 20.04 LTS | GitHub |
|
||||
| GNU 4.9.3 | x86_64 | Ubuntu 20.04 LTS | GitHub |
|
||||
| GNU 5.5.0 | x86_64 | Ubuntu 20.04 LTS | GitHub |
|
||||
| GNU 6.4.0 | x86_64 | Ubuntu 20.04 LTS | GitHub |
|
||||
| GNU 7.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 8.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 9.3.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
@@ -86,7 +91,7 @@ violations will result in a failed build.
|
||||
| GNU 15.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 16.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||
| GNU 16.1.0 | arm64 | Linux 6.1.100 | Cirrus CI |
|
||||
| icpc (ICC) 2021.5.0 20211109 | x86_64 | Ubuntu 20.04.3 LTS | GitHub |
|
||||
| icpc (ICC) 2021.10.0 20230609 | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
||||
| icpx (Intel oneAPI DPC++/C++) 2025.3.2 | x86_64 | Ubuntu 24.04 LTS | GitHub |
|
||||
| nvc++ (NVIDIA HPC SDK) 25.5-0 | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
||||
| MSVC 19.0.24241.7 | x86 | Windows 8.1 | AppVeyor |
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a JSON text with an array and a number inside an object
|
||||
auto text = R"({"IDs": [116, 943], "Width": 800})";
|
||||
|
||||
// discard the array when the parser reads its opening bracket
|
||||
json j_array_start = json::parse(text, [](int /*depth*/, json::parse_event_t event, json& /*parsed*/)
|
||||
{
|
||||
return event != json::parse_event_t::array_start;
|
||||
});
|
||||
|
||||
// discard the same array when the parser reads its closing bracket
|
||||
json j_array_end = json::parse(text, [](int /*depth*/, json::parse_event_t event, json& /*parsed*/)
|
||||
{
|
||||
return event != json::parse_event_t::array_end;
|
||||
});
|
||||
|
||||
// discard the number, but keep its key
|
||||
json j_value = json::parse(text, [](int /*depth*/, json::parse_event_t event, json & parsed)
|
||||
{
|
||||
return !(event == json::parse_event_t::value && parsed == json(800));
|
||||
});
|
||||
|
||||
// discard the key of the number
|
||||
json j_key = json::parse(text, [](int /*depth*/, json::parse_event_t event, json & parsed)
|
||||
{
|
||||
return !(event == json::parse_event_t::key && parsed == json("Width"));
|
||||
});
|
||||
|
||||
// discard the top-level object
|
||||
json j_root = json::parse(text, [](int /*depth*/, json::parse_event_t event, json& /*parsed*/)
|
||||
{
|
||||
return event != json::parse_event_t::object_end;
|
||||
});
|
||||
|
||||
// in every case, the discarded value is removed together with its key
|
||||
std::cout << j_array_start << '\n'
|
||||
<< j_array_end << '\n'
|
||||
<< j_value << '\n'
|
||||
<< j_key << '\n'
|
||||
<< j_root << '\n';
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{"Width":800}
|
||||
{"Width":800}
|
||||
{"IDs":[116,943]}
|
||||
{"IDs":[116,943]}
|
||||
null
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
json parse_strict(const std::string& input)
|
||||
{
|
||||
// one key set per nesting depth, reused across sibling objects
|
||||
std::vector<std::unordered_set<std::string>> keys;
|
||||
|
||||
auto reject_duplicate_keys = [&](int depth, json::parse_event_t event, json & parsed)
|
||||
{
|
||||
if (event == json::parse_event_t::object_start)
|
||||
{
|
||||
// keys of this object are reported at depth+1 (see the event table above)
|
||||
const auto child_depth = static_cast<std::size_t>(depth) + 1;
|
||||
if (keys.size() <= child_depth)
|
||||
{
|
||||
keys.resize(child_depth + 1);
|
||||
}
|
||||
keys[child_depth].clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event == json::parse_event_t::key)
|
||||
{
|
||||
auto& seen = keys[static_cast<std::size_t>(depth)];
|
||||
const auto& key = parsed.get_ref<const std::string&>();
|
||||
if (!seen.insert(key).second)
|
||||
{
|
||||
throw std::runtime_error("duplicate JSON object key: " + key);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return json::parse(input, reject_duplicate_keys);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// parsing succeeds when all keys are unique
|
||||
json j = parse_strict(R"({"one": 1, "two": 2})");
|
||||
std::cout << j << '\n';
|
||||
|
||||
// parsing throws when a key is repeated
|
||||
try
|
||||
{
|
||||
parse_strict(R"({"one": 1, "one": 2})");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"one":1,"two":2}
|
||||
duplicate JSON object key: one
|
||||
@@ -180,6 +180,49 @@ For _derived_ classes and structs, use the following macros
|
||||
}
|
||||
```
|
||||
|
||||
!!! warning "Overriding conversions for natively-supported types"
|
||||
|
||||
The library already provides built-in `to_json`/`from_json` conversions for STL containers such as
|
||||
`std::vector`, `std::array`, and `std::map`. Defining your own free-function `to_json`/`from_json` overload
|
||||
for one of these container types directly (instead of for your own type) can conflict with the built-in
|
||||
overload during overload resolution, producing compiler errors ("no matching overloaded function",
|
||||
"call is ambiguous") that vary by compiler and library version. If you need different conversion behavior
|
||||
for a container type the library already handles, wrap it in your own type (or use `adl_serializer`
|
||||
specialization, as shown [above](#how-do-i-convert-third-party-types) for `boost::optional`) instead of
|
||||
trying to re-specialize `to_json`/`from_json` for the container type itself.
|
||||
|
||||
!!! warning "Raw C-style arrays"
|
||||
|
||||
Members declared as raw C-style arrays (e.g., `char buf[1024]`) do not round-trip safely through
|
||||
`NLOHMANN_DEFINE_TYPE_*` macros or the default (de)serializers: `to_json` serializes any `char` array as a
|
||||
JSON *string* (matching the `std::string`-constructible overload), but the `from_json` overload for
|
||||
fixed-size arrays expects a JSON *array* and iterates it element-wise, which fails with a `type_error` when
|
||||
given a string. Use `std::string`, `std::array<char, N>`, or a manually written `to_json`/`from_json` pair
|
||||
for such members instead.
|
||||
|
||||
!!! note "Macros and `nlohmann::ordered_json`"
|
||||
|
||||
The `NLOHMANN_DEFINE_TYPE_*`/`NLOHMANN_DEFINE_DERIVED_TYPE_*` macros are generic over any `basic_json`
|
||||
specialization, including `nlohmann::ordered_json`. Simply use `ordered_json` as the target type and members
|
||||
are serialized in declaration order -- no separate macro or extra code is needed.
|
||||
|
||||
```cpp
|
||||
namespace ns {
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
|
||||
}
|
||||
|
||||
ns::person p{"Ned Flanders", "744 Evergreen Terrace", 60};
|
||||
nlohmann::ordered_json j = p; // keys appear in declaration order: name, address, age
|
||||
```
|
||||
|
||||
!!! note "No macro for non-default-constructible types"
|
||||
|
||||
There is currently no `NLOHMANN_DEFINE_TYPE_*`-style macro for types that are not
|
||||
[DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). This is not an
|
||||
intentional omission of documentation -- no such macro exists yet; see
|
||||
[How can I use `get()` for non-default constructible/non-copyable types?](#how-can-i-use-get-for-non-default-constructiblenon-copyable-types)
|
||||
for the manual pattern to use instead.
|
||||
|
||||
## How do I convert third-party types?
|
||||
|
||||
This requires a bit more advanced technique. But first, let us see how this conversion mechanism works:
|
||||
@@ -270,6 +313,49 @@ namespace nlohmann {
|
||||
}
|
||||
```
|
||||
|
||||
## Why can't I convert to/from `std::any`?
|
||||
|
||||
`std::any` is intentionally excluded from `get<T>()`/generic conversion support, so `get<std::any>()` and
|
||||
containers like `std::map<std::string, std::any>` fail to compile by design -- there is no way to know, from a
|
||||
`json` value alone, which concrete type to store inside the `std::any`. To work with heterogeneous JSON values,
|
||||
dispatch on the value's type manually and construct the `std::any` (or extract from it) yourself:
|
||||
|
||||
```cpp
|
||||
std::any value_to_any(const json& j) {
|
||||
if (j.is_boolean()) { return j.get<bool>(); }
|
||||
if (j.is_number_integer()) { return j.get<int>(); }
|
||||
if (j.is_number_float()) { return j.get<double>(); }
|
||||
if (j.is_string()) { return j.get<std::string>(); }
|
||||
// ... handle other types (arrays, objects) as needed for your use case
|
||||
return {};
|
||||
}
|
||||
|
||||
json any_to_json(const std::any& a) {
|
||||
if (a.type() == typeid(bool)) { return std::any_cast<bool>(a); }
|
||||
if (a.type() == typeid(int)) { return std::any_cast<int>(a); }
|
||||
if (a.type() == typeid(double)) { return std::any_cast<double>(a); }
|
||||
if (a.type() == typeid(std::string)) { return std::any_cast<std::string>(a); }
|
||||
return nullptr;
|
||||
}
|
||||
```
|
||||
|
||||
## Why does serializing a `std::map`/`std::unordered_map` with non-string keys produce an array?
|
||||
|
||||
A `std::map`/`std::unordered_map` whose key type is not string-like (e.g., `std::map<int, std::string>`) is
|
||||
serialized as a JSON *array* of 2-element `[key, value]` arrays, not as a JSON object -- JSON object keys must be
|
||||
strings, so the library cannot represent an integer-keyed map as an object.
|
||||
|
||||
```cpp
|
||||
std::map<int, std::string> m{{1, "one"}, {2, "two"}};
|
||||
json j = m;
|
||||
// j is [[1,"one"],[2,"two"]], not {"1":"one","2":"two"}
|
||||
```
|
||||
|
||||
## Why does `std::wstring` convert or dump incorrectly?
|
||||
|
||||
The library assumes UTF-8 encoding internally, so `std::wstring` is not supported out of the box -- see the FAQ
|
||||
entry on [wide string handling](../home/faq.md#wide-string-handling) for why, and for a UTF-8 conversion recipe.
|
||||
|
||||
## Can I write my own serializer? (Advanced use)
|
||||
|
||||
Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-udt.cpp) in the test suite, to see a few examples.
|
||||
|
||||
@@ -116,9 +116,19 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
```
|
||||
|
||||
Likewise, when a JSON object in the above form is serialized using
|
||||
[`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array. The
|
||||
only exception is, that when the 1-dimensional vector stored in `"_ArraySize_"` contains a single integer or two
|
||||
integers with one being 1, a regular 1-D optimized array is generated.
|
||||
[`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array. When
|
||||
the 1-dimensional vector stored in `"_ArraySize_"` contains a single integer or two integers with one being 1, a
|
||||
regular 1-D optimized array is generated instead.
|
||||
|
||||
An object is only converted if the annotation actually describes a packed array; otherwise it is serialized as a
|
||||
regular JSON object. This requires all of the following:
|
||||
|
||||
- `"_ArrayType_"` is one of `uint8`, `int8`, `uint16`, `int16`, `uint32`, `int32`, `uint64`, `int64`, `single`,
|
||||
`double`, `char`, or `byte`,
|
||||
- every entry of `"_ArraySize_"` is a non-negative integer, and their product is representable as a `std::size_t`,
|
||||
- `"_ArrayData_"` holds exactly that many elements, and
|
||||
- every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"` (a floating-point number for
|
||||
`single` and `double`, an integer otherwise).
|
||||
|
||||
The current version of this library does not yet support automatic detection of and conversion from a nested JSON
|
||||
array input to a BJData ND-array.
|
||||
|
||||
@@ -35,6 +35,19 @@ The library uses the following mapping from JSON values types to BSON types:
|
||||
The mapping is **incomplete**, since only JSON-objects (and things contained therein) can be serialized to BSON.
|
||||
Also, keys may not contain U+0000, since they are serialized a zero-terminated c-strings.
|
||||
|
||||
!!! warning "BSON type 0x11 interoperability"
|
||||
|
||||
The BSON specification defines type `0x11` as a Timestamp. This library uses marker `0x11` when serializing
|
||||
`number_unsigned` values in the range `9223372036854775808..18446744073709551615`. Other BSON implementations may
|
||||
therefore interpret these values as Timestamps instead of unsigned integers.
|
||||
|
||||
!!! info "Binary values without a subtype"
|
||||
|
||||
BSON requires every binary value to have a subtype. If a binary value has no subtype, this library serializes it
|
||||
with the generic subtype `0x00`. After deserialization, `has_subtype()` returns `true` and `subtype()` returns `0`.
|
||||
As a result, serializing and deserializing a JSON object containing such a value produces a different JSON object,
|
||||
even though the binary data is unchanged.
|
||||
|
||||
??? example
|
||||
|
||||
```cpp
|
||||
@@ -82,8 +95,19 @@ The library maps BSON record types to JSON value types as follows:
|
||||
|
||||
!!! note "Handling of BSON type 0x11"
|
||||
|
||||
BSON type 0x11 is used to represent uint64 numbers. This library treats these values purely as uint64 numbers
|
||||
and does not parse them into date-related formats.
|
||||
This library deserializes BSON type `0x11` (Timestamp) as a `number_unsigned` value. The 64-bit value is preserved,
|
||||
but the Timestamp type information is not.
|
||||
|
||||
!!! warning "Lenient BSON input handling"
|
||||
|
||||
The BSON reader is lenient in a few areas where the BSON specification is more restrictive:
|
||||
|
||||
- array element keys are not checked against the required decimal sequence (`0`, `1`, `2`, ...),
|
||||
- any non-zero byte is accepted as `true` for the boolean type, and
|
||||
- the payload for binary subtype `0x02` is returned as-is, including its inner length prefix.
|
||||
|
||||
If BSON input must be validated for strict specification compliance, validate it separately before passing it to
|
||||
`from_bson()`.
|
||||
|
||||
??? example
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ extremely small code sizes, fairly small message size, and extensibility without
|
||||
|
||||
- [CBOR Website](http://cbor.io) - the main source on CBOR
|
||||
- [CBOR Playground](http://cbor.me) - an interactive webpage to translate between JSON and CBOR
|
||||
- [RFC 7049](https://tools.ietf.org/html/rfc7049) - the CBOR specification
|
||||
- [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949.html) - the CBOR specification
|
||||
|
||||
## Serialization
|
||||
|
||||
The library uses the following mapping from JSON values types to CBOR types according to the CBOR specification
|
||||
([RFC 7049](https://www.rfc-editor.org/rfc/rfc7049.html)):
|
||||
([RFC 8949](https://www.rfc-editor.org/rfc/rfc8949.html)):
|
||||
|
||||
| JSON value type | value/range | CBOR type | first byte |
|
||||
|-----------------|--------------------------------------------|-----------------------------------|------------|
|
||||
@@ -66,7 +66,15 @@ see "binary" cells in the table above.
|
||||
|
||||
!!! info "NaN/infinity handling"
|
||||
|
||||
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the normal JSON serialization which serializes NaN or Infinity to `null`.
|
||||
`NaN`, `Infinity`, and `-Infinity` are serialized as a CBOR half-precision float (type 0xF9, 3 bytes total):
|
||||
`NaN` as `0xF9 0x7E 0x00`, `Infinity` as `0xF9 0x7C 0x00`, and `-Infinity` as `0xF9 0xFC 0x00`. This behavior
|
||||
differs from the normal JSON serialization which serializes NaN or Infinity to `null`.
|
||||
|
||||
!!! note
|
||||
|
||||
Prior to version 3.13.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB,
|
||||
9 bytes total), because the check used to select a smaller encoding compared magnitudes with NaN, which is
|
||||
always `false` and caused the intended half-precision path to be skipped.
|
||||
|
||||
!!! info "Unused CBOR types"
|
||||
|
||||
@@ -152,21 +160,25 @@ The library maps CBOR types to JSON value types as follows:
|
||||
|
||||
The mapping is **incomplete** in the sense that not all CBOR types can be converted to a JSON value. The following CBOR types are not supported and will yield parse errors:
|
||||
|
||||
- date/time (0xC0..0xC1)
|
||||
- bignum (0xC2..0xC3)
|
||||
- decimal fraction (0xC4)
|
||||
- bigfloat (0xC5)
|
||||
- expected conversions (0xD5..0xD7)
|
||||
- simple values (0xE0..0xF3, 0xF8)
|
||||
- undefined (0xF7)
|
||||
|
||||
Tagged items (0xC0..0xDB) are not interpreted either; see the note on tagged items below.
|
||||
|
||||
!!! warning "Negative integer overflow"
|
||||
|
||||
CBOR negative integers (major type 1) are decoded as `-1 - n`. If the encoded magnitude `n` is too large for the
|
||||
result to fit into `number_integer_t` (`std::int64_t` by default), parsing fails with a
|
||||
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) exception rather than overflowing
|
||||
silently.
|
||||
|
||||
!!! warning "Object keys"
|
||||
|
||||
CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys other than UTF-8 strings are rejected.
|
||||
|
||||
!!! warning "Tagged items"
|
||||
|
||||
Tagged items will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`. They can be stored by passing `cbor_tag_handler_t::store` to function `from_cbor`.
|
||||
Tagged items (0xC0..0xDB) will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`, in which case the tag is skipped and the enclosed data item is parsed on its own. They can be stored by passing `cbor_tag_handler_t::store` to function `from_cbor`. Note that no tag is ever interpreted: for instance, a text string tagged with tag 0 (date/time) stays a string.
|
||||
|
||||
??? example
|
||||
|
||||
|
||||
@@ -67,8 +67,15 @@ specification:
|
||||
|
||||
!!! info "NaN/infinity handling"
|
||||
|
||||
If NaN or Infinity are stored inside a JSON number, they are serialized properly in contrast to the
|
||||
[dump](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `null`.
|
||||
`NaN`, `Infinity`, and `-Infinity` are serialized as a MessagePack float 32 (type 0xCA, 5 bytes total),
|
||||
regardless of magnitude, in contrast to the [dump](../../api/basic_json/dump.md) function which serializes NaN
|
||||
or Infinity to `null`.
|
||||
|
||||
!!! note
|
||||
|
||||
Prior to version 3.13.0, NaN and Infinity were instead serialized as a MessagePack float 64 (type 0xCB, 9 bytes
|
||||
total), because the check used to select the smaller float 32 encoding compared magnitudes with NaN, which is
|
||||
always `false` and caused the float 32 path to be skipped.
|
||||
|
||||
??? example
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ This library does not support comments *by default*. It does so for three reason
|
||||
|
||||
3. It is dangerous for interoperability if some libraries add comment support while others do not. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
|
||||
|
||||
However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace.
|
||||
However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. Combined with `ignore_trailing_commas` (also a `parse` parameter), this covers what is commonly referred to as **JSONC** (JSON with Comments, as used e.g. by Visual Studio Code's `.jsonc` files) -- comments and trailing commas, nothing more. This is a different, smaller extension than [JSON5](https://json5.org), which additionally allows unquoted keys, single-quoted strings, and other syntax changes that this library does not support.
|
||||
|
||||
For more information, see [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html).
|
||||
|
||||
|
||||
@@ -47,6 +47,58 @@ json j = {{"one", 1}, {"two", 2}};
|
||||
auto m = j.get<std::map<std::string, int>>(); // {{"one", 1}, {"two", 2}}
|
||||
```
|
||||
|
||||
`#!cpp std::pair` and `#!cpp std::tuple` are also supported, converting positionally to and from a JSON array:
|
||||
|
||||
```cpp
|
||||
json j = {1.0, "hello", 42};
|
||||
auto t = j.get<std::tuple<double, std::string, int>>(); // {1.0, "hello", 42}
|
||||
```
|
||||
|
||||
!!! warning "Serializing a `std::pair`/`std::tuple` whose every element is a string-keyed pair"
|
||||
|
||||
When *every* element of a `#!cpp std::pair` or `#!cpp std::tuple` is itself a two-element array whose first
|
||||
element is a string (for example `#!cpp std::pair<std::string, int>`), serializing it produces a JSON **object**
|
||||
instead of the expected array:
|
||||
|
||||
```cpp
|
||||
using kv = std::pair<std::string, int>;
|
||||
json j = std::pair<kv, kv>{{"a", 1}, {"b", 2}}; // {"a":1,"b":2}, not [["a",1],["b",2]]
|
||||
```
|
||||
|
||||
This is a consequence of the [brace-initializer object-detection rule](creating_values.md): the same rule that
|
||||
lets `#!cpp json{{"a", 1}, {"b", 2}}` create an object also fires here. The resulting object cannot be read back
|
||||
into the original type (`#!cpp get<std::pair<kv, kv>>()` throws [`type_error.302`](../home/exceptions.md#jsonexceptiontype_error302)),
|
||||
and duplicate keys collapse into one, losing elements. This only affects `#!cpp std::pair`/`#!cpp std::tuple`
|
||||
themselves; a `#!cpp std::vector<std::pair<std::string, int>>`, or a pair/tuple with at least one element that is
|
||||
not a string-keyed pair, serializes to an array as expected. To force an array, build one explicitly from the
|
||||
elements with [`array`](../api/basic_json/array.md):
|
||||
|
||||
```cpp
|
||||
std::pair<kv, kv> p{{"a", 1}, {"b", 2}};
|
||||
json a = json::array({p.first, p.second}); // [["a",1],["b",2]]
|
||||
```
|
||||
|
||||
!!! info "Extracting references into a tuple"
|
||||
|
||||
A tuple type may also hold references (e.g. `#!cpp std::tuple<double&, std::string&>`) to avoid copying: `get`
|
||||
then returns a tuple of references pointing directly at the elements stored inside the `basic_json` array,
|
||||
rather than a tuple of copies:
|
||||
|
||||
```cpp
|
||||
json j = {1.0, "hello"};
|
||||
auto refs = j.get<std::tuple<double&, std::string&>>();
|
||||
std::get<1>(refs) = "world"; // modifies j[1] in place
|
||||
```
|
||||
|
||||
A referenced element must name the type the library actually *stores* — one of [`boolean_t`](../api/basic_json/boolean_t.md),
|
||||
[`number_integer_t`](../api/basic_json/number_integer_t.md), [`number_unsigned_t`](../api/basic_json/number_unsigned_t.md),
|
||||
[`number_float_t`](../api/basic_json/number_float_t.md), [`string_t`](../api/basic_json/string_t.md),
|
||||
[`binary_t`](../api/basic_json/binary_t.md), [`array_t`](../api/basic_json/array_t.md), or
|
||||
[`object_t`](../api/basic_json/object_t.md). There is nothing else to refer to, so a reference to any other type is a
|
||||
compile error even when a conversion would exist: `#!cpp std::tuple<int&>` is rejected, because the library stores a
|
||||
`#!cpp number_integer_t` (`#!cpp std::int64_t` by default) and not an `#!cpp int`. This restriction applies only to
|
||||
reference elements — a plain `#!cpp std::tuple<int>` converts by value as usual.
|
||||
|
||||
## Implicit conversions
|
||||
|
||||
By default, a JSON value implicitly converts to a compatible C++ type, so the explicit `get` call can often be omitted:
|
||||
@@ -66,6 +118,84 @@ which forces the explicit `get` form and can catch unintended conversions at com
|
||||
floating-point value as an integer truncates it, and narrowing conversions may overflow. See
|
||||
[number conversion](types/number_handling.md#number-conversion) for details and how to guard against it.
|
||||
|
||||
!!! warning "std::optional direct construction from JSON null throws"
|
||||
|
||||
Constructing or assigning `std::optional<T>` directly from a JSON value does not correctly produce
|
||||
`std::nullopt` for a JSON `null`:
|
||||
|
||||
```cpp
|
||||
json j_null;
|
||||
std::optional<std::string> opt = j_null; // ❌ throws type_error 302
|
||||
```
|
||||
|
||||
This is due to C++ language rules: `std::optional<T>` has its own converting constructor that is chosen over
|
||||
`basic_json::operator T()` when both are viable. Use `get<std::optional<T>>()` or `get_to()` instead:
|
||||
|
||||
```cpp
|
||||
auto opt = j_null.get<std::optional<std::string>>(); // ✅ std::nullopt
|
||||
j_null.get_to(opt); // ✅ std::nullopt
|
||||
```
|
||||
|
||||
!!! warning "`static_cast` and `get<std::optional<T>>()` are not guaranteed equivalent"
|
||||
|
||||
`operator ValueType()` (used by `static_cast` and implicit conversions) intentionally excludes
|
||||
`std::optional<T>` from delegating to `get<T>()`, to avoid a constructor ambiguity with
|
||||
`std::optional<T>`'s own converting constructor from `basic_json`. As a result,
|
||||
`static_cast<std::optional<T>>(json_value)` goes through `std::optional<T>`'s own converting
|
||||
constructor rather than through `get<std::optional<T>>()`, which can behave differently -- for example,
|
||||
with a custom `adl_serializer<std::optional<T>>` specialization. Prefer `get<std::optional<T>>()`/`get_to()`
|
||||
over `static_cast` for optional types.
|
||||
|
||||
!!! warning "Converting to a fixed-size destination does not check the array size"
|
||||
|
||||
Some destination types have a size that is fixed by their C++ type rather than by the JSON value:
|
||||
`#!cpp std::pair<A, B>`, `#!cpp std::tuple<Ts...>`, `#!cpp std::array<T, N>`, C arrays `#!cpp T[N]`, and
|
||||
`#!cpp std::map`/`#!cpp std::unordered_map` with a non-string key type (which is read from an array of
|
||||
two-element arrays). All of them read exactly as many elements as they need via
|
||||
[`at`](../api/basic_json/at.md) and **never compare the JSON array's size to that number**. The two
|
||||
mismatch directions therefore behave differently:
|
||||
|
||||
- The JSON array has **too many** elements: the surplus is **silently discarded**, and no exception is
|
||||
thrown.
|
||||
- The JSON array has **too few** elements: `at` throws
|
||||
[`out_of_range.401`](../home/exceptions.md#jsonexceptionout_of_range401) for the first missing index --
|
||||
an out-of-range error, not a [`type_error`](../home/exceptions.md#type-errors), even though the cause
|
||||
is a shape mismatch.
|
||||
|
||||
```cpp
|
||||
json j = {1, 2, 3, 4, 5};
|
||||
|
||||
auto a = j.get<std::array<int, 3>>(); // {1, 2, 3} -- elements 4 and 5 silently dropped
|
||||
auto p = j.get<std::pair<int, int>>(); // (1, 2) -- elements 3, 4, and 5 silently dropped
|
||||
|
||||
json k = {1};
|
||||
auto q = k.get<std::pair<int, int>>(); // ❌ throws out_of_range.401
|
||||
```
|
||||
|
||||
If a size mismatch is an error in your application, check the size yourself before converting.
|
||||
|
||||
## Omitting a field when serializing `std::optional`
|
||||
|
||||
By default, `to_json` for `std::optional<T>` writes either the value or `#!json null` -- there is no built-in way
|
||||
to make a field disappear from the serialized object entirely when the `std::optional` is `std::nullopt`. Because
|
||||
a specialization of `adl_serializer<std::optional<T>>` only controls how the *value* is converted (it cannot
|
||||
prevent the containing object's `to_json` from inserting the key in the first place), omission has to be
|
||||
implemented in the *containing* type's `to_json`:
|
||||
|
||||
```cpp
|
||||
struct person {
|
||||
std::string name;
|
||||
std::optional<int> age;
|
||||
};
|
||||
|
||||
void to_json(json& j, const person& p) {
|
||||
j = json{{"name", p.name}};
|
||||
if (p.age) {
|
||||
j["age"] = *p.age; // key is only inserted when the optional has a value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Putting values in
|
||||
|
||||
The reverse direction works the same way: assigning or constructing a `json` from a C++ value converts it to JSON.
|
||||
@@ -75,6 +205,20 @@ std::vector<int> numbers = {1, 2, 3};
|
||||
json j = numbers; // [1,2,3]
|
||||
```
|
||||
|
||||
!!! info "Constructing from a C++20 range view"
|
||||
|
||||
A `json` array can also be constructed directly from a C++20 range view (`std::ranges::view`), such as the result
|
||||
of `std::views::filter` or `std::views::transform` -- no intermediate container is needed:
|
||||
|
||||
```cpp
|
||||
std::vector<int> nums{1, 2, 37, 42, 21};
|
||||
auto filtered = nums | std::views::filter([](int i) { return i > 10; });
|
||||
json j(filtered); // [37,42,21]
|
||||
```
|
||||
|
||||
This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due
|
||||
to incomplete C++20 ranges support there.
|
||||
|
||||
## Your own types
|
||||
|
||||
The conversions above are built in for standard types. To make the same syntax work for **your own** types, provide
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
In many situations, such as configuration files, missing values are not exceptional, but may be treated as if a default
|
||||
value was present. For this case, use [`value(key, default_value)`](../../api/basic_json/value.md) which takes the key
|
||||
you want to access and a default value in case there is no value stored with that key.
|
||||
you want to access and a default value in case there is no value stored with that key. This is equivalent to Python's
|
||||
`dict.get(key, default)`.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
@@ -102,6 +102,20 @@ that the passed index is the new maximal index. Intermediate values are filled w
|
||||
`operator[]` can only be used with objects (with a string argument) or with arrays (with a numeric argument). For
|
||||
other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error305) is thrown.
|
||||
|
||||
## Performance: reserving array capacity
|
||||
|
||||
There is no public `reserve(count)` member on `basic_json` for pre-allocating array capacity. If you are building
|
||||
a large array incrementally (e.g., via repeated `push_back()`) and know its final size ahead of time, you can
|
||||
reserve capacity via `get_ref()` to access the underlying `array_t` directly:
|
||||
|
||||
```cpp
|
||||
json j = json::array();
|
||||
j.get_ref<json::array_t&>().reserve(1000);
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
j.push_back(i);
|
||||
}
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
| scenario | non-const value | const value |
|
||||
|
||||
@@ -77,6 +77,11 @@ auto val2 = j.at(json::json_pointer("/nested/three/1")); // false
|
||||
auto val3 = j.value(json::json_pointer("/nested/four"), 0); // 0
|
||||
```
|
||||
|
||||
!!! note "Creating intermediate levels that don't exist"
|
||||
|
||||
See the [`operator[]` notes](../api/basic_json/operator%5B%5D.md#return-value) for how array vs. object is
|
||||
decided when a pointer creates intermediate levels that don't exist yet.
|
||||
|
||||
## Flatten / unflatten
|
||||
|
||||
The library implements a function [`flatten`](../api/basic_json/flatten.md) to convert any JSON document into a JSON
|
||||
|
||||
@@ -27,6 +27,7 @@ json data = json::parse(f);
|
||||
It should be noted that as modules do not export macros, the `nlohmann.json` module will not export any macros.
|
||||
|
||||
## Exported symbols
|
||||
|
||||
Only the following symbols are exported from `nlohmann.json`:
|
||||
|
||||
- `nlohmann::adl_serializer`
|
||||
@@ -38,3 +39,21 @@ Only the following symbols are exported from `nlohmann.json`:
|
||||
- `nlohmann::to_string`
|
||||
- `nlohmann::literals::json_literals::operator""_json`
|
||||
- `nlohmann::literals::json_literals::operator""_json_pointer`
|
||||
|
||||
Additionally, the following `nlohmann::detail` symbols are exported, solely to work around an MSVC compilation issue
|
||||
([#3970](https://github.com/nlohmann/json/issues/3970)). They are implementation details, not part of the public API,
|
||||
and should not be used directly:
|
||||
|
||||
- `nlohmann::detail::json_sax_dom_callback_parser`
|
||||
- `nlohmann::detail::unknown_size`
|
||||
|
||||
## Known issues
|
||||
|
||||
C++20 modules support is exercised in CI against current GCC and Clang on Ubuntu, and the default MSVC toolset on Windows Server 2022 — there is no documented minimum compiler version, unlike feature-test-macro-gated features such as [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md).
|
||||
|
||||
!!! info "Known compiler issues"
|
||||
|
||||
- **GCC** may emit "redefinition" errors when `#include <nlohmann/json.hpp>` appears in a module preamble together with other imports. This is an upstream GCC bug, not yet resolved as of GCC 16. Workarounds: include `nlohmann/json.hpp` before other `#include`s, use `import nlohmann.json;` instead, or upgrade GCC. ([issue #5103](https://github.com/nlohmann/json/issues/5103))
|
||||
- **MSVC** could fail with `C2039: 'json_sax_dom_callback_parser' is not a member of ... detail`; fixed by exporting the required internal symbols from `json.cppm` (see [Exported symbols](#exported-symbols) above). ([issue #3970](https://github.com/nlohmann/json/issues/3970))
|
||||
|
||||
If you hit a different module-related build failure, search [existing issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+modules) before filing a new one.
|
||||
|
||||
@@ -51,7 +51,17 @@ If you do want to preserve the **insertion order**, you can use the type [`nlohm
|
||||
--8<-- "examples/ordered_json.output"
|
||||
```
|
||||
|
||||
Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
|
||||
Alternatively, [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) also preserves the insertion order and, unlike [`ordered_map`](../api/ordered_map.md), keeps a lookup index, so it does not have the quadratic cost described below. It is used through a small adapter ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
|
||||
|
||||
If the order does not matter and you only want faster lookup, `boost::unordered_flat_map`, `absl::flat_hash_map`, `absl::node_hash_map`, and several other hash maps work through an adapter that restores the template argument order `basic_json` expects; see [Template Parameter Requirements](types/template_parameters.md#objecttype). Note these are *unordered*, not insertion-ordered.
|
||||
|
||||
[`tsl::ordered_map`](https://github.com/Tessil/ordered-map) cannot be used: its iterators expose the mapped value as `const`, while `basic_json` needs to modify it in place.
|
||||
|
||||
The [`ordered_map`](../api/ordered_map.md) behind `nlohmann::ordered_json` is deliberately minimal and has no lookup
|
||||
index, so every key access is a linear scan and building an object of `n` keys costs O(n²). This is unnoticeable at
|
||||
typical object sizes but becomes significant for objects with many thousands of keys; see
|
||||
[`ordered_map` complexity](../api/ordered_map.md#complexity). The alternatives above keep a lookup index and do not
|
||||
have this cost.
|
||||
|
||||
### Notes on parsing
|
||||
|
||||
|
||||
@@ -28,6 +28,22 @@ Inputs consisting of multiple values separated by newlines are handled by the [J
|
||||
By default, the library rejects comments and trailing commas. Both can be enabled with parameters of the `parse`
|
||||
function — see [comments](../comments.md) and [trailing commas](../trailing_commas.md).
|
||||
|
||||
## Strictness and trailing data
|
||||
|
||||
[`parse`](../../api/basic_json/parse.md) reads a single JSON value and requires the whole input to be consumed: any
|
||||
non-whitespace data after the value is reported as a parse error. Use it when you want to guarantee that an input is
|
||||
exactly one complete JSON document.
|
||||
|
||||
[`operator>>`](../../api/operator_gtgt.md) follows relaxed `#!cpp std::istream` semantics instead: it parses one JSON
|
||||
value and leaves the stream positioned right after it, without requiring the rest of the stream to be consumed. This is
|
||||
what makes it possible to read several concatenated values from the same stream, but it also means that "a valid
|
||||
document followed by trailing bytes" is accepted rather than rejected. If you are validating conformance, or need to
|
||||
reject any input that is not exactly one JSON document, prefer `parse`.
|
||||
|
||||
When using `operator>>` to read several concatenated values this way, a value that is a number must be followed by
|
||||
whitespace, because `operator>>` consumes the character that terminates a number — see the
|
||||
[`operator>>` notes](../../api/operator_gtgt.md#notes) for details and examples.
|
||||
|
||||
## SAX vs. DOM parsing
|
||||
|
||||
The library offers two parsing models:
|
||||
|
||||
@@ -47,3 +47,7 @@ JSON Lines input with more than one value is treated as invalid JSON by the [`pa
|
||||
```
|
||||
|
||||
with a JSON Lines input does not work, because the parser will try to parse one value after the last one.
|
||||
|
||||
This is different from parsing a stream of *concatenated* (non-newline-delimited) JSON values, for which
|
||||
`operator>>` does work, provided that a value that is a number is followed by whitespace -- see its
|
||||
[notes](../../api/operator_gtgt.md#notes) for details.
|
||||
|
||||
@@ -58,6 +58,14 @@ table describes the values of the parameters `depth`, `event`, and `parsed`.
|
||||
| `array_end` | 1 | `#!json [52.519444,13.406667]` |
|
||||
| `object_end` | 0 | `#!json {"location":[52.519444,13.406667],"name":"Berlin"}` |
|
||||
|
||||
!!! note "No built-in nesting depth limit"
|
||||
|
||||
The library has no built-in limit on recursion/nesting depth while parsing. A parser callback can only
|
||||
*discard* content it has already parsed (by returning `#!c false`); it cannot make parsing fail once a
|
||||
nesting limit is exceeded partway through reading a deeply nested value. If you need to reject over-deep
|
||||
untrusted input outright, track `depth` in a callback and `throw` from it once your limit is exceeded (a
|
||||
thrown exception propagates out of `parse()` as usual).
|
||||
|
||||
## Return value
|
||||
|
||||
Discarding a value (i.e., returning `#!c false`) has different effects depending on the context in which the function
|
||||
@@ -81,3 +89,82 @@ was called:
|
||||
```json
|
||||
--8<-- "examples/parse__string__parser_callback_t.output"
|
||||
```
|
||||
|
||||
## Recipe: rejecting duplicate object keys
|
||||
|
||||
The JSON specification leaves the handling of objects with repeated keys up to the implementation. As described in
|
||||
[`object_t`](../../api/basic_json/object_t.md#behavior), it is unspecified which value for a repeated key ends up in
|
||||
the resulting `#!c json` value -- once parsing has produced that value, the duplicate is already gone, because object
|
||||
storage maps each key to a single value. If duplicate keys should instead be treated as an error, a parser callback
|
||||
can detect them while the object is still being read, before that ambiguity ever applies.
|
||||
|
||||
??? example
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/reject_duplicate_keys.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/reject_duplicate_keys.output"
|
||||
```
|
||||
|
||||
This approach has two limitations:
|
||||
|
||||
- The depth-indexed bookkeeping must account for the fact that `object_start` reports the depth of the *parent* of
|
||||
the object, while the `key` events inside that object are reported one depth deeper (see the event table above);
|
||||
it is easy to get this off by one for nested objects.
|
||||
- The thrown exception cannot carry a `parse_error`-style byte offset, because position tracking only exists inside
|
||||
the parser and lexer, not at the callback layer.
|
||||
|
||||
For strict validation with precise error positions, implementing a [SAX interface](sax_interface.md) instead gives
|
||||
access to the parser's position information directly.
|
||||
|
||||
## Recipe: streaming a large homogeneous array
|
||||
|
||||
A common use case is a huge top-level array of many similarly-shaped objects, too large to hold entirely in
|
||||
memory as a `#!c json` value. A parser callback can hand off each completed element to a user function and then
|
||||
discard it, so memory usage stays bounded by a single element (plus the not-yet-parsed tail of the input) rather
|
||||
than the whole document. Since the top-level array's `array_start`/`array_end` are reported at `depth == 0` (its
|
||||
parent is the document root), the object elements it contains are reported at `depth == 1`:
|
||||
|
||||
??? example
|
||||
|
||||
```cpp
|
||||
std::ifstream input("large_array.json");
|
||||
|
||||
auto callback = [](int depth, json::parse_event_t event, json& parsed) -> bool {
|
||||
if (depth == 1 && event == json::parse_event_t::object_end) {
|
||||
handle_element(parsed); // process the element, e.g. write it elsewhere
|
||||
return false; // discard it -- frees its memory before the next one is parsed
|
||||
}
|
||||
return true; // keep everything else, including the (by then empty) top-level array
|
||||
};
|
||||
|
||||
json::parse(input, callback);
|
||||
```
|
||||
|
||||
If the array's elements are scalars or nested arrays instead of objects, check for `parse_event_t::value` or
|
||||
`parse_event_t::array_end` at `depth == 1` instead. The same approach works for a top-level *object* of many
|
||||
homogeneous values by checking `object_end`/`value` events at `depth == 1` there too.
|
||||
|
||||
## Recipe: max nesting depth via a callback
|
||||
|
||||
Since there is no built-in nesting-depth limit (see the note above), a callback can enforce one manually by
|
||||
tracking the maximum `depth` seen and throwing once it is exceeded:
|
||||
|
||||
??? example
|
||||
|
||||
```cpp
|
||||
constexpr int max_depth = 32;
|
||||
|
||||
auto callback = [](int depth, json::parse_event_t /*event*/, json& /*parsed*/) -> bool {
|
||||
if (depth > max_depth) {
|
||||
throw std::runtime_error("maximum nesting depth exceeded");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
json::parse(input, callback);
|
||||
```
|
||||
|
||||
@@ -79,7 +79,8 @@ template<
|
||||
class NumberFloatType = double,
|
||||
template<typename U> class AllocatorType = std::allocator,
|
||||
template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer,
|
||||
class BinaryType = std::vector<std::uint8_t>
|
||||
class BinaryType = std::vector<std::uint8_t>,
|
||||
class CustomBaseClass = void
|
||||
>
|
||||
class basic_json;
|
||||
```
|
||||
@@ -106,6 +107,10 @@ using number_float_t = NumberFloatType;
|
||||
using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
|
||||
```
|
||||
|
||||
Not every type can be passed for these template arguments: the library uses the resulting types in ways that imply a
|
||||
number of requirements, for instance that `StringType` is `char`-based or that `ArrayType` is vector-like. These
|
||||
requirements are collected in [Template Parameter Requirements](template_parameters.md).
|
||||
|
||||
|
||||
## Objects
|
||||
|
||||
@@ -131,7 +136,7 @@ std::map<
|
||||
The choice of `object_t` influences the behavior of the JSON class. With the default type, objects have the following behavior:
|
||||
|
||||
- When all names are unique, objects will be interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings.
|
||||
- When the names within an object are not unique, it is unspecified which one of the values for a given key will be chosen. For instance, `#!json {"key": 2, "key": 1}` could be equal to either `#!json {"key": 1}` or `#!json {"key": 2}`.
|
||||
- When the names within an object are not unique, it is unspecified which one of the values for a given key will be chosen. For instance, `#!json {"key": 2, "key": 1}` could be equal to either `#!json {"key": 1}` or `#!json {"key": 2}`. To reject duplicate keys instead of silently resolving them one way or another, see [this parsing recipe](../parsing/parser_callbacks.md#recipe-rejecting-duplicate-object-keys).
|
||||
- Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see `dump`) in this order. For instance, both `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be stored and serialized as `#!json {"a": 2, "b": 1}`.
|
||||
- When comparing objects, the order of the name/value pairs is irrelevant. This makes objects interoperable in the sense that they will not be affected by these differences. For instance, `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be treated as equal.
|
||||
|
||||
@@ -151,6 +156,18 @@ In this class, the object's limit of nesting is not explicitly constrained. Howe
|
||||
|
||||
Objects are stored as pointers in a `basic_json` type. That is, for any access to object values, a pointer of type `object_t*` must be dereferenced.
|
||||
|
||||
### Converting maps with non-string keys
|
||||
|
||||
A `std::map`/`std::unordered_map` whose key type is not string-like (e.g., `std::map<int, std::string>`) is
|
||||
converted to a JSON *array* of 2-element `[key, value]` arrays rather than a JSON object, because JSON object
|
||||
keys must be strings:
|
||||
|
||||
```cpp
|
||||
std::map<int, std::string> m{{1, "one"}, {2, "two"}};
|
||||
json j = m;
|
||||
// j is [[1,"one"],[2,"two"]], not {"1":"one","2":"two"}
|
||||
```
|
||||
|
||||
|
||||
## Arrays
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ In the default [`json`](../../api/json.md) type, numbers are stored as `#!c std:
|
||||
number without loss of precision. If this is impossible (e.g., if the number is too large), the number is stored as
|
||||
`#!c double`.
|
||||
|
||||
Positive integers are stored as `#!c std::uint64_t`, while negative integers are stored as `#!c std::int64_t`. This
|
||||
distinction is determined at parse time: if the JSON number has a leading minus sign, it uses signed integer storage;
|
||||
otherwise, it uses unsigned integer storage.
|
||||
|
||||
!!! info "Notes"
|
||||
|
||||
- Numbers with a decimal digit or scientific notation are always stored as `#!c double`.
|
||||
|
||||
@@ -0,0 +1,663 @@
|
||||
# Template Parameter Requirements
|
||||
|
||||
Class [`basic_json`](../../api/basic_json/index.md) is configurable through eleven template parameters. The library
|
||||
never formally states what a type passed for one of these parameters has to provide -- the requirements are implied by
|
||||
the way the library uses the resulting [`object_t`](../../api/basic_json/object_t.md),
|
||||
[`array_t`](../../api/basic_json/array_t.md), [`string_t`](../../api/basic_json/string_t.md), etc. This page collects
|
||||
these requirements so they do not have to be discovered by trial and error. Each section lists the concrete types
|
||||
that are known to work for that parameter and the ones that do not, checked against Boost 1.83, Abseil 20250127.0,
|
||||
Folly, EASTL 3.21, `ankerl::unordered_dense`, `phmap`, `gtl`, `robin_hood`, `tsl::ordered_map`, and Qt 6.
|
||||
|
||||
## How to read this page
|
||||
|
||||
Requirements are split into two groups:
|
||||
|
||||
- **Always required** -- needed to instantiate `basic_json` at all, or needed by functions that virtually every program
|
||||
uses (construction, element access, [`dump`](../../api/basic_json/dump.md)).
|
||||
- **Required for ...** -- only needed when a particular part of the API is instantiated. Member function templates are
|
||||
only instantiated when they are used, so a type may be perfectly usable even though it does not satisfy these
|
||||
requirements, as long as the corresponding functions are never called.
|
||||
|
||||
!!! warning "Requirements are not checked"
|
||||
|
||||
Apart from a `#!cpp static_assert` on the array iterator category, the requirements below are not diagnosed with
|
||||
dedicated error messages. Violating most of them results in a compiler error somewhere inside the library. Six
|
||||
violations are not caught at compile time at all:
|
||||
|
||||
- A [`StringType`](#stringtype) whose `data()` is not null-terminated compiles and silently misparses numbers,
|
||||
because the lexer hands the buffer to `#!cpp std::strtoull`/`#!cpp std::strtoll`/`#!cpp std::strtod`.
|
||||
- A [`BinaryType`](#binarytype) whose `value_type` is wider than one byte compiles and silently produces wrong
|
||||
results, because the readers and writers reinterpret its storage as raw bytes.
|
||||
- A stateful [`AllocatorType`](#allocatortype) compiles and silently ignores its state: allocation, deallocation,
|
||||
and [`get_allocator()`](../../api/basic_json/get_allocator.md) each use a different default-constructed instance.
|
||||
- A [`NumberUnsignedType`](#numberintegertype-and-numberunsignedtype) too narrow to hold the absolute value of
|
||||
every `NumberIntegerType` value silently corrupts: with `#!cpp std::int64_t`/`#!cpp std::uint32_t`,
|
||||
`#!cpp basic_json(INT64_MIN).dump()` yields `#!json -0`.
|
||||
- The two [cross-specialization conversions](#cross-specialization-conversions) below. These abort on an assertion
|
||||
in a normal build, and only fail silently under `#!cpp NDEBUG`.
|
||||
|
||||
## 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 |
|
||||
| [`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"
|
||||
|
||||
`object_t` is instantiated inside the definition of `basic_json` -- it is probed for a `key_compare` member to
|
||||
form [`object_comparator_t`](../../api/basic_json/object_comparator_t.md) -- i.e. while `basic_json` is still an
|
||||
incomplete type. `#!cpp std::map` is required by the standard to support incomplete mapped types; most
|
||||
third-party maps are not, and inspecting the mapped type at class scope (for instance with
|
||||
`#!cpp std::is_trivially_move_assignable`) makes them unusable as `ObjectType`, no matter how their template
|
||||
arguments are adapted. This rules out `absl::btree_map`, `phmap::btree_map`, `gtl::btree_map`,
|
||||
`robin_hood::unordered_node_map`, `folly::F14FastMap`, and `eastl::hash_map`.
|
||||
|
||||
`array_t` is only *named* in the class definition and is not instantiated until `basic_json` is complete, so an
|
||||
`ArrayType` that inspects its value type at class scope is generally fine -- `boost::container::small_vector` and
|
||||
`static_vector` both reject incomplete value types yet work here. `absl::InlinedVector` is the exception: the
|
||||
`#!cpp std::is_trivially_move_assignable<basic_json>` it evaluates while instantiating itself re-enters the
|
||||
library's own trait machinery mid-instantiation.
|
||||
|
||||
!!! note "Folly requires C++20"
|
||||
|
||||
Folly's headers use `#!cpp consteval` and `#!cpp std::type_identity`, so any `basic_json` specialization that
|
||||
names a Folly type has to be compiled as C++20 or later, whatever the rest of the library supports.
|
||||
|
||||
## `ObjectType`
|
||||
|
||||
`ObjectType` is instantiated as
|
||||
|
||||
```cpp
|
||||
using object_t = ObjectType<StringType, // key_type
|
||||
basic_json, // mapped_type
|
||||
default_object_comparator_t, // key_compare
|
||||
AllocatorType<std::pair<const StringType,
|
||||
basic_json>>>; // allocator_type
|
||||
```
|
||||
|
||||
i.e., the template arguments follow the order and meaning of `std::map`.
|
||||
|
||||
### Always required
|
||||
|
||||
- The template must be usable with **four** type arguments in the order shown above. The third argument is a
|
||||
**comparator**; containers that expect something else in this position (e.g., a hash function) need an alias template
|
||||
or wrapper -- see [Notes](#notes).
|
||||
- An optional member type `key_compare`. If it is present it becomes
|
||||
[`object_comparator_t`](../../api/basic_json/object_comparator_t.md); otherwise
|
||||
[`default_object_comparator_t`](../../api/basic_json/default_object_comparator_t.md) is used.
|
||||
- Member types `key_type`, `mapped_type`, `value_type`, and `iterator`.
|
||||
- `value_type` must behave like `#!cpp std::pair<const key_type, mapped_type>`; the library accesses `.first` and
|
||||
`.second` on it.
|
||||
- `iterator` must be default-constructible and satisfy
|
||||
[LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator). The type returned
|
||||
by `cbegin()`/`cend()` must satisfy the same requirements.
|
||||
- Constructors: default, copy, move, and from an iterator range `(first, last)`.
|
||||
- Member functions `begin()`, `end()`, `cbegin()`, `cend()`, `empty()`, `size()`, `max_size()`, `clear()`,
|
||||
`find(key)`, `count(key)`, `emplace(key, value)`, `insert(value_type)`, `insert(first, last)`, `operator[](key)`,
|
||||
`erase(iterator)`, and `erase(first, last)`. `erase(iterator)` may return the following iterator or `#!cpp void`;
|
||||
in the latter case the library computes the successor itself, before erasing.
|
||||
- `erase(key)` is **optional**: if the container does not provide one, the library falls back to `find(key)` followed
|
||||
by `erase(iterator)`.
|
||||
- `at(key)` is required only by [`to_ubjson`](../../api/basic_json/to_ubjson.md) and
|
||||
[`to_bjdata`](../../api/basic_json/to_bjdata.md), but every container tried here provides it.
|
||||
- `emplace` and `insert(value_type)` must return `#!cpp std::pair<iterator, bool>` and must have **unique-key**
|
||||
semantics; multimaps cannot be used.
|
||||
- The type must be swappable (via `std::swap` or an ADL `swap`).
|
||||
- The comparison operators `==` and `<`; `!=`, `<=`, `>`, and `>=` are derived from them. Where the library uses
|
||||
three-way comparison (C++20), `==` and `<=>` are required **instead** -- the six two-way operators do not satisfy
|
||||
it. They implement [`basic_json`'s comparison operators](../../api/basic_json/operator_eq.md).
|
||||
|
||||
### Required for heterogeneous key lookup
|
||||
|
||||
The overloads of [`at`](../../api/basic_json/at.md), [`operator[]`](../../api/basic_json/operator%5B%5D.md),
|
||||
[`find`](../../api/basic_json/find.md), [`contains`](../../api/basic_json/contains.md),
|
||||
[`count`](../../api/basic_json/count.md), [`erase`](../../api/basic_json/erase.md), and
|
||||
[`value`](../../api/basic_json/value.md) that accept a key type other than `object_t::key_type` require
|
||||
|
||||
- a **transparent** comparator, i.e. [`object_comparator_t`](../../api/basic_json/object_comparator_t.md) has a member
|
||||
type `is_transparent` (this is why the default comparator is `#!cpp std::less<>` since C++14), and
|
||||
- corresponding heterogeneous `find`, `count`, `erase`, and `operator[]` overloads on the container.
|
||||
|
||||
### Notes
|
||||
|
||||
#### `std::unordered_map` needs an adapter
|
||||
|
||||
`#!cpp std::unordered_map` cannot be passed directly: its third template parameter is a hash function, but
|
||||
`basic_json` passes a comparator in that position. An alias template or wrapper that restores the expected argument
|
||||
order makes it usable:
|
||||
|
||||
```cpp
|
||||
template<class Key, class T, class IgnoredCompare, class Allocator>
|
||||
struct unordered_map_object
|
||||
: std::unordered_map<Key, T, std::hash<Key>, std::equal_to<Key>, Allocator>
|
||||
{
|
||||
using base_t = std::unordered_map<Key, T, std::hash<Key>, std::equal_to<Key>, Allocator>;
|
||||
using base_t::base_t;
|
||||
};
|
||||
|
||||
using unordered_json = nlohmann::basic_json<unordered_map_object>;
|
||||
```
|
||||
|
||||
Whether `#!cpp std::unordered_map` can be instantiated at all depends on the standard library: `object_t` is formed
|
||||
while `basic_json` is still incomplete (see the warning above), and libstdc++ 9 needs the size of the mapped type to
|
||||
instantiate the hash map's node type, so the adapter does not compile there. Newer libstdc++ versions, and the hash
|
||||
maps listed below, do not have that problem.
|
||||
|
||||
The adapter above works verbatim for Abseil's, Boost's, `phmap`'s and `gtl`'s hash maps, which all place the hash
|
||||
function third and take a `#!cpp std::pair<const Key, T>` allocator fifth. Two need a different adapter:
|
||||
|
||||
- `ankerl::unordered_dense` expects an allocator over `#!cpp std::pair<Key, T>` (non-const key), so the allocator has
|
||||
to be rebound to that or dropped.
|
||||
- `robin_hood`'s fifth parameter is the non-type `MaxLoadFactor100`, so its adapter must drop the allocator entirely.
|
||||
|
||||
None of these hash maps defines `key_compare`, so all of them additionally rely on `object_comparator_t` falling back
|
||||
to [`default_object_comparator_t`](../../api/basic_json/default_object_comparator_t.md); see
|
||||
[`object_comparator_t`](../../api/basic_json/object_comparator_t.md).
|
||||
|
||||
#### Abseil hash maps
|
||||
|
||||
`absl::flat_hash_map` and `absl::node_hash_map` tolerate an incomplete value type, but they take a hash function as
|
||||
their third template argument. The same adapter as for `#!cpp std::unordered_map` makes them usable:
|
||||
|
||||
```cpp
|
||||
template<class Key, class T, class IgnoredCompare, class Allocator>
|
||||
struct flat_hash_object
|
||||
: absl::flat_hash_map<Key, T, absl::Hash<Key>, std::equal_to<Key>, Allocator>
|
||||
{
|
||||
using base_t = absl::flat_hash_map<Key, T, absl::Hash<Key>, std::equal_to<Key>, Allocator>;
|
||||
using base_t::base_t;
|
||||
};
|
||||
|
||||
using flat_hash_json = nlohmann::basic_json<flat_hash_object>;
|
||||
```
|
||||
|
||||
`absl::node_hash_map` keeps references to the mapped values valid across insertions; `absl::flat_hash_map` does not,
|
||||
which makes it behave like [`ordered_json`](../../api/ordered_json.md) with respect to
|
||||
[iterator invalidation](../../api/basic_json/index.md#iterator-invalidation). Both expose a `capacity()` member
|
||||
function, so [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md) treats them conservatively and keeps the
|
||||
parent pointers correct either way.
|
||||
|
||||
#### Iteration order
|
||||
|
||||
The library never relies on the container's iteration order for correctness; it does determine the order in which
|
||||
object keys are serialized by [`dump`](../../api/basic_json/dump.md) and visited by
|
||||
[`items`](../../api/basic_json/items.md). See [Object Order](../object_order.md).
|
||||
|
||||
#### `capacity()` marks a container as insertion-ordered
|
||||
|
||||
With [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md) enabled, the library detects insertion-ordered maps by
|
||||
probing for a `capacity()` member function (`nlohmann::ordered_map` inherits it from `std::vector`) and refreshes all
|
||||
parent pointers after every insertion. An `ObjectType` that happens to have a `capacity()` member is therefore treated
|
||||
conservatively -- this is correct, but slower.
|
||||
|
||||
#### Key order and duplicate keys
|
||||
|
||||
The library does not sort or de-duplicate keys itself; the behavior described in
|
||||
[`object_t`](../../api/basic_json/object_t.md) is entirely the behavior of the chosen container.
|
||||
|
||||
### Compatible containers
|
||||
|
||||
| Container | Notes |
|
||||
|---------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
|
||||
| `#!cpp std::map` (default) | |
|
||||
| [`nlohmann::ordered_map`](../../api/ordered_map.md) | used by [`ordered_json`](../../api/ordered_json.md); keeps insertion order |
|
||||
| [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) | keeps insertion order; adapter puts `fifo_map_compare` in the comparator slot |
|
||||
| `boost::container::map`, `boost::container::flat_map` | no adapter needed |
|
||||
| `#!cpp std::unordered_map` | through the adapter above; not with libstdc++ 9, see the note |
|
||||
| `boost::unordered_map`, `boost::unordered_flat_map`, `boost::unordered_node_map` | through the adapter above |
|
||||
| `absl::flat_hash_map`, `absl::node_hash_map` | through the adapter above; `flat_hash_map` moves mapped values on rehash |
|
||||
| `phmap::flat_hash_map`, `phmap::node_hash_map`, `gtl::flat_hash_map` | through the adapter above |
|
||||
| `ankerl::unordered_dense::map` and `segmented_map` | adapter must rebind or drop the allocator |
|
||||
| `robin_hood::unordered_flat_map` | adapter must drop the allocator |
|
||||
| `folly::F14NodeMap` | through the adapter above; requires C++20, see the note above |
|
||||
| `folly::sorted_vector_map` | alias must drop the allocator, whose value type it disagrees on |
|
||||
|
||||
### Containers that cannot be used
|
||||
|
||||
| Container | Reason |
|
||||
|---------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
|
||||
| `absl::btree_map`, `phmap::btree_map`, `gtl::btree_map`, `robin_hood::unordered_node_map`, `folly::F14FastMap`, `eastl::hash_map` | require a complete mapped type |
|
||||
| `eastl::map` | EASTL iterators do not work with `#!cpp std::iterator_traits` |
|
||||
| `tsl::ordered_map` | its iterators expose the mapped value as `#!cpp const` |
|
||||
| `QMap` | no `value_type` member type |
|
||||
| `QHash` | its `value_type` is the mapped type rather than a key/value pair, and its iterators dereference to the mapped value |
|
||||
| `#!cpp std::multimap`, `#!cpp std::unordered_multimap` | `emplace` does not return `#!cpp std::pair<iterator, bool>` |
|
||||
|
||||
## `ArrayType`
|
||||
|
||||
`ArrayType` is instantiated as
|
||||
|
||||
```cpp
|
||||
using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
```
|
||||
|
||||
### Always required
|
||||
|
||||
- The template must be usable with **two** type arguments (value type and allocator).
|
||||
- Member types `value_type` and `iterator`.
|
||||
- Constructors: default, copy, and move; and from an iterator range `(first, last)`.
|
||||
- Member functions `begin()`, `end()`, `cbegin()`, `cend()`, `empty()`, `size()`, `max_size()`, `clear()`,
|
||||
`operator[](size_type)`, `back()`, `push_back()`, `emplace_back()`, `pop_back()`, `resize()`,
|
||||
`insert()` (single element, count, and range), `erase(pos)`, and `erase(first, last)`.
|
||||
`basic_json::insert(pos, initializer_list)` goes through the range overload, so no initializer-list `insert` is
|
||||
needed. `at(size_type)` is **not** required: [`basic_json::at(size_type)`](../../api/basic_json/at.md) checks the
|
||||
index itself and then uses `operator[]`.
|
||||
- `iterator` must be default-constructible, and it as well as the type returned by `cbegin()`/`cend()` must satisfy
|
||||
[LegacyRandomAccessIterator](https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator).
|
||||
A `#!cpp static_assert` only checks for
|
||||
[LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator), but
|
||||
[`dump`](../../api/basic_json/dump.md) (`cend() - 1`),
|
||||
[`erase(idx)`](../../api/basic_json/erase.md) (`begin() + idx`), and the random-access operations of
|
||||
[`basic_json::iterator`](../../api/basic_json/begin.md) require random access.
|
||||
- The comparison operators, as for [`ObjectType`](#objecttype): `==` and `<`, or `==` and `<=>` under C++20.
|
||||
|
||||
### Required for individual functions
|
||||
|
||||
- A member type `value_type`, for [`to_bson`](../../api/basic_json/to_bson.md) of an array.
|
||||
- A constructor from `(count, value)`, for
|
||||
[`basic_json(size_type, const basic_json&)`](../../api/basic_json/basic_json.md).
|
||||
- Swappability, via `#!cpp std::swap` or an ADL `swap`, for [`swap(array_t&)`](../../api/basic_json/swap.md).
|
||||
|
||||
!!! note "`capacity()` is optional"
|
||||
|
||||
With [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md) enabled, the library reads `array_t::capacity()`
|
||||
to find out whether adding an element reallocated the array and moved its elements, which would invalidate the
|
||||
parent pointers. An array type without a `capacity()` member function is handled conservatively: the parent
|
||||
pointers of all elements are refreshed after every insertion, which makes adding *n* elements cost O(*n*²). Only
|
||||
diagnostics builds pay this; without them `capacity()` is never called.
|
||||
|
||||
### Compatible containers
|
||||
|
||||
| Container | Notes |
|
||||
|-------------------------------------------------------------------------------------------|----------------------------------------------------------|
|
||||
| `#!cpp std::vector` (default) | |
|
||||
| `#!cpp std::deque` | references survive appends, but not insertions elsewhere; see the `capacity()` note above |
|
||||
| `#!cpp std::pmr::vector` | through an alias, as the allocator comes from `AllocatorType` instead |
|
||||
| `boost::container::vector`, `deque`, `devector` | |
|
||||
| `boost::container::stable_vector` | the only one tried that keeps references valid across *every* insertion |
|
||||
| `boost::container::small_vector`, `folly::small_vector` | through an alias that fixes the inline capacity |
|
||||
| `boost::container::static_vector` | through the same kind of alias, for arrays that stay within the fixed capacity |
|
||||
| `folly::fbvector` | requires C++20, see the note above |
|
||||
|
||||
### Containers that cannot be used
|
||||
|
||||
| Container | Reason |
|
||||
|----------------------------------|----------------------------------------------------------------------------------------------|
|
||||
| `#!cpp std::list` | no `operator[]`, and no random-access iterators |
|
||||
| `eastl::vector`, `QList`, `QVector` | no `max_size()`; they handle the incomplete value type fine |
|
||||
| `absl::InlinedVector` | requires a complete value type, see the note above |
|
||||
| `absl::FixedArray` | the size is fixed at construction, so `resize`, `push_back`, `insert` and `erase` are missing |
|
||||
|
||||
## `StringType`
|
||||
|
||||
`StringType` is used **both** for JSON string values and for the keys of JSON objects
|
||||
(`string_t` and `object_t::key_type`).
|
||||
|
||||
### Always required
|
||||
|
||||
- A member type `value_type` that is one byte wide and `char`-compatible. The library stores and processes UTF-8
|
||||
encoded `char` data and hands `data()` to `#!cpp std::strtoull`/`#!cpp std::strtoll`.
|
||||
`#!cpp std::wstring`, `#!cpp std::u16string`, and `#!cpp std::u32string` are **not** valid choices; see the FAQ on
|
||||
[wide string handling](../../home/faq.md#wide-string-handling).
|
||||
- Constructors: default, copy, move, from `#!cpp const char*` (which must not be `#!cpp explicit`), from
|
||||
`#!cpp (const char*, size_type)`, and from `#!cpp (size_type, char)`; and copy or move assignment.
|
||||
- Member functions `size()`, `clear()`, `resize(n, c)`, `data()`, `push_back(char)`, and `operator[]`
|
||||
(const and non-const, returning references). `c_str()` and `back()` are **not** required.
|
||||
- `data()` must return a pointer to a contiguous, **null-terminated** buffer -- the parser hands it to
|
||||
`#!cpp std::strtoull`. A type whose `data()` is not null-terminated does not fail to compile; it silently
|
||||
misparses numbers.
|
||||
- `append(const char*, size_type)`, used by [`dump`](../../api/basic_json/dump.md), and `append(const StringType&)`,
|
||||
used by the CBOR reader for indefinite-length strings. The library's internal string concatenation additionally has
|
||||
to append a `#!cpp char` and a `#!cpp const char*`; for each it selects between `append(arg)`, `#!cpp operator+=`,
|
||||
`append(first, last)`, and `append(data, size)`.
|
||||
- The comparison operator `==` against another `StringType`, and `<` for use as a key of the chosen
|
||||
[`ObjectType`](#objecttype) (with the default comparator, `#!cpp std::less<>` must be able to compare two
|
||||
`StringType` values, and a `StringType` with the key types used for lookup). `!=` is never applied to a
|
||||
`StringType`, and `==` against `#!cpp const char*` is resolved by the implicit `#!cpp const char*` constructor.
|
||||
|
||||
### Required for the binary formats
|
||||
|
||||
- `resize(n)`, used by the readers to make room for a block of bytes.
|
||||
- Non-const `operator[]`, into which the readers `#!cpp std::memcpy` those bytes.
|
||||
|
||||
### Required for JSON Pointer, `flatten`, and `diff`
|
||||
|
||||
- A static member `npos` and the member function `find_first_of(char, size_type)` -- together with `data()`,
|
||||
`reserve(n)`, and `append(const char*, size_type)` they implement the escaping and unescaping of reference tokens
|
||||
described in RFC 6901. Neither `find(const StringType&, size_type)`, nor `substr(pos, count)`, nor
|
||||
`replace(pos, count, const StringType&)` is required.
|
||||
- `empty()`.
|
||||
- `begin()` and `end()` -- used by
|
||||
[`operator[](const json_pointer&)`](../../api/basic_json/operator%5B%5D.md) to decide whether a reference token
|
||||
denotes an array index.
|
||||
|
||||
### Required for other functionality
|
||||
|
||||
| Functionality | Additional requirement |
|
||||
|--------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
|
||||
| [`diff`](../../api/basic_json/diff.md), [`items`](../../api/basic_json/items.md), [`std::hash`](../../api/basic_json/std_hash.md) | conversion of a `#!cpp std::size_t` to `StringType`: either assignability from the result of `#!cpp std::to_string`, or an ADL overload `#!cpp void int_to_string(StringType&, std::size_t)` |
|
||||
| [`std::hash<basic_json>`](../../api/basic_json/std_hash.md) | additionally a specialization of `#!cpp std::hash<StringType>` |
|
||||
| [`to_bson`](../../api/basic_json/to_bson.md) | `find(value_type)` and `npos` |
|
||||
| [`parse`](../../api/basic_json/parse.md) from a `string_t` | the input adapters must accept it; otherwise pass a character range |
|
||||
| `#!cpp operator<<(std::ostream&, const json_pointer&)` | streamability to `#!cpp std::ostream` |
|
||||
| exception messages | `data()` and `size()`, or `begin()` and `end()` |
|
||||
|
||||
### Compatible types
|
||||
|
||||
| Type | Notes |
|
||||
|-------------------------------------------------------------------|---------------------------------------------------------------------------|
|
||||
| `#!cpp std::string` (default) | |
|
||||
| `#!cpp std::basic_string` with a custom **stateless** allocator | |
|
||||
| `#!cpp std::pmr::string` | see the warning below before relying on the memory resource |
|
||||
| `boost::container::string` | needs a user-supplied `#!cpp std::hash` specialization (Boost provides `boost::hash` instead) |
|
||||
| `folly::fbstring` | requires C++20, see the note above |
|
||||
| `eastl::string` | needs a user-supplied `#!cpp std::hash` and an ADL `int_to_string` (it is not assignable from a `#!cpp std::string`); [`parse`](../../api/basic_json/parse.md) does not accept it directly -- pass a character range or a `#!cpp std::string` |
|
||||
| a custom string class in a user-defined namespace | if the requirements above are met |
|
||||
|
||||
### Types that cannot be used
|
||||
|
||||
| Type | Reason |
|
||||
|-----------------------------------------------------------------------|-----------------------------------------------------------------------|
|
||||
| `#!cpp std::wstring`, `#!cpp std::u16string`, `#!cpp std::u32string` | the character type is not one byte wide |
|
||||
| `#!cpp std::u8string` | one byte wide, but `#!cpp char8_t` is not `#!cpp char`-compatible |
|
||||
| `absl::Cord` | no `value_type`, and the storage is not contiguous |
|
||||
| `QString` | no `append(const char*, size_type)`; its `QChar` is also two bytes wide, though that is never diagnosed |
|
||||
|
||||
!!! warning "A `std::pmr::string` mostly does not use the memory resource you choose"
|
||||
|
||||
`basic_json` cannot be given an allocator or a memory resource. `AllocatorType` is default-constructed at every
|
||||
allocation and has to be stateless (see [`AllocatorType`](#allocatortype)), and string values the library creates
|
||||
are constructed with their own default allocator. So:
|
||||
|
||||
- Every string the library itself produces -- from [`parse`](../../api/basic_json/parse.md), from
|
||||
[`dump`](../../api/basic_json/dump.md), or by default construction -- allocates from
|
||||
`#!cpp std::pmr::get_default_resource()`.
|
||||
- **Copying** an arena-backed string into a value silently drops its memory resource: the copy lands on the
|
||||
default resource, because `#!cpp std::pmr::polymorphic_allocator` does not propagate on copy construction.
|
||||
Nothing warns about this.
|
||||
- **Moving** one in does keep it, and later growth still allocates from that arena -- but it does not survive a
|
||||
copy of the enclosing `basic_json`.
|
||||
- Passing `#!cpp std::pmr::polymorphic_allocator` as `AllocatorType` does not work around any of this; it does
|
||||
not compile.
|
||||
|
||||
Apart from moving a string in, the only way to redirect these allocations is the process-global
|
||||
`#!cpp std::pmr::set_default_resource()`.
|
||||
|
||||
!!! tip "Reference implementation"
|
||||
|
||||
The unit test `tests/src/unit-alt-string.cpp` contains `alt_string`, a minimal string type that satisfies the
|
||||
requirements needed for the tested subset of the API. It is a good starting point for a custom `StringType`.
|
||||
|
||||
## `BooleanType`
|
||||
|
||||
`boolean_t` is stored **directly** inside `basic_json`, as a member of an anonymous union.
|
||||
|
||||
### Always required
|
||||
|
||||
- A literal type that is trivially default-constructible, trivially copyable, and trivially destructible; otherwise the
|
||||
union's special member functions are deleted.
|
||||
- **Implicitly** convertible from `#!cpp bool` -- an `#!cpp explicit` constructor is not enough, because the
|
||||
`to_json` overload for a custom `BooleanType` is constrained on `#!cpp std::is_convertible` -- and contextually
|
||||
convertible to `#!cpp bool` (here an `#!cpp explicit operator bool` is fine).
|
||||
- Comparison operators `==`, `!=`, `<`, `<=`, `>`, `>=` (or `<=>`).
|
||||
- Convertible from and to `#!cpp bool` through the serializer, because
|
||||
[`get<bool>()`](../../api/basic_json/get.md) is used internally.
|
||||
|
||||
There is little reason to use anything other than `#!cpp bool` here.
|
||||
|
||||
### Compatible types
|
||||
|
||||
`#!cpp bool` is the only usable choice. Another trivially copyable type that is implicitly convertible to and from
|
||||
`#!cpp bool` -- `#!cpp std::uint8_t`, say -- does compile, and JSON booleans still round-trip, but the type then
|
||||
serves as both `boolean_t` and an ordinary integer: `basic_json` can no longer be constructed or assigned from a
|
||||
`#!cpp std::uint8_t` at all (the boolean and unsigned-integer `to_json` overloads become ambiguous), and
|
||||
[`get<std::uint8_t>()`](../../api/basic_json/get.md) on a number throws
|
||||
[`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) instead of returning the value.
|
||||
|
||||
## `NumberIntegerType` and `NumberUnsignedType`
|
||||
|
||||
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. 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.
|
||||
- `NumberUnsignedType` must be able to represent the absolute value of every `NumberIntegerType` value; serialization
|
||||
of negative numbers converts the value to `NumberUnsignedType`.
|
||||
- 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.
|
||||
|
||||
### Notes
|
||||
|
||||
The number types influence what the parser accepts: an integer literal that does not round-trip through the chosen type
|
||||
is stored as [`number_float_t`](../../api/basic_json/number_float_t.md) instead. Choosing types narrower than 64 bits
|
||||
therefore silently changes parse results rather than raising an error. See
|
||||
[Number Handling](number_handling.md) for details.
|
||||
|
||||
### Compatible types
|
||||
|
||||
| Type pair | Support |
|
||||
|----------------------------------------------------------------------------------------------|---------------------------------------------------------------------|
|
||||
| `#!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 |
|
||||
| class types, enumerations | not usable; `#!cpp std::is_integral` must hold |
|
||||
| `#!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`
|
||||
|
||||
`number_float_t` is stored **directly** inside `basic_json`'s union.
|
||||
|
||||
### Always required
|
||||
|
||||
- Trivially default-constructible, trivially copyable, and trivially destructible (union member).
|
||||
- `#!cpp std::numeric_limits` must be specialized; `max_digits10` is used to size the conversion.
|
||||
- `#!cpp std::isfinite` must be applicable to the type.
|
||||
|
||||
### Required for parsing and serialization
|
||||
|
||||
`NumberFloatType` must be one of `#!cpp float`, `#!cpp double`, or `#!cpp long double`:
|
||||
|
||||
- The [parser](../parsing/index.md) converts number literals with `#!cpp std::strtof`, `#!cpp std::strtod`, or
|
||||
`#!cpp std::strtold`; the library provides overloads for exactly these three types.
|
||||
- [`dump`](../../api/basic_json/dump.md) falls back to `#!cpp std::snprintf` with the `%g` and `%Lg` conversion
|
||||
specifiers, for which the library likewise provides only `#!cpp double` and `#!cpp long double` overloads
|
||||
(`#!cpp float` is promoted to `#!cpp double`).
|
||||
|
||||
If `#!cpp std::numeric_limits<NumberFloatType>` describes an IEEE 754 binary32 or binary64 number, `dump` uses the
|
||||
Grisu2 algorithm, which produces the shortest representation that round-trips. Otherwise the `snprintf` fallback with
|
||||
`max_digits10` digits is used.
|
||||
|
||||
### Required for the binary formats
|
||||
|
||||
`NumberFloatType` must be `#!cpp float` or `#!cpp double`. The writers for
|
||||
[CBOR, MessagePack, UBJSON, BJData, and BSON](../binary_formats/index.md) map a floating-point value onto an IEEE 754
|
||||
binary32 or binary64 field and have no encoding for `#!cpp long double`.
|
||||
|
||||
### Compatible types
|
||||
|
||||
| Type | Support |
|
||||
|-----------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| `#!cpp double` (default) | full; short round-trip output through Grisu2 |
|
||||
| `#!cpp float` | full; short round-trip output through Grisu2 |
|
||||
| `#!cpp long double` | `dump` and `parse` only; the binary format writers do not compile, as they only handle IEEE 754 binary32 and binary64 |
|
||||
| any other type | not usable |
|
||||
|
||||
## `AllocatorType`
|
||||
|
||||
`AllocatorType` is instantiated with **one** argument, for each of `object_t`, `array_t`, `string_t`, `binary_t`,
|
||||
`basic_json`, and `#!cpp std::pair<const StringType, basic_json>`.
|
||||
|
||||
### Always required
|
||||
|
||||
- The template must be usable with exactly one type argument. The library instantiates `AllocatorType<T>` directly and
|
||||
never uses `#!cpp std::allocator_traits<...>::rebind_alloc`.
|
||||
- It must satisfy the [Allocator](https://en.cppreference.com/w/cpp/named_req/Allocator) named requirement so that
|
||||
`#!cpp std::allocator_traits` can be used with it.
|
||||
- It must be **default-constructible and stateless**. Objects are allocated with a default-constructed allocator and
|
||||
deallocated with a *different* default-constructed allocator, and
|
||||
[`get_allocator()`](../../api/basic_json/get_allocator.md) returns a default-constructed instance. Allocators
|
||||
carrying state are not supported, so there is no way to tell a `basic_json` where to allocate from; see the note
|
||||
under [`StringType`](#stringtype) for what that means in practice. A stateful allocator is **not diagnosed**: it
|
||||
compiles and silently ignores the state.
|
||||
- It must support **incomplete types**: `AllocatorType<basic_json>` is instantiated inside the definition of
|
||||
`basic_json` itself.
|
||||
- `#!cpp std::allocator_traits<AllocatorType<basic_json>>::pointer` becomes
|
||||
[`basic_json::pointer`](../../api/basic_json/index.md#container-types), and iterators are constructed from raw
|
||||
`#!cpp basic_json*` values. The `pointer` type must therefore be a plain pointer; fancy pointers are not supported.
|
||||
|
||||
### Compatible types
|
||||
|
||||
| Type | Support |
|
||||
|-----------------------------------------------------------------|----------------------------------------------------|
|
||||
| `#!cpp std::allocator` (default) | full |
|
||||
| a custom stateless allocator template | full |
|
||||
| stateful allocators, e.g. `#!cpp std::pmr::polymorphic_allocator`| not usable; see the requirements above |
|
||||
|
||||
## `JSONSerializer`
|
||||
|
||||
`JSONSerializer` is instantiated as `JSONSerializer<T, void>` and defaults to
|
||||
[`adl_serializer`](../../api/adl_serializer/index.md).
|
||||
|
||||
### Always required
|
||||
|
||||
- The template must accept **two** type arguments. It does not have to give the second one a default -- `basic_json`
|
||||
declares the parameter as `#!cpp template<typename T, typename SFINAE = void> class JSONSerializer`, so uses such as
|
||||
`#!cpp JSONSerializer<T>` inside the library supply `#!cpp void` themselves. The second parameter exists so that
|
||||
partial specializations can be constrained by SFINAE.
|
||||
- For every type `T` that is converted **to** a JSON value, a static member function
|
||||
`#!cpp static void to_json(basic_json&, T)` must exist.
|
||||
- For every type `T` that is converted **from** a JSON value, either
|
||||
`#!cpp static void from_json(const basic_json&, T&)` or `#!cpp static T from_json(const basic_json&)` must exist.
|
||||
The latter form is required for types that are not default-constructible; see
|
||||
[Arbitrary Types Conversions](../arbitrary_types.md).
|
||||
- To support the [converting constructor](../../api/basic_json/basic_json.md) between different `basic_json`
|
||||
specializations, `to_json` must be available for `boolean_t`, `number_integer_t`, `number_unsigned_t`,
|
||||
`number_float_t`, `string_t`, `object_t`, `array_t`, and `binary_t` of the *source* specialization.
|
||||
|
||||
### Compatible types
|
||||
|
||||
| Type | Support |
|
||||
|-------------------------------------------------------------------|-------------------------------------------------------------------------|
|
||||
| [`nlohmann::adl_serializer`](../../api/adl_serializer/index.md) (default) | full |
|
||||
| a class template deriving from `adl_serializer` | full; the usual way to change behavior while keeping the defaults |
|
||||
| an unrelated template with the same interface | full, but it has to handle every type the library converts |
|
||||
|
||||
## `BinaryType`
|
||||
|
||||
`BinaryType` is not a JSON type; it is used for the byte strings of the
|
||||
[binary formats](../binary_formats/index.md). It is wrapped as
|
||||
|
||||
```cpp
|
||||
using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
|
||||
```
|
||||
|
||||
### Always required
|
||||
|
||||
- A non-`final` class type -- [`byte_container_with_subtype`](../../api/byte_container_with_subtype/index.md) derives
|
||||
from it publicly.
|
||||
- A member type `value_type` that is **exactly one byte** wide (e.g., `#!cpp std::uint8_t`, `#!cpp char`, or
|
||||
`#!cpp std::byte`). Readers and writers reinterpret the container's storage as raw bytes. A wider `value_type` is
|
||||
**not diagnosed**: it compiles and silently produces wrong results.
|
||||
- Contiguous storage: the binary readers `#!cpp std::memcpy` into `#!cpp &binary[n]`, the writers `reinterpret_cast`
|
||||
`data()`.
|
||||
- Default-constructible, copy-constructible, and move-constructible.
|
||||
- Member functions `size()`, `empty()`, `data()`, `resize()`, `operator[]`, `back()`, `begin()`, `end()`, `cbegin()`,
|
||||
and `cend()` with random-access iterators, and `insert(pos, first, last)`, which the CBOR reader uses to join the
|
||||
chunks of an indefinite-length byte string. `push_back()` is **not** required.
|
||||
- Comparison operators: `==` is used by
|
||||
[`byte_container_with_subtype`](../../api/byte_container_with_subtype/index.md), the relational operators by
|
||||
[`basic_json`'s comparison operators](../../api/basic_json/operator_le.md).
|
||||
|
||||
### Required for individual functions
|
||||
|
||||
- `clear()`, for [`basic_json::clear()`](../../api/basic_json/clear.md).
|
||||
|
||||
`max_size()`, `at()`, `reserve()`, `erase()`, `pop_back()`, and `emplace_back()` are **not** used at all.
|
||||
|
||||
See [`binary_t`](../../api/basic_json/binary_t.md) for how a non-default `BinaryType` changes the meaning of assigning
|
||||
such a container to a `basic_json` value.
|
||||
|
||||
### Compatible containers
|
||||
|
||||
| Container | Notes |
|
||||
|------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
|
||||
| `#!cpp std::vector<std::uint8_t>` (default) | |
|
||||
| `#!cpp std::vector<char>`, `#!cpp std::vector<std::byte>` | `dump()` writes the bytes as 0..255 whichever is used |
|
||||
| `boost::container::vector<std::uint8_t>`, `boost::container::small_vector<std::uint8_t, N>` | |
|
||||
| `absl::InlinedVector<std::uint8_t, N>` | usable here, unlike as an `ArrayType`, because the value type is complete |
|
||||
| `eastl::vector<std::uint8_t>` | usable here, unlike as an `ArrayType`, because `max_size()` is not needed |
|
||||
| `folly::fbvector<std::uint8_t>` | requires C++20, see the note above |
|
||||
|
||||
### Containers that cannot be used
|
||||
|
||||
| Container | Reason |
|
||||
|--------------------------------------------------------|-----------------------------------------------------------------------------------------|
|
||||
| `QByteArray` | no `empty()` (it spells that `isEmpty()`); its `insert` takes an index rather than an iterator; and it converts to `string_t`, which makes `to_json` ambiguous between a string and a binary value |
|
||||
| `#!cpp std::string` | `binary_t::container_type` and `string_t` would be the same type, so the two [`swap`](../../api/basic_json/swap.md) overloads collide and `basic_json` cannot be instantiated at all |
|
||||
| `#!cpp std::deque<std::uint8_t>` | storage is not contiguous, so there is no `data()` |
|
||||
| containers whose `value_type` is wider than one byte | see above -- accepted by the compiler, wrong at runtime |
|
||||
|
||||
## `CustomBaseClass`
|
||||
|
||||
`CustomBaseClass` is an extension point: unless it is `#!cpp void` (the default, which selects the empty
|
||||
`nlohmann::json_default_base`), `basic_json` publicly derives from it.
|
||||
|
||||
### Always required
|
||||
|
||||
- A non-`final`, default-constructible class type.
|
||||
- `basic_json` is copy-/move-constructible and copy-/move-assignable only if `CustomBaseClass` is.
|
||||
|
||||
### Notes
|
||||
|
||||
`basic_json` is documented to be a
|
||||
[StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType). Because `basic_json` has
|
||||
non-static data members of its own, a `CustomBaseClass` with non-static data members forfeits this guarantee.
|
||||
|
||||
Note the namespace of `CustomBaseClass` becomes an associated namespace of `basic_json` for the purpose of
|
||||
argument-dependent lookup.
|
||||
|
||||
See [`json_base_class_t`](../../api/basic_json/json_base_class_t.md) for an example.
|
||||
|
||||
### Compatible types
|
||||
|
||||
| Type | Support |
|
||||
|----------------------------------------------------------|--------------------------------------------------------------|
|
||||
| `#!cpp void` (default) | an empty base class is used; no effect on `basic_json` |
|
||||
| any default-constructible, non-`final` class | full; see [`json_base_class_t`](../../api/basic_json/json_base_class_t.md) |
|
||||
|
||||
## Cross-specialization conversions
|
||||
|
||||
Converting a value from one `basic_json` specialization into another (see the
|
||||
[converting constructor](../../api/basic_json/basic_json.md)) imposes two additional requirements that are not
|
||||
diagnosed at compile time. With assertions enabled they abort on the `#!cpp JSON_ASSERT` at the end of the converting
|
||||
constructor; under `#!cpp NDEBUG` they fail **silently** at runtime:
|
||||
|
||||
- The target `string_t` must be directly constructible from the source `string_t`. Otherwise the string is converted to
|
||||
an array of character codes.
|
||||
- The target `object_t::key_type` must be directly constructible from the source object's key type. Otherwise the
|
||||
object is converted to an array of key/value pairs.
|
||||
|
||||
See [issue #3425](https://github.com/nlohmann/json/issues/3425), [`string_t`](../../api/basic_json/string_t.md), and
|
||||
[`object_t`](../../api/basic_json/object_t.md).
|
||||
|
||||
## See also
|
||||
|
||||
- [Types](index.md) -- overview of how JSON values are stored
|
||||
- [Number Handling](number_handling.md) -- how the number types affect parsing and serialization
|
||||
- [Object Order](../object_order.md) -- using an insertion-ordered `ObjectType`
|
||||
- [`basic_json`](../../api/basic_json/index.md) -- API documentation of the class template
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user