Compare commits

..

11 Commits

Author SHA1 Message Date
Niels Lohmann cb7f1ae838 Avoid strlen() in test container to fix Codacy CWE-126 flag
Suppressing the strlen()-based CWE-126 warning with NOLINT/nosec
comments only silenced clang-tidy and the standalone Flawfinder
Action; Codacy's own analysis (which also flags this pattern and
doesn't honor those suppression comments) still reported it as a new
issue, plus flagged the near-duplicate begin/end pair as cloned code.

Store the buffer's size explicitly in MyContainerNonConstADL instead
of computing it via strlen() in end(), which removes the flagged
pattern outright and also de-duplicates the struct from the existing
MyContainer's char*-based begin/end pair.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 21:26:24 +02:00
Niels Lohmann fc7fde6910 Fix container input_adapter SFINAE for lvalue-only ADL begin/end (#111)
The container overload of json::parse(c) / accept(c) / sax_parse(c, ...)
silently dropped from overload resolution for user types whose ADL
begin(T&) / end(T&) accepted only non-const lvalue references
(a legitimate pattern matching std::begin semantics). This was because
the detection code used std::declval<ContainerType>() which synthesized
an rvalue, and the rvalue failed to bind to lvalue-only ADL functions.

Fix by making both the outer input_adapter(ContainerType&&) and the
factory's create(ContainerType&&) forwarding references, preserving the
caller's value category and constness via reference collapsing. This
ensures detection (std::declval) and actual use (std::forward) always
match without needing decay/remove_reference.

- Rewrite input_adapters.hpp container overload with forwarding refs
- Add regression tests for lvalue-only non-const ADL begin/end
- Add regression test for rvalue containers (no breakage)
- Update API docs (parse, accept, sax_parse, from_*) to clarify
  that begin/end must match std::begin/std::end semantics
- Add version history notes for 3.13.0
- Regenerate amalgamation

Second-order effect: binary_reader.hpp's internal call to
input_adapter(number_vector) now deduces iterator vs const_iterator
based on the lvalue; functionally harmless (iterator_input_adapter is
iterator-type-agnostic), verified via unit-ubjson/unit-bjdata tests.

Closes remaining limitation from #4354 / PR #5218 (todo 106).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 21:22:17 +02:00
Niels Lohmann d0de6a9111 Document std::optional<T> direct construction limitation (#5247)
* Document std::optional<T> direct-init/copy-init limitation with null

Add regression test pinning current behavior (CHECK_THROWS_AS) in the null
section of unit-conversions.cpp with detailed comment explaining the C++
language-level cause (std::optional's own converting constructor wins
overload resolution over basic_json::operator T()).

Add a warning callout in conversions.md documenting that direct construction/
assignment of std::optional<T> from JSON null throws type_error 302, with a
clear workaround (use get<std::optional<T>>() or get_to() instead, which
correctly produce std::nullopt).

This is a limitation at the language level: there is no SFINAE path to
distinguish "called from inside std::optional's own constructor" from "direct
call", so fixing it would require breaking changes to operator ValueType().
A permanent fix belongs in the 4.0 type-strictness redesign (#3453).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-Authored-By: Claude Code <noreply@anthropic.com>

* Fix issue reference in std::optional test comment

Update the comment in the null section test to reference #5246 instead of
placeholder #XXXX, clarifying where the direct-init/copy-init limitation is tracked.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Use CHECK_THROWS_AS_WITH for std::optional test assertions

Update the regression tests to use CHECK_THROWS_AS_WITH instead of
CHECK_THROWS_AS to verify both the exception type and the error message.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix CI: use CHECK_THROWS_WITH_AS, the macro that actually exists

CHECK_THROWS_AS_WITH is not a doctest macro; the correct one used throughout
this test suite is CHECK_THROWS_WITH_AS(expr, message, exception_type&), with
the message before the type and the type as a reference. The previous commit
didn't catch this because it only compiled the file standalone with default
settings; this TEST_CASE only compiles under
`#if !JSON_USE_IMPLICIT_CONVERSIONS`, which is why ci_test_noimplicitconversions
was the job that failed. Verified by building and running the test in that
exact configuration (JSON_USE_IMPLICIT_CONVERSIONS=0): 14/14 assertions pass.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Run std::optional test under default implicit-conversions build too

TEST_CASE("std::optional") was guarded by #if !JSON_USE_IMPLICIT_CONVERSIONS,
so it only ever compiled in the non-default build with implicit conversions
disabled. This traces back to commit 1d7688aef (fixes #3859), which changed a
previously dead #ifndef JSON_USE_IMPLICIT_CONVERSIONS guard (the macro is
always defined by that point, so it never held) to #if !JSON_USE_IMPLICIT_CONVERSIONS
-- making the test compile for the first time, but only in the disabled-conversions
build. As a result, std::optional support had zero test coverage in the default
configuration almost every user builds with.

Verified the entire test case (all sections: null, string, bool, number, array,
object) compiles and passes identically with JSON_USE_IMPLICIT_CONVERSIONS both
on (default) and off -- nothing in it actually depends on the setting. Removing
the guard closes the coverage gap with no behavior change: 285 assertions pass
with implicit conversions on, 232 with them off (the difference comes from
other, unrelated conditionally-compiled tests in this file).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* 🎓 fix warning

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-07-09 19:03:49 +02:00
Niels Lohmann f8e99e856c Fix nvcc CUDA 12.0/12.1 C++20 ranges parse error (#3907) (#5248)
* Test ci_cuda_example against a CUDA version matrix at C++20 (#3907)

The ci_cuda_example job compiled against the json-ci image's CUDA
11.0 toolkit at cuda_std_11, which cannot exercise #3907 (a c++20
parse error in iteration_proxy.hpp's enable_borrowed_range reported
under nvcc). Switch the job to pull official nvidia/cuda devel images
directly and matrix across CUDA 11.8-12.6 at cuda_std_20 so CI can
empirically confirm which versions are actually affected before any
source-level fix is attempted.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix nvcc CUDA 12.0/12.1 C++20 ranges parse error (#3907)

The diagnostic matrix in this PR confirmed the affected range exactly:
nvcc 12.0.1 and 12.1.1 both fail with "expected initializer before
'<' token" on iteration_proxy.hpp's enable_borrowed_range variable
template specialization at -std=c++20; 12.2.2 and newer already build
cleanly. Guard JSON_HAS_RANGES off for that narrow nvcc version range,
matching the existing GCC-11/libstdc++ carve-outs in the same ifdef
chain, and regenerate single_include accordingly.

Broaden the CUDA smoke test to also exercise comparisons
(operator==/operator<=>, gated independently by
JSON_HAS_THREE_WAY_COMPARISON) and range-based iteration, not just
dump()/erase(), so the fix's actual scope is evidenced by CI rather
than assumed from the single reported symptom.

Have tests/cuda_example/CMakeLists.txt pick the newest C++ standard
the detected nvcc version actually supports (20/17/11) instead of
hard-requiring C++20, so older toolkits build at a lower standard
instead of failing CMake configure outright. This is test-project-local
only; the JSON_HAS_RANGES guard is what protects real client code,
since a header can't control what -std= flag it's compiled with.

Right-size the CI matrix from the 8-version diagnostic sweep down to
11.8.0 (C++17 fallback path) / 12.1.1 (permanent #3907 regression
guard) / 12.6.3 (recent coverage), and update the compiler-version
table in the quality assurance docs to match.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix ci_cuda_example CUDA 11.8 build after C++17 fallback (#3907)

The 11.8.0 leg's graceful C++17 fallback (added in the previous commit)
worked correctly, but the broadened smoke test used the <=> operator
unconditionally, which isn't valid syntax pre-C++20 — nvcc rejected it
with "expected an expression" once the CMake logic picked cuda_std_17
for the older toolkit. Gate those two lines behind
JSON_HAS_THREE_WAY_COMPARISON like the library itself does internally.

Sanity-compiled the file as plain C++ at both -std=c++17 (skips the
guarded block) and -std=c++20 (includes it) locally; the actual nvcc
build is verified via CI on PR #5248.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 19:02:36 +02:00
Niels Lohmann 521a084827 Documentation review (#5257)
* 📡 Fix documentation gaps for 3.13.0 release (todos 138-142)

- Todo 138: Add "Known issues" section to modules.md with compiler-specific troubleshooting (GCC redefinition, MSVC symbol export). Add pointer note to quality_assurance.md.
- Todo 139: Document CBOR/MessagePack half-precision float encoding for NaN/Infinity (0xF9/0xCA with exact byte sequences). Explain pre-3.13.0 double-precision bug mechanism without issue citations.
- Todo 140: Document CBOR negative-integer-overflow rejection (parse_error.112) for magnitudes exceeding int64_t range (already implemented in rev 1).
- Todo 141: Update version history in value.md and operator[].md with behavior-change details, removing issue citations per citation policy (prose is self-contained).
- Todo 142: Global sed replace of 3.12.x → 3.13.0 placeholder across all 20 documentation files.

Revision 2 incorporates feedback to reduce changelog-like issue citations. Only citations that add unique troubleshooting value are retained (#5103 for GCC workaround, #3970 for MSVC symbol export). "Known issues" section follows PR #5252's visual pattern (info admonition with bold-bullet format).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* 📡 Document integer type selection, type_name() invalid value, and std::optional get() fix

- number_handling.md: clarify that positive/negative integers select
  unsigned/signed storage based on the leading minus sign (todo 143).
- type_name.md: document the new "invalid" return value for corrupted
  JSON values (todo 145).
- get.md: note that get<std::optional<T>>() was unreachable in every
  configuration prior to 3.13.0 due to an internal macro-guard bug,
  unrelated to JSON_USE_IMPLICIT_CONVERSIONS's actual effect (todo 144).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 17:24:19 +02:00
Niels Lohmann ca91678af1 Document compiler/stdlib exclusions in macro_scope.hpp (#5252)
* 📡 Document compiler/stdlib exclusions in macro_scope.hpp

Add "Known compiler/stdlib exclusions" subsections to the public documentation for
JSON_HAS_FILESYSTEM and JSON_HAS_RANGES, listing the exact compiler/stdlib versions
that are silently excluded even when feature-test macros indicate support. Each
exclusion references the originating issue. Also add a pointer note in the compiler
compatibility section linking to these details.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-Authored-By: Claude Code <noreply@anthropic.com>

* 🧛 fix build

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-07-09 17:15:57 +02:00
Niels Lohmann ff34a3fd2f Fix flaky ci_nvhpc job: pin nvc++ target to generic baseline (-tp=px) (#5254) 2026-07-09 15:16:28 +02:00
Niels Lohmann fe0299545a 📡 Document cross-basic_json conversion limitation (#3425) (#5249)
When converting objects or strings between different basic_json specializations,
the target's object_t::key_type or string_t must be directly constructible from
the source's corresponding type. If this requirement is not met, the conversion
silently falls back to the array-conversion path, producing incorrect results.

This documents the limitation and provides references to issue #3425, which tracks
this behavior. The comment in unit-alt-string.cpp is clarified to reference the
known limitation with a link to the issue, and suggests the parse() workaround.

Fixes #3425 (documentation; full fix deferred pending type-trait redesign)

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 06:44:51 +02:00
Niels Lohmann 366f3d26e5 Replace snprintf with a branch-free writer for \uXXXX escapes (#5235)
* Replace snprintf with a branch-free writer for \uXXXX escapes

dump_escaped called std::snprintf(..., "\u%04x", ...) once per escaped
code point in the string serialization hot path. snprintf re-parses
the format string and pulls in locale/printf machinery on every call,
which is far heavier than the fixed 6-/12-byte output warrants. This
is hot for any string containing control characters, and for all
non-ASCII text when ensure_ascii is set.

Replace it with write_u_escape, a small helper that writes the escape
directly into string_buffer via a nibble-to-hex lookup table, mirroring
the existing hand-rolled dump_integer fast path in the same file.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix clang-tidy avoid-c-arrays warning in write_u_escape

Use a const char* rather than a char[] lookup table, matching the
existing hex_bytes helper in the same file.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* ♻️ adjust write_u_escape signature

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-08 20:25:13 +02:00
Niels Lohmann 7c9208bfb3 📡 make documentation more LLM friendly (#5244)
Implement the scoped agent-readiness subset for json.nlohmann.me:
- Add the mkdocs-llmstxt plugin to generate llms.txt from the nav
  (full_output/llms-full.txt deliberately omitted to avoid dumping
  500+ API reference pages into one giant file).
- Add a permissive robots.txt with a Sitemap reference.
- Add a build hook (hooks/copy_markdown_source.py) that copies each
  page's Markdown source into the built site as a `<path>.md` sibling
  of its HTML output, so agents/tools can fetch raw Markdown directly.

sitemap.xml was already emitted by default and needed no change.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-08 20:18:24 +02:00
Niels Lohmann bb60941f0e 👪 fix security findings (#5245)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-08 16:40:58 +02:00
62 changed files with 5596 additions and 7202 deletions
+12
View File
@@ -4,6 +4,8 @@ updates:
directory: /
schedule:
interval: daily
cooldown:
default-days: 7
groups:
codeql-action:
patterns:
@@ -13,23 +15,33 @@ updates:
directory: /docs/mkdocs
schedule:
interval: daily
cooldown:
default-days: 7
- package-ecosystem: pip
directory: /tools/astyle
schedule:
interval: daily
cooldown:
default-days: 7
- package-ecosystem: pip
directory: /tools/generate_natvis
schedule:
interval: daily
cooldown:
default-days: 7
- package-ecosystem: pip
directory: /tools/serve_header
schedule:
interval: daily
cooldown:
default-days: 7
- package-ecosystem: pip
directory: /cmake/requirements
schedule:
interval: daily
cooldown:
default-days: 7
+1 -1
View File
@@ -49,7 +49,7 @@ jobs:
# SEMGREP_APP_TOKEN is still passed through so registry auth works if a
# token is ever added.
- name: Install Semgrep
run: python3 -m pip install --user semgrep
run: python3 -m pip install --user semgrep==1.168.0
# `semgrep scan --sarif` always exits 0 even with findings; continue-on-error
# is a safety net so the SARIF upload still runs if the scan itself errors.
+12 -1
View File
@@ -234,11 +234,22 @@ jobs:
ci_cuda_example:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v2.4.0
strategy:
fail-fast: false
matrix:
# 11.8.0: newest pre-C++20 CUDA release, exercises the C++17 fallback
# path (tests/cuda_example/CMakeLists.txt picks the standard per nvcc
# version); 12.1.1: permanent regression guard for #3907 (nvcc 12.0/12.1
# choke on enable_borrowed_range at C++20, fixed in 12.2); 12.6.3: recent
# CUDA/C++20 coverage.
cuda: ['11.8.0', '12.1.1', '12.6.3']
container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu22.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
+4 -2
View File
@@ -90,11 +90,13 @@ jobs:
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
- 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)
run: |
if [ "${{ matrix.std_version }}" = "latest" ]; then
echo "flags=/permissive- /std:c++latest /utf-8 /W4 /WX" >> $GITHUB_ENV
echo "flags=/permissive- /std:c++latest /utf-8 /W4 /WX /wd5285" >> $GITHUB_ENV
else
echo "flags=/W4 /WX" >> $GITHUB_ENV
echo "flags=/W4 /WX /wd5285" >> $GITHUB_ENV
fi
shell: bash
- name: Run CMake (Release)
+6 -2
View File
@@ -669,7 +669,6 @@ add_custom_target(ci_test_compiler_default
add_custom_target(ci_cuda_example
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DCMAKE_CUDA_HOST_COMPILER=g++-8
-S${PROJECT_SOURCE_DIR}/tests/cuda_example -B${PROJECT_BINARY_DIR}/build_cuda_example
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_cuda_example
)
@@ -720,6 +719,11 @@ add_custom_target(ci_icpx
# to zero and does not honor NaN ordering; -Kieee restores strict IEEE 754 behavior
# (needed for the dtoa/grisu and NaN-comparison code paths).
#
# -tp=px pins the target processor to the generic x86-64 baseline (SSE2-only) to avoid
# a nvc++ 25.5 / LLVM issue: when nvc++ auto-detects -tp from the runner's CPU (e.g. -tp znver4),
# certain attribute combinations trigger an llc instruction-selection crash on std::ldexp<unsigned>.
# Pinning to px removes this variability and is robust to future llc/nvc++ updates.
#
# The following tests are excluded as they trigger known nvc++ 25.5 defects (not
# library bugs); see https://github.com/nlohmann/json for tracking. Only the
# affected language-standard variants are excluded so coverage is otherwise kept:
@@ -733,7 +737,7 @@ add_custom_target(ci_nvhpc
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DCMAKE_C_COMPILER=nvc -DCMAKE_CXX_COMPILER=nvc++
-DCMAKE_CXX_FLAGS=-Kieee
-DCMAKE_CXX_FLAGS="-Kieee;-tp=px"
-DJSON_BuildTests=ON -DJSON_FastTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_nvhpc
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_nvhpc
+1 -1
View File
@@ -5,7 +5,7 @@
# -Wno-extra-semi-stmt The library uses assert which triggers this warning.
# -Wno-padded We do not care about padding warnings.
# -Wno-covered-switch-default All switches list all cases and a default case.
# -Wno-unsafe-buffer-usage Otherwise library code (strlen) would not compile.
# -Wno-unsafe-buffer-usage Otherwise Doctest would not compile.
# -Wno-missing-noreturn We found no way to silence this warning otherwise, see PR #4871
set(CLANG_CXXFLAGS
+2
View File
@@ -4,6 +4,7 @@
# -Wno-aggregate-return The library uses aggregate returns.
# -Wno-long-long The library uses the long long type to interface with system functions.
# -Wno-namespaces The library uses namespaces.
# -Wno-nrvo Doctest triggers this warning.
# -Wno-padded We do not care about padding warnings.
# -Wno-system-headers We do not care about warnings in system headers.
# -Wno-templates The library uses templates.
@@ -231,6 +232,7 @@ set(GCC_CXXFLAGS
-Wnonnull
-Wnonnull-compare
-Wnormalized=nfkc
-Wno-nrvo
-Wnull-dereference
-Wodr
-Wold-style-cast
+4 -2
View File
@@ -35,7 +35,8 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters (throws if null)
- a `std::string`
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type, for instance.
@@ -109,7 +110,8 @@ A UTF-8 byte order mark is silently ignored.
- Added in version 3.0.0.
- Ignoring comments via `ignore_comments` added in version 3.9.0.
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
- Added `ignore_trailing_commas` in version 3.12.x.
- Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
!!! warning "Deprecation"
+12 -1
View File
@@ -82,7 +82,13 @@ basic_json(basic_json&& other) noexcept;
4. This is a constructor for existing `basic_json` types. It does not hijack copy/move constructors, since the parameter
has different template arguments than the current ones.
The constructor tries to convert the internal `m_value` of the parameter.
The constructor tries to convert the internal `m_value` of the parameter. Each member value (object, array, string,
etc.) is serialized via the corresponding `to_json()` overload. For objects and strings, the conversion requires
that the *target* `basic_json` type's `object_t::key_type` (or `string_t`) be directly constructible from the
*source* type's corresponding member type via `is_constructible`. If this requirement is not met, the conversion
does not fail to compile; instead, it silently falls back to the array-conversion path, which represents objects
as arrays of `[key, value]` pairs and strings as arrays of character codes. This is a known limitation tracked in
[issue #3425](https://github.com/nlohmann/json/issues/3425).
5. Creates a JSON value of type array or object from the passed initializer list `init`. In case `type_deduction` is
`#!cpp true` (default), the type of the JSON value to be created is deducted from the initializer list `init`
@@ -146,6 +152,11 @@ basic_json(basic_json&& other) noexcept;
- `BasicJsonType` is a `basic_json` type.
- `BasicJsonType` has different template arguments than `basic_json_t`.
**Note:** For cross-`basic_json` conversions to produce correct results, the target `basic_json`'s
`object_t::key_type` and `string_t` must be directly constructible from the source `basic_json`'s
corresponding types. See the description of overload (4) above for details on what happens when
this requirement is not met.
`U`:
: `uncvref_t<CompatibleType>`
+1 -1
View File
@@ -92,4 +92,4 @@ std::string format_as(const BasicJsonType& j)
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -29,7 +29,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
@@ -101,3 +102,4 @@ Linear in the size of the input.
## Version history
- Added in version 3.11.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
+3 -1
View File
@@ -29,7 +29,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
@@ -101,6 +102,7 @@ Linear in the size of the input.
## Version history
- Added in version 3.4.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
!!! warning "Deprecation"
+3 -1
View File
@@ -32,7 +32,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
@@ -111,6 +112,7 @@ Linear in the size of the input.
- Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0.
- Added `allow_exceptions` parameter in version 3.2.0.
- Added `tag_handler` parameter in version 3.9.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
!!! warning "Deprecation"
@@ -29,7 +29,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
@@ -103,6 +104,7 @@ Linear in the size of the input.
- Parameter `start_index` since version 2.1.1.
- Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0.
- Added `allow_exceptions` parameter in version 3.2.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
!!! warning "Deprecation"
@@ -29,7 +29,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
@@ -102,6 +103,7 @@ Linear in the size of the input.
- Added in version 3.1.0.
- Added `allow_exceptions` parameter in version 3.2.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
!!! warning "Deprecation"
+7
View File
@@ -114,6 +114,13 @@ overload (3).
See [Number conversion](../../features/types/number_handling.md#number-conversion)
for more information.
!!! note "`std::optional` conversions"
Prior to version 3.13.0, `#!cpp get<std::optional<T>>()` (and other conversions to `std::optional<T>`) failed to
compile in every configuration, due to an internal implementation bug that made the `from_json` overload for
`std::optional` unreachable regardless of the [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md)
setting. This has been fixed.
## Examples
??? example
@@ -93,6 +93,15 @@ alphabetical order as `std::map` with `std::less` is used by default. Please not
[RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON
objects.
#### Cross-`basic_json` conversion requirements
When converting an object from one `basic_json` specialization to another via the
[converting constructor](basic_json.md#overload-4), the target `object_t`'s `key_type` must be
directly constructible from the source `basic_json`'s `string_t` type (or more generally, from the
source object's key type). If this requirement is not met, the conversion does not fail; instead,
the object is silently converted as an array of key-value pairs, which is incorrect. See
[issue #3425](https://github.com/nlohmann/json/issues/3425) for details and an example.
## Examples
??? example
@@ -251,5 +251,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. Added in version 1.0.0.
2. Added in version 1.0.0. Added overloads for `T* key` in version 1.1.0. Removed overloads for `T* key` (replaced by 3)
in version 3.11.0.
3. Added in version 3.11.0.
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
already supported by [`at`](at.md), [`value`](value.md), [`find`](find.md), and other lookup functions.
4. Added in version 2.0.0.
+4 -2
View File
@@ -34,7 +34,8 @@ static basic_json parse(IteratorType first, IteratorType last,
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters (throws if null)
- a `std::string`
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type, for instance.
@@ -235,7 +236,8 @@ Invalid Unicode escapes and unpaired surrogates in the input are reported as
- Overload for contiguous containers (1) added in version 2.0.3.
- Ignoring comments via `ignore_comments` added in version 3.9.0.
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
- Added `ignore_trailing_commas` in version 3.12.x.
- Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
!!! warning "Deprecation"
+1 -1
View File
@@ -74,4 +74,4 @@ is thrown. In any case, the original value is not changed: the patch is applied
- Added in version 2.0.0.
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
target location has a non-object/non-array parent in version 3.12.x.
target location has a non-object/non-array parent in version 3.13.0.
@@ -71,4 +71,4 @@ function throws an exception.
- Added in version 3.11.0.
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
target location has a non-object/non-array parent in version 3.12.x.
target location has a non-object/non-array parent in version 3.13.0.
+4 -3
View File
@@ -39,8 +39,8 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of
iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type for overload (2); a pair of character iterators whose `value_type` is an integral type
@@ -126,7 +126,8 @@ A UTF-8 byte order mark is silently ignored.
- Added in version 3.2.0.
- Ignoring comments via `ignore_comments` added in version 3.9.0.
- Added `ignore_trailing_commas` in version 3.12.x.
- Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
!!! warning "Deprecation"
@@ -54,4 +54,4 @@ provides `<format>`, controlled by the [`JSON_HAS_STD_FORMAT`](../macros/json_ha
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -45,6 +45,15 @@ This implementation is interoperable as it does compare strings code unit by cod
String values are stored as pointers in a `basic_json` type. That is, for any access to string values, a pointer of type
`string_t*` must be dereferenced.
#### Cross-`basic_json` conversion requirements
When converting a string value from one `basic_json` specialization to another via the
[converting constructor](basic_json.md#overload-4), the target `string_t` must be directly
constructible from the source `basic_json`'s `string_t` type. If this requirement is not met, the
conversion does not fail; instead, the string is silently converted as an array of character codes,
which is incorrect. See [issue #3425](https://github.com/nlohmann/json/issues/3425) for details
and an example.
## Examples
??? example
@@ -21,6 +21,12 @@ a string representation of the type ([`value_t`](value_t.md)):
| array | `"array"` |
| binary | `"binary"` |
| discarded | `"discarded"` |
| invalid (corrupted value) | `"invalid"` |
!!! note "The \"invalid\" type"
The `"invalid"` return value indicates a corrupted JSON value — this can occur if an enum value falls outside the
range of valid `value_t` values. This is useful for diagnosing data corruption or internal errors.
## Exception safety
@@ -52,3 +58,4 @@ Constant.
- Part of the public API version since 2.1.0.
- Changed return value to `const char*` and added `noexcept` in version 3.0.0.
- Added support for binary type in version 3.8.0.
- Added `"invalid"` return value for corrupted JSON values in version 3.13.0.
+3 -1
View File
@@ -184,4 +184,6 @@ changes to any JSON value.
1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version 3.11.0.
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2.
3. Added in version 2.0.2. Extended to work with arrays in version 3.12.x.
3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0, including fixing an issue where resolving
`ptr` through an array unexpectedly threw `out_of_range` instead of returning the resolved element (or
`default_value`, as documented).
+1 -1
View File
@@ -36,4 +36,4 @@ Constant.
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -32,4 +32,4 @@ Linear in the number of reference tokens in the `json_pointer`.
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -35,4 +35,4 @@ Linear in the number of reference tokens in the `json_pointer`.
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -92,4 +92,4 @@ The default value is `0` (disabled — existing behavior is preserved).
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -44,4 +44,4 @@ The default value is detected based on preprocessor macros such as `#!cpp __cplu
- Added in version 3.10.5.
- Added `JSON_HAS_CPP_23` in version 3.12.0.
- Added `JSON_HAS_CPP_26` in version 3.12.x.
- Added `JSON_HAS_CPP_26` in version 3.13.0.
@@ -19,6 +19,20 @@ The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_
`#!cpp __cpp_lib_experimental_filesystem`, `#!cpp __has_include(<filesystem>)`, or
`#!cpp __has_include(<experimental/filesystem>)`.
!!! info "Known compiler/stdlib exclusions"
Even when the feature-test macro indicates filesystem support is available, the library disables it on the following broken toolchains:
- **MinGW + GCC 8** — disabled entirely (broken `std::filesystem` implementation; [MinGW-w64 bug 737](https://sourceforge.net/p/mingw-w64/bugs/737/))
- **GCC (non-Clang) < 8** — disabled (no filesystem support)
- **Clang < 7** — disabled (no filesystem support)
- **MSVC < 19.14** — disabled (no filesystem support)
- **iOS < 13** — disabled (no filesystem support)
- **macOS < Catalina (10.15)** — disabled (no filesystem support)
If `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERIMENTAL_FILESYSTEM` is `0` despite `__cpp_lib_filesystem` being defined, one
of the exclusions above likely applies to your toolchain.
## Notes
- Note that older compilers or older versions of libstdc++ also require the library `stdc++fs` to be linked to for
@@ -13,6 +13,18 @@ The default value is detected based on the preprocessor macro `#!cpp __cpp_lib_r
When the macro is not defined, the library will define it to its default value.
!!! info "Known compiler/stdlib exclusions"
Even when the feature-test macro `__cpp_lib_ranges` indicates ranges support is available, the library disables it on
the following incomplete or broken toolchains:
- **GCC 11.1.0** — disabled (the shipped `<ranges>` header has a syntax error; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **libstdc++ < 11** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **Clang < 16 with libstdc++** — disabled (incomplete ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **libc++ < 160000** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
If `JSON_HAS_RANGES` is `0` despite `__cpp_lib_ranges` being defined, one of the exclusions above likely applies to your toolchain.
## Examples
??? example
@@ -38,4 +38,4 @@ When the macro is not defined, the library will define it to its default value.
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -75,4 +75,4 @@ For further information please refer to the corresponding macros without `WITH_N
## Version history
1. Added in version 3.12.x.
1. Added in version 3.13.0.
@@ -102,4 +102,4 @@ inline void from_json(const BasicJsonType& j, type& e);
## Version history
Added in version 3.12.x.
Added in version 3.13.0.
@@ -64,4 +64,4 @@ Linear.
- Added in version 1.0.0.
- Moved to namespace `nlohmann::literals::json_literals` in 3.11.0.
- Added `char8_t*` overload in 3.12.x.
- Added `char8_t*` overload in 3.13.0.
@@ -63,4 +63,4 @@ Linear.
- Added in version 2.0.0.
- Moved to namespace `nlohmann::literals::json_literals` in 3.11.0.
- Added `char8_t*` overload in 3.12.x.
- Added `char8_t*` overload in 3.13.0.
@@ -10,6 +10,10 @@ violations will result in a failed build.
Any compiler with complete C++11 support can compile the library without warnings.
Note: C++20 modules support may hit compiler-specific issues not covered by the general compiler matrix below. See [Modules](../features/modules.md#known-issues) for known issues and workarounds.
Note: Some modern features (like C++20 ranges or filesystem support) may be disabled on specific broken or incomplete toolchains even when standard feature-test macros indicate support. See [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) and [`JSON_HAS_FILESYSTEM`](../api/macros/json_has_filesystem.md) for details on known exclusions.
- [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms,
including the oldest versions known to compile the library.
@@ -62,7 +66,9 @@ violations will result in a failed build.
| Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub |
| Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| CUDA 11.0.221 (nvcc) | x86_64 | Ubuntu 20.04 LTS | GitHub |
| CUDA 11.8.0 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| CUDA 12.1.1 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| CUDA 12.6.3 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| Emscripten 4.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.8.5 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.9.3 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
@@ -66,7 +66,15 @@ see "binary" cells in the table above.
!!! info "NaN/infinity handling"
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the normal JSON serialization which serializes NaN or Infinity to `null`.
`NaN`, `Infinity`, and `-Infinity` are serialized as a CBOR half-precision float (type 0xF9, 3 bytes total):
`NaN` as `0xF9 0x7E 0x00`, `Infinity` as `0xF9 0x7C 0x00`, and `-Infinity` as `0xF9 0xFC 0x00`. This behavior
differs from the normal JSON serialization which serializes NaN or Infinity to `null`.
!!! note
Prior to version 3.13.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB,
9 bytes total), because the check used to select a smaller encoding compared magnitudes with NaN, which is
always `false` and caused the intended half-precision path to be skipped.
!!! info "Unused CBOR types"
@@ -160,6 +168,13 @@ The library maps CBOR types to JSON value types as follows:
- simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7)
!!! warning "Negative integer overflow"
CBOR negative integers (major type 1) are decoded as `-1 - n`. If the encoded magnitude `n` is too large for the
result to fit into `number_integer_t` (`std::int64_t` by default), parsing fails with a
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) exception rather than overflowing
silently.
!!! warning "Object keys"
CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys other than UTF-8 strings are rejected.
@@ -67,8 +67,15 @@ specification:
!!! info "NaN/infinity handling"
If NaN or Infinity are stored inside a JSON number, they are serialized properly in contrast to the
[dump](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `null`.
`NaN`, `Infinity`, and `-Infinity` are serialized as a MessagePack float 32 (type 0xCA, 5 bytes total),
regardless of magnitude, in contrast to the [dump](../../api/basic_json/dump.md) function which serializes NaN
or Infinity to `null`.
!!! note
Prior to version 3.13.0, NaN and Infinity were instead serialized as a MessagePack float 64 (type 0xCB, 9 bytes
total), because the check used to select the smaller float 32 encoding compared magnitudes with NaN, which is
always `false` and caused the float 32 path to be skipped.
??? example
+18
View File
@@ -66,6 +66,24 @@ which forces the explicit `get` form and can catch unintended conversions at com
floating-point value as an integer truncates it, and narrowing conversions may overflow. See
[number conversion](types/number_handling.md#number-conversion) for details and how to guard against it.
!!! warning "std::optional direct construction from JSON null throws"
Constructing or assigning `std::optional<T>` directly from a JSON value does not correctly produce
`std::nullopt` for a JSON `null`:
```cpp
json j_null;
std::optional<std::string> opt = j_null; // ❌ throws type_error 302
```
This is due to C++ language rules: `std::optional<T>` has its own converting constructor that is chosen over
`basic_json::operator T()` when both are viable. Use `get<std::optional<T>>()` or `get_to()` instead:
```cpp
auto opt = j_null.get<std::optional<std::string>>(); // ✅ std::nullopt
j_null.get_to(opt); // ✅ std::nullopt
```
## Putting values in
The reverse direction works the same way: assigning or constructing a `json` from a C++ value converts it to JSON.
+19
View File
@@ -27,6 +27,7 @@ json data = json::parse(f);
It should be noted that as modules do not export macros, the `nlohmann.json` module will not export any macros.
## Exported symbols
Only the following symbols are exported from `nlohmann.json`:
- `nlohmann::adl_serializer`
@@ -38,3 +39,21 @@ Only the following symbols are exported from `nlohmann.json`:
- `nlohmann::to_string`
- `nlohmann::literals::json_literals::operator""_json`
- `nlohmann::literals::json_literals::operator""_json_pointer`
Additionally, the following `nlohmann::detail` symbols are exported, solely to work around an MSVC compilation issue
([#3970](https://github.com/nlohmann/json/issues/3970)). They are implementation details, not part of the public API,
and should not be used directly:
- `nlohmann::detail::json_sax_dom_callback_parser`
- `nlohmann::detail::unknown_size`
## Known issues
C++20 modules support is exercised in CI against current GCC and Clang on Ubuntu, and the default MSVC toolset on Windows Server 2022 — there is no documented minimum compiler version, unlike feature-test-macro-gated features such as [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md).
!!! info "Known compiler issues"
- **GCC** may emit "redefinition" errors when `#include <nlohmann/json.hpp>` appears in a module preamble together with other imports. This is an upstream GCC bug, not yet resolved as of GCC 16. Workarounds: include `nlohmann/json.hpp` before other `#include`s, use `import nlohmann.json;` instead, or upgrade GCC. ([issue #5103](https://github.com/nlohmann/json/issues/5103))
- **MSVC** could fail with `C2039: 'json_sax_dom_callback_parser' is not a member of ... detail`; fixed by exporting the required internal symbols from `json.cppm` (see [Exported symbols](#exported-symbols) above). ([issue #3970](https://github.com/nlohmann/json/issues/3970))
If you hit a different module-related build failure, search [existing issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+modules) before filing a new one.
@@ -63,6 +63,10 @@ In the default [`json`](../../api/json.md) type, numbers are stored as `#!c std:
number without loss of precision. If this is impossible (e.g., if the number is too large), the number is stored as
`#!c double`.
Positive integers are stored as `#!c std::uint64_t`, while negative integers are stored as `#!c std::int64_t`. This
distinction is determined at parse time: if the JSON number has a leading minus sign, it uses signed integer storage;
otherwise, it uses unsigned integer storage.
!!! info "Notes"
- Numbers with a decimal digit or scientific notation are always stored as `#!c double`.
+4 -1
View File
@@ -326,6 +326,9 @@ An unexpected byte was read in a [binary format](../features/binary_formats/inde
```
[json.exception.parse_error.112] parse error at byte 15: syntax error while parsing BSON binary: byte array length cannot be negative, is -1
```
```
[json.exception.parse_error.112] parse error at byte 9: syntax error while parsing CBOR value: negative integer overflow
```
### json.exception.parse_error.113
@@ -893,7 +896,7 @@ A JSON Patch `add` operation cannot be applied because the target location's par
!!! note
This exception was added in version 3.12.x. Before that, this situation hit an internal assertion (aborting the program in debug builds) or was silently ignored when assertions were disabled.
This exception was added in version 3.13.0. Before that, this situation hit an internal assertion (aborting the program in debug builds) or was silently ignored when assertions were disabled.
## Further exceptions
+1 -1
View File
@@ -178,7 +178,7 @@ See [this section](../features/types/number_handling.md#number-serialization) on
- Can I use `std::format("{}", j)` on a JSON value?
- Can I use `fmt::format("{}", j)` or `fmt::print("{}", j)` (the [{fmt}](https://github.com/fmtlib/fmt) library) on a JSON value?
`std::format` works out of the box since version 3.12.x, as long as the standard library provides
`std::format` works out of the box since version 3.13.0, as long as the standard library provides
`<format>` (see [`JSON_HAS_STD_FORMAT`](../api/macros/json_has_std_format.md)); see
[`std::formatter<basic_json>`](../api/basic_json/std_formatter.md) for details, including the `#!cpp "{:#}"`
pretty-print spec, indent widths (`#!cpp "{:2}"`), and custom indent characters (`#!cpp "{:.>#}"`).
+4
View File
@@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://json.nlohmann.me/sitemap.xml
+25
View File
@@ -0,0 +1,25 @@
"""Copy each documentation page's Markdown source into the built site."""
# Creates a `<path>.md` sibling of each HTML output (for example,
# `features/comments/` becomes `features/comments.md`) so agents and tools can
# fetch the raw Markdown directly instead of parsing rendered HTML.
import os
import shutil
_pages = []
def on_files(files, config):
global _pages
_pages = [f for f in files if f.is_documentation_page()]
return files
def on_post_build(config):
site_dir = config["site_dir"]
for file in _pages:
url = file.url.rstrip("/")
target = os.path.join(site_dir, (url or "index") + ".md")
os.makedirs(os.path.dirname(target), exist_ok=True)
shutil.copyfile(file.abs_src_path, target)
+30
View File
@@ -367,6 +367,9 @@ markdown_extensions:
auto_append:
- ../includes/glossary.md
hooks:
- hooks/copy_markdown_source.py
plugins:
- search:
separator: '[\s\-\.]'
@@ -389,6 +392,33 @@ plugins:
- https://nlohmann.github.io/json/*
- mailto:*
- privacy
- llmstxt:
markdown_description: >
JSON for Modern C++ is a C++11 header-only library implementing a JSON
value type with an STL-like API, JSON Pointer/Patch, CBOR/MessagePack/
BSON/UBJSON/BJData binary format support, and a SAX-style parser interface.
sections:
Home:
- index.md
- home/*.md
Features:
- features/*.md
- features/binary_formats/*.md
- features/element_access/*.md
- features/parsing/*.md
- features/types/*.md
Integration:
- integration/*.md
API Documentation:
- api/*.md
- api/basic_json/*.md
- api/adl_serializer/*.md
- api/byte_container_with_subtype/*.md
- api/json_pointer/*.md
- api/json_sax/*.md
- api/macros/*.md
Community:
- community/*.md
extra_css:
- css/custom.css
+1
View File
@@ -7,5 +7,6 @@ mkdocs-material-extensions==1.3.1 # extensions
mkdocs-minify-plugin==0.8.0 # plugin "minify"
mkdocs-redirects==1.2.3 # plugin "redirects"
mkdocs-htmlproofer-plugin==1.5.0 # plugin "htmlproofer"
mkdocs-llmstxt==0.5.0 # plugin "llmstxt"
PyYAML==6.0.3 # linter
@@ -517,18 +517,19 @@ struct container_input_adapter_factory< ContainerType,
{
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
static adapter_type create(const ContainerType& container)
static adapter_type create(ContainerType&& container)
{
return input_adapter(begin(container), end(container));
return input_adapter(begin(std::forward<ContainerType>(container)), end(std::forward<ContainerType>(container)));
}
};
} // namespace container_input_adapter_factory_impl
template<typename ContainerType>
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
auto input_adapter(ContainerType&& container)
-> typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type
{
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(std::forward<ContainerType>(container));
}
// specialization for std::string
+5
View File
@@ -146,6 +146,11 @@
#define JSON_HAS_RANGES 0
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
#define JSON_HAS_RANGES 0
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
// syntax when compiling as CUDA source; fixed in CUDA 12.2 (issue #3907)
#elif defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) && __CUDACC_VER_MAJOR__ == 12 \
&& defined(__CUDACC_VER_MINOR__) && (__CUDACC_VER_MINOR__ == 0 || __CUDACC_VER_MINOR__ == 1)
#define JSON_HAS_RANGES 0
#elif defined(__cpp_lib_ranges)
#define JSON_HAS_RANGES 1
#else
+29 -9
View File
@@ -465,18 +465,12 @@ class serializer
{
if (codepoint <= 0xFFFF)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<std::uint16_t>(codepoint)));
bytes += 6;
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
}
else
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
bytes += 12;
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)));
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
}
}
else
@@ -683,6 +677,32 @@ class serializer
return result;
}
/*!
* @brief write a lowercase "\uXXXX" escape sequence into @a string_buffer
*
* Branch-free replacement for `snprintf(buf, 7, "\\u%04x", codeunit)` in the
* string escaping hot path. It writes exactly six characters ('\\', 'u' and
* four hex digits) at position @a pos of @a string_buffer via a nibble
* lookup table, avoiding the format-string parsing and locale machinery of
* `snprintf`. Advances @a pos by the number of bytes written (6).
*
* @param[in] pos position in @a string_buffer to write at; there must
* be at least 6 bytes of headroom
* @param[in] codeunit 16-bit value to encode
*/
void write_u_escape(std::size_t& pos, std::uint16_t codeunit) noexcept
{
JSON_ASSERT(string_buffer.size() - pos >= 6);
constexpr const char* nibble_to_hex = "0123456789abcdef";
string_buffer[pos + 0] = '\\';
string_buffer[pos + 1] = 'u';
string_buffer[pos + 2] = nibble_to_hex[(codeunit >> 12u) & 0x0Fu];
string_buffer[pos + 3] = nibble_to_hex[(codeunit >> 8u) & 0x0Fu];
string_buffer[pos + 4] = nibble_to_hex[(codeunit >> 4u) & 0x0Fu];
string_buffer[pos + 5] = nibble_to_hex[codeunit & 0x0Fu];
pos += 6;
}
// templates to avoid warnings about useless casts
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
bool is_negative_number(NumberType x)
+39 -13
View File
@@ -2520,6 +2520,11 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define JSON_HAS_RANGES 0
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
#define JSON_HAS_RANGES 0
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
// syntax when compiling as CUDA source; fixed in CUDA 12.2 (issue #3907)
#elif defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) && __CUDACC_VER_MAJOR__ == 12 \
&& defined(__CUDACC_VER_MINOR__) && (__CUDACC_VER_MINOR__ == 0 || __CUDACC_VER_MINOR__ == 1)
#define JSON_HAS_RANGES 0
#elif defined(__cpp_lib_ranges)
#define JSON_HAS_RANGES 1
#else
@@ -7349,18 +7354,19 @@ struct container_input_adapter_factory< ContainerType,
{
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
static adapter_type create(const ContainerType& container)
static adapter_type create(ContainerType&& container)
{
return input_adapter(begin(container), end(container));
return input_adapter(begin(std::forward<ContainerType>(container)), end(std::forward<ContainerType>(container)));
}
};
} // namespace container_input_adapter_factory_impl
template<typename ContainerType>
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
auto input_adapter(ContainerType&& container)
-> typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type
{
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(std::forward<ContainerType>(container));
}
// specialization for std::string
@@ -19962,18 +19968,12 @@ class serializer
{
if (codepoint <= 0xFFFF)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<std::uint16_t>(codepoint)));
bytes += 6;
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
}
else
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
bytes += 12;
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)));
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
}
}
else
@@ -20180,6 +20180,32 @@ class serializer
return result;
}
/*!
* @brief write a lowercase "\uXXXX" escape sequence into @a string_buffer
*
* Branch-free replacement for `snprintf(buf, 7, "\\u%04x", codeunit)` in the
* string escaping hot path. It writes exactly six characters ('\\', 'u' and
* four hex digits) at position @a pos of @a string_buffer via a nibble
* lookup table, avoiding the format-string parsing and locale machinery of
* `snprintf`. Advances @a pos by the number of bytes written (6).
*
* @param[in] pos position in @a string_buffer to write at; there must
* be at least 6 bytes of headroom
* @param[in] codeunit 16-bit value to encode
*/
void write_u_escape(std::size_t& pos, std::uint16_t codeunit) noexcept
{
JSON_ASSERT(string_buffer.size() - pos >= 6);
constexpr const char* nibble_to_hex = "0123456789abcdef";
string_buffer[pos + 0] = '\\';
string_buffer[pos + 1] = 'u';
string_buffer[pos + 2] = nibble_to_hex[(codeunit >> 12u) & 0x0Fu];
string_buffer[pos + 3] = nibble_to_hex[(codeunit >> 8u) & 0x0Fu];
string_buffer[pos + 4] = nibble_to_hex[(codeunit >> 4u) & 0x0Fu];
string_buffer[pos + 5] = nibble_to_hex[codeunit & 0x0Fu];
pos += 6;
}
// templates to avoid warnings about useless casts
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
bool is_negative_number(NumberType x)
+12 -1
View File
@@ -3,7 +3,18 @@ project(json_cuda LANGUAGES CUDA)
add_executable(json_cuda json_cuda.cu)
target_include_directories(json_cuda PRIVATE ../../include)
target_compile_features(json_cuda PUBLIC cuda_std_11)
# nvcc added C++20 support in CUDA 12.0 and C++17 in CUDA 11.0; pick the
# newest standard the detected compiler actually supports (see #3907)
# instead of hard-requiring one standard for every CUDA version.
if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0)
set(json_cuda_std 20)
elseif(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0)
set(json_cuda_std 17)
else()
set(json_cuda_std 11)
endif()
target_compile_features(json_cuda PUBLIC cuda_std_${json_cuda_std})
set_target_properties(json_cuda PROPERTIES
CUDA_EXTENSIONS OFF
CUDA_STANDARD_REQUIRED ON
+16
View File
@@ -16,4 +16,20 @@ int main()
// regression for #3013 (ordered_json::reset() compile error with nvcc)
nlohmann::ordered_json metadata;
metadata.erase("key");
// exercise comparisons (operator==/operator<=>, gated by
// JSON_HAS_THREE_WAY_COMPARISON, independent of JSON_HAS_RANGES) and
// range-based iteration (exercises iteration_proxy/ranges machinery
// beyond just the enable_borrowed_range specialization) — see #3907
nlohmann::json a = {1, 2, 3};
nlohmann::json b = {1, 2, 3};
static_cast<void>(a == b);
#if JSON_HAS_THREE_WAY_COMPARISON
static_cast<void>(a <=> b); // *NOPAD*
static_cast<void>(a <=> 1); // *NOPAD*
#endif
for (const auto& element : a)
{
static_cast<void>(element);
}
}
+3
View File
@@ -232,6 +232,9 @@ TEST_CASE("algorithms")
// only the first four elements are expected to be sorted, the rest are
// unspecified by the standard
const json expected({nullptr, false, true, 3});
// std::equal below only bounds-checks the first range; assert the
// second range is at least as long to rule out an over-read (CWE-126)
CHECK(std::distance(begin(expected), end(expected)) >= 4);
CHECK(std::equal(j.begin(), j.begin() + 4, begin(expected)));
}
}
+6 -8
View File
@@ -322,14 +322,12 @@ TEST_CASE("alternative string type")
SECTION("JSON pointer")
{
// conversion from json to alt_json fails to compile (see #3425);
// attempted fix(*) produces: [[['b','a','r'],['b','a','z']]] (with each char being an integer)
// (*) disable implicit conversion for json_refs of any basic_json type
// alt_json j = R"(
// {
// "foo": ["bar", "baz"]
// }
// )"_json;
// Direct conversion from a json literal to alt_json is not supported due to issue #3425:
// alt_json's string_t (alt_string) is not directly constructible from std::string, so the
// cross-basic_json conversion falls back to the array-conversion path, incorrectly representing
// objects as arrays of [key, value] pairs and strings as arrays of character codes.
// See https://github.com/nlohmann/json/issues/3425 for details.
// Workaround: use alt_json::parse() instead of implicit conversion.
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]);
+26
View File
@@ -168,6 +168,32 @@ TEST_CASE("convenience functions")
CHECK_THROWS_WITH_AS(check_escaped("\xC2"), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
}
SECTION("string escape with ensure_ascii")
{
// control characters are escaped regardless of ensure_ascii
check_escaped("\x01", "\\u0001", true);
check_escaped("\x1f", "\\u001f", true);
// non-ASCII code points in the Basic Multilingual Plane are emitted as
// a single lowercase \uXXXX escape (exercises every nibble position)
check_escaped("\xC2\x80", "\\u0080", true); // U+0080
check_escaped("\xC3\xBF", "\\u00ff", true); // U+00FF (ÿ)
check_escaped("\xDF\xBF", "\\u07ff", true); // U+07FF
check_escaped("\xE4\xBD\xA0", "\\u4f60", true); // U+4F60 (你)
check_escaped("\xEA\xAF\x8D", "\\uabcd", true); // U+ABCD
check_escaped("\xEF\xBF\xBD", "\\ufffd", true); // U+FFFD (replacement char, all-f nibbles)
// code points outside the BMP are emitted as a UTF-16 surrogate pair
// of two lowercase \uXXXX escapes
check_escaped("\xF0\x90\x80\x80", "\\ud800\\udc00", true); // U+10000 (lowest astral)
check_escaped("\xF0\x9F\x98\x80", "\\ud83d\\ude00", true); // U+1F600 (😀)
check_escaped("\xF4\x8F\xBF\xBF", "\\udbff\\udfff", true); // U+10FFFF (highest code point)
// with ensure_ascii disabled, non-ASCII input is passed through verbatim
check_escaped("\xE4\xBD\xA0", "\xE4\xBD\xA0", false);
check_escaped("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", false);
}
SECTION("string concat")
{
using nlohmann::detail::concat;
+14 -4
View File
@@ -1761,16 +1761,27 @@ TEST_CASE("std::filesystem::path")
}
#endif
#if !JSON_USE_IMPLICIT_CONVERSIONS
TEST_CASE("std::optional")
{
SECTION("null")
{
json j_null;
std::optional<std::string> opt_null;
const json j_null;
const std::optional<std::string> opt_null;
CHECK(json(opt_null) == j_null);
CHECK(j_null.get<std::optional<std::string>>() == std::nullopt);
// Constructing std::optional<T> directly from JSON null throws because
// std::optional's own converting constructor is chosen over basic_json's
// operator T(). This is a language-level limitation (std::optional<T> is
// constructible from T, and T is constructible from basic_json via the
// operator); there is no SFINAE path that distinguishes "call from inside
// std::optional's constructor" from "direct call". Use get<std::optional<T>>()
// or get_to() instead for correct null handling. See #4864 and #5246.
CHECK_THROWS_WITH_AS(std::optional<std::string>(j_null),
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
CHECK_THROWS_WITH_AS(std::optional<int>(j_null),
"[json.exception.type_error.302] type must be number, but is null", json::type_error&);
}
SECTION("string")
@@ -1819,7 +1830,6 @@ TEST_CASE("std::optional")
}
}
#endif
#endif
#ifdef JSON_HAS_CPP_17
#undef JSON_HAS_CPP_17
+41
View File
@@ -54,6 +54,47 @@ TEST_CASE("Custom container non-member begin/end")
}
struct MyContainerNonConstADL
{
char* data;
std::size_t size;
};
char* begin(MyContainerNonConstADL& c)
{
return c.data;
}
char* end(MyContainerNonConstADL& c)
{
return c.data + c.size; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
TEST_CASE("Custom container non-member non-const begin/end")
{
// Container with lvalue-only non-const ADL begin/end (bug reproduction)
char raw_data[] = "[1,2,3,4]";
MyContainerNonConstADL data{raw_data, sizeof(raw_data) - 1};
const json as_json = json::parse(data);
CHECK(as_json.at(0) == 1);
CHECK(as_json.at(1) == 2);
CHECK(as_json.at(2) == 3);
CHECK(as_json.at(3) == 4);
// Same container with accept()
CHECK(json::accept(data));
}
TEST_CASE("Custom container non-member begin/end, rvalue")
{
// Regression check: rvalue container parsing should still work
const json as_json = json::parse(MyContainer{"[1,2,3,4]"});
CHECK(as_json.at(0) == 1);
CHECK(as_json.at(1) == 2);
CHECK(as_json.at(2) == 3);
CHECK(as_json.at(3) == 4);
}
TEST_CASE("Custom container member begin/end")
{
struct MyContainer2
+5108 -7121
View File
File diff suppressed because it is too large Load Diff