mirror of
https://github.com/nlohmann/json.git
synced 2026-09-06 16:27:59 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db1d0983e6 |
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -67,18 +67,8 @@ 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 $SOURCE_DIRS -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort)
|
||||
$(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)
|
||||
|
||||
- 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@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -38,14 +38,14 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
||||
uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
||||
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@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
||||
uses: github/codeql-action/autobuild@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
||||
uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -43,6 +43,6 @@ jobs:
|
||||
output: 'flawfinder_results.sarif'
|
||||
|
||||
- name: Upload analysis results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
||||
uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
||||
with:
|
||||
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ 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
|
||||
@@ -26,7 +27,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -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@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
||||
uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
|
||||
# Upload SARIF file generated in previous step
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
||||
uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
||||
with:
|
||||
sarif_file: semgrep.sarif
|
||||
if: always()
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -60,7 +60,7 @@ 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@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -184,7 +184,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: CXX=g++-${{ matrix.compiler }} cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -202,7 +202,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -212,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', '21', '22', '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', 'latest']
|
||||
container: silkeh/clang:${{ matrix.compiler }}
|
||||
steps:
|
||||
- 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
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- 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' }}
|
||||
@@ -239,7 +239,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -259,7 +259,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build with libc++
|
||||
@@ -286,7 +286,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -306,7 +306,7 @@ jobs:
|
||||
# import-std support. Its opt-in token is CMake-version-specific, so pin
|
||||
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
|
||||
- name: Get pinned CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
with:
|
||||
cmakeVersion: 4.3.4
|
||||
# Clang: the std library module is provided by libc++ (the image's libstdc++
|
||||
@@ -332,7 +332,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -347,7 +347,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -359,7 +359,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
@@ -369,7 +369,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -379,7 +379,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -GNinja
|
||||
- name: Build
|
||||
@@ -392,7 +392,7 @@ jobs:
|
||||
target: [ci_test_examples, ci_test_build_documentation]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
- 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)
|
||||
@@ -153,16 +153,10 @@ 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 ^
|
||||
@@ -199,7 +193,7 @@ jobs:
|
||||
# import-std support. Its opt-in token is CMake-version-specific, so pin
|
||||
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
|
||||
- name: Get pinned CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
||||
with:
|
||||
cmakeVersion: 4.3.4
|
||||
- name: Run CMake (Debug)
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
- [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)
|
||||
@@ -1187,11 +1186,6 @@ 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:
|
||||
|
||||
+1
-1
@@ -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/mkdocs/docs/examples/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/docs/examples/*.cpp
|
||||
)
|
||||
|
||||
set(include_dir ${PROJECT_SOURCE_DIR}/single_include/nlohmann)
|
||||
|
||||
@@ -128,10 +128,13 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
|
||||
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).
|
||||
pointer token is a valid array index: a token that is a nonempty sequence of digits without a leading
|
||||
`0` (or the token `-`) creates an array, and every other 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. Tokens such as `01` or the empty token cannot be array indices (cf. RFC 6901, Sect. 4)
|
||||
and therefore create objects, just as they would if the level already existed as an object. 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
|
||||
|
||||
|
||||
@@ -52,11 +52,6 @@ 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`.
|
||||
|
||||
@@ -46,9 +46,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
|
||||
## Complexity
|
||||
|
||||
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.
|
||||
Linear in the size of the JSON value `j`.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -45,11 +45,6 @@ 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`.
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
# 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,6 +1,5 @@
|
||||
# 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
|
||||
|
||||
@@ -66,7 +66,6 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa
|
||||
| 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 |
|
||||
|
||||
@@ -9,13 +9,13 @@ int main()
|
||||
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*/)
|
||||
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*/)
|
||||
json j_array_end = json::parse(text, [](int /*depth*/, json::parse_event_t event, json & /*parsed*/)
|
||||
{
|
||||
return event != json::parse_event_t::array_end;
|
||||
});
|
||||
@@ -33,7 +33,7 @@ int main()
|
||||
});
|
||||
|
||||
// discard the top-level object
|
||||
json j_root = json::parse(text, [](int /*depth*/, json::parse_event_t event, json& /*parsed*/)
|
||||
json j_root = json::parse(text, [](int /*depth*/, json::parse_event_t event, json & /*parsed*/)
|
||||
{
|
||||
return event != json::parse_event_t::object_end;
|
||||
});
|
||||
|
||||
@@ -116,20 +116,9 @@ 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. 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`,
|
||||
- `"_ArraySize_"` is an array, since the dimensions are written as the ND-array header's length,
|
||||
- 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).
|
||||
[`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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -98,17 +98,6 @@ The library maps BSON record types to JSON value types as follows:
|
||||
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
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -160,11 +160,14 @@ 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
|
||||
@@ -178,7 +181,7 @@ The library maps CBOR types to JSON value types as follows:
|
||||
|
||||
!!! warning "Tagged items"
|
||||
|
||||
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.
|
||||
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`.
|
||||
|
||||
??? example
|
||||
|
||||
|
||||
@@ -54,30 +54,6 @@ 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`
|
||||
|
||||
@@ -8,72 +8,41 @@ the result of an internet search. If you know further customers of the library,
|
||||
## Space Exploration
|
||||
|
||||
- [**Peregrine Lunar Lander Flight 01**](https://en.wikipedia.org/wiki/Peregrine_Mission_One) - The library was used for payload management in the **Peregrine Moon Lander**, developed by **Astrobotic Technology** and launched as part of NASA's **Commercial Lunar Payload Services (CLPS)** program. After six days in orbit, the spacecraft was intentionally redirected into Earth's atmosphere, where it burned up over the Pacific Ocean on **January 18, 2024**.
|
||||
- [**NASA Unsteady Pressure-Sensitive Paint Processing**](https://github.com/nasa/upsp-processing), NASA software for processing high-speed video recordings of wind tunnel tests on launch vehicle and aircraft models
|
||||
- [**Terma TEMU**](https://temu.terma.com/docs/public/temu-release-notes/latest/copying/json-for-modern-cpp.html), an emulator of spacecraft on-board computers used to develop and validate flight software for European space missions
|
||||
|
||||
## Automotive
|
||||
|
||||
- [**Alexa Auto SDK**](https://github.com/alexa/alexa-auto-sdk), a software development kit enabling the integration of Alexa into automotive systems
|
||||
- [**Apollo**](https://github.com/ApolloAuto/apollo), a framework for building autonomous driving systems
|
||||
- [**Automotive Grade Linux (AGL)**](https://download.automotivelinux.org/AGL/release/jellyfish/latest/qemux86-64/deploy/licenses/nlohmann-json/), a collaborative open-source platform for automotive software development
|
||||
- [**Autoware**](https://github.com/autowarefoundation/autoware_universe), an open-source software stack for autonomous driving built on ROS 2
|
||||
- [**Eclipse S-CORE**](https://github.com/eclipse-score/nlohmann_json), an open-source software platform for the software-defined vehicle backed by major automotive manufacturers and suppliers
|
||||
- [**Genesis Motor** (infotainment)](http://webmanual.genesis.com/ccIC/AVNT/JW/KOR/English/reference010.html), a luxury automotive brand
|
||||
- [**Hyundai** (infotainment)](https://www.hyundai.com/wsvc/ww/download.file.do?id=/content/hyundai/ww/data/opensource/data/GN7-2022/licenseCode/info), a global automotive brand
|
||||
- [**Kia** (infotainment)](http://webmanual.kia.com/PREM_GEN6/AVNT/RJPE/KOR/Korean/reference010.html), a global automotive brand
|
||||
- [**Mercedes-Benz Operating System (MB.OS)**](https://group.mercedes-benz.com/careers/about-us/mercedes-benz-operating-system/), a core component of the vehicle software ecosystem from Mercedes-Benz
|
||||
- [**NVIDIA DRIVE OS**](https://developer.nvidia.com/docs/drive/drive-os/6.0.5/public/driveworks-nvcgf/dwx_open_source_attribution.html), the operating system and DriveWorks SDK powering NVIDIA's platform for autonomous vehicles
|
||||
- [**Rivian** (infotainment)](https://assets.ctfassets.net/2md5qhoeajym/3cwyo4eoufk4yingUwusFt/ded2c47da620fdfc99c88c7156d2c1d8/In-Vehicle_OSS_Attribution_2024__11-24_.pdf), an electric vehicle manufacturer
|
||||
- [**Suzuki** (infotainment)](https://www.globalsuzuki.com/motorcycle/ipc/oss/oss_48KA_00.pdf), a global automotive and motorcycle manufacturer
|
||||
|
||||
## Gaming and Entertainment
|
||||
|
||||
- [**Anno 117: Pax Romana**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a city-building strategy game set in the Roman Empire
|
||||
- [**Assassin's Creed: Mirage**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a stealth-action game set in the Middle East, focusing on the journey of a young assassin with classic parkour and stealth mechanics
|
||||
- [**Battlefield 6**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a military first-person shooter known for its large-scale multiplayer battles
|
||||
- [**Battlefield: REDSEC**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a free-to-play battle royale experience set in the Battlefield universe
|
||||
- [**BioMenace: Remastered**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a remaster of the classic side-scrolling platform shooter
|
||||
- [**Chasm: The Rift**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a first-person shooter blending horror and adventure, where players navigate dark realms and battle monsters
|
||||
- [**College Football 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a college football simulation game featuring gameplay that mimics real-life college teams and competitions
|
||||
- [**College Football 26**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a college football simulation game featuring licensed teams and stadiums
|
||||
- [**College Football 27**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), the latest installment of the college football simulation series
|
||||
- [**Concepts**](https://concepts.app/en/licenses), a digital sketching app designed for creative professionals, offering flexible drawing tools for illustration, design, and brainstorming
|
||||
- [**Depthkit**](https://www.depthkit.tv/third-party-licenses), a tool for creating and capturing volumetric video, enabling immersive 3D experiences and interactive content
|
||||
- [**Dune: Awakening**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an open-world survival MMO set on the desert planet Arrakis
|
||||
- [**EA Sports FC 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an association football simulation with club, career, and online modes
|
||||
- [**EA Sports FC 26**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), the latest installment of the association football simulation series
|
||||
- [**EA Sports UFC 6**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a mixed martial arts fighting simulation
|
||||
- [**FiveM**](https://github.com/citizenfx/fivem), a modification framework for Grand Theft Auto V that powers custom multiplayer servers
|
||||
- [**FLUX:: Immersive**](https://doc.flux.audio/syrah/Credits.html), a suite of professional audio processing and immersive mixing plugins used in music and post-production
|
||||
- [**IMG.LY**](https://img.ly/acknowledgements), a platform offering creative tools and SDKs for integrating advanced image and video editing in applications
|
||||
- [**immersivetech**](https://immersitech.io/open-source-third-party-software/), a technology company focused on immersive experiences, providing tools and solutions for virtual and augmented reality applications
|
||||
- [**Kodi**](https://github.com/xbmc/xbmc/blob/master/xbmc/utils/JSONVariantWriter.cpp), a home theater and media center application
|
||||
- [**LOOT**](https://loot.readthedocs.io/_/downloads/en/0.13.0/pdf/), a tool for optimizing the load order of game plugins, commonly used in The Elder Scrolls and Fallout series
|
||||
- [**LunaTranslator**](https://github.com/HIllya51/LunaTranslator/blob/main/src/NativeImpl/LunaSubprocess/aspatch.cpp), a real-time translation tool for visual novels
|
||||
- [**MaaAssistantArknights**](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/dev-v2/src/MaaCore/Vision/Roguelike/BlackFlow/BlackFlowMapAnalyzer.cpp), an automation assistant for the mobile game Arknights
|
||||
- [**Madden NFL 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a sports simulation game capturing the excitement of American football with realistic gameplay and team management features
|
||||
- [**Madden NFL 26**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an American football simulation with franchise and team management modes
|
||||
- [**Madden NFL 27**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), the latest installment of the American football simulation series
|
||||
- [**Marne**](https://marne.io/licenses), an unofficial private server platform for hosting custom Battlefield 1 game experiences
|
||||
- [**Minecraft**](https://www.minecraft.net/zh-hant/attribution), a popular sandbox video game
|
||||
- [**Mumble**](https://github.com/mumble-voip/mumble), a low-latency, open-source voice chat application widely used by gaming communities
|
||||
- [**NHL 22**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a hockey simulation game offering realistic gameplay, team management, and various modes to enhance the hockey experience
|
||||
- [**OBS Studio**](https://github.com/obsproject/obs-studio), a free and open-source suite for video recording and live streaming
|
||||
- [**OpenRCT2**](https://github.com/OpenRCT2/OpenRCT2/blob/develop/src/openrct2/core/JsonFwd.hpp), an open source re-implementation of RollerCoaster Tycoon 2
|
||||
- [**Pixelpart**](https://pixelpart.net/documentation/book/third-party.html), a 2D animation and video compositing software that allows users to create animated graphics and visual effects with a focus on simplicity and ease of use
|
||||
- [**Razer Cortex**](https://mysupport.razer.com/app/answers/detail/a_id/14146/~/open-source-software-for-razer-software), a gaming performance optimizer and system booster designed to enhance the gaming experience
|
||||
- [**Red Dead Redemption II**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an open-world action-adventure game following an outlaw's story in the late 1800s, emphasizing deep storytelling and immersive gameplay
|
||||
- [**RetroArch**](https://github.com/libretro/RetroArch), a frontend for emulators, game engines, and media players built on the libretro API
|
||||
- [**shadPS4**](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/user_manager.h), a PlayStation 4 emulator for Windows, Linux and macOS
|
||||
- [**skate.**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a free-to-play skateboarding game set in an open world
|
||||
- [**Snapchat**](https://www.snap.com/terms/license-android), a multimedia messaging and augmented reality app for communication and entertainment
|
||||
- [**Steel Century Groove**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an action game released in 2026
|
||||
- [**Sunshine**](https://github.com/LizardByte/Sunshine/blob/master/src/confighttp.h), a self-hosted game streaming host compatible with Moonlight clients
|
||||
- [**Tactics Ogre: Reborn**](https://www.square-enix-games.com/en_US/documents/tactics-ogre-reborn-pc-installer-software-and-associated-plug-ins-disclosure), a tactical role-playing game featuring strategic battles and deep storytelling elements
|
||||
- [**Throne and Liberty**](https://www.amazon.com/gp/help/customer/display.html?nodeId=T7fLNw5oAevCMtJFPj&pop-up=1), an MMORPG that offers an expansive fantasy world with dynamic gameplay and immersive storytelling
|
||||
- [**Unity Vivox**](https://docs.unity3d.com/Packages/com.unity.services.vivox@15.1/license/Third%20Party%20Notices.html), a communication service that enables voice and text chat functionality in multiplayer games developed with Unity
|
||||
- [**xemu**](https://github.com/xemu-project/xemu), an emulator of the original Xbox console
|
||||
- [**Zool: Redimensioned**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a modern reimagining of the classic platformer featuring fast-paced gameplay and vibrant environments
|
||||
- [**immersivetech**](https://immersitech.io/open-source-third-party-software/), a technology company focused on immersive experiences, providing tools and solutions for virtual and augmented reality applications
|
||||
|
||||
## Consumer Electronics
|
||||
|
||||
@@ -81,195 +50,109 @@ the result of an internet search. If you know further customers of the library,
|
||||
- [**Canon CanoScan LIDE**](https://carolburo.com/wp-content/uploads/2024/06/LiDE400_OnlineManual_Win_FR_V02.pdf), a series of flatbed scanners offering high-resolution image scanning for home and office use
|
||||
- [**Canon PIXMA Printers**](https://www.mediaexpert.pl/products/files/73/7338196/Instrukcja-obslugi-CANON-Pixma-TS7450i.pdf), a line of all-in-one inkjet printers known for high-quality printing and wireless connectivity
|
||||
- [**Cisco Webex Desk Camera**](https://www.cisco.com/c/dam/en_us/about/doing_business/open_source/docs/CiscoWebexDeskCamera-23-1622100417.pdf), a video camera designed for professional-quality video conferencing and remote collaboration
|
||||
- [**DJI Edge SDK**](https://github.com/dji-sdk/Edge-SDK-V2-Demo), the reference applications for DJI's Edge SDK, used to build edge computing services on DJI drone docks
|
||||
- [**Elgato Stream Deck**](https://github.com/elgatosf/streamdeck-obs-plugin2), a family of programmable control surfaces for content creators and their plugin ecosystem
|
||||
- [**Instagrid**](https://instagrid.co/intellectual-property/foss), a manufacturer of portable, high-performance battery systems for professional mobile power supply
|
||||
- [**iRobot**](https://iot-content.irobot.com/iw/sfsites/c/cms/delivery/media/MCKRLTPDJSSJBNJKDA5SG5UVVIIQ), a manufacturer of autonomous home robots including the Roomba vacuum cleaner range
|
||||
- [**Logitech Logi Bolt**](https://opensource.logitech.com/wiki/Logi_BoltApp/), the management application for Logitech's secure wireless connectivity technology
|
||||
- [**Novitus**](https://novitus.pl/licencjepensource), a manufacturer of fiscal cash registers and point-of-sale devices
|
||||
- [**Philips Hue Personal Wireless Lighting**](http://2ak5ape.257.cz/), a smart lighting system for customizable and wireless home illumination
|
||||
- [**Ray-Ban Meta Smart glasses**](https://www.meta.com/de/en/legal/smart-glasses/third-party-notices-android/03/), a pair of smart glasses designed for capturing photos and videos with integrated connectivity and social features
|
||||
- [**Razer Synapse**](https://mysupport.razer.com/app/answers/detail/a_id/14146/~/open-source-software-for-razer-software), a unified configuration software enabling hardware customization for Razer devices
|
||||
- [**Sharp Professional Displays**](https://jp.sharp/restricted/business/lcd-display/cms/images/source_pnla862/PN-LA652_752_862_LicenseInformation.pdf), a range of large-format interactive displays for business and education
|
||||
- [**Siemens SINEMA Remote Connect**](https://cache.industry.siemens.com/dl/files/790/109793790/att_1054961/v2/OSS_SINEMA-RC_86.pdf), a remote connectivity solution for monitoring and managing industrial networks and devices securely
|
||||
- [**Skydio**](https://pages.skydio.com/rs/784-TUF-591/images/Open%20Source%20Software%20Notice%20v0.2.html), a manufacturer of autonomous drones for inspection, public safety, and defense applications
|
||||
- [**Sony PlayStation 4**](https://doc.dl.playstation.net/doc/ps4-oss/index.html), a gaming console developed by Sony that offers a wide range of games and multimedia entertainment features
|
||||
- [**Sony Spatial Reality Display**](https://www.sony.co.jp/en/Products/Developer-Spatial-Reality-display/download/dcc-tools/blender-plugin/SpatiaRealityDisplayPluginforPreviewBL_Manual.pdf), a glasses-free stereoscopic 3D display and its plugins for Blender, 3ds Max, and ZBrush
|
||||
- [**Sony Virtual Webcam Driver for Remote Camera**](https://helpguide.sony.net/rc/vwd/v1/zh-cn/print.pdf), a software driver that enables the use of Sony cameras as virtual webcams for video conferencing and streaming
|
||||
- [**Yamaha Clavinova**](https://usa.yamaha.com/files/download/other_assets/1/2298171/CLP-800_oss_license.pdf), a series of digital pianos combining acoustic piano feel with digital sound technology
|
||||
|
||||
## Operating Systems and Platforms
|
||||
## Operating Systems
|
||||
|
||||
- [**Apple iOS and macOS**](https://www.apple.com/macos), a family of operating systems developed by Apple, including iOS for mobile devices and macOS for desktop computers
|
||||
- [**Chromium**](https://chromium.googlesource.com/chromium/src/+/main/third_party/nlohmann_json/), the open-source browser project that Google Chrome, Microsoft Edge, and many other browsers are built on, where the library is used as data container for on-device model execution
|
||||
- [**Google Fuchsia**](https://fuchsia.googlesource.com/third_party/json/), an open-source operating system developed by Google, designed to be secure, updatable, and adaptable across various devices
|
||||
- [**LG webOS**](https://github.com/webosose/com.webos.service.camera), a Linux-based operating system used in LG smart TVs, signage, and embedded devices
|
||||
- [**Microsoft Azure Linux**](https://github.com/microsoft/azurelinux), a Linux distribution developed by Microsoft for Azure infrastructure and edge workloads
|
||||
- [**OpenHarmony**](https://github.com/openharmony/third_party_json), an open-source operating system for smart devices and the foundation of HarmonyOS
|
||||
- [**SerenityOS**](https://github.com/SerenityOS/serenity), an open-source operating system that aims to provide a simple and beautiful user experience with a focus on simplicity and elegance
|
||||
- [**Windows Subsystem for Linux**](https://github.com/microsoft/WSL), a compatibility layer that runs Linux environments natively on Windows
|
||||
- [**Yocto**](http://ftp.emacinc.com/openembedded-sw/kirkstone-icop-5.15-kirkstone-6.0/archive-2024-10/pn8m-090t-ppc/licenses/nlohmann-json/), a Linux-based build system for creating custom operating systems and software distributions, tailored for embedded devices and IoT applications
|
||||
|
||||
## Development Tools and IDEs
|
||||
|
||||
- [**Accentize SpectralBalance**](https://www.accentize.com/products/SpectralBalanceManual.pdf), an adaptive speech analysis tool designed to enhance audio quality by optimizing frequency balance in recordings
|
||||
- [**Airbus Ghidralligator**](https://www.cyber.airbus.com/en/newsroom/stories/2025-06-ghidralligator), a Ghidra-based emulator from Airbus CyberSecurity used to fuzz and analyse embedded firmware
|
||||
- [**Apache brpc**](https://github.com/apache/brpc/blob/master/src/butil/iobuf.h), an industrial-grade remote procedure call framework for C++
|
||||
- [**Arm Compiler for Linux**](https://documentation-service.arm.com/static/66558e9d876c8d213b7843e4), a software development toolchain for compiling and optimizing applications on Arm-based Linux systems
|
||||
- [**BBEdit**](https://s3.amazonaws.com/BBSW-download/BBEdit_15.1.2_User_Manual.pdf), a professional text and code editor for macOS
|
||||
- [**CoderPad**](https://coderpad.io), a collaborative coding platform that enables real-time code interviews and assessments for developers; the library is included in every CoderPad instance and can be accessed with a simple `#include "json.hpp"`
|
||||
- [**Codon**](https://github.com/exaloop/codon/blob/develop/jupyter/jupyter.h), an ahead-of-time compiler for a Python-like language
|
||||
- [**Compiler Explorer**](https://godbolt.org), a web-based tool that allows users to write, compile, and visualize the assembly output of code in various programming languages; the library is readily available and accessible with the directive `#include <nlohmann/json.hpp>`.
|
||||
- [**Flutter**](https://github.com/flutter/flutter/blob/master/engine/src/flutter/impeller/compiler/reflector.cc), a UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase
|
||||
- [**Fraunhofer VVenC**](https://github.com/fraunhoferhhi/vvenc), a fast and efficient encoder for the Versatile Video Coding (H.266/VVC) standard
|
||||
- [**GitHub CodeQL**](https://github.com/github/codeql/blob/main/shared/cpp/Diagnostics.h), a code analysis tool used for identifying security vulnerabilities and bugs in software through semantic queries
|
||||
- [**GoPro ngfx**](https://github.com/gopro/ngfx), a low-level graphics abstraction and profiling framework developed by GoPro
|
||||
- [**gRPC**](https://github.com/grpc/grpc/blob/master/tools/artifact_gen/utils.h), a high-performance universal remote procedure call framework
|
||||
- [**GitHub CodeQL**](https://github.com/github/codeql), a code analysis tool used for identifying security vulnerabilities and bugs in software through semantic queries
|
||||
- [**Hex-Rays**](https://docs.hex-rays.com/user-guide/user-interface/licenses), a reverse engineering toolset for analyzing and decompiling binaries, primarily used for security research and vulnerability analysis
|
||||
- [**ImHex**](https://github.com/WerWolv/ImHex), a hex editor designed for reverse engineering, providing advanced features for data analysis and manipulation
|
||||
- [**Intel GITS**](https://github.com/intel/gits), a tool for capturing and replaying graphics API calls for debugging and performance analysis
|
||||
- [**Intel GPA Framework**](https://intel.github.io/gpasdk-doc/src/licenses.html), a suite of cross-platform tools for capturing, analyzing, and optimizing graphics applications across different APIs
|
||||
- [**Intopix**](https://www.intopix.com/software-licensing), a provider of advanced image processing and compression solutions used in software development and AV workflows
|
||||
- [**Java SE**](https://www.oracle.com/a/tech/docs/jdk8-lium.pdf), the core Java platform that provides the libraries and runtime needed to build and run general-purpose Java applications
|
||||
- [**Meta Yoga**](https://github.com/facebook/yoga), a layout engine that facilitates flexible and efficient user interface design across multiple platforms
|
||||
- [**MKVToolNix**](https://mkvtoolnix.download/doc/README.md), a set of tools for creating, editing, and inspecting MKV (Matroska) multimedia container files
|
||||
- [**MRTech IFF SDK**](https://mr-technologies.com/pub/iff-sdk-manual-2-0-1/iff-sdk-manual-2-0-1.pdf), an image processing SDK for machine vision applications with GPU-accelerated pipelines
|
||||
- [**Nix**](https://github.com/NixOS/nix/blob/master/src/nix/build.cc), a purely functional package manager
|
||||
- [**Notepad++**](https://github.com/notepad-plus-plus/notepad-plus-plus), a free source code editor that supports various programming languages
|
||||
- [**Meta Yoga**](https://github.com/facebook/yoga), a layout engine that facilitates flexible and efficient user interface design across multiple platforms
|
||||
- [**NVIDIA Nsight Compute**](https://docs.nvidia.com/nsight-compute/2022.2/pdf/CopyrightAndLicenses.pdf), a performance analysis tool for CUDA applications that provides detailed insights into GPU performance metrics
|
||||
- [**openFrameworks**](https://github.com/openframeworks/openFrameworks/blob/master/libs/openFrameworks/utils/ofJson.h), a community-developed C++ toolkit for creative coding
|
||||
- [**Notepad++**](https://github.com/notepad-plus-plus/notepad-plus-plus), a free source code editor that supports various programming languages
|
||||
- [**OpenRGB**](https://gitlab.com/CalcProgrammer1/OpenRGB), an open source RGB lighting control that doesn't depend on manufacturer software
|
||||
- [**OpenTelemetry C++**](https://github.com/open-telemetry/opentelemetry-cpp), a library for collecting and exporting observability data in C++, enabling developers to implement distributed tracing and metrics in their application
|
||||
- [**Oracle GraalVM**](https://docs.oracle.com/en/graalvm/jdk/21/docs/licensing-information/), a high-performance JDK distribution with ahead-of-time compilation and polyglot runtime support
|
||||
- [**Philips amp-cucumber-cpp-runner**](https://github.com/philips-software/amp-cucumber-cpp-runner), a behaviour-driven development test runner for embedded C++ software developed at Philips
|
||||
- [**Qt Creator**](https://doc.qt.io/qtcreator/qtcreator-attribution-json-nlohmann.html), an IDE for developing applications using the Qt application framework
|
||||
- [**Qt for MCUs**](https://doc.qt.io/QtForMCUs/quickultralite-attribution-nlohmann-json.html), a graphics framework for building fluid user interfaces on microcontrollers
|
||||
- [**React Native**](https://github.com/react/react-native/blob/main/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.cpp), a framework for building native mobile applications using React
|
||||
- [**Scanbot SDK**](https://docs.scanbot.io/barcode-scanner-sdk/web/third-party-libraries/), a software development kit (SDK) that provides tools for integrating advanced document scanning and barcode scanning capabilities into applications
|
||||
- [**STMicroelectronics TouchGFX**](https://www.st.com/resource/en/additional_license_terms/additional-license-terms-x-cube-touchgfx.html), a graphical user interface framework shipped with STM32 microcontrollers for building embedded HMIs
|
||||
- [**swagger-codegen**](https://github.com/swagger-api/swagger-codegen/blob/master/samples/server/petstore/pistache-server/model/Pet.h), a template-driven engine that generates API clients and server stubs from an OpenAPI specification
|
||||
- [**Swoole**](https://github.com/swoole/swoole-src/blob/master/ext-src/swoole_admin_server.cc), a coroutine-based concurrency engine for PHP
|
||||
- [**Tracy Profiler**](https://github.com/wolfpld/tracy/blob/master/profiler/src/profiler/TracyLlm.hpp), a real-time frame profiler for games and other applications
|
||||
- [**WasmEdge**](https://github.com/WasmEdge/WasmEdge/blob/master/plugins/wasi_nn/GGML/tts/tts_core.cpp), a lightweight WebAssembly runtime for edge and cloud workloads
|
||||
- [**x64dbg**](https://github.com/x64dbg/x64dbg/blob/development/src/cross/remote_table/TableRpcData.h), an open source user mode debugger for Windows, aimed at reverse engineering and malware analysis
|
||||
|
||||
## Machine Learning and AI
|
||||
|
||||
- [**Alibaba MNN**](https://github.com/alibaba/MNN), a lightweight deep learning inference engine for mobile and embedded devices
|
||||
- [**AMD Gaia**](https://github.com/amd/gaia), an open-source framework for running generative AI applications locally on AMD hardware
|
||||
- [**AMD Vitis AI (VAIP)**](https://github.com/amd/vaip), the execution provider stack that runs AI models on AMD Ryzen AI and adaptive computing devices
|
||||
- [**Apple Core ML Tools**](https://github.com/apple/coremltools), a set of tools for converting and configuring machine learning models for deployment in Apple's Core ML framework
|
||||
- [**Avular Mobile Robotics**](https://www.avular.com/licenses/nlohmann-json-3.9.1.txt), a platform for developing and deploying mobile robotics solutions
|
||||
- [**FunASR**](https://github.com/modelscope/FunASR/blob/main/runtime/http/bin/asr_sessions.h), a speech recognition toolkit for training and deploying end-to-end models
|
||||
- [**Google gemma.cpp**](https://github.com/google/gemma.cpp), a lightweight C++ inference engine designed for running AI models from the Gemma family
|
||||
- [**Google Magenta The Infinite Crate**](https://github.com/magenta/the-infinite-crate), an open-source generative AI plugin for digital audio workstations from Google's Magenta research team
|
||||
- [**GPT4All**](https://github.com/nomic-ai/gpt4all/blob/main/gpt4all-chat/src/tool.h), a desktop application for running local large language models on consumer hardware
|
||||
- [**Huawei MindSpore**](https://github.com/mindspore-ai/mindspore/blob/master/Third_Party_Open_Source_Software_Notice), a deep learning framework for training and inference across device, edge, and cloud
|
||||
- [**KTransformers**](https://github.com/kvcache-ai/ktransformers/blob/main/archive/csrc/balance_serve/sched/model_config.h), a framework for heterogeneous large language model inference
|
||||
- [**llama.cpp**](https://github.com/ggerganov/llama.cpp), a C++ library designed for efficient inference of large language models (LLMs), enabling streamlined integration into applications
|
||||
- [**LocalAI**](https://github.com/mudler/LocalAI/blob/master/backend/cpp/ds4/dsml_renderer.cpp), a self-hosted inference engine that exposes local models through an OpenAI-compatible API
|
||||
- [**MLX**](https://github.com/ml-explore/mlx), an array framework for machine learning on Apple Silicon
|
||||
- [**Mozilla llamafile**](https://github.com/Mozilla-Ocho/llamafile), a tool designed for distributing and executing large language models (LLMs) efficiently using a single file format
|
||||
- [**NVIDIA ACE**](https://docs.nvidia.com/ace/latest/index.html), a suite of real-time AI solutions designed for the development of interactive avatars and digital human applications, enabling scalable and sophisticated user interactions
|
||||
- [**NVIDIA Instant NGP**](https://github.com/NVlabs/instant-ngp/blob/master/src/nerf_loader.cu), an implementation of instant neural graphics primitives for rapid scene reconstruction
|
||||
- [**NVIDIA TensorRT**](https://github.com/NVIDIA/TensorRT), an SDK for high-performance deep learning inference, including its TensorRT-LLM extension for large language models
|
||||
- [**NVIDIA TensorRT-LLM**](https://github.com/NVIDIA/TensorRT-LLM/blob/main/cpp/tensorrt_llm/common/safetensors.cpp), a toolkit for optimizing and serving large language model inference on GPUs
|
||||
- [**ONNX Runtime**](https://github.com/microsoft/onnxruntime), a cross-platform inference and training accelerator for machine learning models
|
||||
- [**OpenVINO**](https://github.com/openvinotoolkit/openvino), Intel's toolkit for optimizing and deploying deep learning inference across CPUs, GPUs, and NPUs
|
||||
- [**PaddleOCR**](https://github.com/PaddlePaddle/PaddleOCR/blob/main/deploy/cpp_infer/src/modules/text_detection/result.cc), an optical character recognition toolkit that turns documents and images into structured data
|
||||
- [**PaddlePaddle**](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/ap/src/axpr/anf_expr.cc), a deep learning framework for distributed training and inference
|
||||
- [**Peer**](https://support.peer.inc/hc/en-us/articles/17261335054235-Licenses), a platform offering personalized AI assistants for interactive learning and creative collaboration
|
||||
- [**PyTorch**](https://github.com/pytorch/pytorch), a machine learning framework for building and training neural networks, widely used in research and production
|
||||
- [**Qualcomm AI Engine Direct**](https://github.com/qualcomm/qai-appbuilder), a toolchain for building and running generative AI applications on Snapdragon devices
|
||||
- [**sherpa-onnx**](https://github.com/k2-fsa/sherpa-onnx/blob/master/sherpa-onnx/csrc/sentence-piece-tokenizer.cc), a speech toolkit for on-device recognition, synthesis and speaker diarization
|
||||
- [**stable-diffusion.cpp**](https://github.com/leejet/stable-diffusion.cpp), a C++ implementation of the Stable Diffusion image generation model
|
||||
- [**TanvasTouch**](https://tanvas.co/tanvastouch-sdk-third-party-acknowledgments), a software development kit (SDK) that enables developers to create tactile experiences on touchscreens, allowing users to feel textures and physical sensations in a digital environment
|
||||
- [**TensorFlow**](https://github.com/tensorflow/tensorflow), a machine learning framework that facilitates the development and training of models, supporting data serialization and efficient data exchange between components
|
||||
- [**whisper.cpp**](https://github.com/ggml-org/whisper.cpp), a C++ implementation of OpenAI's Whisper automatic speech recognition model
|
||||
|
||||
## Scientific Research and Analysis
|
||||
|
||||
- [**BLACK**](https://www.black-sat.org/en/stable/installation/linux.html), a bounded linear temporal logic (LTL) satisfiability checker
|
||||
- [**CERN ALICE O2**](https://github.com/AliceO2Group/AliceO2), the online-offline computing framework of the ALICE heavy-ion experiment at the Large Hadron Collider
|
||||
- [**CERN Atlas Athena**](https://gitlab.cern.ch/atlas/athena/-/blob/main/Control/PerformanceMonitoring/PerfMonComps/src/PerfMonMTSvc.h), a software framework used in the ATLAS experiment at the Large Hadron Collider (LHC) for performance monitoring
|
||||
- [**CERN CMSSW**](https://github.com/cms-sw/cmssw), the offline software framework of the CMS experiment at the Large Hadron Collider
|
||||
- [**CERN Gaudi**](https://gitlab.cern.ch/gaudi/Gaudi), the event-processing framework used by the LHCb and ATLAS experiments at the Large Hadron Collider
|
||||
- [**ICU**](https://github.com/unicode-org/icu), the International Components for Unicode, a mature library for software globalization and multilingual support
|
||||
- [**KAMERA**](https://github.com/Kitware/kamera), a platform for synchronized data collection and real-time deep learning to map marine species like polar bears and seals, aiding Arctic ecosystem research
|
||||
- [**KiCad**](https://gitlab.com/kicad/code/kicad/-/tree/master/thirdparty/nlohmann_json), a free and open-source software suite for electronic design automation
|
||||
- [**LLNL ROSE**](https://github.com/llnl/rose), a compiler infrastructure from Lawrence Livermore National Laboratory for building source-to-source program analysis and transformation tools
|
||||
- [**Maple**](https://www.maplesoft.com/support/help/Maple/view.aspx?path=copyright), a symbolic and numeric computing environment for advanced mathematical modeling and analysis
|
||||
- [**MeVisLab**](https://mevislabdownloads.mevis.de/docs/current/MeVis/ThirdParty/Documentation/Publish/ThirdPartyReference/index.html), a software framework for medical image processing and visualization.
|
||||
- [**MITK**](https://github.com/MITK/MITK), the Medical Imaging Interaction Toolkit, a framework for developing interactive medical image processing software
|
||||
- [**OpenPMD API**](https://openpmd-api.readthedocs.io/en/0.8.0-alpha/backends/json.html), a versatile programming interface for accessing and managing scientific data, designed to facilitate the efficient storage, retrieval, and sharing of simulation data across various applications and platforms
|
||||
- [**ORNL DataFed**](https://github.com/ORNL/DataFed), a federated scientific data management system developed at Oak Ridge National Laboratory
|
||||
- [**ParaView**](https://github.com/Kitware/ParaView), an open-source tool for large-scale data visualization and analysis across various scientific domains
|
||||
- [**QGIS**](https://gitlab.b-data.ch/qgis/qgis/-/blob/backport-57658-to-release-3_34/external/nlohmann/json.hpp), a free and open-source geographic information system (GIS) application that allows users to create, edit, visualize, and analyze geospatial data across a variety of formats
|
||||
- [**Sandia InterSpec**](https://github.com/sandialabs/InterSpec), spectral radiation analysis software from Sandia National Laboratories for identifying radioactive isotopes
|
||||
- [**VolView**](https://github.com/Kitware/VolView), a lightweight application for interactive visualization and analysis of 3D medical imaging data.
|
||||
- [**VTK**](https://github.com/Kitware/VTK), a software library for 3D computer graphics, image processing, and visualization
|
||||
- [**VolView**](https://github.com/Kitware/VolView), a lightweight application for interactive visualization and analysis of 3D medical imaging data.
|
||||
|
||||
## Business and Productivity Software
|
||||
|
||||
- [**ArcGIS PRO**](https://www.esri.com/content/dam/esrisites/en-us/media/legal/open-source-acknowledgements/arcgis-pro-2-8-attribution-report.html), a desktop geographic information system (GIS) application developed by Esri for mapping and spatial analysis
|
||||
- [**Autodesk Desktop**](https://damassets.autodesk.net/content/dam/autodesk/www/Company/legal-notices-trademarks/autodesk-desktop-platform-components/internal-autodesk-components-web-page-2023.pdf), a software platform developed by Autodesk for creating and managing desktop applications and services
|
||||
- [**Check Point**](https://www.checkpoint.com/about-us/copyright-and-trademarks/), a cybersecurity company specializing in threat prevention and network security solutions, offering a range of products designed to protect enterprises from cyber threats and ensure data integrity
|
||||
- [**EasyEffects**](https://github.com/wwmm/easyeffects/blob/master/src/presets_manager.hpp), an audio effects processor for PipeWire offering limiting, compression and equalization
|
||||
- [**espanso**](https://github.com/espanso/espanso/blob/dev/espanso-ui/src/win32/native.cpp), a cross-platform text expander
|
||||
- [**Karabiner-Elements**](https://github.com/pqrs-org/Karabiner-Elements/blob/main/src/share/app_icon.hpp), a keyboard customizer for macOS
|
||||
- [**MacType**](https://github.com/snowie2000/mactype/blob/directwrite/settings.h), a font rendering engine for Windows
|
||||
- [**magicplan**](https://help.magicplan.app/acknowledgments), a mobile application for creating floor plans and interior designs using augmented reality
|
||||
- [**Microsoft Office for Mac**](https://officecdnmac.microsoft.com/pr/legal/mac/OfficeforMacAttributions.html), a suite of productivity applications developed by Microsoft for macOS, including tools for word processing, spreadsheets, and presentations
|
||||
- [**Microsoft Teams**](https://www.microsoft.com/microsoft-teams/), a team collaboration application offering workspace chat and video conferencing, file storage, and integration of proprietary and third-party applications and services
|
||||
- [**MuseScore**](https://github.com/musescore/MuseScore), a free and open-source music notation and composition application
|
||||
- [**NanaZip**](https://github.com/M2Team/NanaZip/blob/main/NanaZip.Codecs/NanaZip.Codecs.Archive.ElectronAsar.cpp), a 7-Zip derivative built for modern Windows
|
||||
- [**Nexthink Infinity**](https://docs.nexthink.com/legal/services-terms/experience-open-source-software-licenses/infinity-2022.8-software-licenses), a digital employee experience management platform for monitoring and improving IT performance
|
||||
- [**Sophos Connect Client**](https://docs.sophos.com/nsg/licenses/SophosConnect/SophosConnectAttribution.html), a secure VPN client from Sophos that allows remote users to connect to their corporate network, ensuring secure access to resources and data
|
||||
- [**Stonebranch**](https://stonebranchdocs.atlassian.net/wiki/spaces/UA77/pages/799545647/Licenses+for+Third-Party+Libraries), a cloud-based cybersecurity solution that integrates backup, disaster recovery, and cybersecurity features to protect data and ensure business continuity for organizations
|
||||
- [**Tablecruncher**](https://tablecruncher.com/), a data analysis tool that allows users to import, analyze, and visualize spreadsheet data, offering interactive features for better insights and decision-making
|
||||
- [**VNote**](https://github.com/vnotex/vnote/blob/master/src/core/services/notebookcoreservice.cpp), a Markdown-based note-taking application written in C++
|
||||
- [**magicplan**](https://help.magicplan.app/acknowledgments), a mobile application for creating floor plans and interior designs using augmented reality
|
||||
|
||||
## Databases and Big Data
|
||||
|
||||
- [**ADIOS2**](https://code.ornl.gov/ecpcitest/adios2/-/tree/pr4285_FFSUpstream/thirdparty/nlohmann_json?ref_type=heads), a data management framework designed for high-performance input and output operations
|
||||
- [**Apache Doris**](https://github.com/apache/doris/blob/master/be/src/runtime/be_proc_monitor.cpp), a real-time analytical database for high-concurrency queries
|
||||
- [**Claris FileMaker Server**](https://www.claris.com/company/legal/docs/acknowledgements/filemaker-server-macwin/claris_fms2025_acknowledgements_en.pdf), the server platform hosting FileMaker custom apps and databases, developed by Apple subsidiary Claris
|
||||
- [**ClickHouse**](https://github.com/ClickHouse/ClickHouse), a column-oriented database management system for real-time analytical queries
|
||||
- [**Cribl Stream**](https://docs.cribl.io/stream/third-party-current-list/), a real-time data processing platform that enables organizations to collect, route, and transform observability data, enhancing visibility and insights into their systems
|
||||
- [**DB Browser for SQLite**](https://github.com/sqlitebrowser/sqlitebrowser), a visual open-source tool for creating, designing, and editing SQLite database files
|
||||
- [**Manticore Search**](https://github.com/manticoresoftware/manticoresearch/blob/main/src/searchdhttpcompat.cpp), a database for search, offering full-text and vector queries
|
||||
- [**Milvus**](https://github.com/milvus-io/milvus/blob/master/internal/core/src/query/PlanImpl.h), a cloud-native vector database built for embedding similarity search
|
||||
- [**MongoDB**](https://github.com/mongodb/mongo/blob/master/src/mongo/replay/config_handler.cpp), a general-purpose document database
|
||||
- [**MySQL Connector/C++**](https://docs.oracle.com/cd/E17952_01/connector-cpp-9.1-license-com-en/license-opentelemetry-cpp-com.html), a C++ library for connecting and interacting with MySQL databases
|
||||
- [**MySQL NDB Cluster**](https://downloads.mysql.com/docs/licenses/cluster-9.0-com-en.pdf), a distributed database system that provides high availability and scalability for MySQL databases
|
||||
- [**MySQL Shell**](https://downloads.mysql.com/docs/licenses/mysql-shell-8.0-gpl-en.pdf), an advanced client and code editor for interacting with MySQL servers, supporting SQL, Python, and JavaScript
|
||||
- [**PrestoDB**](https://github.com/prestodb/presto/blob/master/presto-native-execution/presto_cpp/main/Announcer.cpp), a distributed SQL query engine designed for large-scale data analytics, originally developed by Facebook
|
||||
- [**PrestoDB**](https://github.com/prestodb/presto), a distributed SQL query engine designed for large-scale data analytics, originally developed by Facebook
|
||||
- [**ROOT Data Analysis Framework**](https://root.cern/doc/v614/classnlohmann_1_1basic__json.html), an open-source data analysis framework widely used in high-energy physics and other fields for data processing and visualization
|
||||
- [**Typesense**](https://github.com/typesense/typesense/blob/v31/include/join.h), an open source typo-tolerant search engine
|
||||
- [**Vearch**](https://github.com/jd-opensource/vearch), a distributed vector database developed at JD.com for similarity search and retrieval-augmented generation
|
||||
- [**WiredTiger**](https://github.com/wiredtiger/wiredtiger), a high-performance storage engine for databases, offering support for compression, concurrency, and checkpointing
|
||||
|
||||
## Simulation and Modeling
|
||||
|
||||
- [**Adobe Lagrange**](https://github.com/adobe/lagrange), a geometry processing library developed by Adobe for mesh manipulation and analysis
|
||||
- [**Arcturus HoloSuite**](https://www.datocms-assets.com/104353/1698904597-holosuite-third-party-software-credits-and-attributions-2.pdf), a software toolset for capturing, editing, and streaming volumetric video, featuring advanced compression technologies for high-quality 3D content creation
|
||||
- [**azul**](https://pure.tudelft.nl/ws/files/85338589/tgis.12673.pdf), a fast and efficient 3D city model viewer designed for visualizing urban environments and spatial data
|
||||
- [**Bambu Studio**](https://github.com/bambulab/BambuStudio), a slicing and print management application for Bambu Lab 3D printers
|
||||
- [**Blender**](https://projects.blender.org/blender/blender/search?q=nlohmann), a free and open-source 3D creation suite for modeling, animation, rendering, and more
|
||||
- [**cpplot**](https://cpplot.readthedocs.io/en/latest/library_api/function_eigen_8h_1ac080eac0541014c5892a55e41bf785e6.html), a library for creating interactive graphs and charts in C++, which can be viewed in web browsers
|
||||
- [**Foundry Nuke**](https://learn.foundry.com/nuke/content/misc/studio_third_party_libraries.html), a powerful node-based digital compositing and visual effects application used in film and television post-production
|
||||
- [**FreeCAD**](https://github.com/FreeCAD/FreeCAD), a free and open-source parametric 3D CAD modeler for product design and engineering
|
||||
- [**GAMS**](https://www.gams.com/47/docs/THIRDPARTY.html), a high-performance mathematical modeling system for optimization and decision support
|
||||
- [**Keysight WirelessPro**](https://docs.keysight.com/display/engdocwirelesspro/WirelessPro+2026+Release+Notes), a simulation platform for 5G, 5G-Advanced, and 6G cellular network research
|
||||
- [**Kitware SMTK**](https://github.com/Kitware/SMTK), a software toolkit for managing simulation models and workflows in scientific and engineering applications
|
||||
- [**M-Star**](https://docs.mstarcfd.com/3_Licensing/thirdparty-licenses.html), a computational fluid dynamics software for simulating and analyzing fluid flow
|
||||
- [**MapleSim CAD Toolbox**](https://www.maplesoft.com/support/help/MapleSim/view.aspx?path=CADToolbox/copyright), a software extension for MapleSim that integrates CAD models, allowing users to import, manipulate, and analyze 3D CAD data within the MapleSim environment for enhanced modeling and simulation
|
||||
- [**Microsoft AirSim**](https://github.com/microsoft/AirSim/blob/main/AirLib/include/common/Settings.hpp), a simulator for autonomous vehicles and drones built on Unreal Engine
|
||||
- [**NVIDIA Omniverse**](https://docs.omniverse.nvidia.com/composer/latest/common/product-licenses/usd-explorer/usd-explorer-2023.2.0-licenses-manifest.html), a platform for 3D content creation and collaboration that enables real-time simulations and interactive experiences across various industries
|
||||
- [**OpenSCAD**](https://github.com/openscad/openscad/blob/master/src/core/AIClient.cc), a script-driven solid 3D CAD modeller
|
||||
- [**OrcaSlicer**](https://github.com/SoftFever/OrcaSlicer), an open-source slicer supporting a wide range of consumer 3D printers
|
||||
- [**Pixar Renderman**](https://rmanwiki-26.pixar.com/space/REN26/19662083/Legal+Notice), a photorealistic 3D rendering software developed by Pixar, widely used in the film industry for creating high-quality visual effects and animations
|
||||
- [**PrusaSlicer**](https://github.com/prusa3d/PrusaSlicer), the slicing software developed by Prusa Research for its 3D printers
|
||||
- [**ROS - Robot Operating System**](http://docs.ros.org/en/noetic/api/behaviortree_cpp/html/json_8hpp_source.html), a set of software libraries and tools that assist in developing robot applications
|
||||
- [**UBS**](https://www.ubs.com/), a multinational financial services and banking company
|
||||
|
||||
@@ -278,31 +161,18 @@ the result of an internet search. If you know further customers of the library,
|
||||
- [**Acronis Cyber Protect Cloud**](https://care.acronis.com/s/article/59533-Third-party-software-used-in-Acronis-Cyber-Protect-Cloud?language=en_US), an all-in-one data protection solution that combines backup, disaster recovery, and cybersecurity to safeguard business data from threats like ransomware
|
||||
- [**Baereos**](https://gitlab.tiger-computing.co.uk/packages/bareos/-/blob/tiger/bullseye/third-party/CLI11/examples/json.cpp), a backup solution that provides data protection and recovery options for various environments, including physical and virtual systems
|
||||
- [**Bitdefender Home Scanner**](https://www.bitdefender.de/site/Main/view/home-scanner-open-source.html), a tool from Bitdefender that scans devices for malware and security threats, providing a safeguard against potential online dangers
|
||||
- [**Cisco MLS++**](https://github.com/cisco/mlspp), an implementation of the Messaging Layer Security protocol for end-to-end encrypted group messaging
|
||||
- [**Citrix Provisioning**](https://docs.citrix.com/en-us/provisioning/2203-ltsr/downloads/pvs-third-party-notices-2203.pdf), a solution that streamlines the delivery of virtual desktops and applications by allowing administrators to manage and provision resources efficiently across multiple environments
|
||||
- [**Citrix Virtual Apps and Desktops**](https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/2305/downloads/third-party-notices-apps-and-desktops.pdf), a solution from Citrix that delivers virtual apps and desktops
|
||||
- [**Cyberarc**](https://docs.cyberark.com/Downloads/Legal/Privileged%20Session%20Manager%20for%20SSH%20Third-Party%20Notices.pdf), a security solution that specializes in privileged access management, enabling organizations to control and monitor access to critical systems and data, thereby enhancing overall cybersecurity posture
|
||||
- [**Deutsche Telekom sysrepo-plugins**](https://github.com/telekom/sysrepo-plugins), a collection of YANG datastore plugins used to manage network devices
|
||||
- [**Egnyte Desktop**](https://helpdesk.egnyte.com/hc/en-us/articles/360007071732-Third-Party-Software-Acknowledgements), a secure cloud storage solution designed for businesses, enabling file sharing, collaboration, and data management across teams while ensuring compliance and data protection
|
||||
- [**Elster**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use), a digital platform developed by German tax authorities for secure and efficient electronic tax filing and management using secunet protect4use
|
||||
- [**Envoy**](https://github.com/envoyproxy/envoy), a cloud-native edge and service proxy that forms the data plane of many service meshes
|
||||
- [**Ethereum Solidity**](https://github.com/ethereum/solidity), a high-level, object-oriented programming language designed for implementing smart contracts on the Ethereum platform
|
||||
- [**gVisor**](https://github.com/google/gvisor), an application kernel that provides a secure sandbox for running untrusted containers
|
||||
- [**IBM Storage Virtualize**](https://public.dhe.ibm.com/systems/support/warranty/pdfs/stgoilc/SV_for_FS_7300_v8_7_0_Base_OILC.pdf), the software powering IBM FlashSystem enterprise storage arrays
|
||||
- [**Inciga**](https://fossies.org/linux/icinga2/third-party/nlohmann_json/json.hpp), a monitoring tool for IT infrastructure, designed to provide insights into system performance and availability through customizable dashboards and alerts
|
||||
- [**Intel Accelerator Management Daemon for VMware ESXi**](https://downloadmirror.intel.com/772507/THIRD-PARTY.txt), a management tool designed for monitoring and controlling Intel hardware accelerators within VMware ESXi environments, optimizing performance and resource allocation
|
||||
- [**Juniper Identity Management Service**](https://www.juniper.net/documentation/us/en/software/jims/jims-guide/jims-guide.pdf)
|
||||
- [**Meta FBOSS**](https://github.com/facebook/fboss), the software stack that controls the network switches in Meta's data centers
|
||||
- [**Microsoft Azure IoT SDK**](https://library.e.abb.com/public/2779c5f85f30484192eb3cb3f666a201/IP%20Gateway%20Open%20License%20Declaration_9AKK108467A4095_Rev_C.pdf), a collection of tools and libraries to help developers connect, build, and deploy Internet of Things (IoT) solutions on the Azure cloud platform
|
||||
- [**Microsoft Confidential Consortium Framework**](https://github.com/microsoft/CCF), a framework for building secure, highly available applications on trusted execution environments
|
||||
- [**Microsoft WinGet**](https://github.com/microsoft/winget-cli), a command-line utility included in the Windows Package Manager
|
||||
- [**Mitsubishi Electric SECS/GEM**](https://dl.mitsubishielectric.com/dl/fa/document/manual/plc/sh082483eng/sh082483engi.pdf), the semiconductor equipment communication software running on Mitsubishi Electric C Controller and C intelligent function modules
|
||||
- [**Moxa**](https://www.moxa.com/getmedia/fbe2a0c7-8dda-4b5b-a501-15e45adebb1f/moxa-foss-statement-for-da-720-series-win-10-ltsc-21h2-declaration-v1.0.pdf), a provider of industrial networking, computing, and automation infrastructure
|
||||
- [**plexusAV**](https://www.sisme.com/media/10994/manual_plexusav-p-avn-4-form8244-c.pdf), a high-performance AV-over-IP transceiver device capable of video encoding and decoding using the IPMX standard
|
||||
- [**Pointr**](https://docs-dev.pointr.tech/docs/8.x/Developer%20Portal/Open%20Source%20Licenses/), a platform for indoor positioning and navigation solutions, offering tools and SDKs for developers to create location-based applications
|
||||
- [**secunet protect4use**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use), a secure, passwordless multifactor authentication solution that transforms smartphones into digital keyrings, ensuring high security for online services and digital identities
|
||||
- [**Sencore MRD 7000**](https://www.foccusdigital.com/wp-content/uploads/2025/03/MRD-7000-Manual-8175V.pdf), a professional multi-channel receiver and decoder supporting UHD and HD stream decoding
|
||||
- [**Siemens SINEC**](https://cache.industry.siemens.com/dl/files/917/109974917/att_1298783/v2/OSS_SINEC-NMS_99.pdf), a family of network management and infrastructure services for industrial networks
|
||||
- [**Toshiba Industrial Servers**](https://www.global.toshiba/content/dam/toshiba/jp/products-solutions/industrial/computer/product/server/fs20000r/pdf/FS20000R_OSS_License_6E8C5817_rev0.pdf), the FS20000R series of industrial servers for factory automation and control systems
|
||||
- [**Wazuh**](https://github.com/wazuh/wazuh/blob/main/src/data_provider/src/sysInfo.cpp), a security platform for threat detection, integrity monitoring and incident response
|
||||
- [**ZeroTier**](https://github.com/zerotier/ZeroTierOne/blob/dev/osdep/OSUtils.hpp), a software-defined networking service that creates virtual Ethernet networks
|
||||
|
||||
@@ -965,19 +965,3 @@ A JSON Patch operation 'test' failed. The unsuccessful operation is also printed
|
||||
```
|
||||
[json.exception.other_error.501] unsuccessful: {"op":"test","path":"/baz","value":"bar"}
|
||||
```
|
||||
|
||||
### json.exception.other_error.502
|
||||
|
||||
[`to_ubjson`](../api/basic_json/to_ubjson.md) and [`to_bjdata`](../api/basic_json/to_bjdata.md) were called with
|
||||
`use_type = true` but `use_size = false`. UBJSON requires a size marker (`#`) after a type marker (`$`).
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
[json.exception.other_error.502] use_type requires use_size = true
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
This exception was added in version 3.13.0. Before that, debug builds aborted on an assertion and release builds
|
||||
wrote a `$` marker without `#`, which [`from_ubjson`](../api/basic_json/from_ubjson.md) then rejected.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1001 KiB After Width: | Height: | Size: 1.3 MiB |
@@ -308,7 +308,6 @@ nav:
|
||||
- 'NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH': api/macros/nlohmann_json_version_major.md
|
||||
- Community:
|
||||
- community/index.md
|
||||
- community/ecosystem.md
|
||||
- "Code of Conduct": community/code_of_conduct.md
|
||||
- community/contribution_guidelines.md
|
||||
- community/quality_assurance.md
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
wheel==0.48.0
|
||||
wheel==0.47.0
|
||||
|
||||
mkdocs==1.6.1 # documentation framework
|
||||
mkdocs-git-revision-date-localized-plugin==1.5.4 # plugin "git-revision-date-localized"
|
||||
mkdocs-git-revision-date-localized-plugin==1.5.3 # plugin "git-revision-date-localized"
|
||||
mkdocs-material==9.7.7 # theme for mkdocs
|
||||
mkdocs-material-extensions==1.3.1 # extensions
|
||||
mkdocs-minify-plugin==0.8.0 # plugin "minify"
|
||||
|
||||
@@ -465,6 +465,15 @@ class binary_reader
|
||||
// CBOR //
|
||||
//////////
|
||||
|
||||
/*!
|
||||
@param[in] get_char whether a new character should be retrieved from the
|
||||
input (true) or whether the last read character should
|
||||
be considered instead (false)
|
||||
@param[in] tag_handler how CBOR tags should be treated
|
||||
|
||||
@return whether a valid CBOR value was passed to the SAX parser
|
||||
*/
|
||||
|
||||
template<typename NumberType>
|
||||
bool get_cbor_negative_integer()
|
||||
{
|
||||
@@ -483,14 +492,6 @@ class binary_reader
|
||||
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
|
||||
}
|
||||
|
||||
/*!
|
||||
@param[in] get_char whether a new character should be retrieved from the
|
||||
input (true) or whether the last read character should
|
||||
be considered instead (false)
|
||||
@param[in] tag_handler how CBOR tags should be treated
|
||||
|
||||
@return whether a valid CBOR value was passed to the SAX parser
|
||||
*/
|
||||
bool parse_cbor_internal(const bool get_char,
|
||||
const cbor_tag_handler_t tag_handler)
|
||||
{
|
||||
@@ -773,13 +774,7 @@ class binary_reader
|
||||
case 0xBF: // map (indefinite length)
|
||||
return get_cbor_object(detail::unknown_size(), tag_handler);
|
||||
|
||||
case 0xC0: // tagged item
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC6: // tagged item
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -794,9 +789,6 @@ class binary_reader
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8: // tagged item (1 byte follows)
|
||||
case 0xD9: // tagged item (2 bytes follow)
|
||||
case 0xDA: // tagged item (4 bytes follow)
|
||||
@@ -1996,11 +1988,7 @@ class binary_reader
|
||||
{
|
||||
if (get_char)
|
||||
{
|
||||
// no get_ignore_noop() here: the byte read next must be a string
|
||||
// length type specification, and a no-op ('N') is not valid in
|
||||
// that position. No-ops at positions where a value may appear are
|
||||
// already consumed by the callers via get_ignore_noop().
|
||||
get();
|
||||
get(); // TODO(niels): may we ignore N here?
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
|
||||
|
||||
@@ -345,12 +345,8 @@ struct wide_string_input_helper<BaseInputAdapter, 4>
|
||||
}
|
||||
else
|
||||
{
|
||||
// A code point above U+10FFFF has no UTF-8 encoding. Passing the
|
||||
// unit through would narrow it to int, where 0xFFFFFFFF becomes
|
||||
// char_traits<char>::eof() and would end the input silently, so
|
||||
// emit a byte that is never valid UTF-8 and let the decoder
|
||||
// reject it.
|
||||
utf8_bytes[0] = 0xFF;
|
||||
// unknown character
|
||||
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,10 +370,8 @@ class json_sax_dom_parser
|
||||
|
||||
case value_t::string:
|
||||
{
|
||||
// escape sequences make the token longer than the value it
|
||||
// parses to, so the start position cannot be derived from
|
||||
// the value; use the offset the lexer recorded instead
|
||||
v.start_position = m_lexer_ref->get_token_start_position();
|
||||
// include the length of the quotes, which is 2
|
||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -771,10 +769,8 @@ class json_sax_dom_callback_parser
|
||||
|
||||
case value_t::string:
|
||||
{
|
||||
// escape sequences make the token longer than the value it
|
||||
// parses to, so the start position cannot be derived from
|
||||
// the value; use the offset the lexer recorded instead
|
||||
v.start_position = m_lexer_ref->get_token_start_position();
|
||||
// include the length of the quotes, which is 2
|
||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1357,11 +1357,6 @@ scan_number_done:
|
||||
token_buffer.clear();
|
||||
decimal_point_position = std::string::npos;
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// the first character of the token has already been read, hence the -1
|
||||
token_start_position = position.chars_read_total - 1;
|
||||
#endif
|
||||
|
||||
note_token_start(std::integral_constant<bool, lazy_token_string> {});
|
||||
}
|
||||
|
||||
@@ -1524,15 +1519,6 @@ scan_number_done:
|
||||
return position;
|
||||
}
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
/// return the offset of the first character of the last read token; unlike
|
||||
/// the token's parsed value, this accounts for escape sequences
|
||||
constexpr std::size_t get_token_start_position() const noexcept
|
||||
{
|
||||
return token_start_position;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// seekable adapter: rebuild the last read token from the input on demand
|
||||
const std::vector<char_type>& collect_token_chars(std::vector<char_type>& out, std::true_type /*lazy*/) const
|
||||
{
|
||||
@@ -1733,12 +1719,6 @@ scan_number_done:
|
||||
/// the last read token on error for seekable adapters (see collect_token_chars)
|
||||
std::size_t token_string_start = 0;
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
/// start offset of the current token within the input, used to report
|
||||
/// diagnostic positions (see reset())
|
||||
std::size_t token_start_position = 0;
|
||||
#endif
|
||||
|
||||
/// buffer for variable-length tokens (numbers, strings)
|
||||
string_t token_buffer {};
|
||||
|
||||
|
||||
@@ -396,15 +396,19 @@ class json_pointer
|
||||
// convert null values to arrays or objects before continuing
|
||||
if (ptr->is_null())
|
||||
{
|
||||
// check if the reference token is a number
|
||||
const bool nums =
|
||||
std::all_of(reference_token.begin(), reference_token.end(),
|
||||
[](const unsigned char x)
|
||||
// check if the reference token is a valid array index, that is
|
||||
// a nonempty sequence of digits without a leading '0'
|
||||
// (cf. RFC 6901, Sect. 4); tokens that could never be a valid
|
||||
// array index (such as "01" or "") are treated as object keys
|
||||
const bool nums = !reference_token.empty()
|
||||
&& (reference_token.size() == 1 || reference_token[0] != '0')
|
||||
&& std::all_of(reference_token.begin(), reference_token.end(),
|
||||
[](const unsigned char x)
|
||||
{
|
||||
return std::isdigit(x);
|
||||
});
|
||||
|
||||
// change value to an array for numbers or "-" or to object otherwise
|
||||
// change value to an array for array indices or "-" or to object otherwise
|
||||
*ptr = (nums || reference_token == "-")
|
||||
? detail::value_t::array
|
||||
: detail::value_t::object;
|
||||
|
||||
@@ -813,10 +813,7 @@ class binary_writer
|
||||
bool prefix_required = true;
|
||||
if (use_type && !j.m_data.m_value.array->empty())
|
||||
{
|
||||
if (!use_count)
|
||||
{
|
||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||
}
|
||||
JSON_ASSERT(use_count);
|
||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
||||
[this, first_prefix, use_bjdata](const BasicJsonType & v)
|
||||
@@ -862,10 +859,7 @@ class binary_writer
|
||||
|
||||
if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty()))
|
||||
{
|
||||
if (!use_count)
|
||||
{
|
||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||
}
|
||||
JSON_ASSERT(use_count);
|
||||
oa->write_character(to_char_type('$'));
|
||||
oa->write_character(bjdata_draft3 ? 'B' : 'U');
|
||||
}
|
||||
@@ -917,10 +911,7 @@ class binary_writer
|
||||
bool prefix_required = true;
|
||||
if (use_type && !j.m_data.m_value.object->empty())
|
||||
{
|
||||
if (!use_count)
|
||||
{
|
||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||
}
|
||||
JSON_ASSERT(use_count);
|
||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
||||
[this, first_prefix, use_bjdata](const BasicJsonType & v)
|
||||
@@ -1668,15 +1659,6 @@ class binary_writer
|
||||
CharType dtype = it->second;
|
||||
|
||||
key = "_ArraySize_";
|
||||
// the dimensions are written verbatim as the header length below, so a
|
||||
// value that is not an array cannot produce a valid one: null emits 'Z'
|
||||
// and an object emits '{', neither of which a reader accepts after '#'.
|
||||
// Such an object is not a valid ndarray and falls back to a plain object.
|
||||
if (!value.at(key).is_array())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t len = (value.at(key).empty() ? 0 : 1);
|
||||
for (const auto& el : value.at(key))
|
||||
{
|
||||
@@ -1688,23 +1670,7 @@ class binary_writer
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// a dimension that does not fit into std::size_t, or a product that
|
||||
// overflows it, would wrap around and could match the size of
|
||||
// _ArrayData_ by accident; the resulting header announces an
|
||||
// element count that no reader can honor (the binary reader rejects
|
||||
// it with out_of_range.408), so encode as a plain object instead
|
||||
const auto dim = el.template get<std::uint64_t>();
|
||||
if (!value_in_range_of<std::size_t>(dim))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const auto dim_size = static_cast<std::size_t>(dim);
|
||||
if (dim_size != 0 && len > (std::numeric_limits<std::size_t>::max)() / dim_size)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
len *= dim_size;
|
||||
len *= static_cast<std::size_t>(el.template get<std::uint64_t>());
|
||||
}
|
||||
|
||||
key = "_ArrayData_";
|
||||
|
||||
@@ -9,12 +9,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cmath> // isnan, ldexp, trunc
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint8_t
|
||||
#include <limits> // numeric_limits
|
||||
#include <string> // string
|
||||
#include <type_traits> // is_signed
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
@@ -117,67 +114,5 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
@brief compare an integer with a floating point number without precision loss
|
||||
|
||||
Widening the integer to the floating point type loses precision beyond the
|
||||
float's mantissa, which makes equality intransitive: both 2^63-2 and 2^63-1
|
||||
round to 2^63, so each compares equal to that float while differing from each
|
||||
other. Ordering built on that is not a strict weak ordering, so sorting such
|
||||
values, or using them as keys in an ordered container, is undefined behavior.
|
||||
|
||||
Returns a value to be compared against zero with the original operator, which
|
||||
reproduces the exact ordering. A NaN operand is returned as is, so comparing it
|
||||
against zero keeps NaN's semantics: false for the relational operators and
|
||||
unordered for `<=>`.
|
||||
*/
|
||||
template<typename IntegerType, typename FloatType>
|
||||
FloatType compare_integer_with_float(const IntegerType i, const FloatType f) noexcept
|
||||
{
|
||||
const auto ordered = [](int c) noexcept
|
||||
{
|
||||
return static_cast<FloatType>(c);
|
||||
};
|
||||
|
||||
if (std::isnan(f))
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
// values of IntegerType lie in [-bound, bound) when signed and in
|
||||
// [0, bound) when unsigned; digits excludes the sign bit, so bound is a
|
||||
// power of two that the float represents exactly
|
||||
const FloatType bound = std::ldexp(static_cast<FloatType>(1), std::numeric_limits<IntegerType>::digits);
|
||||
if (f >= bound)
|
||||
{
|
||||
return ordered(-1);
|
||||
}
|
||||
if (std::is_signed<IntegerType>::value ? (f < -bound) : (f < static_cast<FloatType>(0)))
|
||||
{
|
||||
return ordered(1);
|
||||
}
|
||||
|
||||
// f is now within the integer's range, so truncating it is exact
|
||||
const FloatType truncated = std::trunc(f);
|
||||
const auto as_integer = static_cast<IntegerType>(truncated);
|
||||
if (i != as_integer)
|
||||
{
|
||||
return ordered(i < as_integer ? -1 : 1);
|
||||
}
|
||||
|
||||
// the integer parts agree, so any fractional part decides
|
||||
const FloatType fraction = f - truncated;
|
||||
if (fraction > static_cast<FloatType>(0))
|
||||
{
|
||||
return ordered(-1);
|
||||
}
|
||||
if (fraction < static_cast<FloatType>(0))
|
||||
{
|
||||
return ordered(1);
|
||||
}
|
||||
return ordered(0);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
+16
-27
@@ -3516,10 +3516,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
if (merge_objects && it.value().is_object())
|
||||
{
|
||||
auto it2 = m_data.m_value.object->find(it.key());
|
||||
// Only recurse when the existing value is itself an object.
|
||||
// Otherwise overwrite, matching the documented "all other values
|
||||
// are overwritten as usual" behavior (see #5402).
|
||||
if (it2 != m_data.m_value.object->end() && it2->second.is_object())
|
||||
if (it2 != m_data.m_value.object->end())
|
||||
{
|
||||
it2->second.update(it.value(), true);
|
||||
#if JSON_DIAGNOSTICS
|
||||
@@ -3655,12 +3652,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
// note parentheses around operands are necessary; see
|
||||
// https://github.com/nlohmann/json/issues/1530
|
||||
// Mixed signed/unsigned integer comparisons check whether the signed value
|
||||
// is negative before casting. If it is, the comparison is performed with
|
||||
// the fixed values -1 and 1, which preserves the ordering relationship
|
||||
// because any negative signed value is smaller than any unsigned value.
|
||||
// Otherwise, the non-negative signed value is cast to unsigned before the
|
||||
// comparison to avoid wraparound.
|
||||
#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \
|
||||
const auto lhs_type = lhs.type(); \
|
||||
const auto rhs_type = rhs.type(); \
|
||||
@@ -3703,32 +3694,28 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
} \
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \
|
||||
{ \
|
||||
return (detail::compare_integer_with_float(lhs.m_data.m_value.number_integer, rhs.m_data.m_value.number_float)) op (static_cast<number_float_t>(0)); \
|
||||
return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \
|
||||
{ \
|
||||
return (static_cast<number_float_t>(0)) op (detail::compare_integer_with_float(rhs.m_data.m_value.number_integer, lhs.m_data.m_value.number_float)); \
|
||||
return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer); \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \
|
||||
{ \
|
||||
return (detail::compare_integer_with_float(lhs.m_data.m_value.number_unsigned, rhs.m_data.m_value.number_float)) op (static_cast<number_float_t>(0)); \
|
||||
return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \
|
||||
{ \
|
||||
return (static_cast<number_float_t>(0)) op (detail::compare_integer_with_float(rhs.m_data.m_value.number_unsigned, lhs.m_data.m_value.number_float)); \
|
||||
return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned); \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
|
||||
{ \
|
||||
return (rhs.m_data.m_value.number_integer < 0) \
|
||||
? (number_integer_t(1) op number_integer_t(-1)) \
|
||||
: (lhs.m_data.m_value.number_unsigned op static_cast<number_unsigned_t>(rhs.m_data.m_value.number_integer)); \
|
||||
return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \
|
||||
{ \
|
||||
return (lhs.m_data.m_value.number_integer < 0) \
|
||||
? (number_integer_t(-1) op number_integer_t(1)) \
|
||||
: (static_cast<number_unsigned_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \
|
||||
} \
|
||||
return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
|
||||
} \
|
||||
else if(compares_unordered(lhs, rhs))\
|
||||
{\
|
||||
return (unordered_result);\
|
||||
@@ -5128,17 +5115,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// We now reached the end of at least one array
|
||||
// in a second pass, traverse the remaining elements
|
||||
|
||||
// remove my remaining elements, highest index first; appending
|
||||
// in that order avoids the quadratic reinsertion done before
|
||||
for (std::size_t j = source.size(); j > i; --j)
|
||||
// remove my remaining elements
|
||||
const auto end_index = static_cast<difference_type>(result.size());
|
||||
while (i < source.size())
|
||||
{
|
||||
result.push_back(object(
|
||||
// add operations in reverse order to avoid invalid
|
||||
// indices
|
||||
result.insert(result.begin() + end_index, object(
|
||||
{
|
||||
{"op", "remove"},
|
||||
{"path", detail::concat<string_t>(path, '/', detail::to_string<string_t>(j - 1))}
|
||||
{"path", detail::concat<string_t>(path, '/', detail::to_string<string_t>(i))}
|
||||
}));
|
||||
++i;
|
||||
}
|
||||
i = source.size();
|
||||
|
||||
// add other remaining elements
|
||||
while (i < target.size())
|
||||
|
||||
@@ -223,12 +223,9 @@
|
||||
|
||||
|
||||
#include <array> // array
|
||||
#include <cmath> // isnan, ldexp, trunc
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint8_t
|
||||
#include <limits> // numeric_limits
|
||||
#include <string> // string
|
||||
#include <type_traits> // is_signed
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
// __ _____ _____ _____
|
||||
@@ -3286,68 +3283,6 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
@brief compare an integer with a floating point number without precision loss
|
||||
|
||||
Widening the integer to the floating point type loses precision beyond the
|
||||
float's mantissa, which makes equality intransitive: both 2^63-2 and 2^63-1
|
||||
round to 2^63, so each compares equal to that float while differing from each
|
||||
other. Ordering built on that is not a strict weak ordering, so sorting such
|
||||
values, or using them as keys in an ordered container, is undefined behavior.
|
||||
|
||||
Returns a value to be compared against zero with the original operator, which
|
||||
reproduces the exact ordering. A NaN operand is returned as is, so comparing it
|
||||
against zero keeps NaN's semantics: false for the relational operators and
|
||||
unordered for `<=>`.
|
||||
*/
|
||||
template<typename IntegerType, typename FloatType>
|
||||
FloatType compare_integer_with_float(const IntegerType i, const FloatType f) noexcept
|
||||
{
|
||||
const auto ordered = [](int c) noexcept
|
||||
{
|
||||
return static_cast<FloatType>(c);
|
||||
};
|
||||
|
||||
if (std::isnan(f))
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
// values of IntegerType lie in [-bound, bound) when signed and in
|
||||
// [0, bound) when unsigned; digits excludes the sign bit, so bound is a
|
||||
// power of two that the float represents exactly
|
||||
const FloatType bound = std::ldexp(static_cast<FloatType>(1), std::numeric_limits<IntegerType>::digits);
|
||||
if (f >= bound)
|
||||
{
|
||||
return ordered(-1);
|
||||
}
|
||||
if (std::is_signed<IntegerType>::value ? (f < -bound) : (f < static_cast<FloatType>(0)))
|
||||
{
|
||||
return ordered(1);
|
||||
}
|
||||
|
||||
// f is now within the integer's range, so truncating it is exact
|
||||
const FloatType truncated = std::trunc(f);
|
||||
const auto as_integer = static_cast<IntegerType>(truncated);
|
||||
if (i != as_integer)
|
||||
{
|
||||
return ordered(i < as_integer ? -1 : 1);
|
||||
}
|
||||
|
||||
// the integer parts agree, so any fractional part decides
|
||||
const FloatType fraction = f - truncated;
|
||||
if (fraction > static_cast<FloatType>(0))
|
||||
{
|
||||
return ordered(-1);
|
||||
}
|
||||
if (fraction < static_cast<FloatType>(0))
|
||||
{
|
||||
return ordered(1);
|
||||
}
|
||||
return ordered(0);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
@@ -7413,12 +7348,8 @@ struct wide_string_input_helper<BaseInputAdapter, 4>
|
||||
}
|
||||
else
|
||||
{
|
||||
// A code point above U+10FFFF has no UTF-8 encoding. Passing the
|
||||
// unit through would narrow it to int, where 0xFFFFFFFF becomes
|
||||
// char_traits<char>::eof() and would end the input silently, so
|
||||
// emit a byte that is never valid UTF-8 and let the decoder
|
||||
// reject it.
|
||||
utf8_bytes[0] = 0xFF;
|
||||
// unknown character
|
||||
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
}
|
||||
@@ -9140,11 +9071,6 @@ scan_number_done:
|
||||
token_buffer.clear();
|
||||
decimal_point_position = std::string::npos;
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// the first character of the token has already been read, hence the -1
|
||||
token_start_position = position.chars_read_total - 1;
|
||||
#endif
|
||||
|
||||
note_token_start(std::integral_constant<bool, lazy_token_string> {});
|
||||
}
|
||||
|
||||
@@ -9307,15 +9233,6 @@ scan_number_done:
|
||||
return position;
|
||||
}
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
/// return the offset of the first character of the last read token; unlike
|
||||
/// the token's parsed value, this accounts for escape sequences
|
||||
constexpr std::size_t get_token_start_position() const noexcept
|
||||
{
|
||||
return token_start_position;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// seekable adapter: rebuild the last read token from the input on demand
|
||||
const std::vector<char_type>& collect_token_chars(std::vector<char_type>& out, std::true_type /*lazy*/) const
|
||||
{
|
||||
@@ -9516,12 +9433,6 @@ scan_number_done:
|
||||
/// the last read token on error for seekable adapters (see collect_token_chars)
|
||||
std::size_t token_string_start = 0;
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
/// start offset of the current token within the input, used to report
|
||||
/// diagnostic positions (see reset())
|
||||
std::size_t token_start_position = 0;
|
||||
#endif
|
||||
|
||||
/// buffer for variable-length tokens (numbers, strings)
|
||||
string_t token_buffer {};
|
||||
|
||||
@@ -9898,10 +9809,8 @@ class json_sax_dom_parser
|
||||
|
||||
case value_t::string:
|
||||
{
|
||||
// escape sequences make the token longer than the value it
|
||||
// parses to, so the start position cannot be derived from
|
||||
// the value; use the offset the lexer recorded instead
|
||||
v.start_position = m_lexer_ref->get_token_start_position();
|
||||
// include the length of the quotes, which is 2
|
||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -10299,10 +10208,8 @@ class json_sax_dom_callback_parser
|
||||
|
||||
case value_t::string:
|
||||
{
|
||||
// escape sequences make the token longer than the value it
|
||||
// parses to, so the start position cannot be derived from
|
||||
// the value; use the offset the lexer recorded instead
|
||||
v.start_position = m_lexer_ref->get_token_start_position();
|
||||
// include the length of the quotes, which is 2
|
||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11152,6 +11059,15 @@ class binary_reader
|
||||
// CBOR //
|
||||
//////////
|
||||
|
||||
/*!
|
||||
@param[in] get_char whether a new character should be retrieved from the
|
||||
input (true) or whether the last read character should
|
||||
be considered instead (false)
|
||||
@param[in] tag_handler how CBOR tags should be treated
|
||||
|
||||
@return whether a valid CBOR value was passed to the SAX parser
|
||||
*/
|
||||
|
||||
template<typename NumberType>
|
||||
bool get_cbor_negative_integer()
|
||||
{
|
||||
@@ -11170,14 +11086,6 @@ class binary_reader
|
||||
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
|
||||
}
|
||||
|
||||
/*!
|
||||
@param[in] get_char whether a new character should be retrieved from the
|
||||
input (true) or whether the last read character should
|
||||
be considered instead (false)
|
||||
@param[in] tag_handler how CBOR tags should be treated
|
||||
|
||||
@return whether a valid CBOR value was passed to the SAX parser
|
||||
*/
|
||||
bool parse_cbor_internal(const bool get_char,
|
||||
const cbor_tag_handler_t tag_handler)
|
||||
{
|
||||
@@ -11460,13 +11368,7 @@ class binary_reader
|
||||
case 0xBF: // map (indefinite length)
|
||||
return get_cbor_object(detail::unknown_size(), tag_handler);
|
||||
|
||||
case 0xC0: // tagged item
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC6: // tagged item
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -11481,9 +11383,6 @@ class binary_reader
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8: // tagged item (1 byte follows)
|
||||
case 0xD9: // tagged item (2 bytes follow)
|
||||
case 0xDA: // tagged item (4 bytes follow)
|
||||
@@ -12683,11 +12582,7 @@ class binary_reader
|
||||
{
|
||||
if (get_char)
|
||||
{
|
||||
// no get_ignore_noop() here: the byte read next must be a string
|
||||
// length type specification, and a no-op ('N') is not valid in
|
||||
// that position. No-ops at positions where a value may appear are
|
||||
// already consumed by the callers via get_ignore_noop().
|
||||
get();
|
||||
get(); // TODO(niels): may we ignore N here?
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
|
||||
@@ -16042,15 +15937,19 @@ class json_pointer
|
||||
// convert null values to arrays or objects before continuing
|
||||
if (ptr->is_null())
|
||||
{
|
||||
// check if the reference token is a number
|
||||
const bool nums =
|
||||
std::all_of(reference_token.begin(), reference_token.end(),
|
||||
[](const unsigned char x)
|
||||
// check if the reference token is a valid array index, that is
|
||||
// a nonempty sequence of digits without a leading '0'
|
||||
// (cf. RFC 6901, Sect. 4); tokens that could never be a valid
|
||||
// array index (such as "01" or "") are treated as object keys
|
||||
const bool nums = !reference_token.empty()
|
||||
&& (reference_token.size() == 1 || reference_token[0] != '0')
|
||||
&& std::all_of(reference_token.begin(), reference_token.end(),
|
||||
[](const unsigned char x)
|
||||
{
|
||||
return std::isdigit(x);
|
||||
});
|
||||
|
||||
// change value to an array for numbers or "-" or to object otherwise
|
||||
// change value to an array for array indices or "-" or to object otherwise
|
||||
*ptr = (nums || reference_token == "-")
|
||||
? detail::value_t::array
|
||||
: detail::value_t::object;
|
||||
@@ -17821,10 +17720,7 @@ class binary_writer
|
||||
bool prefix_required = true;
|
||||
if (use_type && !j.m_data.m_value.array->empty())
|
||||
{
|
||||
if (!use_count)
|
||||
{
|
||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||
}
|
||||
JSON_ASSERT(use_count);
|
||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
||||
[this, first_prefix, use_bjdata](const BasicJsonType & v)
|
||||
@@ -17870,10 +17766,7 @@ class binary_writer
|
||||
|
||||
if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty()))
|
||||
{
|
||||
if (!use_count)
|
||||
{
|
||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||
}
|
||||
JSON_ASSERT(use_count);
|
||||
oa->write_character(to_char_type('$'));
|
||||
oa->write_character(bjdata_draft3 ? 'B' : 'U');
|
||||
}
|
||||
@@ -17925,10 +17818,7 @@ class binary_writer
|
||||
bool prefix_required = true;
|
||||
if (use_type && !j.m_data.m_value.object->empty())
|
||||
{
|
||||
if (!use_count)
|
||||
{
|
||||
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||
}
|
||||
JSON_ASSERT(use_count);
|
||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
||||
[this, first_prefix, use_bjdata](const BasicJsonType & v)
|
||||
@@ -18676,15 +18566,6 @@ class binary_writer
|
||||
CharType dtype = it->second;
|
||||
|
||||
key = "_ArraySize_";
|
||||
// the dimensions are written verbatim as the header length below, so a
|
||||
// value that is not an array cannot produce a valid one: null emits 'Z'
|
||||
// and an object emits '{', neither of which a reader accepts after '#'.
|
||||
// Such an object is not a valid ndarray and falls back to a plain object.
|
||||
if (!value.at(key).is_array())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t len = (value.at(key).empty() ? 0 : 1);
|
||||
for (const auto& el : value.at(key))
|
||||
{
|
||||
@@ -18696,23 +18577,7 @@ class binary_writer
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// a dimension that does not fit into std::size_t, or a product that
|
||||
// overflows it, would wrap around and could match the size of
|
||||
// _ArrayData_ by accident; the resulting header announces an
|
||||
// element count that no reader can honor (the binary reader rejects
|
||||
// it with out_of_range.408), so encode as a plain object instead
|
||||
const auto dim = el.template get<std::uint64_t>();
|
||||
if (!value_in_range_of<std::size_t>(dim))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const auto dim_size = static_cast<std::size_t>(dim);
|
||||
if (dim_size != 0 && len > (std::numeric_limits<std::size_t>::max)() / dim_size)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
len *= dim_size;
|
||||
len *= static_cast<std::size_t>(el.template get<std::uint64_t>());
|
||||
}
|
||||
|
||||
key = "_ArrayData_";
|
||||
@@ -24944,10 +24809,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
if (merge_objects && it.value().is_object())
|
||||
{
|
||||
auto it2 = m_data.m_value.object->find(it.key());
|
||||
// Only recurse when the existing value is itself an object.
|
||||
// Otherwise overwrite, matching the documented "all other values
|
||||
// are overwritten as usual" behavior (see #5402).
|
||||
if (it2 != m_data.m_value.object->end() && it2->second.is_object())
|
||||
if (it2 != m_data.m_value.object->end())
|
||||
{
|
||||
it2->second.update(it.value(), true);
|
||||
#if JSON_DIAGNOSTICS
|
||||
@@ -25083,12 +24945,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
// note parentheses around operands are necessary; see
|
||||
// https://github.com/nlohmann/json/issues/1530
|
||||
// Mixed signed/unsigned integer comparisons check whether the signed value
|
||||
// is negative before casting. If it is, the comparison is performed with
|
||||
// the fixed values -1 and 1, which preserves the ordering relationship
|
||||
// because any negative signed value is smaller than any unsigned value.
|
||||
// Otherwise, the non-negative signed value is cast to unsigned before the
|
||||
// comparison to avoid wraparound.
|
||||
#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \
|
||||
const auto lhs_type = lhs.type(); \
|
||||
const auto rhs_type = rhs.type(); \
|
||||
@@ -25131,32 +24987,28 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
} \
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \
|
||||
{ \
|
||||
return (detail::compare_integer_with_float(lhs.m_data.m_value.number_integer, rhs.m_data.m_value.number_float)) op (static_cast<number_float_t>(0)); \
|
||||
return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \
|
||||
{ \
|
||||
return (static_cast<number_float_t>(0)) op (detail::compare_integer_with_float(rhs.m_data.m_value.number_integer, lhs.m_data.m_value.number_float)); \
|
||||
return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer); \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \
|
||||
{ \
|
||||
return (detail::compare_integer_with_float(lhs.m_data.m_value.number_unsigned, rhs.m_data.m_value.number_float)) op (static_cast<number_float_t>(0)); \
|
||||
return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \
|
||||
{ \
|
||||
return (static_cast<number_float_t>(0)) op (detail::compare_integer_with_float(rhs.m_data.m_value.number_unsigned, lhs.m_data.m_value.number_float)); \
|
||||
return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned); \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
|
||||
{ \
|
||||
return (rhs.m_data.m_value.number_integer < 0) \
|
||||
? (number_integer_t(1) op number_integer_t(-1)) \
|
||||
: (lhs.m_data.m_value.number_unsigned op static_cast<number_unsigned_t>(rhs.m_data.m_value.number_integer)); \
|
||||
return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \
|
||||
{ \
|
||||
return (lhs.m_data.m_value.number_integer < 0) \
|
||||
? (number_integer_t(-1) op number_integer_t(1)) \
|
||||
: (static_cast<number_unsigned_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \
|
||||
} \
|
||||
return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
|
||||
} \
|
||||
else if(compares_unordered(lhs, rhs))\
|
||||
{\
|
||||
return (unordered_result);\
|
||||
@@ -26556,17 +26408,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// We now reached the end of at least one array
|
||||
// in a second pass, traverse the remaining elements
|
||||
|
||||
// remove my remaining elements, highest index first; appending
|
||||
// in that order avoids the quadratic reinsertion done before
|
||||
for (std::size_t j = source.size(); j > i; --j)
|
||||
// remove my remaining elements
|
||||
const auto end_index = static_cast<difference_type>(result.size());
|
||||
while (i < source.size())
|
||||
{
|
||||
result.push_back(object(
|
||||
// add operations in reverse order to avoid invalid
|
||||
// indices
|
||||
result.insert(result.begin() + end_index, object(
|
||||
{
|
||||
{"op", "remove"},
|
||||
{"path", detail::concat<string_t>(path, '/', detail::to_string<string_t>(j - 1))}
|
||||
{"path", detail::concat<string_t>(path, '/', detail::to_string<string_t>(i))}
|
||||
}));
|
||||
++i;
|
||||
}
|
||||
i = source.size();
|
||||
|
||||
// add other remaining elements
|
||||
while (i < target.size())
|
||||
|
||||
@@ -177,24 +177,6 @@ json_test_add_test_for(src/unit-comparison.cpp
|
||||
MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force}
|
||||
)
|
||||
|
||||
# test the parser again with JSON_DIAGNOSTIC_POSITIONS enabled
|
||||
json_test_set_test_options(test-class_parser_diagnostic_positions
|
||||
COMPILE_DEFINITIONS JSON_DIAGNOSTIC_POSITIONS=1
|
||||
)
|
||||
json_test_add_test_for(src/unit-class_parser.cpp
|
||||
NAME test-class_parser_diagnostic_positions
|
||||
MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force}
|
||||
)
|
||||
|
||||
# test diagnostic positions again without regular diagnostics (JSON pointer paths)
|
||||
json_test_set_test_options(test-diagnostic-positions_only
|
||||
COMPILE_DEFINITIONS JSON_DIAGNOSTICS=0
|
||||
)
|
||||
json_test_add_test_for(src/unit-diagnostic-positions.cpp
|
||||
NAME test-diagnostic-positions_only
|
||||
MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force}
|
||||
)
|
||||
|
||||
# *DO NOT* use json_test_set_test_options() below this line
|
||||
|
||||
#############################################################################
|
||||
|
||||
@@ -2730,52 +2730,6 @@ TEST_CASE("BJData")
|
||||
CHECK(json::from_bjdata(json::to_bjdata(j_type), true, true) == j_type);
|
||||
CHECK(json::from_bjdata(json::to_bjdata(j_size), true, true) == j_size);
|
||||
}
|
||||
|
||||
SECTION("ndarray whose dimensions overflow stays as object")
|
||||
{
|
||||
// the product of the dimensions wraps around std::size_t to 0
|
||||
// and so matches the size of the empty _ArrayData_; writing this
|
||||
// as an ndarray would announce an element count no reader can
|
||||
// honor, so it has to stay a plain object
|
||||
json j_overflow = json({{"_ArrayData_", json::array()}, {"_ArraySize_", {9223372036854775808ull, 2}}, {"_ArrayType_", "uint8"}});
|
||||
CHECK(json::from_bjdata(json::to_bjdata(j_overflow), true, true) == j_overflow);
|
||||
|
||||
// a single dimension that does not fit into std::size_t is
|
||||
// rejected for the same reason (only observable where
|
||||
// std::size_t is narrower than 64 bit)
|
||||
json j_huge = json({{"_ArrayData_", json::array()}, {"_ArraySize_", {18446744073709551615ull}}, {"_ArrayType_", "uint8"}});
|
||||
CHECK(json::from_bjdata(json::to_bjdata(j_huge), true, true) == j_huge);
|
||||
|
||||
// a well-formed ndarray is still encoded as one
|
||||
json j_ok = json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "uint8"}});
|
||||
CHECK(json::to_bjdata(j_ok) == std::vector<uint8_t>({'[', '$', 'U', '#', '[', 'i', 2, 'i', 3, ']', 1, 2, 3, 4, 5, 6}));
|
||||
CHECK(json::from_bjdata(json::to_bjdata(j_ok), true, true) == j_ok);
|
||||
}
|
||||
|
||||
SECTION("ndarray whose _ArraySize_ is not an array stays as object")
|
||||
{
|
||||
// the shape is written verbatim as the header length, so a
|
||||
// value that is not an array cannot produce a valid one: null
|
||||
// would emit 'Z' and an object '{', neither of which a reader
|
||||
// accepts after '#'. Both have to stay plain objects.
|
||||
json const j_null = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", nullptr}, {"_ArrayData_", json::array()}});
|
||||
const auto out_null = json::to_bjdata(j_null);
|
||||
CHECK(out_null.at(0) == '{');
|
||||
CHECK(json::from_bjdata(out_null) == j_null);
|
||||
|
||||
// an object shape passes the per-entry check by iterating its
|
||||
// values rather than dimensions, so it needs rejecting too
|
||||
json const j_obj = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", {{"a", 1}}}, {"_ArrayData_", {1}}});
|
||||
const auto out_obj = json::to_bjdata(j_obj);
|
||||
CHECK(out_obj.at(0) == '{');
|
||||
CHECK(json::from_bjdata(out_obj) == j_obj);
|
||||
|
||||
// a scalar shape is not a dimension list either
|
||||
json const j_num = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", 1}, {"_ArrayData_", {1}}});
|
||||
const auto out_num = json::to_bjdata(j_num);
|
||||
CHECK(out_num.at(0) == '{');
|
||||
CHECK(json::from_bjdata(out_num) == j_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3868,48 +3822,6 @@ TEST_CASE("all BJData first bytes")
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("BJData use_type requires use_size")
|
||||
{
|
||||
SECTION("non-empty object throws other_error.502")
|
||||
{
|
||||
const json j = {{"a", 1}, {"b", 2}};
|
||||
CHECK_THROWS_WITH_AS(json::to_bjdata(j, false, true),
|
||||
"[json.exception.other_error.502] use_type requires use_size = true",
|
||||
json::other_error&);
|
||||
}
|
||||
|
||||
SECTION("non-empty array throws other_error.502")
|
||||
{
|
||||
const json j = {1, 2, 3};
|
||||
CHECK_THROWS_WITH_AS(json::to_bjdata(j, false, true),
|
||||
"[json.exception.other_error.502] use_type requires use_size = true",
|
||||
json::other_error&);
|
||||
}
|
||||
|
||||
SECTION("scalars do not throw with use_type=true, use_count=false")
|
||||
{
|
||||
CHECK_NOTHROW(json::to_bjdata(42, false, true));
|
||||
CHECK_NOTHROW(json::to_bjdata(3.14, false, true));
|
||||
CHECK_NOTHROW(json::to_bjdata("hello", false, true));
|
||||
CHECK_NOTHROW(json::to_bjdata(true, false, true));
|
||||
CHECK_NOTHROW(json::to_bjdata(nullptr, false, true));
|
||||
}
|
||||
|
||||
SECTION("empty containers do not throw with use_type=true, use_count=false")
|
||||
{
|
||||
CHECK_NOTHROW(json::to_bjdata(json::array(), false, true));
|
||||
CHECK_NOTHROW(json::to_bjdata(json::object(), false, true));
|
||||
}
|
||||
|
||||
SECTION("valid combinations on non-empty containers")
|
||||
{
|
||||
const json j = {{"a", 1}, {"b", 2}};
|
||||
CHECK_NOTHROW(json::to_bjdata(j, false, false));
|
||||
CHECK_NOTHROW(json::to_bjdata(j, true, false));
|
||||
CHECK_NOTHROW(json::to_bjdata(j, true, true));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("BJData roundtrips" * doctest::skip())
|
||||
{
|
||||
SECTION("input from self-generated BJData files")
|
||||
|
||||
+2
-13
@@ -2565,16 +2565,11 @@ TEST_CASE("Tagged values")
|
||||
const json j = "s";
|
||||
auto v = json::to_cbor(j);
|
||||
|
||||
const json j_bin_payload = json::binary(std::vector<std::uint8_t> {0x01, 0x02, 0x03});
|
||||
auto v_bin_payload = json::to_cbor(j_bin_payload);
|
||||
|
||||
SECTION("0xC0..0xD7")
|
||||
SECTION("0xC6..0xD4")
|
||||
{
|
||||
for (const auto b : std::vector<std::uint8_t>
|
||||
{
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5,
|
||||
0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
|
||||
0xD5, 0xD6, 0xD7
|
||||
0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4
|
||||
})
|
||||
{
|
||||
CAPTURE(b);
|
||||
@@ -2594,12 +2589,6 @@ TEST_CASE("Tagged values")
|
||||
|
||||
auto j_tagged_stored = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::store);
|
||||
CHECK(j_tagged_stored == j);
|
||||
|
||||
auto v_binary_tagged = v_bin_payload;
|
||||
v_binary_tagged.insert(v_binary_tagged.begin(), b);
|
||||
auto j_binary_tagged_stored = json::from_cbor(v_binary_tagged, true, true, json::cbor_tag_handler_t::store);
|
||||
CHECK(j_binary_tagged_stored == j_bin_payload);
|
||||
CHECK(!j_binary_tagged_stored.get_binary().has_subtype());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ using nlohmann::json;
|
||||
|
||||
#include <valarray>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -346,50 +344,6 @@ void trailing_comma_helper(const std::string& s)
|
||||
}
|
||||
}
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
/**
|
||||
* Validates that the generated JSON object is the same as expected
|
||||
* Validates that the start position and end position match the start and end of the string
|
||||
*
|
||||
* This check assumes that there is no whitespace around the json object in the original string.
|
||||
*/
|
||||
void validate_generated_json_and_start_end_pos_helper(const std::string& original_string, const json& j, const json& check)
|
||||
{
|
||||
CHECK(j == check);
|
||||
CHECK(j.start_pos() == 0);
|
||||
CHECK(j.end_pos() == original_string.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the root object from the given root string and validates that the start and end positions for the nested object are correct.
|
||||
*
|
||||
* This checks that whitespace around the nested object is included in the start and end positions of the root object.
|
||||
*/
|
||||
void validate_start_end_pos_for_nested_obj_helper(const std::string& nested_type_json_str, const std::string& root_type_json_str, const json& expected_json, const json::parser_callback_t& cb = nullptr)
|
||||
{
|
||||
json j;
|
||||
|
||||
// 1. If callback is provided, use callback version of parse()
|
||||
if (cb)
|
||||
{
|
||||
j = json::parse(root_type_json_str, cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
j = json::parse(root_type_json_str);
|
||||
}
|
||||
|
||||
// 2. Check if the generated JSON is as expected
|
||||
// Assumptions: The root_type_json_str does not have any whitespace around the json object
|
||||
validate_generated_json_and_start_end_pos_helper(root_type_json_str, j, expected_json);
|
||||
|
||||
// 3. Get the nested object
|
||||
const auto& nested = j["nested"];
|
||||
// 4. Check if the start and end positions are generated correctly for nested objects and arrays
|
||||
CHECK(nested_type_json_str == root_type_json_str.substr(nested.start_pos(), nested.end_pos() - nested.start_pos()));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("parser class")
|
||||
@@ -1825,228 +1779,6 @@ TEST_CASE("parser class")
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse("/a", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid comment; expecting '/' or '*' after '/'; last read: '/a'", json::parse_error);
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse("/*", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid comment; missing closing '*/'; last read: '/*<U+0000>'", json::parse_error);
|
||||
}
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// Macro for all test cases for start_pos and end_pos
|
||||
#define SETUP_TESTCASES() \
|
||||
SECTION("with callback") \
|
||||
{ \
|
||||
SECTION("filter nothing") \
|
||||
{ \
|
||||
json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept \
|
||||
{ \
|
||||
return true; \
|
||||
}; \
|
||||
validate_start_end_pos_for_nested_obj_helper(nested_type_json_str, root_type_json_str, expected, cb); \
|
||||
} \
|
||||
SECTION("filter element") \
|
||||
{ \
|
||||
json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t event, json& j) noexcept \
|
||||
{ \
|
||||
return (event != json::parse_event_t::key && event != json::parse_event_t::value) || j != json("a"); \
|
||||
}; \
|
||||
validate_start_end_pos_for_nested_obj_helper(nested_type_json_str, root_type_json_str, filteredExpected, cb); \
|
||||
} \
|
||||
} \
|
||||
SECTION("without callback") \
|
||||
{ \
|
||||
validate_start_end_pos_for_nested_obj_helper(nested_type_json_str, root_type_json_str, expected); \
|
||||
}
|
||||
|
||||
SECTION("retrieve start position and end position")
|
||||
{
|
||||
SECTION("for object")
|
||||
{
|
||||
// Create an object with spaces to test the start and end positions. Spaces will not be included in the
|
||||
// JSON object, however, the start and end positions should include the spaces from the input JSON string.
|
||||
const std::string nested_type_json_str = R"({ "a": 1,"b" : "test1"})";
|
||||
const std::string root_type_json_str = R"({ "nested": )" + nested_type_json_str + R"(, "anotherValue": "test2"})";
|
||||
auto expected = json({{"nested", {{"a", 1}, {"b", "test1"}}}, {"anotherValue", "test2"}});
|
||||
auto filteredExpected = expected;
|
||||
filteredExpected["nested"].erase("a");
|
||||
|
||||
SETUP_TESTCASES()
|
||||
}
|
||||
|
||||
SECTION("for array")
|
||||
{
|
||||
const std::string nested_type_json_str = R"(["a", "test", 45])";
|
||||
const std::string root_type_json_str = R"({ "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })";
|
||||
auto expected = json({{"nested", {"a", "test", 45}}, {"anotherValue", "test"}});
|
||||
auto filteredExpected = expected;
|
||||
filteredExpected["nested"] = json({"test", 45});
|
||||
SETUP_TESTCASES()
|
||||
}
|
||||
|
||||
SECTION("for array with objects")
|
||||
{
|
||||
const std::string nested_type_json_str = R"([{"a": 1, "b": "test"}, {"c": 2, "d": "test2"}])";
|
||||
const std::string root_type_json_str = R"({ "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })";
|
||||
auto expected = json({{"nested", {{{"a", 1}, {"b", "test"}}, {{"c", 2}, {"d", "test2"}}}}, {"anotherValue", "test"}});
|
||||
auto filteredExpected = expected;
|
||||
filteredExpected["nested"][0].erase("a");
|
||||
SETUP_TESTCASES()
|
||||
|
||||
auto j = json::parse(root_type_json_str);
|
||||
auto nested_array = j["nested"];
|
||||
const auto& nested_obj = nested_array[0];
|
||||
CHECK(nested_type_json_str.substr(1, 21) == root_type_json_str.substr(nested_obj.start_pos(), nested_obj.end_pos() - nested_obj.start_pos()));
|
||||
CHECK(nested_type_json_str.substr(24, 22) == root_type_json_str.substr(nested_array[1].start_pos(), nested_array[1].end_pos() - nested_array[1].start_pos()));
|
||||
}
|
||||
|
||||
SECTION("for two levels of nesting objects")
|
||||
{
|
||||
const std::string nested_type_json_str = R"({"nested2": {"b": "test"}})";
|
||||
const std::string root_type_json_str = R"({ "a": 2, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })";
|
||||
auto expected = json({{"a", 2}, {"nested", {{"nested2", {{"b", "test"}}}}}, {"anotherValue", "test"}});
|
||||
auto filteredExpected = expected;
|
||||
filteredExpected.erase("a");
|
||||
SETUP_TESTCASES()
|
||||
|
||||
auto j = json::parse(root_type_json_str);
|
||||
auto nested_obj = j["nested"]["nested2"];
|
||||
CHECK(nested_type_json_str.substr(12, 13) == root_type_json_str.substr(nested_obj.start_pos(), nested_obj.end_pos() - nested_obj.start_pos()));
|
||||
}
|
||||
|
||||
SECTION("for simple types")
|
||||
{
|
||||
SECTION("no nested")
|
||||
{
|
||||
SECTION("with callback")
|
||||
{
|
||||
json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
// 1. string type
|
||||
std::string json_str = R"("test")";
|
||||
auto j = json::parse(json_str, cb);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, "test");
|
||||
|
||||
// 2. number type
|
||||
json_str = R"(1)";
|
||||
j = json::parse(json_str, cb);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, 1);
|
||||
|
||||
// 3. boolean type
|
||||
json_str = R"(true)";
|
||||
j = json::parse(json_str, cb);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, true);
|
||||
|
||||
// 4. null type
|
||||
json_str = R"(null)";
|
||||
j = json::parse(json_str, cb);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, nullptr);
|
||||
}
|
||||
|
||||
SECTION("without callback")
|
||||
{
|
||||
// 1. string type
|
||||
std::string json_str = R"("test")";
|
||||
auto j = json::parse(json_str);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, "test");
|
||||
|
||||
// 2. number type
|
||||
json_str = R"(1)";
|
||||
j = json::parse(json_str);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, 1);
|
||||
|
||||
json_str = R"(1.001239923)";
|
||||
j = json::parse(json_str);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, 1.001239923);
|
||||
|
||||
json_str = R"(1.123812389000000)";
|
||||
j = json::parse(json_str);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, 1.123812389);
|
||||
|
||||
// 3. boolean type
|
||||
json_str = R"(true)";
|
||||
j = json::parse(json_str);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, true);
|
||||
|
||||
json_str = R"(false)";
|
||||
j = json::parse(json_str);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, false);
|
||||
|
||||
// 4. null type
|
||||
json_str = R"(null)";
|
||||
j = json::parse(json_str);
|
||||
validate_generated_json_and_start_end_pos_helper(json_str, j, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string type")
|
||||
{
|
||||
const std::string nested_type_json_str = R"("test")";
|
||||
const std::string root_type_json_str = R"({ "a": 1, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })";
|
||||
auto expected = json({{"nested", "test"}, {"anotherValue", "test"}, {"a", 1}});
|
||||
auto filteredExpected = expected;
|
||||
filteredExpected.erase("a");
|
||||
SETUP_TESTCASES()
|
||||
}
|
||||
|
||||
SECTION("number type")
|
||||
{
|
||||
const std::string nested_type_json_str = R"(2)";
|
||||
const std::string root_type_json_str = R"({ "a": 1, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })";
|
||||
auto expected = json({{"nested", 2}, {"anotherValue", "test"}, {"a", 1}});
|
||||
auto filteredExpected = expected;
|
||||
filteredExpected.erase("a");
|
||||
SETUP_TESTCASES()
|
||||
}
|
||||
|
||||
SECTION("boolean type")
|
||||
{
|
||||
const std::string nested_type_json_str = R"(true)";
|
||||
const std::string root_type_json_str = R"({ "a": 1, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })";
|
||||
auto expected = json({{"nested", true}, {"anotherValue", "test"}, {"a", 1}});
|
||||
auto filteredExpected = expected;
|
||||
filteredExpected.erase("a");
|
||||
SETUP_TESTCASES()
|
||||
}
|
||||
|
||||
SECTION("null type")
|
||||
{
|
||||
const std::string nested_type_json_str = R"(null)";
|
||||
const std::string root_type_json_str = R"({ "a": 1, "nested": )" + nested_type_json_str + R"(, "anotherValue": "test" })";
|
||||
auto expected = json({{"nested", nullptr}, {"anotherValue", "test"}, {"a", 1}});
|
||||
auto filteredExpected = expected;
|
||||
filteredExpected.erase("a");
|
||||
SETUP_TESTCASES()
|
||||
}
|
||||
}
|
||||
SECTION("with leading whitespace and newlines around root JSON")
|
||||
{
|
||||
const std::string initial_whitespace = R"(
|
||||
|
||||
)";
|
||||
const std::string nested_type_json_str = R"({
|
||||
"a": 1,
|
||||
"nested": {
|
||||
"b": "test"
|
||||
},
|
||||
"anotherValue": "test"
|
||||
})";
|
||||
const std::string end_whitespace = R"(
|
||||
|
||||
)";
|
||||
const std::string root_type_json_str = initial_whitespace + nested_type_json_str + end_whitespace;
|
||||
|
||||
auto expected = json({{"a", 1}, {"nested", {{"b", "test"}}}, {"anotherValue", "test"}});
|
||||
|
||||
auto j = json::parse(root_type_json_str);
|
||||
|
||||
// 2. Check if the generated JSON is as expected
|
||||
CHECK(j == expected);
|
||||
|
||||
// 3. Check if the start and end positions do not include the surrounding whitespace
|
||||
CHECK(j.start_pos() == initial_whitespace.size());
|
||||
CHECK(j.end_pos() == root_type_json_str.size() - end_whitespace.size());
|
||||
}
|
||||
}
|
||||
#undef SETUP_TESTCASES
|
||||
#endif
|
||||
}
|
||||
|
||||
// this test relies on parse errors being thrown, so it is skipped when
|
||||
@@ -2155,321 +1887,3 @@ TEST_CASE("last-read diagnostics are identical across input adapters")
|
||||
}
|
||||
}
|
||||
#endif // !defined(JSON_NOEXCEPTION)
|
||||
|
||||
// this test characterizes the current (documented-by-example, not otherwise
|
||||
// specified) behavior of JSON_DIAGNOSTIC_POSITIONS positions with respect to
|
||||
// value lifetime (copy/move/swap/mutation), the various input adapters, and
|
||||
// user-driven SAX usage. It is regression protection, not a behavior
|
||||
// specification: if any of these checks fail after a change to json.hpp,
|
||||
// that change deliberately altered observable behavior and the test (and
|
||||
// this comment) should be updated accordingly, rather than "fixed" blindly.
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
TEST_CASE("diagnostic positions: value lifetime, input adapters, and SAX")
|
||||
{
|
||||
SECTION("value lifetime")
|
||||
{
|
||||
SECTION("copy constructor copies positions, recursively")
|
||||
{
|
||||
// basic_json(const basic_json&) (json.hpp, around line 1192) copies
|
||||
// start_position/end_position for the value itself; nested values
|
||||
// are copied via their own copy constructor (through the copied
|
||||
// object/array container), so positions are preserved throughout
|
||||
// the whole tree.
|
||||
const std::string s = R"({"a":1,"b":[1,2,3]})";
|
||||
const json a = json::parse(s);
|
||||
const json b = a; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
|
||||
CHECK(b.start_pos() == a.start_pos());
|
||||
CHECK(b.end_pos() == a.end_pos());
|
||||
CHECK(b["b"].start_pos() == a["b"].start_pos());
|
||||
CHECK(b["b"].end_pos() == a["b"].end_pos());
|
||||
CHECK(b["b"][0].start_pos() == a["b"][0].start_pos());
|
||||
CHECK(b["b"][0].end_pos() == a["b"][0].end_pos());
|
||||
|
||||
// sanity: the positions are meaningful (not all npos)
|
||||
CHECK(b.start_pos() == 0);
|
||||
CHECK(b.end_pos() == s.size());
|
||||
}
|
||||
|
||||
SECTION("move constructor resets the moved-from value to npos")
|
||||
{
|
||||
// basic_json(basic_json&&) (json.hpp, around line 1265) copies
|
||||
// other's start_position/end_position into *this and then resets
|
||||
// other's to npos (see the cppcheck-suppress[accessForwarded]
|
||||
// annotation there, which flags this reset as worth a second
|
||||
// look). Only the top-level moved-from value is affected; its
|
||||
// (moved-away) children are gone along with it.
|
||||
const std::string s = R"({"a":1,"b":[1,2,3]})";
|
||||
json a = json::parse(s);
|
||||
const auto a_start = a.start_pos();
|
||||
const auto a_end = a.end_pos();
|
||||
const auto nested_start = a["b"].start_pos();
|
||||
const auto nested_end = a["b"].end_pos();
|
||||
|
||||
const json b(std::move(a));
|
||||
|
||||
// the destination retains the original positions, recursively
|
||||
CHECK(b.start_pos() == a_start);
|
||||
CHECK(b.end_pos() == a_end);
|
||||
CHECK(b["b"].start_pos() == nested_start);
|
||||
CHECK(b["b"].end_pos() == nested_end);
|
||||
|
||||
// the moved-from value is reset to a null and reports npos
|
||||
CHECK(a.is_null()); // NOLINT(bugprone-use-after-move,clang-analyzer-cplusplus.Move)
|
||||
CHECK(a.start_pos() == std::string::npos); // NOLINT(bugprone-use-after-move,clang-analyzer-cplusplus.Move)
|
||||
CHECK(a.end_pos() == std::string::npos); // NOLINT(bugprone-use-after-move,clang-analyzer-cplusplus.Move)
|
||||
}
|
||||
|
||||
SECTION("swap() does NOT exchange positions (likely a real bug, see below)")
|
||||
{
|
||||
// NOTE (characterizing, not fixing, for #5420): basic_json::swap()
|
||||
// (json.hpp, around line 3540, and the friend swap() that forwards
|
||||
// to it) swaps m_data.m_type and m_data.m_value but -- unlike
|
||||
// copy-assignment's operator=(basic_json) (json.hpp, around line
|
||||
// 1291), which swaps start_position/end_position as part of its
|
||||
// copy-and-swap implementation -- it never touches
|
||||
// start_position/end_position. So after swap(a, b), the *values*
|
||||
// of a and b are exchanged, but their *positions* are not: each
|
||||
// ends up with its own original position describing the other's
|
||||
// new content. This looks like an oversight/inconsistency rather
|
||||
// than intended behavior, and is flagged to the maintainer; this
|
||||
// test only pins the current (surprising) behavior so a fix (or a
|
||||
// deliberate decision to keep it) shows up here as an intentional
|
||||
// change rather than a silent regression.
|
||||
json a = json::parse(R"({"a":1})");
|
||||
json b = json::parse(R"([1,2,3,4,5])");
|
||||
const auto a_start = a.start_pos();
|
||||
const auto a_end = a.end_pos();
|
||||
const auto b_start = b.start_pos();
|
||||
const auto b_end = b.end_pos();
|
||||
// both start at 0 (root values start right away), but their
|
||||
// lengths (and thus end positions) differ, which is enough to
|
||||
// tell after the swap whether positions actually moved with
|
||||
// the values
|
||||
CHECK(a_end != b_end);
|
||||
|
||||
using std::swap;
|
||||
swap(a, b);
|
||||
|
||||
// values were exchanged as expected ...
|
||||
CHECK(a == json::parse(R"([1,2,3,4,5])"));
|
||||
CHECK(b == json::parse(R"({"a":1})"));
|
||||
|
||||
// ... but positions were NOT: each variable kept its own
|
||||
// original position, now describing the other's content
|
||||
CHECK(a.start_pos() == a_start);
|
||||
CHECK(a.end_pos() == a_end);
|
||||
CHECK(b.start_pos() == b_start);
|
||||
CHECK(b.end_pos() == b_end);
|
||||
}
|
||||
|
||||
SECTION("mutating a parsed document leaves positions of unrelated values untouched")
|
||||
{
|
||||
// Positions are recorded once, during parsing, and are not
|
||||
// recomputed on mutation. As a consequence, after a mutation the
|
||||
// parent's own recorded span may no longer describe its current
|
||||
// (serialized) content -- it still describes what was originally
|
||||
// parsed. This is characterized here as current behavior, not
|
||||
// asserted to be desirable or specified.
|
||||
SECTION("operator[] adding a new object key")
|
||||
{
|
||||
const std::string s = R"({"a":1})";
|
||||
json j = json::parse(s);
|
||||
const auto root_start = j.start_pos();
|
||||
const auto root_end = j.end_pos();
|
||||
const auto a_start = j["a"].start_pos();
|
||||
const auto a_end = j["a"].end_pos();
|
||||
|
||||
j["c"] = 42;
|
||||
|
||||
// the newly-added value was never parsed, so it has no position
|
||||
CHECK(j["c"].start_pos() == std::string::npos);
|
||||
CHECK(j["c"].end_pos() == std::string::npos);
|
||||
|
||||
// the existing sibling's position is unaffected
|
||||
CHECK(j["a"].start_pos() == a_start);
|
||||
CHECK(j["a"].end_pos() == a_end);
|
||||
|
||||
// the parent's own recorded span is left as-is (now stale:
|
||||
// it still reflects the original, shorter `{"a":1}` string)
|
||||
CHECK(j.start_pos() == root_start);
|
||||
CHECK(j.end_pos() == root_end);
|
||||
}
|
||||
|
||||
SECTION("push_back on a parsed array")
|
||||
{
|
||||
const std::string s = R"([1,2,3])";
|
||||
json j = json::parse(s);
|
||||
const auto root_start = j.start_pos();
|
||||
const auto root_end = j.end_pos();
|
||||
const auto first_start = j[0].start_pos();
|
||||
|
||||
j.push_back(4);
|
||||
|
||||
CHECK(j.back().start_pos() == std::string::npos);
|
||||
CHECK(j.back().end_pos() == std::string::npos);
|
||||
CHECK(j[0].start_pos() == first_start);
|
||||
CHECK(j.start_pos() == root_start);
|
||||
CHECK(j.end_pos() == root_end);
|
||||
}
|
||||
|
||||
SECTION("erase on a parsed array shifts elements but keeps their own positions")
|
||||
{
|
||||
const std::string s = R"([1,2,3])";
|
||||
json j = json::parse(s);
|
||||
const auto second_start = j[1].start_pos();
|
||||
const auto third_start = j[2].start_pos();
|
||||
const auto root_start = j.start_pos();
|
||||
const auto root_end = j.end_pos();
|
||||
|
||||
j.erase(0);
|
||||
|
||||
// remaining elements moved down an index, but each one still
|
||||
// reports the position it had *before* the erase (i.e. its
|
||||
// position in the original source string, not a
|
||||
// recalculated one)
|
||||
CHECK(j[0].start_pos() == second_start);
|
||||
CHECK(j[1].start_pos() == third_start);
|
||||
|
||||
// the parent's own recorded span is again left as-is
|
||||
CHECK(j.start_pos() == root_start);
|
||||
CHECK(j.end_pos() == root_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("input adapters")
|
||||
{
|
||||
SECTION("wide string input: positions count transcoded UTF-8 bytes, not wide characters")
|
||||
{
|
||||
// 'é' (U+00E9) is a single code unit in a wchar_t/UTF-16 string, but
|
||||
// transcodes to 2 bytes in UTF-8; the lexer only ever sees the
|
||||
// transcoded UTF-8 byte stream, so reported positions are byte
|
||||
// offsets into that UTF-8 stream, not indices into the original
|
||||
// std::wstring.
|
||||
// é (rather than a literal 'é' byte sequence in this source
|
||||
// file) so the wide-string literal's meaning does not depend on
|
||||
// the compiler's assumed source character set (MSVC, without
|
||||
// /utf-8, would otherwise decode the raw UTF-8 bytes using the
|
||||
// system code page instead of as UTF-8)
|
||||
const std::wstring ws = L"{\"a\":\"\u00e9\u00e9\"}";
|
||||
CHECK(ws.size() == 10); // 10 wide characters
|
||||
|
||||
const json j = json::parse(ws);
|
||||
CHECK(j.start_pos() == 0);
|
||||
// the transcoded UTF-8 form is 2 bytes longer than the wide string,
|
||||
// because each of the two 'é' characters becomes 2 UTF-8 bytes
|
||||
CHECK(j.end_pos() == 12);
|
||||
CHECK(j.end_pos() != ws.size());
|
||||
|
||||
const json& a = j["a"];
|
||||
CHECK(a.start_pos() == 5);
|
||||
CHECK(a.end_pos() == 11);
|
||||
}
|
||||
|
||||
SECTION("BOM-prefixed input: start_pos() reflects the skipped 3-byte BOM")
|
||||
{
|
||||
const std::string s = "\xEF\xBB\xBF{\"a\":1}";
|
||||
const json j = json::parse(s);
|
||||
|
||||
// the lexer silently skips the BOM before parsing the value, so
|
||||
// the root value's recorded span starts right after it
|
||||
CHECK(j.start_pos() == 3);
|
||||
CHECK(j.end_pos() == s.size());
|
||||
}
|
||||
|
||||
SECTION("std::istringstream: positions are consistent, not npos")
|
||||
{
|
||||
const std::string s = R"({"a":1,"b":2})";
|
||||
std::istringstream ss(s);
|
||||
const json j = json::parse(ss);
|
||||
|
||||
CHECK(j.start_pos() == 0);
|
||||
CHECK(j.end_pos() == s.size());
|
||||
CHECK(j["a"].start_pos() == 5);
|
||||
}
|
||||
|
||||
SECTION("std::ifstream: positions are consistent, not npos")
|
||||
{
|
||||
const std::string s = R"({"a":1,"b":2})";
|
||||
{
|
||||
std::ofstream file("unit-class_parser_diagnostic_positions.tmp");
|
||||
file << s;
|
||||
}
|
||||
|
||||
{
|
||||
std::ifstream f("unit-class_parser_diagnostic_positions.tmp");
|
||||
const json j = json::parse(f);
|
||||
|
||||
CHECK(j.start_pos() == 0);
|
||||
CHECK(j.end_pos() == s.size());
|
||||
CHECK(j["a"].start_pos() == 5);
|
||||
}
|
||||
|
||||
static_cast<void>(std::remove("unit-class_parser_diagnostic_positions.tmp"));
|
||||
}
|
||||
|
||||
SECTION("iterator-pair input: positions are consistent, not npos")
|
||||
{
|
||||
const std::string s = R"({"a":1,"b":2})";
|
||||
const json j = json::parse(s.begin(), s.end());
|
||||
|
||||
CHECK(j.start_pos() == 0);
|
||||
CHECK(j.end_pos() == s.size());
|
||||
CHECK(j["a"].start_pos() == 5);
|
||||
}
|
||||
|
||||
SECTION("binary formats have no text positions")
|
||||
{
|
||||
// binary formats (CBOR, MessagePack, UBJSON, BSON, BJData) are
|
||||
// parsed via detail::binary_reader, which never sets
|
||||
// start_position/end_position on the values it produces (they
|
||||
// have no notion of a text offset), so every value's position
|
||||
// stays at its default of npos.
|
||||
const json src = json::parse(R"({"a":1,"b":[1,2]})");
|
||||
|
||||
const json from_cbor = json::from_cbor(json::to_cbor(src));
|
||||
CHECK(from_cbor.start_pos() == std::string::npos);
|
||||
CHECK(from_cbor.end_pos() == std::string::npos);
|
||||
CHECK(from_cbor["a"].start_pos() == std::string::npos);
|
||||
CHECK(from_cbor["b"][0].start_pos() == std::string::npos);
|
||||
|
||||
const json from_msgpack = json::from_msgpack(json::to_msgpack(src));
|
||||
CHECK(from_msgpack.start_pos() == std::string::npos);
|
||||
CHECK(from_msgpack.end_pos() == std::string::npos);
|
||||
|
||||
const json from_ubjson = json::from_ubjson(json::to_ubjson(src));
|
||||
CHECK(from_ubjson.start_pos() == std::string::npos);
|
||||
CHECK(from_ubjson.end_pos() == std::string::npos);
|
||||
|
||||
const json from_bson_val = json::from_bson(json::to_bson(src));
|
||||
CHECK(from_bson_val.start_pos() == std::string::npos);
|
||||
CHECK(from_bson_val.end_pos() == std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("user-driven SAX consumers with no lexer report npos")
|
||||
{
|
||||
// json::parse() internally wires up its json_sax_dom_parser with a
|
||||
// pointer to its own lexer (see parser.hpp), which is how positions
|
||||
// get set at all. A user who constructs a json_sax_dom_parser
|
||||
// directly (e.g. to drive it via json::sax_parse()) and does not
|
||||
// supply a lexer pointer gets a consumer with m_lexer_ref == nullptr;
|
||||
// every "if (m_lexer_ref)" guard in json_sax.hpp is then skipped, so
|
||||
// every value it produces keeps its default, unset position (npos).
|
||||
// This was previously true but silently unasserted (operator==
|
||||
// ignores positions), see #5420.
|
||||
json result;
|
||||
nlohmann::detail::json_sax_dom_parser<json, nlohmann::detail::string_input_adapter_type> sdp(result);
|
||||
const std::string s = R"({"a":1,"b":[1,2,3]})";
|
||||
CHECK(json::sax_parse(s, &sdp));
|
||||
|
||||
CHECK(result.start_pos() == std::string::npos);
|
||||
CHECK(result.end_pos() == std::string::npos);
|
||||
CHECK(result["a"].start_pos() == std::string::npos);
|
||||
CHECK(result["a"].end_pos() == std::string::npos);
|
||||
CHECK(result["b"][0].start_pos() == std::string::npos);
|
||||
CHECK(result["b"][0].end_pos() == std::string::npos);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
@@ -257,126 +255,6 @@ TEST_CASE("lexicographical comparison operators")
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21
|
||||
};
|
||||
|
||||
SECTION("signed/unsigned mixed comparison above INT64_MAX")
|
||||
{
|
||||
const json above_int64_max = static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()) + 1ULL;
|
||||
const json max_uint64 = (std::numeric_limits<std::uint64_t>::max)();
|
||||
const json negative_one = -1;
|
||||
const json one = 1;
|
||||
const json max_int64 = (std::numeric_limits<std::int64_t>::max)();
|
||||
|
||||
CHECK_FALSE(above_int64_max == negative_one);
|
||||
CHECK(above_int64_max != negative_one);
|
||||
CHECK(negative_one < above_int64_max);
|
||||
CHECK(negative_one <= above_int64_max);
|
||||
CHECK_FALSE(negative_one > above_int64_max);
|
||||
CHECK_FALSE(negative_one >= above_int64_max);
|
||||
CHECK_FALSE(above_int64_max < negative_one);
|
||||
CHECK_FALSE(above_int64_max <= negative_one);
|
||||
CHECK(above_int64_max > negative_one);
|
||||
CHECK(above_int64_max >= negative_one);
|
||||
CHECK(negative_one != above_int64_max);
|
||||
CHECK_FALSE(negative_one == above_int64_max);
|
||||
|
||||
CHECK_FALSE(max_uint64 == negative_one);
|
||||
CHECK(max_uint64 != negative_one);
|
||||
CHECK(negative_one < max_uint64);
|
||||
CHECK(negative_one <= max_uint64);
|
||||
CHECK_FALSE(negative_one > max_uint64);
|
||||
CHECK_FALSE(negative_one >= max_uint64);
|
||||
CHECK_FALSE(max_uint64 < negative_one);
|
||||
CHECK_FALSE(max_uint64 <= negative_one);
|
||||
CHECK(max_uint64 > negative_one);
|
||||
CHECK(max_uint64 >= negative_one);
|
||||
CHECK(negative_one != max_uint64);
|
||||
CHECK_FALSE(negative_one == max_uint64);
|
||||
|
||||
CHECK_FALSE(one == above_int64_max);
|
||||
CHECK(one != above_int64_max);
|
||||
CHECK(one < above_int64_max);
|
||||
CHECK(one <= above_int64_max);
|
||||
CHECK_FALSE(one > above_int64_max);
|
||||
CHECK_FALSE(one >= above_int64_max);
|
||||
CHECK_FALSE(above_int64_max < one);
|
||||
CHECK_FALSE(above_int64_max <= one);
|
||||
CHECK(above_int64_max > one);
|
||||
CHECK(above_int64_max >= one);
|
||||
|
||||
CHECK_FALSE(max_int64 == above_int64_max);
|
||||
CHECK(max_int64 != above_int64_max);
|
||||
CHECK(max_int64 < above_int64_max);
|
||||
CHECK(max_int64 <= above_int64_max);
|
||||
CHECK_FALSE(max_int64 > above_int64_max);
|
||||
CHECK_FALSE(max_int64 >= above_int64_max);
|
||||
CHECK_FALSE(above_int64_max < max_int64);
|
||||
CHECK_FALSE(above_int64_max <= max_int64);
|
||||
CHECK(above_int64_max > max_int64);
|
||||
CHECK(above_int64_max >= max_int64);
|
||||
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
||||
CHECK((negative_one <=> above_int64_max) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((above_int64_max <=> negative_one) == std::partial_ordering::greater); // *NOPAD*
|
||||
CHECK((negative_one <=> max_uint64) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((max_uint64 <=> negative_one) == std::partial_ordering::greater); // *NOPAD*
|
||||
CHECK((one <=> above_int64_max) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((above_int64_max <=> one) == std::partial_ordering::greater); // *NOPAD*
|
||||
CHECK((max_int64 <=> above_int64_max) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((above_int64_max <=> max_int64) == std::partial_ordering::greater); // *NOPAD*
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("integer/float mixed comparison is exact")
|
||||
{
|
||||
// Widening the integer to a double loses precision past the
|
||||
// mantissa, so 2^63-2 and 2^63-1 both used to compare equal to the
|
||||
// double 2^63 while differing from each other. That makes equality
|
||||
// intransitive and the ordering not a strict weak ordering.
|
||||
const json below_two_63 = static_cast<std::int64_t>(9223372036854775806LL);
|
||||
const json max_int64 = (std::numeric_limits<std::int64_t>::max)();
|
||||
const json two_63 = 9223372036854775808.0;
|
||||
|
||||
CHECK_FALSE(below_two_63 == two_63);
|
||||
CHECK_FALSE(max_int64 == two_63);
|
||||
CHECK(below_two_63 != max_int64);
|
||||
CHECK(below_two_63 < max_int64);
|
||||
CHECK(below_two_63 < two_63);
|
||||
CHECK(max_int64 < two_63);
|
||||
CHECK(two_63 > max_int64);
|
||||
CHECK_FALSE(two_63 < max_int64);
|
||||
|
||||
// the same past the unsigned range
|
||||
const json max_uint64 = (std::numeric_limits<std::uint64_t>::max)();
|
||||
const json two_64 = 18446744073709551616.0;
|
||||
CHECK_FALSE(max_uint64 == two_64);
|
||||
CHECK(max_uint64 < two_64);
|
||||
CHECK(two_64 > max_uint64);
|
||||
|
||||
// values a double represents exactly still compare equal
|
||||
CHECK(json(1) == json(1.0));
|
||||
CHECK(json(1u) == json(1.0));
|
||||
CHECK(json(-3) == json(-3.0));
|
||||
CHECK(json(1) < json(1.5));
|
||||
CHECK(json(1.5) < json(2));
|
||||
CHECK(json(2) > json(1.5));
|
||||
|
||||
// a NaN operand stays unordered against either integer kind
|
||||
CHECK_FALSE(json(1) == json(nan));
|
||||
CHECK_FALSE(json(1) < json(nan));
|
||||
CHECK_FALSE(json(nan) < json(1));
|
||||
CHECK_FALSE(json(1u) == json(nan));
|
||||
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
||||
CHECK((max_int64 <=> two_63) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((two_63 <=> max_int64) == std::partial_ordering::greater); // *NOPAD*
|
||||
CHECK((below_two_63 <=> max_int64) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((max_uint64 <=> two_64) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((json(1) <=> json(1.0)) == std::partial_ordering::equivalent); // *NOPAD*
|
||||
CHECK((json(1) <=> json(nan)) == std::partial_ordering::unordered); // *NOPAD*
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("compares unordered")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#ifdef JSON_DIAGNOSTICS
|
||||
#undef JSON_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 1
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
TEST_CASE("Better diagnostics with positions only")
|
||||
{
|
||||
SECTION("invalid type")
|
||||
{
|
||||
const std::string json_invalid_string = R"(
|
||||
{
|
||||
"address": {
|
||||
"street": "Fake Street",
|
||||
"housenumber": "1"
|
||||
}
|
||||
}
|
||||
)";
|
||||
json j = json::parse(json_invalid_string);
|
||||
CHECK_THROWS_WITH_AS(j.at("address").at("housenumber").get<int>(),
|
||||
"[json.exception.type_error.302] (bytes 108-111) type must be number, but is string", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("invalid type without positions")
|
||||
{
|
||||
const json j = "foo";
|
||||
CHECK_THROWS_WITH_AS(j.get<int>(),
|
||||
"[json.exception.type_error.302] type must be number, but is string", json::type_error);
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,7 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#ifndef JSON_DIAGNOSTICS
|
||||
#define JSON_DIAGNOSTICS 1
|
||||
#endif
|
||||
#define JSON_DIAGNOSTICS 1
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 1
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -29,13 +27,8 @@ TEST_CASE("Better diagnostics with positions")
|
||||
}
|
||||
)";
|
||||
json j = json::parse(json_invalid_string);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(j.at("address").at("housenumber").get<int>(),
|
||||
"[json.exception.type_error.302] (/address/housenumber) (bytes 108-111) type must be number, but is string", json::type_error);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(j.at("address").at("housenumber").get<int>(),
|
||||
"[json.exception.type_error.302] (bytes 108-111) type must be number, but is string", json::type_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("invalid type without positions")
|
||||
@@ -45,48 +38,13 @@ TEST_CASE("Better diagnostics with positions")
|
||||
"[json.exception.type_error.302] type must be number, but is string", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("positions of strings containing escape sequences")
|
||||
{
|
||||
// escape sequences make the token longer than the string it parses to,
|
||||
// so the positions must not be derived from the parsed value's length
|
||||
const auto check = [](const std::string & text, const std::string & token)
|
||||
{
|
||||
CAPTURE(text)
|
||||
CAPTURE(token)
|
||||
const json j = json::parse(text);
|
||||
const json& v = j.at("a");
|
||||
CHECK(text.substr(v.start_pos(), v.end_pos() - v.start_pos()) == token);
|
||||
};
|
||||
|
||||
check(R"({"a":"plain"})", R"("plain")");
|
||||
check(R"({"a":"tab\there"})", R"("tab\there")");
|
||||
check(R"({"a":"\n\n\n\n\n\n"})", R"("\n\n\n\n\n\n")");
|
||||
check(R"({"a":"\""})", R"("\"")");
|
||||
check(R"({"a":"\\"})", R"("\\")");
|
||||
check(R"({"a":"é"})", R"("é")");
|
||||
check(R"({"a":"🌞"})", R"("🌞")");
|
||||
check("{\"a\":\"\xc3\xa9\"}", "\"\xc3\xa9\""); // multi-byte UTF-8, no escapes
|
||||
|
||||
// a string at the root, where an escape would otherwise push the
|
||||
// reported start position past the opening quote
|
||||
const std::string root = R"("a\tb")";
|
||||
const json j = json::parse(root);
|
||||
CHECK(j.start_pos() == 0);
|
||||
CHECK(j.end_pos() == root.size());
|
||||
}
|
||||
|
||||
SECTION("JSON patch add to primitive parent (#4292)")
|
||||
{
|
||||
// the JSON Patch "add" target /foo/bar/baz has a string parent
|
||||
// (/foo/bar); the position of that parent is reported in the message
|
||||
const json doc = json::parse(R"({"foo":{"bar":"a string"}})");
|
||||
const json patch = json::parse(R"([{"op":"add","path":"/foo/bar/baz","value":1}])");
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch),
|
||||
"[json.exception.out_of_range.411] (/foo/bar) (bytes 14-24) cannot add value: the JSON Patch 'add' target's parent is of type string, but must be an object or array", json::out_of_range);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch),
|
||||
"[json.exception.out_of_range.411] (bytes 14-24) cannot add value: the JSON Patch 'add' target's parent is of type string, but must be an object or array", json::out_of_range);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1388,84 +1388,3 @@ TEST_CASE("JSON patch - add to a primitive parent (regression #4292)")
|
||||
CHECK_THROWS_AS(doc.patch(patch), json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JSON patch - diff emits array removals in descending index order")
|
||||
{
|
||||
SECTION("array shrunk to empty")
|
||||
{
|
||||
json const source = {0, 1, 2, 3, 4};
|
||||
json const target = json::array();
|
||||
|
||||
json const patch = json::diff(source, target);
|
||||
|
||||
json const expected = R"(
|
||||
[
|
||||
{"op": "remove", "path": "/4"},
|
||||
{"op": "remove", "path": "/3"},
|
||||
{"op": "remove", "path": "/2"},
|
||||
{"op": "remove", "path": "/1"},
|
||||
{"op": "remove", "path": "/0"}
|
||||
]
|
||||
)"_json;
|
||||
|
||||
CHECK(patch == expected);
|
||||
CHECK(source.patch(patch) == target);
|
||||
}
|
||||
|
||||
SECTION("array partially shrunk, after a replacement at a common index")
|
||||
{
|
||||
json const source = {0, 1, 2, 3, 4};
|
||||
json const target = {0, 9};
|
||||
|
||||
json const patch = json::diff(source, target);
|
||||
|
||||
// the replacement comes first, then the removals, highest index first
|
||||
json const expected = R"(
|
||||
[
|
||||
{"op": "replace", "path": "/1", "value": 9},
|
||||
{"op": "remove", "path": "/4"},
|
||||
{"op": "remove", "path": "/3"},
|
||||
{"op": "remove", "path": "/2"}
|
||||
]
|
||||
)"_json;
|
||||
|
||||
CHECK(patch == expected);
|
||||
CHECK(source.patch(patch) == target);
|
||||
}
|
||||
|
||||
SECTION("nested array shrunk")
|
||||
{
|
||||
json const source = {{"a", {0, 1, 2}}};
|
||||
json const target = {{"a", json::array()}};
|
||||
|
||||
json const patch = json::diff(source, target);
|
||||
|
||||
json const expected = R"(
|
||||
[
|
||||
{"op": "remove", "path": "/a/2"},
|
||||
{"op": "remove", "path": "/a/1"},
|
||||
{"op": "remove", "path": "/a/0"}
|
||||
]
|
||||
)"_json;
|
||||
|
||||
CHECK(patch == expected);
|
||||
CHECK(source.patch(patch) == target);
|
||||
}
|
||||
|
||||
SECTION("many removals still round-trip")
|
||||
{
|
||||
json source = json::array();
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
source.push_back(i);
|
||||
}
|
||||
json const target = json::array();
|
||||
|
||||
json const patch = json::diff(source, target);
|
||||
|
||||
CHECK(patch.size() == 1000);
|
||||
CHECK(patch.front().at("path") == "/999");
|
||||
CHECK(patch.back().at("path") == "/0");
|
||||
CHECK(source.patch(patch) == target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,6 +396,72 @@ TEST_CASE("JSON pointers")
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("creating intermediate levels")
|
||||
{
|
||||
SECTION("tokens that are valid array indices create arrays")
|
||||
{
|
||||
json j;
|
||||
j["/0"_json_pointer] = 1;
|
||||
CHECK(j == json({1}));
|
||||
|
||||
json j2;
|
||||
j2["/2"_json_pointer] = 1;
|
||||
CHECK(j2 == json({nullptr, nullptr, 1}));
|
||||
|
||||
json j3;
|
||||
j3["/-"_json_pointer] = 1;
|
||||
CHECK(j3 == json({1}));
|
||||
|
||||
json j4;
|
||||
j4["/foo/0/0"_json_pointer] = 1;
|
||||
CHECK(j4 == json({{"foo", {{1}}}}));
|
||||
}
|
||||
|
||||
SECTION("tokens that are no valid array indices create objects")
|
||||
{
|
||||
json j;
|
||||
j["/one"_json_pointer] = 1;
|
||||
CHECK(j == json({{"one", 1}}));
|
||||
|
||||
// leading '0' can never be a valid array index (RFC 6901, Sect. 4)
|
||||
json j2;
|
||||
j2["/01"_json_pointer] = 1;
|
||||
CHECK(j2 == json({{"01", 1}}));
|
||||
|
||||
// the empty token is a valid object key, but no valid array index
|
||||
json j3;
|
||||
j3["/"_json_pointer] = 1;
|
||||
CHECK(j3 == json({{"", 1}}));
|
||||
}
|
||||
|
||||
SECTION("creating a level yields the same result as reusing it (#5357)")
|
||||
{
|
||||
json j;
|
||||
j["/a/b/01/d"_json_pointer] = "value";
|
||||
|
||||
json j_init = json::object();
|
||||
j_init["/a/b"_json_pointer] = json::object();
|
||||
j_init["/a/b/01/d"_json_pointer] = "value";
|
||||
|
||||
const json expected = json::parse(R"({"a":{"b":{"01":{"d":"value"}}}})");
|
||||
CHECK(j == expected);
|
||||
CHECK(j_init == expected);
|
||||
|
||||
// unflatten uses the same key
|
||||
const json flat = {{"/a/b/01/d", "value"}};
|
||||
CHECK(flat.unflatten() == expected);
|
||||
}
|
||||
|
||||
SECTION("existing arrays still reject invalid indices")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
CHECK_THROWS_WITH_AS(j["/01"_json_pointer],
|
||||
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j.at("/01"_json_pointer),
|
||||
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("flatten")
|
||||
{
|
||||
json j =
|
||||
|
||||
@@ -801,30 +801,6 @@ TEST_CASE("modifiers")
|
||||
j1.update(j2, true);
|
||||
CHECK(j1 == json({{"string", "t"}, {"numbers", 1}}));
|
||||
}
|
||||
|
||||
SECTION("overwrite primitive with object")
|
||||
{
|
||||
json j1 = {{"k", 1}};
|
||||
json const j2 = {{"k", {{"x", 2}}}};
|
||||
j1.update(j2, true);
|
||||
CHECK(j1 == json({{"k", {{"x", 2}}}}));
|
||||
}
|
||||
|
||||
SECTION("overwrite array with object")
|
||||
{
|
||||
json j1 = {{"k", {1, 2}}};
|
||||
json const j2 = {{"k", {{"x", 2}}}};
|
||||
j1.update(j2, true);
|
||||
CHECK(j1 == json({{"k", {{"x", 2}}}}));
|
||||
}
|
||||
|
||||
SECTION("overwrite nested primitive with object")
|
||||
{
|
||||
json j1 = {{"k", {{"inner", 1}}}};
|
||||
json const j2 = {{"k", {{"inner", {{"x", 2}}}}}};
|
||||
j1.update(j2, true);
|
||||
CHECK(j1 == json({{"k", {{"inner", {{"x", 2}}}}}}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1555,15 +1555,4 @@ TEST_CASE("issue #5338 - truncated CBOR tagged binary subtype is rejected")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("issue #5402 - update(merge_objects=true) overwrites a primitive with an object")
|
||||
{
|
||||
json t = {{"k", 1}};
|
||||
t.update(json{{"k", {{"x", 2}}}}, true);
|
||||
CHECK(t == json({{"k", {{"x", 2}}}}));
|
||||
|
||||
json mixed = {{"keep", {{"a", 1}}}, {"replace", 1}};
|
||||
mixed.update(json{{"keep", {{"b", 2}}}, {"replace", {{"x", 2}}}}, true);
|
||||
CHECK(mixed == json({{"keep", {{"a", 1}, {"b", 2}}}, {"replace", {{"x", 2}}}}));
|
||||
}
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
|
||||
@@ -1713,44 +1713,6 @@ TEST_CASE("UBJSON")
|
||||
CHECK(json::to_ubjson(json::from_ubjson(s_L)) == s_i);
|
||||
}
|
||||
|
||||
SECTION("no-op markers")
|
||||
{
|
||||
// A no-op ('N') is valid wherever a value may start; it is consumed
|
||||
// by get_ignore_noop() before the value is read. It is not valid
|
||||
// where a string length type specification is expected.
|
||||
|
||||
SECTION("accepted where a value may start")
|
||||
{
|
||||
// at top level, also repeated
|
||||
CHECK(json::from_ubjson(std::vector<uint8_t>({'N', 'i', 1})) == json(1));
|
||||
CHECK(json::from_ubjson(std::vector<uint8_t>({'N', 'N', 'N', 'i', 1})) == json(1));
|
||||
|
||||
// inside an array of unknown size, before and after an element
|
||||
CHECK(json::from_ubjson(std::vector<uint8_t>({'[', 'N', 'i', 1, ']'})) == json({1}));
|
||||
CHECK(json::from_ubjson(std::vector<uint8_t>({'[', 'i', 1, 'N', ']'})) == json({1}));
|
||||
|
||||
// inside an object of unknown size: before a key, between key
|
||||
// and value, and before the closing '}'
|
||||
CHECK(json::from_ubjson(std::vector<uint8_t>({'{', 'N', 'U', 1, 'a', 'i', 1, '}'})) == json({{"a", 1}}));
|
||||
CHECK(json::from_ubjson(std::vector<uint8_t>({'{', 'U', 1, 'a', 'N', 'i', 1, '}'})) == json({{"a", 1}}));
|
||||
CHECK(json::from_ubjson(std::vector<uint8_t>({'{', 'U', 1, 'a', 'i', 1, 'N', '}'})) == json({{"a", 1}}));
|
||||
}
|
||||
|
||||
SECTION("rejected where a length type specification is expected")
|
||||
{
|
||||
json _;
|
||||
|
||||
// after the 'S' marker of a string value
|
||||
std::vector<uint8_t> const v_S = {'S', 'N', 'U', 1, 'a'};
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v_S), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x4E", json::parse_error&);
|
||||
|
||||
// as the key length of an object with a known size, where
|
||||
// no-ops are not permitted in the first place
|
||||
std::vector<uint8_t> const v_key = {'{', '#', 'i', 1, 'N', 'U', 1, 'a', 'i', 1};
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v_key), "[json.exception.parse_error.113] parse error at byte 5: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x4E", json::parse_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
SECTION("float")
|
||||
@@ -2503,48 +2465,6 @@ TEST_CASE("all UBJSON first bytes")
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("UBJSON use_type requires use_size")
|
||||
{
|
||||
SECTION("non-empty array throws other_error.502")
|
||||
{
|
||||
const json j = {1, 2, 3};
|
||||
CHECK_THROWS_WITH_AS(json::to_ubjson(j, false, true),
|
||||
"[json.exception.other_error.502] use_type requires use_size = true",
|
||||
json::other_error&);
|
||||
}
|
||||
|
||||
SECTION("non-empty object throws other_error.502")
|
||||
{
|
||||
const json j = {{"a", 1}, {"b", 2}};
|
||||
CHECK_THROWS_WITH_AS(json::to_ubjson(j, false, true),
|
||||
"[json.exception.other_error.502] use_type requires use_size = true",
|
||||
json::other_error&);
|
||||
}
|
||||
|
||||
SECTION("scalars do not throw with use_type=true, use_count=false")
|
||||
{
|
||||
CHECK_NOTHROW(json::to_ubjson(42, false, true));
|
||||
CHECK_NOTHROW(json::to_ubjson(3.14, false, true));
|
||||
CHECK_NOTHROW(json::to_ubjson("hello", false, true));
|
||||
CHECK_NOTHROW(json::to_ubjson(true, false, true));
|
||||
CHECK_NOTHROW(json::to_ubjson(nullptr, false, true));
|
||||
}
|
||||
|
||||
SECTION("empty containers do not throw with use_type=true, use_count=false")
|
||||
{
|
||||
CHECK_NOTHROW(json::to_ubjson(json::array(), false, true));
|
||||
CHECK_NOTHROW(json::to_ubjson(json::object(), false, true));
|
||||
}
|
||||
|
||||
SECTION("valid combinations on non-empty containers")
|
||||
{
|
||||
const json j = {1, 2, 3};
|
||||
CHECK_NOTHROW(json::to_ubjson(j, false, false));
|
||||
CHECK_NOTHROW(json::to_ubjson(j, true, false));
|
||||
CHECK_NOTHROW(json::to_ubjson(j, true, true));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("UBJSON roundtrips" * doctest::skip())
|
||||
{
|
||||
SECTION("input from self-generated UBJSON files")
|
||||
|
||||
@@ -125,16 +125,6 @@ TEST_CASE("wide strings")
|
||||
std::u32string const w = U"\"\x110000";
|
||||
json _;
|
||||
CHECK_THROWS_AS(_ = json::parse(w), json::parse_error&);
|
||||
|
||||
// a code unit above U+10FFFF must not be narrowed onto the EOF
|
||||
// sentinel: 0xFFFFFFFF would otherwise end the document silently and
|
||||
// let everything following it pass the strict end-of-input check
|
||||
std::u32string const trailing{U'[', U'1', U']', static_cast<char32_t>(0xFFFFFFFF), U'x'};
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse(trailing), "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '1]\xFF'; expected end of input", json::parse_error&);
|
||||
CHECK(!json::accept(trailing));
|
||||
|
||||
// the same unit inside a string is reported as an ill-formed byte
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse(std::u32string{U'"', static_cast<char32_t>(0xFFFFFFFF), U'"'}), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\xFF'", json::parse_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user