Compare commits

..
Author SHA1 Message Date
dependabot[bot] e5d6bb85d4 Bump astyle from 3.4.13 to 3.6.18 in /tools/astyle
Bumps [astyle](https://github.com/Freed-Wu/astyle-wheel) from 3.4.13 to 3.6.18.
- [Release notes](https://github.com/Freed-Wu/astyle-wheel/releases)
- [Commits](https://github.com/Freed-Wu/astyle-wheel/commits)

---
updated-dependencies:
- dependency-name: astyle
  dependency-version: 3.6.18
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-31 15:43:48 +00:00
elix3r 35705d79d8 Fix update(merge_objects=true) throwing on primitive-to-object merge (#5414)
When merge_objects is true, recurse only if the existing value is an
object. Otherwise overwrite, matching the documented "all other values
are overwritten as usual" behavior.

Fixes #5402

Signed-off-by: elix3r <157088510+22elix3r@users.noreply.github.com>
2026-08-28 13:38:28 +01:00
dependabot[bot] 892be68ca4 Bump the codeql-action group across 1 directory with 4 updates (#5388)
Bumps the codeql-action group with 4 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

Updates `github/codeql-action/autobuild` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

Updates `github/codeql-action/analyze` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

Updates `github/codeql-action/upload-sarif` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-28 13:30:33 +01:00
whn 1ac268d409 docs: correct to_bson complexity (#5334)
Signed-off-by: whn <142425816+Whning0513@users.noreply.github.com>
2026-08-28 13:27:18 +01:00
Niels LohmannandClaude 3fa93dac65 docs: document std::pair/std::tuple serializing as an object for string-keyed pairs (#5442)
A std::pair or std::tuple whose every element is itself a two-element array
with a string first element (e.g. std::pair<std::string, int>) serializes to
a JSON object instead of a JSON array, because to_json builds the value with a
brace initializer and the initializer-list object-detection rule fires. The
resulting object cannot be read back into the original type and collapses
duplicate keys. Document this quirk in the conversions guide, together with the
unaffected cases and the idiom to force an array.


Claude-Session: https://claude.ai/code/session_016cwQq8WQRFzQcGQtbJTtJg

Signed-off-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-08-28 13:26:01 +01:00
dependabot[bot] 1876493f87 Bump step-security/harden-runner from 2.20.1 to 2.21.0 (#5394)
Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.20.1 to 2.21.0.
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](https://github.com/step-security/harden-runner/compare/b09bb98e06d4d774595224525879c09bc6e98c40...05e31511f85b41b11d1cf0ef85d0992719546e2c)

---
updated-dependencies:
- dependency-name: step-security/harden-runner
  dependency-version: 2.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-27 07:39:56 +01:00
whn 01853ed6bc docs: document lenient BSON input handling (#5333)
Signed-off-by: whn <142425816+Whning0513@users.noreply.github.com>
2026-08-25 07:18:50 +01:00
Krishnanand G 2f025f401e Throw other_error.502 when UBJSON use_type is set without use_size (#5380)
* Throw other_error.502 when UBJSON use_type is set without use_size

Fixes #5321

Signed-off-by: Krishnanand G <118352827+Krishnanand-G@users.noreply.github.com>

* Scope UBJSON use_type check to container branches and expand tests

Signed-off-by: Krishnanand G <118352827+Krishnanand-G@users.noreply.github.com>

* Re-amalgamate single_include/json.hpp

The previous commit updated the split headers but the amalgamated
file didn't go back through astyle before I committed it, so CI's
amalgamation check caught formatting drift in json_fwd.hpp and a
few noexcept clauses in basic_json, plus one doc example. None of
it touches the UBJSON logic. Applied the patch CI generated to
bring single_include back in sync.

Signed-off-by: Krishnanand G <118352827+Krishnanand-G@users.noreply.github.com>

---------

Signed-off-by: Krishnanand G <118352827+Krishnanand-G@users.noreply.github.com>
2026-08-25 07:16:10 +01:00
Niels Lohmann 734fd305a1 Format-check the documentation examples in CI (#5386)
* Reformat parser_callback_t example with astyle

The file uses "json & /*parsed*/" in three lambda parameter lists, which
astyle rewrites to "json& /*parsed*/" per --align-reference=type. The
drift went unnoticed because CI never format-checked the documentation
examples; "make pretty" does cover them.

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

* Format-check the documentation examples in CI

The examples live in docs/mkdocs/docs/examples, but both format checks
still referenced the long-gone docs/examples path:

- check_amalgamation.yml passed it to find, which printed an error for
  the missing path and carried on, so astyle only ever saw include and
  tests. The step still exited 0.
- ci.cmake globbed it into INDENT_FILES, and a GLOB_RECURSE over a
  missing directory silently yields nothing, so the ci_test_amalgamation
  target skipped the examples too.

Either way the 231 example files have never been format-checked. Point
both at the real path, and guard the workflow with an explicit directory
check so a future rename fails the job instead of quietly shrinking the
file list again.

Also drop the dead docs/examples/** path filter from
publish_documentation.yml; docs/mkdocs/** already covers the examples.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-20 12:32:50 +02:00
dependabot[bot] 36187cacfb ⬆️ Bump wheel from 0.47.0 to 0.48.0 in /docs/mkdocs (#5385)
Bumps [wheel](https://github.com/pypa/wheel) from 0.47.0 to 0.48.0.
- [Release notes](https://github.com/pypa/wheel/releases)
- [Changelog](https://github.com/pypa/wheel/blob/main/docs/news.rst)
- [Commits](https://github.com/pypa/wheel/compare/0.47.0...0.48.0)

---
updated-dependencies:
- dependency-name: wheel
  dependency-version: 0.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-20 12:32:34 +02:00
Sahil_Kamate b5378e8deb Fix CBOR tag handlers not recognizing tags 0-5 and 21-23 (#5331)
* Fix CBOR tag handlers not recognizing tags 0-5 and 21-23

The tagged-item switch in binary_reader::parse_cbor_internal() only handled
head bytes 0xC6-0xD4 and 0xD8-0xDB. Bytes 0xC0-0xC5 (tags 0-5: date/time,
epoch, bignum, decimal, bigfloat) and 0xD5-0xD7 (tags 21-23: base64url,
base64, base16 conversion hints) fell through to the default case and were
reported as invalid bytes, even under cbor_tag_handler_t::ignore and ::store,
despite being valid CBOR major-type-6 tags per RFC 8949.

Add the missing case labels so the full 0xC0-0xDB range is handled
uniformly. Extend the "Tagged values" test in unit-cbor.cpp to cover
0xC0-0xD7, and update the CBOR docs to state the corrected tag range.

Fixes #5315

Signed-off-by: sahilkamate03 <45514385+sahilkamate03@users.noreply.github.com>

* Fix stale CBOR tag docs and add store-mode binary-payload test

The "Incomplete mapping" warning still listed tags 0-5 (date/time,
bignum, decimal fraction, bigfloat) and 21-23 (expected conversions)
as unsupported, even though they now parse correctly under
cbor_tag_handler_t::ignore/store, same as 0xC6..0xD4/0xD8..0xDB.
Remove those five bullets and cross-reference the "Tagged items"
warning below, matching the equivalent docs fix landed independently
in PR #5367.

Also add a cbor_tag_handler_t::store test that wraps a binary
payload (not just a string) for every byte in 0xC0..0xD7, confirming
these tags are unwrapped the same way as 0xC6..0xD4 rather than
mistaken for the 0xD8..0xDB binary-subtype marker syntax, per review
feedback on #5331.

Signed-off-by: sahilkamate03 <45514385+sahilkamate03@users.noreply.github.com>

---------

Signed-off-by: sahilkamate03 <45514385+sahilkamate03@users.noreply.github.com>
2026-08-19 20:19:47 +02:00
dependabot[bot] ce87157d4e ⬆️ Bump the codeql-action group across 1 directory with 4 updates (#5379)
Bumps the codeql-action group with 4 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.5 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3)

Updates `github/codeql-action/autobuild` from 4.37.5 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3)

Updates `github/codeql-action/analyze` from 4.37.5 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3)

Updates `github/codeql-action/upload-sarif` from 4.37.5 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-18 21:47:20 +02:00
dependabot[bot] cdf52ae9be ⬆️ Bump lukka/get-cmake from 4.4.1 to 4.4.2 (#5373)
Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.4.1 to 4.4.2.
- [Release notes](https://github.com/lukka/get-cmake/releases)
- [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md)
- [Commits](https://github.com/lukka/get-cmake/compare/4a7d025fc60f00db0c7b44ebf783d19b52444830...fffaaafeea488556c2c12dad60690008bc1caacb)

---
updated-dependencies:
- dependency-name: lukka/get-cmake
  dependency-version: 4.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-12 21:18:24 +02:00
dependabot[bot] 146ba55453 ⬆️ Bump step-security/harden-runner from 2.20.0 to 2.20.1 (#5375)
Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.20.0 to 2.20.1.
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](https://github.com/step-security/harden-runner/compare/bf7454d06d71f1098171f2acdf0cd4708d7b5920...b09bb98e06d4d774595224525879c09bc6e98c40)

---
updated-dependencies:
- dependency-name: step-security/harden-runner
  dependency-version: 2.20.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-12 09:21:46 +02:00
dependabot[bot] e6978ba50c ⬆️ Bump the codeql-action group with 4 updates (#5372)
Bumps the codeql-action group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.4 to 4.37.5
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43)

Updates `github/codeql-action/autobuild` from 4.37.4 to 4.37.5
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43)

Updates `github/codeql-action/analyze` from 4.37.4 to 4.37.5
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43)

Updates `github/codeql-action/upload-sarif` from 4.37.4 to 4.37.5
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-12 09:21:41 +02:00
ljcjclljc 6285225fd0 Fix integer comparison bug (#5211)
* Fix integer comparison bug

Signed-off-by: ljccjlljc <939159710@qq.com>

* commit

Signed-off-by: ljccjlljc <939159710@qq.com>

* Remove generated CI artifacts and update amalgamation

Signed-off-by: ljccjlljc <939159710@qq.com>

* Silence cpplint braces warning in comparison macro

Signed-off-by: ljccjlljc <939159710@qq.com>

* Update amalgamation after cpplint fix

Signed-off-by: ljccjlljc <939159710@qq.com>

* Add mixed signed and unsigned comparison regression test

Signed-off-by: ljccjlljc <939159710@qq.com>

* Clarify mixed signed and unsigned comparison handling

Signed-off-by: ljccjlljc <939159710@qq.com>

* Expand mixed signed and unsigned comparison tests

Signed-off-by: ljccjlljc <939159710@qq.com>

---------

Signed-off-by: ljccjlljc <939159710@qq.com>
2026-08-12 09:21:19 +02:00
dependabot[bot] 21af527e75 ⬆️ Bump the codeql-action group with 4 updates (#5365) 2026-08-07 19:30:42 +02:00
Niels Lohmann 23518f54fe Add an Ecosystem page for third-party projects built on nlohmann::json (#5369) 2026-08-07 19:29:58 +02:00
Dmitry 1c136a66c4 Move the CBOR doc block to the function it describes (#5363)
The block documenting get_char and tag_handler sat above
get_cbor_negative_integer(), which takes neither, so Doxygen attached it
there and parse_cbor_internal() was left undocumented.

Comment placement only.

Signed-off-by: Dmitry <45711841+darkdi@users.noreply.github.com>
2026-08-06 08:30:15 +02:00
dependabot[bot] c1c19a7bcd ⬆️ Bump lukka/get-cmake from 4.4.0 to 4.4.1 (#5364)
Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.4.0 to 4.4.1.
- [Release notes](https://github.com/lukka/get-cmake/releases)
- [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md)
- [Commits](https://github.com/lukka/get-cmake/compare/e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3...4a7d025fc60f00db0c7b44ebf783d19b52444830)

---
updated-dependencies:
- dependency-name: lukka/get-cmake
  dependency-version: 4.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-06 08:30:00 +02:00
Niels Lohmann bacdabd176 Fix start_pos() for strings containing escape sequences (#5361)
The diagnostic position of a string value was derived by subtracting the
parsed value's length from the end position. Escape sequences make the
source token longer than the value it parses to, so the reported start
position landed inside the string, one byte off per escape sequence:

    input: {"a":"\n\n\n\n\n\n"}
      start_pos() == 11, so the reported range covered  n\n\n\n"
      instead of the documented "\n\n\n\n\n\n"

This contradicts the documented behavior of start_pos(), which is the
position of the opening quote, and it also corrupted the "(bytes N-M)"
part of JSON_DIAGNOSTICS exception messages. Strings with multi-byte
UTF-8 but no escapes were unaffected, which is why this went unnoticed.

Record the offset of the token in the lexer when it starts scanning and
use that, instead of reconstructing it from the parsed value. Booleans,
null and numbers already reported correct positions and are unchanged.

The new lexer member and accessor are compiled only when
JSON_DIAGNOSTIC_POSITIONS is enabled, which is already part of the ABI
tag, so the default build is unaffected.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-05 16:01:23 +02:00
Niels Lohmann d5647e6a3b Resolve the TODO(niels) in get_ubjson_string (#5355)
The comment asked whether the no-op marker 'N' may be ignored when a
string is read. It may not: at that point the next byte must be a string
length type specification, and 'N' is not one. No-ops at positions where
a value may start are already consumed by the callers through
get_ignore_noop(), so nothing is lost by not skipping them here.

Replace the TODO with a comment stating that, and add regression tests
pinning both directions: a no-op is accepted at top level (also
repeated), before and after an array element, and before an object key,
between key and value, and before the closing brace of an object of
unknown size; it is rejected where a length type specification is
expected, i.e. after the 'S' marker of a string value and as the key
length of an object of known size.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-05 14:47:40 +02:00
Niels Lohmann 9a091d2b82 Do not write BJData ndarrays whose size overflows std::size_t (#5362)
* Do not write BJData ndarrays whose size overflows std::size_t

write_bjdata_ndarray() multiplied the _ArraySize_ dimensions into a
std::size_t without checking for overflow. A product that wraps around
to a value that happens to match the size of _ArrayData_ passed the
length check, and the writer emitted an ndarray header announcing an
element count that cannot be represented:

    {"_ArrayType_":"uint8","_ArraySize_":[9223372036854775808,2],"_ArrayData_":[]}

was encoded as 5b 24 55 23 5b 4d 00 00 00 00 00 00 00 80 69 02 5d, an
ndarray of 2^64 elements followed by no data. Reading that back throws
out_of_range.408 ("excessive ndarray size caused overflow"), so to_bjdata
produced output that from_bjdata rejects. This is reachable by parsing
untrusted JSON and re-encoding it as BJData.

Mirror the overflow check the binary reader already performs, and also
reject a single dimension that does not fit into std::size_t, which the
previous cast silently truncated where std::size_t is narrower than 64
bits. Such objects now fall back to a plain object encoding, which is
what the surrounding type and length validation already does for
annotations it cannot represent, and they round-trip unchanged.

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

* Document when to_bjdata converts a JData annotation to an ND-array

The BJData page described the 1-D vector case as the only situation in
which an object carrying _ArrayType_/_ArraySize_/_ArrayData_ is not
written as a compact ND-array. The writer has always had several other
fallbacks -- an unknown _ArrayType_, a dimension that is not a
non-negative integer, an _ArrayData_ whose length does not match the
product of the dimensions, and elements that are not numbers of the
annotated kind -- all of which cause the value to be serialized as a
regular JSON object instead.

Spell out the conditions, including the size-overflow check added in the
preceding commit, so the documented behavior matches the implementation.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-05 13:44:15 +02:00
Niels Lohmann b890b4cba3 CI: build the MinGW Clang matrix without debug info (#5360)
Linking test-regression2_cpp20 intermittently fails with

  unit-regression2.cpp.obj:(.debug_info+0x16): relocation truncated to
  fit: IMAGE_REL_AMD64_SECREL against `.debug_line'

The failure moves between matrix entries from run to run, and the same
commit can pass and fail on consecutive runs, so it is the size of the
debug sections rather than any one Clang version.

The jobs only build and run the tests, so override CMAKE_CXX_FLAGS_DEBUG
to drop the default -g. Everything else about the Debug build is
unchanged: no optimization flag is added and NDEBUG stays undefined, so
JSON_ASSERT remains active.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-05 13:44:05 +02:00
Angadi56 dca9d49a33 reject out-of-range code points in UTF-32 wide-string input (#5348)
* reject out-of-range code points in UTF-32 wide-string input

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

* remove useless cast to char_traits<char>::int_type

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

---------

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>
2026-08-05 13:43:36 +02:00
Petr Bělohlávek acd87e2336 CI: Add clang 21&22 to Ubuntu CLang build matrix (#5347)
* Add clang 21 to ubuntu build matrix (CI)

Signed-off-by: Petr Belohlavek <me@petrbel.cz>

* Add clang 22 to ubuntu build matrix (CI)

Signed-off-by: Petr Belohlavek <me@petrbel.cz>

* Register Clang 22.1.8 to quality_assurance.md

Signed-off-by: Petr Belohlavek <me@petrbel.cz>

---------

Signed-off-by: Petr Belohlavek <me@petrbel.cz>
2026-08-04 16:14:35 +02:00
Niels Lohmann ad94fb01cc docs: document size-mismatch behavior of fixed-size conversions (#5352)
Conversions whose element count is fixed by the destination C++ type --
`std::pair`, `std::tuple`, `std::array<T, N>`, C arrays, and
`std::map`/`std::unordered_map` with a non-string key -- read exactly the
elements they need via `at` and never compare the JSON array's size to
that number. Excess elements are silently discarded, while a shortfall
throws `out_of_range.401` rather than a `type_error`. Neither direction
was documented in `conversions.md`, `get.md`, or `from_json.md`.

The existing warning covered only `std::array` and stated that a too-short
JSON array leaves the remaining elements default-constructed with no
exception thrown; that is not what happens. Generalize it to all
fixed-size destinations and correct the shortfall direction.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-04 08:45:50 +02:00
Niels Lohmann c2e1cc50e0 docs: document the complexity of ordered_map operations (#5353)
* docs: document the complexity of ordered_map operations

ordered_map stores its elements in a std::vector in insertion order and
has no lookup index, so emplace, operator[], at, find, count, erase, and
insert are all linear scans. The documentation stated no complexity for
any operation, neither in ordered_map.md nor in ordered_json.md.

Add a per-operation complexity table and note the consequence: building
or parsing an ordered_json object of n keys is O(n^2). Measured with
-O2 -DNDEBUG for parsing a flat object of n keys, ordered_json is 5x
slower than json at n=2000 and 54x slower at n=16000, with the timings
quadrupling per doubling of n. Cross-reference the table from
ordered_json.md and from the object order page, which recommends
ordered_json without mentioning the cost.

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

* docs: move the Complexity section after Member functions

scripts/check_structure.py enforces a fixed section order for pages under
docs/mkdocs/docs/api, in which Complexity comes after Member functions.
The section had been placed right after Iterator invalidation, which made
ci_test_build_documentation fail with structure/section_order.

No content change beyond the move; the table columns are realigned to the
narrower content.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-04 08:45:35 +02:00
Niels Lohmann 173f2a7407 Documentation review: exceptions from binary-format hardening, and tuple reference types (#5359)
* 📝 Document exceptions newly thrown by the binary-format hardening

A round of binary-format input validation (#5274, #5284, #5287, #5332)
added new failure modes without updating exceptions.md, and left two
descriptions factually narrower than the code:

- parse_error.110 said "CBOR or MessagePack"; BSON and UBJSON also
  throw it. Generalized, and added the BSON EOF example (#5332).
- parse_error.112: added the BSON document-size mismatch example
  (#5287).
- parse_error.113 said "while parsing a map key", but its own existing
  UBJSON char example already contradicted that. Broadened to cover
  invalid length specifications, and added the negative-string-length
  example (#5284).
- out_of_range.408 said "of an UBJSON array or object"; CBOR now throws
  it too (#5274). Generalized and added both CBOR examples.

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

* 📝 Correct which types may be referenced in a tuple extraction

The note added in #5271 said a referenced type must be one the library
stores "or an arithmetic type it can convert to/from". The parenthetical
is wrong: is_compatible_reference_type requires an exact match against
the stored types, so std::tuple<int&> is rejected by static_assert even
though int converts fine as a value. Only the value case is permissive.

Spell out the eight admissible types, give the int& counter-example, and
separate the reference restriction from by-value conversion.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-04 08:45:18 +02:00
Niels Lohmann 1c63a120b6 docs: document how discarded values are removed by the parser callback (#5354)
Follow-up to #5342, which fixed the parser callback leaving a discarded
member behind when an array or a value under an object key was rejected.
The documentation of parser_callback_t only stated that discarded values
in structured types are skipped, without saying that this covers object
parents and that the key is removed along with the value, so there was no
way to tell the fixed behavior from the buggy one.

Spell out the discarding rules, add an example that exercises the cases
the fix repaired, and correct the return value description: a discarded
top-level value is replaced by null, not by "an empty discarded object".

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-04 08:45:02 +02:00
Niels Lohmann 85889e8843 docs: use HTTPS for the astyle and cppcheck links in README (#5351)
* docs: use HTTPS for the astyle and cppcheck links in README

Both links were still `http://`. `astyle.sourceforge.net` serves HTTPS
directly; `cppcheck.sourceforge.net` redirects to
`https://cppcheck.sourceforge.io`, which is also the URL already used in
`docs/mkdocs/docs/community/quality_assurance.md`, so the redirect is
skipped here.

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

* CI: suppress -Wc2y-extensions for Clang

Clang 22.1 (now shipped by silkeh/clang:latest) diagnoses __COUNTER__ as a
C2y extension, and does so in C++ mode as well. Under -Weverything -Werror
this breaks every ci_test_clang_cxx* / ci_test_clang_libcxx_cxx* target,
independently of the code under test.

The library itself does not use __COUNTER__; all diagnostics originate in
vendored Doctest (DOCTEST_ANONYMOUS, used by TEST_CASE and SECTION).

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-04 08:43:59 +02:00
dependabot[bot] 3c0a9a99fd ⬆️ Bump actions/stale from 10.4.0 to 11.0.0 (#5350)
Bumps [actions/stale](https://github.com/actions/stale) from 10.4.0 to 11.0.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/1e223db275d687790206a7acac4d1a11bd6fe629...4391f3da665fdf50b6810c1a66712fb9ba21aa93)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 11.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-03 20:50:15 +02:00
dependabot[bot] e82724d87f ⬆️ Bump coverallsapp/github-action from 2.3.7 to 2.3.8 (#5349)
Bumps [coverallsapp/github-action](https://github.com/coverallsapp/github-action) from 2.3.7 to 2.3.8.
- [Release notes](https://github.com/coverallsapp/github-action/releases)
- [Commits](https://github.com/coverallsapp/github-action/compare/5cbfd81b66ca5d10c19b062c04de0199c215fb6e...8d6379e14d29928660c4ba802d8e85393440b329)

---
updated-dependencies:
- dependency-name: coverallsapp/github-action
  dependency-version: 2.3.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-03 20:50:05 +02:00
KBSandmanon 78821cd9c2 docs: document standards compliance and parse() vs operator>> strictness (#5326)
* docs: document RFC 8259 / JSONTestSuite compliance and parse() vs operator>> strictness

The compliance story lived only in tests/src/unit-testsuites.cpp, so
drive-by comparisons kept claiming the library "does not fully pass
JSONTestSuite". Make it discoverable:

- README: add a "Standards compliance" note stating that both nst
  JSONTestSuite revisions run in CI, that all mandatory y_/n_ cases pass
  through the strict parse() entry point, and listing the deliberate
  implementation-defined i_ choices (unbounded nesting, silent BOM
  stripping, noncharacters forwarded, strict rejection of invalid UTF-8
  and lone surrogates, out_of_range.406 on numeric overflow).
- features/parsing: add a "Strictness and trailing data" section
  documenting that parse() is strict and rejects trailing data while
  operator>> follows relaxed iostream semantics (parses one value and
  leaves the stream positioned after it) -- the single place a naive
  test yields a "non-compliant" result.

Documentation only; no parser behavior change. Closes #5290.

Signed-off-by: manon <youdie006@users.noreply.github.com>

* docs: correct test-data vendoring and parse()/operator>> claims per review

- README: the JSONTestSuite data is downloaded from nlohmann/json_test_data at
  configure time, not vendored/committed; say so.
- README: only the updated suite runs y_ and n_ cases through strict parse();
  the original suite's y_ cases go through operator>>. Narrow the claim.
- parsing/index.md and operator_gtgt.md: note that operator>> consumes a number's
  terminating byte, so concatenated numbers must be whitespace-separated (1 2
  works, 1true does not); structural and literal values are unaffected.

Signed-off-by: manon <youdie006@users.noreply.github.com>

---------

Signed-off-by: manon <youdie006@users.noreply.github.com>
Co-authored-by: manon <youdie006@users.noreply.github.com>
2026-08-03 19:15:53 +02:00
Angadi56 68f0722a19 remove discarded array from parent object in end_array (#5342)
* remove discarded array from parent object in end_array

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

* remove discarded scalar value from parent object in handle_value

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

---------

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>
2026-08-03 19:13:31 +02:00
Angadi56 5f121d8c50 avoid sign extension in char_traits<signed char>::to_int_type (#5336)
* avoid sign extension in char_traits<signed char>::to_int_type

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

* spell out-of-range signed char constants as negative values (MSVC C4309)

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

---------

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>
2026-08-03 08:35:53 +02:00
Niels Lohmann 585929bff9 Fix Clang deprecation warning for json_pointer operator== with ordered_json (#5289)
is_comparable used a flat && chain to both exclude json_pointer/string
comparisons (added for #4621) and check whether Compare(A, B) is well-formed.
Naming std::is_constructible<decltype(...)> as a later operand of that chain
still causes the decltype to be substituted regardless of the first
operand's value, since the operands aren't lazily deferred like
std::conjunction would defer them. That instantiates the transparent
std::equal_to<>::operator() used by ordered_json, whose noexcept-specifier
evaluates the deprecated json_pointer/string operator==, which Clang (unlike
GCC in this case) warns about even though the result is discarded.

Split is_comparable so the Compare(A, B) checks live in a separate helper
that is only referenced from the specialization selected when
is_json_pointer_of is false, so the decltype is never written when A/B are
a json_pointer/string pair, regardless of compiler.

Signed-off-by: Niels Lohmann <niels.lohmann@gmail.com>
2026-08-03 08:20:41 +02:00
Niels Lohmann 31ba5208c8 docs: qualify the operator>> stream positioning guarantee (#5343)
operator>>'s notes state that it leaves the stream positioned right
after the parsed value, so that concatenated JSON values can be read
back to back. That does not hold when the value is a number: a number
is only terminated by the character that follows it, and the lexer's
unget() is simulated (it rewinds only the lexer's own bookkeeping),
so that character stays consumed from the stream.

Document the actual behaviour: the guarantee holds for all value types
except numbers, which must be followed by whitespace. Also qualify the
cross-reference on the JSON Lines page, which repeated the unqualified
claim.

Documentation only; the behaviour itself is tracked in #5340.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-03 08:18:03 +02:00
tomatotomata 2222d386c9 fix: check CBOR tagged subtype reads (#5339) 2026-07-31 22:06:55 +02:00
dependabot[bot] eaedec859a ⬆️ Bump the codeql-action group with 4 updates (#5341)
Bumps the codeql-action group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.2 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e0647621c2984b5ed2f768cb892365bf2a616ad1...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

Updates `github/codeql-action/autobuild` from 4.37.2 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e0647621c2984b5ed2f768cb892365bf2a616ad1...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

Updates `github/codeql-action/analyze` from 4.37.2 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e0647621c2984b5ed2f768cb892365bf2a616ad1...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

Updates `github/codeql-action/upload-sarif` from 4.37.2 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e0647621c2984b5ed2f768cb892365bf2a616ad1...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-31 20:45:32 +02:00
Angadi56 d94cbd99dc reject CBOR array/map length equal to the indefinite-length marker (#5274)
* reject CBOR array/map length equal to the indefinite-length marker

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

* reject CBOR lengths that do not fit in std::size_t via value_in_range_of

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

---------

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>
2026-07-31 18:04:30 +02:00
hum4nBeingandAJ369ninja bc48951128 Fix UBJSON high-precision floating-point overflow handling (#5323)
This adds a std::isfinite check to the UBJSON floating-point parsing path, throwing out_of_range.406 on overflow. This makes the UBJSON parser's behavior consistent with the normal JSON parser. Fixes #5322.

Signed-off-by: AJ369ninja <abhishek.j@iitg.ac.in>
Co-authored-by: AJ369ninja <abhishek.j@iitg.ac.in>
2026-07-31 18:04:13 +02:00
Angadi56 fd72ecfc8c validate ndarray element types in write_bjdata_ndarray (#5301)
* validate ndarray element types in write_bjdata_ndarray

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

* read ndarray elements through get<> instead of a fixed union member

_ArrayType_ names the wire type, not how the value is stored: parsing
keeps a non-negative integer as number_unsigned while the C++ API keeps
an int literal as number_integer. Selecting the union member from the
type marker therefore reads the inactive alternative for one of the two,
so read through get<> instead, which dispatches on the active member.

Also reject a negative _ArraySize_ entry, which is not a usable
dimension, and cover the parse-built path in the tests.

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>

---------

Signed-off-by: Angadi Yashaswini <angadi@digiscrypt.com>
2026-07-31 08:52:27 +02:00
YingqiDuan de8a099ba5 Document BSON interoperability and subtype-less binary round trips (#5330)
- warn about BSON marker 0x11 interoperability in both directions
- explain subtype-less binary normalization to subtype 0x00
- add a round-trip test for binary values without a subtype

Signed-off-by: YingqiDuan <141370165+YingqiDuan@users.noreply.github.com>
2026-07-31 08:33:07 +02:00
Yash Bavadiya dd24e2dffd check all BSON reads and add an EOF check for booleans (#5332)
Signed-off-by: Yash Bavadiya <krbavadiya11@gmail.com>
2026-07-30 23:44:31 +02:00
Patrick10199 868506dcc0 Fix CBOR half-float assertion bounds (#5335)
Signed-off-by: Patrick Armstrong <patrick@erpassistant.ai>
2026-07-30 23:38:13 +02:00
dependabot[bot] 58ce09dcfd ⬆️ Bump the codeql-action group with 4 updates (#5329)
Bumps the codeql-action group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.1 to 4.37.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e0647621c2984b5ed2f768cb892365bf2a616ad1)

Updates `github/codeql-action/autobuild` from 4.37.1 to 4.37.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e0647621c2984b5ed2f768cb892365bf2a616ad1)

Updates `github/codeql-action/analyze` from 4.37.1 to 4.37.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e0647621c2984b5ed2f768cb892365bf2a616ad1)

Updates `github/codeql-action/upload-sarif` from 4.37.1 to 4.37.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e0647621c2984b5ed2f768cb892365bf2a616ad1)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-30 22:12:23 +02:00
dependabot[bot] 8dacb98041 ⬆️ Bump ossf/scorecard-action from 2.4.3 to 2.4.4 (#5337)
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.4.3 to 2.4.4.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/4eaacf0543bb3f2c246792bd56e8cdeffafb205a...2d1146689b8cda280b9bc96326124645441f03bc)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-30 22:11:56 +02:00
Luke Banicevic 2e23687092 to_bson() silently emits corrupt documents when a length exceeds INT32_MAX (#5314) 2026-07-28 09:08:57 +00:00
dependabot[bot] 227c5cdfb1 ⬆️ Bump mkdocs-material from 9.7.6 to 9.7.7 in /docs/mkdocs (#5324) 2026-07-27 17:36:07 +00:00
dependabot[bot] 0832fd1cb4 ⬆️ Bump lukka/get-cmake from 4.3.4 to 4.4.0 (#5303) 2026-07-27 12:40:58 +00:00
Luke Banicevic 8ec98e2c9e adding cleanups to bson writer (#5313) 2026-07-27 10:11:10 +00:00
dependabot[bot] 88b28ac43c ⬆️ Bump actions/checkout from 7.0.0 to 7.0.1 (#5302) 2026-07-26 23:28:28 +00:00
dependabot[bot] e0c3c819e1 ⬆️ Bump the codeql-action group across 1 directory with 4 updates (#5300) 2026-07-26 21:41:52 +00:00
Niels Lohmann 06ac77f4fd Remove Lion Yang from sponsors list (sponsorship cancelled) (#5306) 2026-07-26 19:42:28 +00:00
Luke Banicevic dfa51af692 Enhance documentation on serializing untrusted input in dump() (#5304) 2026-07-26 08:29:31 +00:00
Niels Lohmann d0d29039da ci: retry ubuntu-toolchain-r PPA add to survive Launchpad flakiness (#5305) 2026-07-25 19:57:26 +00:00
Angadi56 9a3ebb9456 validate BSON document size against the bytes read (#5287) 2026-07-23 19:51:40 +00:00
Luke Banicevic 3296a3ad8c Docs: clarify there is no official npm package (impersonation/typosquat awareness) (#5299) 2026-07-23 16:02:29 +00:00
Angadi56 3565f40229 reject negative UBJSON/BJData string length (#5284) 2026-07-20 20:32:38 +00:00
Angadi56 1c5a953de5 reject unpaired UTF-16 surrogates in wide-string input (#5276) 2026-07-19 18:33:42 +02:00
dependabot[bot] a03e65420c ⬆️ Bump the codeql-action group with 4 updates (#5275) 2026-07-18 13:59:20 +02:00
dependabot[bot] d6ede37088 ⬆️ Bump actions/stale from 10.3.0 to 10.4.0 (#5277) 2026-07-18 13:58:45 +02:00
Niels Lohmann 722c03495f Extend std::optional null regression coverage (assignment, get_to) (#5269) 2026-07-12 09:16:25 +02:00
Niels Lohmann c197feff81 Extend memcpy fast path to sized sentinels (e.g. std::counted_iterator) (#5268) 2026-07-12 09:16:06 +02:00
Niels Lohmann b2b47c69b1 📝 Document std::pair/std::tuple conversion and C++20 range-view construction (#5271)
Both had zero documentation anywhere in docs/mkdocs/. The tuple/pair
gap was first spotted in the very first git-log audit pass but never
turned into an actionable todo, so it persisted uncaught across four
subsequent passes.

- Document basic positional std::pair/std::tuple <-> json array
  conversion, plus #5016's reference-extraction capability
  (get<std::tuple<T&, T&>>() returning references into the stored
  array elements).
- Document #5205's new json-from-C++20-range-view constructor
  (e.g. nums | std::views::filter(...)).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 23:58:49 +02:00
Niels LohmannandClaude Sonnet 5 6a406ee141 Document that JSON_Diagnostics CMake option doesn't apply to pre-installed packages (#5270)
Closes #3106. set(JSON_Diagnostics ON) before find_package() has no
effect on a package built and installed elsewhere (Homebrew, vcpkg, a
system package, etc.) -- the compile definition is baked into the
exported nlohmann_jsonTargets.cmake at install time and the generated
config script never re-reads that variable. Verified empirically
against the real Homebrew-installed 3.12.0 package: the exported
target carries a fixed $<$<BOOL:OFF>:JSON_DIAGNOSTICS=1>, and the
suggested set(JSON_Diagnostics ON) snippet produces no change in
exception output.

Documents the actual working fix (overriding the imported target's
INTERFACE_COMPILE_DEFINITIONS property after find_package()) and the
multi-target "JSON_DIAGNOSTICS redefined" pitfall reported earlier in
the issue thread.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-11 23:58:18 +02:00
Niels Lohmann ca76c37650 Add iterator+sentinel tests and docs for binary deserializers (#5265)
* Add iterator+sentinel tests and docs for binary deserializers

This commit extends the C++20 ranges support (iterator+sentinel pairs) to the
binary format deserializers from_cbor, from_msgpack, from_ubjson, from_bjdata,
and from_bson, matching what was already done for parse(), accept(), and
sax_parse().

Changes:
- Add istreambuf_sentinel helper to test_utils.hpp for EOF detection in tests
- Add 5 new test cases that read binary files directly via
  std::istreambuf_iterator<char> + sentinel, without pre-buffering
- Update documentation for all 5 from_* functions to document overload (3)
  with SentinelType parameter
- All tests pass; verified against existing test suite data
- Fix potential buffer over-read warning in heterogeneous iterator test

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

* Merge iterator+sentinel overloads and fix ambiguity/CI issues

Address PR review feedback and CI failures:

- Merge the separate same-type and sentinel-type iterator overloads of
  parse(), accept(), sax_parse(), and the five from_* binary deserializers
  into a single overload with SentinelType defaulted to IteratorType,
  as suggested in review. Applied the same simplification to the
  detail::input_adapter() free functions.
- Fix a latent ambiguity: some compilers (e.g. GCC 4.8) unreliably SFINAE
  the operator!= detection for std::nullptr_t against container/string
  types, making calls like parse(s, nullptr, ...) ambiguous with the
  compatible-input overload. can_compare_ne now explicitly excludes
  std::nullptr_t as a SentinelType.
- Use a named enable_if_t template parameter instead of an unnamed
  function parameter for the SFINAE guard, fixing a clang-tidy
  hicpp-named-parameter/readability-named-parameter failure.
- Update parse.md, accept.md, sax_parse.md, and the five from_*.md pages
  to document the merged overload instead of separate (2)/(3) overloads,
  also fixing an over-160-char line that broke the documentation
  style_check CI job.
- Rework the BSON iterator+sentinel test to parse a BSON file already
  present in the test suite instead of writing/deleting a temp file.

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

* Fix -Wunneeded-internal-declaration for CustomSentinel in test

CustomSentinel lives in an anonymous namespace (internal linkage), and
the library's parse loop only ever evaluates the iterator-first
direction (it != last), so the reversed-order friend operator!= was
never referenced. Clang's -Weverything flags such unused internal
declarations as an error. Drop the unused overload; the used direction
is enough to satisfy can_compare_ne's either-order detection.

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

* Fix clang-tidy hicpp-named-parameter and misc-const-correctness

- Drop the unused reversed-order operator!= overload from
  utils::istreambuf_sentinel (only iterator != sentinel is ever
  evaluated) and name the remaining friend's sentinel parameter, fixing
  hicpp-named-parameter/readability-named-parameter.
- Mark the istreambuf_iterator first/last helper variable const in the
  five binary-format sentinel tests, fixing misc-const-correctness.

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

* Fix clang-tidy misc-const-correctness in heterogeneous sentinel test

json_str is only read via .data()/.size() and never reassigned, so
clang-tidy correctly flags it as const-able. Verified against the exact
CI job (silkeh/clang:dev, ci_clang_tidy target) by running clang-tidy
directly on this file plus the five binary-format sentinel tests
touched by prior commits; all are now clean.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 15:09:28 +02:00
Niels Lohmann fe2bcc080f Custom BinaryType direct assignment (#5266)
* Fix discussion #4209: custom BinaryType direct assignment and extraction

When a custom BinaryType is configured (other than the default std::vector<uint8_t>),
users can now:
1. Assign values of that type directly to create binary values (not arrays)
2. Extract binary values back to that type with get<>()
3. Extract arrays to that type (for backward compatibility)

Implementation:
- Add is_compatible_binary_type trait to centralize SFINAE condition
- Update to_json to accept custom BinaryType values directly
- Update from_json to handle both binary and array inputs for custom BinaryType
- Add #include <vector> with IWYU comment to from_json.hpp
- Add comprehensive tests for assignment and array extraction
- Update binary_t documentation with example

This is purely additive and invisible to the default nlohmann::json alias, which
continues to treat std::vector<uint8_t> as arrays.

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

* Fix CI: missing include and const-correctness

- Add #include <vector> to type_traits.hpp for the new
  is_compatible_binary_type trait's std::vector<std::uint8_t> reference
  (caught by cpplint's include-what-you-use check)
- Mark test-local json variables const where never reassigned
  (caught by clang-tidy's misc-const-correctness check)

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 15:09:05 +02:00
Federico Sfriso c60217e801 fix: support constructing json from C++20 range views (#4916) (#5205) 2026-07-11 09:13:04 +02:00
Niels Lohmann 6ba332c7df Migrate remaining CI jobs off custom json-ci image to official images (#5263)
* Migrate ci_icpc/ci_test_compilers_gcc_old/ci_infer off custom json-ci image

Replaces the last three consumers of ghcr.io/nlohmann/json-ci with official
images: ci_icpc now uses Intel's own intel/oneapi-hpckit:2023.2.1-devel-ubuntu22.04
(the last release with classic icc/icpc before Intel dropped it in oneAPI
2024.0), ci_test_compilers_gcc_old installs old GCCs on official ubuntu:20.04
via the same PPA/archive setup the custom image used (working around
actions/checkout's incompatibility with official gcc:4/5/6 images), and
ci_infer runs directly on ubuntu-latest, fetching Facebook's official Infer
release tarball inline instead of a maintained image. No job in
ubuntu.yml references the custom image anymore.

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

* Update quality-assurance compiler table for CI image migration

Reflects the ci_icpc/ci_test_compilers_gcc_old container migration: the
old-GCC jobs (4.8/4.9/5/6) now compile inside official ubuntu:20.04 rather
than the custom Focal-based json-ci image (same OS, just now attributed to
the official image), and ci_icpc now uses Intel's official
intel/oneapi-hpckit:2023.2.1-devel-ubuntu22.04, bumping the reported ICC
version from 2021.5.0 to 2021.10.0 and the OS from Ubuntu 20.04.3 to 22.04.

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

* Fix CI failures from the json-ci image migration

- ci_icpc: the official intel/oneapi-hpckit image has no CMake preinstalled
  (the custom image bundled one); add the missing lukka/get-cmake step.
- ci_test_compilers_gcc_old: official ubuntu:20.04 has no build tool, so
  CMake's default Unix Makefiles generator failed with "CMAKE_MAKE_PROGRAM
  is not set"; install make alongside the PPA-provided g++.
- ci_infer: Infer v1.1.0's bundled Clang frontend can't parse GCC 14's
  headers (ubuntu-latest's default toolchain), failing with parse errors in
  <bits/unicode.h>; bump to the latest release, v1.3.0, whose newer bundled
  frontend understands them (release asset also renamed upstream from
  infer-linux64-v1.1.0.tar.xz to infer-linux-x86_64-v1.3.0.tar.xz).

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

* Fix ci_test_compilers_gcc_old: g++-6 missing from xenial-only archives

My inline PPA/archive replication only added the xenial main/universe
suites, but g++-6 isn't available there ("has no installation candidate").
The original custom Dockerfile also pulled from bionic main/universe and
xenial-updates main/universe; add those back to match.

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

* Fix ci_test_compilers_gcc_old: install git for CMake's FetchContent tests

Official ubuntu:20.04 ships no git at all (actions/checkout only succeeded
via its API-download fallback). The cmake_fetch_content(2) tests invoke
CMake's own ExternalProject_Add, which needs a real git binary and failed
with "could not find git for clone of json-populate". Install git alongside
the other build prerequisites.

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

* Fix ci_icpc: drop redundant setvars.sh sourcing

Unlike the old custom image, the official intel/oneapi-hpckit image already
has the oneAPI environment (icc/icpc on PATH) baked in at the container
level. Explicitly re-sourcing setvars.sh in the Build step failed with
"setvars.sh has already been run. Skipping re-execution." (exit code 3,
aborting the step under `sh -e`). Drop the now-unnecessary sourcing.

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

* Fix ci_icpc: exclude classic ICC from the std::span regression test

Bumping to Intel's official intel/oneapi-hpckit:2023.2.1 image (see previous
commit) also bumped classic icc/icpc from 2021.5.0 to 2021.10.0. The newer
version's __has_include(<span>) now returns true, but it still can't
actually compile std::span/std::as_bytes usage:

  error: namespace "std" has no member "as_bytes"
  error: namespace "std" has no member "span"

Exclude __ICC/__INTEL_COMPILER the same way _LIBCPP_VERSION is already
excluded for issue #4490.

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

* Fix amalgamation/style check: indent comment per astyle

Verified with the pinned astyle 3.4.13 (make install_astyle) locally;
no further diff.

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

* Fix ci_icpc: skip UTF-8 u8-literal comparison test on classic ICC

test-deserialization_cpp20 failed:

  ERROR: CHECK( j2["emoji"] == "😀" ) is NOT correct!

check_utf8() only guards against MSVC's ANSI-codepage quirk (its docstring
example), but classic ICC has an analogous problem: it doesn't encode a
narrow string literal containing non-ASCII source characters as UTF-8,
so comparing a decoded u8R"(...)" literal against a narrow literal with
the same characters fails. Extend the existing guard.

Verified with the pinned astyle 3.4.13; no diff.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-10 16:11:41 +02:00
Niels Lohmann e9c3985f0a Fix documentation gaps found in a full GitHub Discussions review (#5264)
* 📝 Fix documentation gaps found in a full GitHub Discussions review

Reviewed all 1008 GitHub Discussions (2020-2026) for recurring questions
that better or more visible documentation would have avoided. Adds/expands
documentation for ~26 distinct gaps, including:

- New "Debugging" page collecting natvis, GDB pretty printer, LLDB status,
  and JSON_DIAGNOSTICS pointers (previously scattered/undiscoverable)
- Thread-safety and schema-validation FAQ entries
- StringType's char-based requirement (no wstring/u16string/u32string)
- Brace-initialization-yields-arrays warning directly on the constructor
  reference page (previously only in the FAQ, missed by users reading
  the constructor docs)
- std::any exclusion from get<T>(), with a manual-dispatch example
- Non-string-keyed std::map serializing as an array of pairs
- ordered_json compatibility with NLOHMANN_DEFINE_TYPE_* macros
  (already worked, was undocumented)
- std::array truncation on size-mismatched conversion (no exception)
- static_cast vs. get<std::optional<T>>() divergence
- Recipe for omitting a std::optional field instead of emitting null
- No built-in nesting-depth limit during parsing + a callback-based
  workaround recipe
- Recipe for streaming a large homogeneous array via parser callbacks
- operator>> stream-position semantics for concatenated JSON values
- JSON Pointer array-vs-object creation rule for non-existing paths
- CMake target name (nlohmann_json_modules) needed to link C++20 modules
- ESP-IDF/PlatformIO: no official package, link to a community fork
- get(key, default) as the Python dict.get() equivalent
- reserve() recipe for pre-allocating array capacity
- JSONC as an alias for the existing ignore_comments/ignore_trailing_commas
  combination (distinct from the unsupported JSON5)
- items() dereferenced-element type: decltype() idiom + detail-namespace
  stability caveat
- Various macro/type-conversion limitations (MSGPACK_DEFINE_ARRAY
  equivalent, char-array round-tripping, ADL serializer macro gap)

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

* 🎨 fix format

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-10 16:01:08 +02:00
Niels Lohmann b630f5e9c7 Fix container input_adapter SFINAE for lvalue-only ADL begin/end (#5260)
* 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>

* 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>

* Avoid trailing return type to satisfy clang-tidy fuchsia-trailing-return

The forwarding-reference input_adapter(ContainerType&&) entry point was
written with an auto/trailing-decltype return type, but this project's
ci_clang_tidy job enables the fuchsia-trailing-return check as an
error, which rejects it. The return type only depends on the template
parameter ContainerType, not on the runtime parameter, so it can be
written as an ordinary leading return type instead - no functional
change.

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

* Avoid C-style array in test to satisfy clang-tidy avoid-c-arrays

clang-tidy's cppcoreguidelines/hicpp/modernize-avoid-c-arrays checks
flagged the char raw_data[] declaration used to reproduce the
lvalue-only non-const ADL begin/end scenario. Use std::string instead
and take a mutable pointer via &raw_data[0], which is the standard
way to get a non-const char* into a string's buffer under C++11
(std::string::data() only returns non-const in C++17 and later).

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-10 13:56:06 +02:00
Niels Lohmann 4d8e7a7210 💚 fix build
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 23:05:56 +02:00
Niels Lohmann 75e8fbac32 Documentation review: fix stale version-history placeholder in operator_ne.md (#5261)
* 📝 Fix stale 3.12.x placeholder in operator_ne.md version history

PR #5253 (removing the hand-written operator!= to fix #3868/P2468R2)
merged after the earlier 3.12.x -> 3.13.0 global sweep, so its new
version-history entries were written with the stale placeholder.

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

* 🐛 Fix stale twitter.com link in docset.json

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 20:57:41 +02:00
Niels Lohmann 631e667fe5 Document a duplicate-object-key rejection recipe (#5259)
* 📝 Document a duplicate-object-key rejection recipe

RFC 8259 leaves handling of duplicate object keys to the implementation;
this library silently keeps only the last value for a repeated key.
Discussion #5085 asked for an opt-in rejection mode. Decision: don't
change library behavior, but document the existing parser-callback
workaround instead.

Adds a "Recipe: rejecting duplicate object keys" section to
parser_callbacks.md, adapted from a community-contributed workaround.
Fixed an off-by-one bug in the original snippet: object_start reports
the depth of the object's parent, while key events inside that object
report depth+1, so indexing the per-depth key set with the same depth
in both places caused an out-of-bounds access on nested objects.
Verified the published snippet compiles and behaves correctly for flat
duplicates, nested duplicates, sibling objects sharing key names, and
arrays of objects.

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

* Cross-link the duplicate-key recipe with the existing object_t behavior docs

object_t.md and features/types/index.md already document that duplicate
object keys resolve to an unspecified value (RFC 8259 leaves this to the
implementation). The new recipe's intro overstated this as a guaranteed
"last value wins" rule, which isn't true in general -- parsing text keeps
the last value, but constructing from an initializer list keeps the first.
Reworded the recipe to point at object_t's "unspecified" behavior instead
of asserting a specific rule, and added cross-links from both existing
pages to the new recipe.

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

* Turn the duplicate-key recipe into a standalone, compiled example

Replace the inline code fence in the "rejecting duplicate object keys"
recipe with a proper docs/mkdocs/docs/examples/*.cpp + .output pair,
included via --8<-- like every other example on the site. The .output
file was generated by running it through the project's actual example
build (docs/Makefile: single_include, -std=c++11, -DJSON_USE_GLOBAL_UDLS=0)
and cross-checked with `make check_output`, and the source passes the
pinned astyle 3.4.13 formatting unchanged.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 20:39:59 +02:00
Niels LohmannandClaude Sonnet 5 d0a43141ea Fix #3868: Remove operator!= to enable P2468R2 rewritten candidate synthesis (#5253)
* Fix #3868: Remove operator!= to enable P2468R2 rewritten candidate synthesis

Under C++20 P2468R2, a hand-written operator!= suppresses the compiler's
rewritten-candidate synthesis for operator==, preventing heterogeneous
comparisons like `std::string s; json j; s == j;` from compiling.

Fix by removing the hand-written operator!=, allowing the compiler to
synthesize != as !(a==b) in all language modes (C++20 member functions
and pre-C++20 friend functions).

Behavior change: operator!= now returns !(a==b) unconditionally, including
for special values like NaN and discarded. This means:
- NaN != NaN now returns true (matches IEEE-754 semantics)
- discarded != x now returns true for any x (matches !(discarded == x))

This also fixes underlying defects in previously-working code:
- Restores direct == comparison for views vs json (reverts std::ranges::equal
  workaround added in PR #3950 to dodge this bug)
- Re-enables std::string == json comparisons (uncomments check in
  unit-constructor1.cpp)

Fixes: #3868, #3979

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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 Sonnet 5 <noreply@anthropic.com>
2026-07-09 20:38:39 +02:00
Niels Lohmann ecff144b3a 📝 Document nvcc CUDA 12.0/12.1 JSON_HAS_RANGES exclusion (#5258)
PR #5248 added a 5th JSON_HAS_RANGES exclusion branch to
macro_scope.hpp (nvcc CUDA 12.0.x/12.1.x, fixed in 12.2, issue #3907)
shortly after #5252 added the "Known compiler/stdlib exclusions"
list to json_has_ranges.md, so the new branch was missing from the
just-added doc section. Bring the list back to parity with the code
(5 exclusion branches, 5 documented).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 20:19:22 +02:00
Niels Lohmann 855f511db4 Fix stale Clang -Weverything suppression comments; drop -Wno-missing-noreturn (#5250)
* Fix stale Clang -Weverything suppression comments; eliminate -Wno-missing-noreturn

cmake/clang_flags.cmake claimed -Wno-unsafe-buffer-usage was needed only
for Doctest and that -Wno-missing-noreturn had "no way to silence...
otherwise" (PR #4871, which never actually attempted a source fix).
Neither held up under investigation (todo 130):

- -Wno-unsafe-buffer-usage is pervasive (208 distinct sites across 19
  files measured with clang trunk in silkeh/clang:dev), spanning the
  library's own low-level numeric/buffer code (to_chars, serializer,
  lexer, binary reader/writer, input adapters, json_pointer) as well as
  vendored Doctest itself (96 of the 208 sites). A source-level fix is
  not feasible at this scale; the comment now says so instead of
  blaming Doctest alone.

- -Wno-missing-noreturn had exactly two real trigger sites, both
  genuinely and unconditionally non-returning: a test-only throwing
  allocator (tests/src/unit-allocator.cpp) and, previously undiscovered,
  wide_string_input_adapter::get_elements<T>() in
  include/nlohmann/detail/input/input_adapters.hpp. Verified this isn't
  a wider pattern by checking all 160 JSON_THROW call sites in the
  library for functions whose entire body is an unconditional throw.
  Annotated both ([[noreturn]] in the test file, since JSON_HEDLEY_NO_RETURN
  is #undef'd by the time test code runs; JSON_HEDLEY_NO_RETURN in the
  library file, its first real use anywhere in the codebase) and
  dropped the suppression entirely.

single_include/nlohmann/json.hpp regenerated via `make amalgamate`;
`make check-amalgamation` passes.

Verified in Docker (silkeh/clang:dev, matching the ci_static_analysis_clang
CI job): baseline builds clean, and the full 194-target test suite builds
with zero warnings under the corrected CLANG_CXXFLAGS (-Wno-missing-noreturn
no longer in the list). Also sanity-compiled and ran unit-allocator.cpp and
unit-wstring.cpp on host Apple Clang to confirm behavior is unchanged.

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

* Fix MSVC C4702 warning caused by JSON_HEDLEY_NO_RETURN on get_elements()

PR #5250 annotated wide_string_input_adapter::get_elements<T>() with
JSON_HEDLEY_NO_RETURN (it unconditionally throws). On MSVC this expands to
__declspec(noreturn), and MSVC correctly determined that the code following
its call in binary_reader.hpp is unreachable for that instantiation, firing
C4702 under /W4 /WX in the msvc, msvc-vs2026, and msvc-arm64 Debug jobs.

Clang doesn't flag this case, so the Docker verification for #5250 (which
only checked Clang -Weverything) didn't catch it.

This is the same warning class already tolerated for Release builds since
PR #5216, where MSVC's optimizer independently found the same dead code
after /Od was removed. Extend that existing /wd4702 suppression to Debug
builds too, instead of reverting the noreturn annotation.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 20:18:28 +02:00
Niels LohmannandClaude Code 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 LohmannandClaude Code 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
dependabot[bot] 3b0dd69928 ⬆️ Bump step-security/harden-runner from 2.19.4 to 2.20.0 (#5242) 2026-07-07 20:01:40 +02:00
Daniel Falk c05c5e229b Add missing copyright notices to SBOM (#5241) 2026-07-07 20:00:49 +02:00
Niels Lohmann acf076a677 Fix ADL leak of nlohmann::detail through basic_json's default base class (#5238) 2026-07-06 12:47:24 +02:00
Paul Dreik 33edc9751c fix unit-algorithms test reliance on implementation specific behaviour (#5236)
the standard only specifies that the first elements are sorted.

this caused my experimental C++ standard library implementation to fail.

Signed-off-by: Paul Dreik <github@pauldreik.se>
2026-07-06 08:25:30 +02:00
Niels Lohmann 83c87cb9e0 Read binary strings/blobs in bulk chunks with a memcpy fast path (#5233) 2026-07-05 19:26:02 +02:00
Niels LohmannandClaude Opus 4.8 eed1587000 Reconstruct lexer diagnostics lazily for seekable input (#120) (#5234)
`lexer::get()` copied every scanned character into `token_string` on the
whole successful-parse hot path, yet that buffer is consumed only by
`get_token_string()` when rendering the "last read" fragment of a parse
error. On well-formed input the per-byte copy (plus the `unget()` pop)
is pure overhead that is always discarded.

For seekable input adapters - random-access, single-byte iterators such
as those backing `std::string`, `const char*`, and `std::vector<char>` -
the offending token is now reconstructed on demand from the input when
an error is reported, using a saved start offset, and the eager copy is
skipped. Streaming adapters (file, istream, wide-string, and user-defined
adapters) keep the eager copy; the strategy is chosen at compile time via
`input_adapter_supports_seek`, so adapters without the capability are
unaffected.

Error messages are byte-for-byte identical across all adapters, verified
by a new parity regression test. Microbenchmark (4 MB mixed JSON, parsed
from a std::string): ~149 -> ~160 MB/s, about +8%.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 10:42:48 +02:00
Niels Lohmann c034480c22 📝 add more docs (#5231)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-04 11:13:25 +02:00
Niels LohmannandClaude Opus 4.8 899cf31255 Harden CI: validate PR artifact inputs, migrate off deprecated Semgrep action (#5232)
* Harden CI workflows: validate PR artifact inputs and migrate off deprecated Semgrep action

Address two CI/supply-chain hardening items from the 2026-07-03 security
audit:

- comment_check_amalgamation.yml (todo 117): the privileged `workflow_run`
  job consumes an untrusted PR artifact. Validate `author` against a strict
  GitHub-username pattern and `number` as a positive integer before use, and
  extract the artifact into a dedicated directory (`unzip -o pr.zip -d
  ./pr_artifact`), reading only the two expected files by fixed path. This
  prevents Markdown/mention injection via the attacker-controlled `author`
  text and avoids a malicious archive touching the workspace.

- semgrep.yml (todo 118): `returntocorp/semgrep-action` is deprecated (the
  org was renamed to `semgrep/*`). Replace it with an explicit `semgrep ci`
  invocation via the maintained CLI; the deployment is inferred from
  SEMGREP_APP_TOKEN.

Todo 116 (CIFuzz `@master` refs) already carries a comment documenting the
OSS-Fuzz-recommended exception, so no change is needed there.

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

* Fix Semgrep step: use `semgrep scan` instead of token-gated `semgrep ci`

The CI `Scan` job failed with "Path does not exist: semgrep.sarif" because
`semgrep ci` requires a login token (SEMGREP_APP_TOKEN), which this repo does
not have configured, so it bailed without producing a SARIF file. The former
returntocorp/semgrep-action, given no token, fell back to plain
`semgrep scan --sarif`; match that with `semgrep scan --config auto`, which
needs no token and always produces the SARIF for upload.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 11:10:02 +02:00
Niels Lohmann c363dc3e4d Bump codeql-action to v4.36.3 and group future updates (#5230)
Bumps init/analyze/autobuild together (previously split across #5226,
#5227, #5228, which each failed CI due to a version mismatch between
the CodeQL config and the running action). Also adds a dependabot
group so future codeql-action bumps land in a single PR.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-03 08:04:41 +02:00
Niels LohmannandClaude Opus 4.8 972f5cc10b Attach a ready-to-apply patch when the amalgamation check fails (#5229)
When a PR is not amalgamated/formatted, the astyle version friction (see
the recurring blocker across many PRs) means contributors often struggle
to reproduce the exact fix locally. The check now regenerates the
amalgamation and formatting, captures the difference as a patch, and
uploads it as the `amalgamation-patch` artifact. The failure comment
links to that artifact and tells contributors to run
`git apply amalgamation.patch`, so they no longer need to install the
pinned astyle version themselves.

The pass/fail verdict is unchanged: the same PRs fail as before, and a
correctly amalgamated PR uploads nothing and passes.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:05:00 +02:00
dependabot[bot] 518c5c887a ⬆️ Bump github/codeql-action/upload-sarif from 4.36.2 to 4.36.3 (#5225)
Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...54f647b7e1bb85c95cddabcd46b0c578ec92bc1a)

---
updated-dependencies:
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.36.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-02 23:04:05 +02:00
163 changed files with 5578 additions and 760 deletions
+8
View File
@@ -15,6 +15,14 @@ guidance.
For vulnerabilities in third-party dependencies or modules, please report them directly to the respective maintainers.
## Unofficial packages
This project does not publish an official npm package. The npm package
[`nlohmann-json`](https://www.npmjs.com/package/nlohmann-json) (or similarly named packages) is not maintained or
endorsed by this project. See the
[package managers documentation](https://json.nlohmann.me/integration/package_managers/#npm) for supported
integration options.
## Additional Resources
- Explore security-related topics and contribute to tools and projects through
+16
View File
@@ -4,28 +4,44 @@ updates:
directory: /
schedule:
interval: daily
cooldown:
default-days: 7
groups:
codeql-action:
patterns:
- "github/codeql-action/*"
- package-ecosystem: pip
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
+46 -16
View File
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
@@ -34,19 +34,19 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Checkout pull request
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: main
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false
- name: Checkout tools
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: tools
ref: develop
@@ -57,22 +57,52 @@ jobs:
python3 -mvenv venv
venv/bin/pip3 install -r $MAIN_DIR/tools/astyle/requirements.txt
- name: Check amalgamation
- name: Regenerate amalgamation and formatting
run: |
cd $MAIN_DIR
rm -fr $INCLUDE_DIR/json.hpp~ $INCLUDE_DIR/json_fwd.hpp~
cp $INCLUDE_DIR/json.hpp $INCLUDE_DIR/json.hpp~
cp $INCLUDE_DIR/json_fwd.hpp $INCLUDE_DIR/json_fwd.hpp~
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json.json -s .
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json_fwd.json -s .
echo "Format (1)"
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet $INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp
diff $INCLUDE_DIR/json.hpp~ $INCLUDE_DIR/json.hpp
diff $INCLUDE_DIR/json_fwd.hpp~ $INCLUDE_DIR/json_fwd.hpp
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
$INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=orig $(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)
echo Check
find $MAIN_DIR -name '*.orig' -exec false {} \+
# 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)
- name: Build patch and check for differences
id: diff
run: |
cd $MAIN_DIR
mkdir -p ${{ github.workspace }}/patch
git diff --patch --no-color > ${{ github.workspace }}/patch/amalgamation.patch
if [ -s ${{ github.workspace }}/patch/amalgamation.patch ]; then
echo "The source code has not been amalgamated/formatted correctly. Diff:"
cat ${{ github.workspace }}/patch/amalgamation.patch
echo "has_diff=true" >> "$GITHUB_OUTPUT"
else
echo "has_diff=false" >> "$GITHUB_OUTPUT"
fi
# Uploaded so contributors can fix their PR with `git apply amalgamation.patch`
# instead of installing the pinned astyle version locally.
- name: Upload patch
if: steps.diff.outputs.has_diff == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: amalgamation-patch
path: patch/amalgamation.patch
- name: Fail if not amalgamated/formatted
if: steps.diff.outputs.has_diff == 'true'
run: exit 1
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
+5 -5
View File
@@ -27,25 +27,25 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
languages: c-cpp
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
uses: github/codeql-action/autobuild@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
@@ -19,11 +19,12 @@ jobs:
pull-requests: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: 'Download artifact'
id: download
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
@@ -43,7 +44,13 @@ jobs:
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- run: unzip pr.zip
var hasPatch = artifacts.data.artifacts.some((artifact) => artifact.name == "amalgamation-patch");
core.setOutput('has_patch', String(hasPatch));
# Extract the untrusted PR artifact into a dedicated empty directory and
# read only the two expected files by fixed path afterwards. This avoids a
# malicious archive overwriting workspace files or escaping via ../ paths.
- run: unzip -o pr.zip -d ./pr_artifact
- name: 'Comment on PR'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -51,8 +58,19 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
var fs = require('fs');
const author = fs.readFileSync('./author')
const issue_number = Number(fs.readFileSync('./number'));
// Both values come from a fork-triggered workflow and are therefore
// attacker-controlled. Validate them strictly before use to prevent
// Markdown/mention injection and bogus REST API filters.
const author = fs.readFileSync('./pr_artifact/author', 'utf8').trim();
if (!/^[A-Za-z0-9-]{1,39}$/.test(author)) {
core.setFailed(`Refusing to proceed: untrusted author value '${author}' is not a valid GitHub username.`);
return;
}
const issue_number = Number(fs.readFileSync('./pr_artifact/number', 'utf8').trim());
if (!Number.isInteger(issue_number) || issue_number <= 0) {
core.setFailed('Refusing to proceed: untrusted PR number is not a positive integer.');
return;
}
const opts = github.rest.issues.listForRepo.endpoint.merge({
owner: context.repo.owner,
repo: context.repo.repo,
@@ -70,12 +88,20 @@ jobs:
break
}
}
const hasPatch = '${{ steps.download.outputs.has_patch }}' === 'true';
const runUrl = '${{ github.event.workflow_run.html_url }}';
await github.rest.issues.createComment({
issue_number: issue_number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '## 🔴 Amalgamation check failed! 🔴\nThe source code has not been amalgamated.'
+ (first ? ' @' + author + ' Please read and follow the [Contribution Guidelines]'
body: '## 🔴 Amalgamation check failed! 🔴\nThe source code has not been amalgamated and/or formatted correctly.'
+ (hasPatch ? '\n\n📎 A ready-to-apply patch is attached to the [failed workflow run](' + runUrl + ') as the `amalgamation-patch` artifact.'
+ ' Download it, then apply it locally from the repository root with:'
+ '\n\n```shell\ngit apply amalgamation.patch\n```\n\n'
+ 'This does not require installing astyle yourself.'
: '')
+ (first ? '\n\n@' + author + ' Please read and follow the [Contribution Guidelines]'
+ '(https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md#files-to-change).'
: '')
})
+2 -2
View File
@@ -17,12 +17,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: 'Checkout Repository'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: 'Dependency Review'
+3 -3
View File
@@ -27,12 +27,12 @@ jobs:
security-events: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
@@ -43,6 +43,6 @@ jobs:
output: 'flawfinder_results.sarif'
- name: Upload analysis results to GitHub Security tab
uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
+3 -3
View File
@@ -26,7 +26,7 @@ jobs:
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run CMake
@@ -45,7 +45,7 @@ jobs:
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run CMake
@@ -62,7 +62,7 @@ jobs:
standard: [11, 14, 17, 20, 23, 26]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run CMake
+2 -3
View File
@@ -7,7 +7,6 @@ on:
- develop
paths:
- docs/mkdocs/**
- docs/examples/**
workflow_dispatch:
# we don't want to have concurrent jobs, and we don't want to cancel running jobs to avoid broken publications
@@ -27,11 +26,11 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install virtual environment
run: make install_venv -C docs/mkdocs
+4 -4
View File
@@ -36,17 +36,17 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: "Checkout code"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
with:
results_file: results.sarif
results_format: sarif
@@ -76,6 +76,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
sarif_file: results.sarif
+20 -9
View File
@@ -32,25 +32,36 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
# Checkout project source
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Scan code using project's configuration on https://semgrep.dev/manage
- uses: returntocorp/semgrep-action@713efdd345f3035192eaa63f56867b88e63e4e5d
with:
publishToken: ${{ secrets.SEMGREP_APP_TOKEN }}
publishDeployment: ${{ secrets.SEMGREP_DEPLOYMENT_ID }}
generateSarif: "1"
# The former returntocorp/semgrep-action is deprecated (the org was renamed
# to semgrep/*); the maintained approach is to install the CLI and invoke
# it directly. We use `semgrep scan` (not `semgrep ci`, which requires a
# login token): with no SEMGREP_APP_TOKEN configured this is exactly what
# the old action fell back to, running community rules with no token.
# 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==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.
- name: Run Semgrep
run: semgrep scan --config auto --sarif --output=semgrep.sarif
continue-on-error: true
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
# Upload SARIF file generated in previous step
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
sarif_file: semgrep.sarif
if: always()
+2 -2
View File
@@ -16,11 +16,11 @@ jobs:
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
- uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
with:
stale-issue-label: 'state: stale'
stale-pr-label: 'state: stale'
+96 -43
View File
@@ -21,11 +21,11 @@ jobs:
runs-on: ubuntu-latest
container: gcc:latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -33,11 +33,21 @@ jobs:
ci_infer:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v2.4.0
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Install Infer
run: |
wget -q -O - "https://github.com/facebook/infer/releases/download/v1.3.0/infer-linux-x86_64-v1.3.0.tar.xz" | sudo tar -C /opt -xJ
sudo ln -s /opt/infer-linux-x86_64-v1.3.0/bin/infer /usr/local/bin/infer
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -50,17 +60,17 @@ jobs:
target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind]
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Install Valgrind
run: sudo apt-get update ; sudo apt-get install -y valgrind
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -75,11 +85,11 @@ jobs:
steps:
- name: Install git, clang-tools, iwyu (ci_single_binaries), and unzip
run: apt-get update ; apt-get install -y git clang-tools iwyu unzip
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -94,11 +104,11 @@ jobs:
steps:
- name: Install build-essential
run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -108,11 +118,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install dependencies and de_DE locale
@@ -132,7 +142,7 @@ jobs:
name: code-coverage-report
path: ${{ github.workspace }}/build/html
- name: Publish report to Coveralls
uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
uses: coverallsapp/github-action@8d6379e14d29928660c4ba802d8e85393440b329 # v2.3.8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ${{ github.workspace }}/build/json.info.filtered.noexcept
@@ -143,11 +153,38 @@ jobs:
strategy:
matrix:
compiler: ['4.8', '4.9', '5', '6']
container: ghcr.io/nlohmann/json-ci:v2.4.0
# official gcc:4.8/4.9/5/6 images fail to check out code (too old for
# actions/checkout); install the old compilers on top of official ubuntu:20.04
# instead, mirroring what the (now retired) custom json-ci image did.
container: ubuntu:20.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install g++-${{ matrix.compiler }}
run: |
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends software-properties-common ca-certificates gnupg make git
# add-apt-repository resolves the PPA through the Launchpad API,
# which intermittently times out or fails the team lookup (the plain
# "deb ..." sources below never hit Launchpad and never flake).
# Retry with backoff so a transient Launchpad blip does not fail CI.
for attempt in 1 2 3 4 5; do
add-apt-repository -y ppa:ubuntu-toolchain-r/test && break
echo "::warning::add-apt-repository ppa:ubuntu-toolchain-r/test failed (attempt ${attempt}/5); retrying"
sleep $((attempt * 10))
done
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ bionic main"
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ bionic universe"
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial main"
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial universe"
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial-updates main"
apt-add-repository -y "deb http://archive.ubuntu.com/ubuntu/ xenial-updates universe"
apt-get update
apt-get install -y --no-install-recommends g++-${{ matrix.compiler }}
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: CXX=g++-${{ matrix.compiler }} cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -161,11 +198,11 @@ jobs:
compiler: ['7', '8', '9', '10', '11', '12', '13', '14', '15', 'latest']
container: gcc:${{ matrix.compiler }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -175,14 +212,14 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', 'latest']
compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', '21', '22', 'latest']
container: silkeh/clang:${{ matrix.compiler }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Set env FORCE_STDCPPFS_FLAG for clang 7 / 8 / 9 / 10
run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV"
if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }}
@@ -198,11 +235,11 @@ jobs:
matrix:
standard: [11, 14, 17, 20, 23, 26]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -218,11 +255,11 @@ jobs:
steps:
- name: Install git and unzip
run: apt-get update ; apt-get install -y git unzip
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build with libc++
@@ -234,11 +271,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
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -251,14 +299,14 @@ jobs:
runs-on: ubuntu-latest
container: ${{ matrix.container }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# The module test uses `import std;`, which needs CMake's experimental
# import-std support. Its opt-in token is CMake-version-specific, so pin
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
- name: Get pinned CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
with:
cmakeVersion: 4.3.4
# Clang: the std library module is provided by libc++ (the image's libstdc++
@@ -276,25 +324,30 @@ jobs:
ci_icpc:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v2.2.0
# Intel discontinued the classic icc/icpc compiler in oneAPI 2024.0; this is
# Intel's own last officially published image that still includes it.
container: intel/oneapi-hpckit:2023.2.1-devel-ubuntu22.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
run: |
. /opt/intel/oneapi/setvars.sh
cmake --build build --target ci_icpc
# No need to source setvars.sh here: unlike the old custom image, this
# official image already has the oneAPI environment (icc/icpc on PATH)
# baked in, and re-sourcing it fails with "already been run" (exit 3).
run: cmake --build build --target ci_icpc
ci_icpx:
runs-on: ubuntu-latest
container: intel/oneapi-hpckit:latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -304,9 +357,9 @@ jobs:
runs-on: ubuntu-latest
container: nvcr.io/nvidia/nvhpc:25.5-devel-cuda12.9-ubuntu22.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
@@ -316,17 +369,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Install emscripten
uses: mymindstorm/setup-emsdk@4528d102f7230f0e7b276855c01ea1159be0e984 # v16
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
run: cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -GNinja
- name: Build
@@ -339,11 +392,11 @@ jobs:
target: [ci_test_examples, ci_test_build_documentation]
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run CMake
+15 -9
View File
@@ -24,7 +24,7 @@ jobs:
architecture: [x64, x86]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up MinGW
@@ -49,7 +49,7 @@ jobs:
runs-on: windows-2022
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set extra CXX_FLAGS for latest std_version
@@ -86,9 +86,9 @@ jobs:
runs-on: windows-2025
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Set extra CXX_FLAGS for latest std_version
# /wd5285 silences C5285 emitted by the bundled third-party doctest.h, which
# specializes std::tuple (newly diagnosed by the VS2026 v145 toolset)
@@ -122,7 +122,7 @@ jobs:
runs-on: windows-11-arm
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Run CMake (Release)
run: cmake -S . -B build -G "Visual Studio 17 2022" -A ARM64 -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX"
if: matrix.build_type == 'Release'
@@ -143,7 +143,7 @@ jobs:
version: [11.0.1, 12.0.1, 13.0.1, 14.0.6, 15.0.7, 16.0.6, 18.1.8, 19.1.7, 20.1.8]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Clang
@@ -153,10 +153,16 @@ jobs:
with:
platform: x64
version: 12.2.0 # https://github.com/egor-tensin/setup-mingw/issues/14
# CMAKE_CXX_FLAGS_DEBUG is overridden to drop the default -g: linking
# test-regression2_cpp20 intermittently fails with "relocation truncated
# to fit: IMAGE_REL_AMD64_SECREL against `.debug_line'" because the
# MinGW linker cannot relocate the debug sections this test produces.
# The tests are only built and run here, so the debug info is not used.
- name: Run CMake
run: cmake -S . -B build ^
-DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" ^
-DCMAKE_CXX_FLAGS="--target=x86_64-w64-mingw32 -stdlib=libstdc++ -pthread" ^
-DCMAKE_CXX_FLAGS_DEBUG="-g0" ^
-DCMAKE_EXE_LINKER_FLAGS="-lwinpthread" ^
-G"MinGW Makefiles" ^
-DCMAKE_BUILD_TYPE=Debug ^
@@ -173,7 +179,7 @@ jobs:
architecture: [Win32, x64]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run CMake
@@ -186,14 +192,14 @@ jobs:
ci_module_cpp20:
runs-on: windows-2022
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# The module test uses `import std;`, which needs CMake's experimental
# import-std support. Its opt-in token is CMake-version-specific, so pin
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
- name: Get pinned CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
with:
cmakeVersion: 4.3.4
- name: Run CMake (Debug)
+4
View File
@@ -11,6 +11,10 @@ Files: include/nlohmann/thirdparty/hedley.hpp
Copyright: 2016-2021 Evan Nemerson <evan@nemerson.com>
License: CC0
Files: include/nlohmann/detail/meta/cpp_future.hpp
Copyright: 2013-2026 Niels Lohmann <https://nlohmann.me> and 2018 The Abseil Authors
License: MIT AND Apache-2.0
Files: tests/thirdparty/doctest/*
Copyright: 2016-2023 Viktor Kirilov
License: MIT
+17 -3
View File
@@ -42,6 +42,7 @@
- [Specializing enum conversion](#specializing-enum-conversion)
- [Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData)](#binary-formats-bson-cbor-messagepack-ubjson-and-bjdata)
- [Customers](#customers)
- [Ecosystem](#ecosystem)
- [Supported compilers](#supported-compilers)
- [Integration](#integration)
- [CMake](#cmake)
@@ -90,7 +91,6 @@ You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nl
- [Steve Sperandeo](https://github.com/homer6)
- [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe)
- [Steve Wagner](https://github.com/ciroque)
- [Lion Yang](https://github.com/LionNatsu)
### Further support
@@ -1187,6 +1187,11 @@ The library is used in multiple projects, applications, operating systems, etc.
[![logos of customers using the library](docs/mkdocs/docs/images/customers.png)](https://json.nlohmann.me/home/customers/)
## Ecosystem
Beyond projects that use the library, there are third-party projects that build on top of it - schema validators,
language bindings, format converters, and the like. See the curated [Ecosystem](https://json.nlohmann.me/community/ecosystem/) page.
## Supported compilers
Though it's 2026 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
@@ -1802,13 +1807,13 @@ The library itself consists of a single header file licensed under the MIT licen
- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file
- [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) for fuzz testing
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation
- [**Artistic Style**](https://astyle.sourceforge.net) for automatic source code indentation
- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers
- [**CMake**](https://cmake.org) for build automation
- [**Codacy**](https://www.codacy.com) for further [code analysis](https://app.codacy.com/gh/nlohmann/json/dashboard)
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)
- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis
- [**cppcheck**](https://cppcheck.sourceforge.io) for static analysis
- [**doctest**](https://github.com/onqtam/doctest) for the unit tests
- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)
- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks
@@ -1823,6 +1828,15 @@ The library itself consists of a single header file licensed under the MIT licen
## Notes
### Standards compliance
The library targets strict conformance with [RFC 8259](https://tools.ietf.org/html/rfc8259.html). Both the original [JSONTestSuite](https://github.com/nst/JSONTestSuite) and its updated revision are exercised in CI; their test data is downloaded from [`nlohmann/json_test_data`](https://github.com/nlohmann/json_test_data) at configure time rather than committed to this repository (see [`tests/src/unit-testsuites.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-testsuites.cpp)):
- The updated revision runs all mandatory `y_` (must-accept) and `n_` (must-reject) cases through the strict [`parse()`](https://json.nlohmann.me/api/basic_json/parse/) entry point; the original suite runs its `n_` cases through `parse()` and its `y_` cases through [`operator>>`](https://json.nlohmann.me/api/operator_gtgt/).
- The `i_` (implementation-defined) cases are, by RFC 8259, free to be accepted *or* rejected, so "passing all `i_` cases" is not a meaningful conformance metric. The library makes deliberate, documented choices there: nesting depth is not artificially limited, a leading UTF-8 byte order mark is silently ignored, [Unicode noncharacters](https://www.unicode.org/faq/private_use.html#nonchar1) are forwarded unchanged, invalid UTF-8 and lone/unpaired UTF-16 surrogates are rejected (stricter than required), and a number that cannot be stored without becoming `NaN`/`INF` raises [`out_of_range.406`](https://json.nlohmann.me/home/exceptions/#jsonexceptionout_of_range406).
One behavioral nuance is worth calling out, because a superficial test often misreads it as non-compliance: [`parse()`](https://json.nlohmann.me/api/basic_json/parse/) is strict and rejects trailing data after a value, whereas [`operator>>`](https://json.nlohmann.me/api/operator_gtgt/) follows relaxed iostream semantics — it parses a single value and leaves the stream positioned right after it. Feeding "a valid document followed by trailing bytes" through `operator>>` reports success; the same input through `parse()` is rejected. This is a documented two-API design, not a conformance gap. See [**parsing**](https://json.nlohmann.me/features/parsing/) for details.
### Character encoding
The library supports **Unicode input** as follows:
+7 -3
View File
@@ -294,7 +294,7 @@ file(GLOB_RECURSE INDENT_FILES
${PROJECT_SOURCE_DIR}/tests/src/*.cpp
${PROJECT_SOURCE_DIR}/tests/src/*.hpp
${PROJECT_SOURCE_DIR}/tests/benchmarks/src/benchmarks.cpp
${PROJECT_SOURCE_DIR}/docs/examples/*.cpp
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cpp
)
set(include_dir ${PROJECT_SOURCE_DIR}/single_include/nlohmann)
@@ -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
+9 -3
View File
@@ -5,8 +5,14 @@
# -Wno-extra-semi-stmt The library uses assert which triggers this warning.
# -Wno-padded We do not care about padding warnings.
# -Wno-covered-switch-default All switches list all cases and a default case.
# -Wno-unsafe-buffer-usage Otherwise Doctest would not compile.
# -Wno-missing-noreturn We found no way to silence this warning otherwise, see PR #4871
# -Wno-c2y-extensions Clang 22.1 diagnoses __COUNTER__ as a C2y extension, also in
# C++ mode. The library does not use __COUNTER__; the warnings
# all come from vendored Doctest (SECTION/TEST_CASE macros).
# -Wno-unsafe-buffer-usage Pervasive: the library's own low-level numeric/buffer code
# (to_chars, serializer, lexer, binary reader/writer, input
# adapters, json_pointer) plus vendored Doctest itself (~208
# distinct sites measured 2026-07-08 on clang trunk) all use
# raw pointer arithmetic / libc string calls by necessity.
set(CLANG_CXXFLAGS
-Werror
@@ -17,6 +23,6 @@ set(CLANG_CXXFLAGS
-Wno-extra-semi-stmt
-Wno-padded
-Wno-covered-switch-default
-Wno-c2y-extensions
-Wno-unsafe-buffer-usage
-Wno-missing-noreturn
)
+1 -1
View File
@@ -4,7 +4,7 @@
"archive": "JSON_for_Modern_C++.tgz",
"author": {
"name": "Niels Lohmann",
"link": "https://twitter.com/nlohmann"
"link": "https://nlohmann.me"
},
"aliases": ["nlohmann/json"]
}
+17 -7
View File
@@ -8,8 +8,8 @@ static bool accept(InputType&& i,
const bool ignore_trailing_commas = false);
// (2)
template<typename IteratorType>
static bool accept(IteratorType first, IteratorType last,
template<typename IteratorType, typename SentinelType = IteratorType>
static bool accept(IteratorType first, SentinelType last,
const bool ignore_comments = false,
const bool ignore_trailing_commas = false);
```
@@ -17,10 +17,11 @@ static bool accept(IteratorType first, IteratorType last,
Checks whether the input is valid JSON.
1. Reads from a compatible input.
2. Reads from a pair of character iterators
2. Reads from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support)
The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted
respectively as UTF-8, UTF-16, and UTF-32.
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to
the iterator type with `operator!=`.
Unlike the [`parse()`](parse.md) function, this function neither throws an exception in case of invalid JSON input
(i.e., a parse error) nor creates diagnostic information.
@@ -35,7 +36,8 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters (throws if null)
- a `std::string`
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type, for instance.
@@ -43,6 +45,12 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
- a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator`
- a pair of pointers such as `ptr` and `ptr + len`
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
## Parameters
`i` (in)
@@ -60,7 +68,7 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
: iterator to the start of the character range
`last` (in)
: iterator to the end of the character range
: iterator to the end of the character range, or a sentinel value that compares equal to the end iterator with `operator!=`
## Return value
@@ -109,7 +117,9 @@ A UTF-8 byte order mark is silently ignored.
- Added in version 3.0.0.
- Ignoring comments via `ignore_comments` added in version 3.9.0.
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
- Added `ignore_trailing_commas` in version 3.12.x.
- Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation"
+1
View File
@@ -54,6 +54,7 @@ This function is only needed to express two edge cases that cannot be realized w
- [`basic_json(initializer_list_t)`](basic_json.md) - create a JSON value from an initializer list
- [`object`](object.md) - create a JSON object value from an initializer list
- [Creating JSON values](../../features/creating_values.md) - the article on creating JSON values
## Version history
+28 -2
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`
@@ -109,7 +115,22 @@ basic_json(basic_json&& other) noexcept;
Function [`array()`](array.md) and [`object()`](object.md) force array and object creation from initializer lists,
respectively.
!!! warning "Brace initialization yields arrays"
Because this constructor takes an `initializer_list_t`, brace-initializing a `json`/`ordered_json` from
another `json` value wraps it in a single-element array rather than copying it:
```cpp
json j1 = "hello";
json j2{j1}; // [!] j2 is ["hello"], NOT a copy of j1
json j3(j1); // j3 is "hello" -- parentheses copy as expected
```
See the FAQ entry on [brace initialization](../../home/faq.md#brace-initialization-yields-arrays) for the
full explanation, an opt-in macro to change this behavior, and how to explicitly create a single-element
array (`json::array({value})`) if that is what you want.
6. Constructs a JSON array value by creating `cnt` copies of a passed value. In case `cnt` is `0`, an empty array is
created.
@@ -146,6 +167,11 @@ basic_json(basic_json&& other) noexcept;
- `BasicJsonType` is a `basic_json` type.
- `BasicJsonType` has different template arguments than `basic_json_t`.
**Note:** For cross-`basic_json` conversions to produce correct results, the target `basic_json`'s
`object_t::key_type` and `string_t` must be directly constructible from the source `basic_json`'s
corresponding types. See the description of overload (4) above for details on what happens when
this requirement is not met.
`U`:
: `uncvref_t<CompatibleType>`
+42 -3
View File
@@ -13,9 +13,8 @@ is compatible with both of the binary data formats that use binary subtyping, (t
incompatible with each other, and it is up to the user to translate between them). The subtype is added to `BinaryType`
via the helper type [byte_container_with_subtype](../byte_container_with_subtype/index.md).
[CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as:
> Major type 2: a byte string. The string's length in bytes is represented following the rules for positive integers
> (major type 0).
[CBOR's RFC 8949](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.1) describes this type as:
> Major type 2: A byte string. The number of bytes in the string is equal to the argument.
[MessagePack's documentation on the bin type
family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family) describes this type as:
@@ -37,12 +36,52 @@ represent a byte array in modern C++.
`BinaryType`
: container type to store arrays
Although not formally expressed as a C++ concept, `BinaryType` must be default-constructible,
copy/move-constructible, and support `push_back()`, `.data()`, and `.size()`, because
[`byte_container_with_subtype`](../byte_container_with_subtype/index.md) derives directly from it. Its
`value_type` must additionally be exactly one byte wide (e.g., `std::uint8_t`/`char`/`std::byte`): the binary
serializers (CBOR, MessagePack, BSON, UBJSON) read and write the container's raw bytes via
`reinterpret_cast`, which is only correct for byte-sized elements -- a container like
`#!cpp std::vector<std::intptr_t>` will not work as `BinaryType`.
## Notes
#### Default type
The default values for `BinaryType` is `#!cpp std::vector<std::uint8_t>`.
#### Custom BinaryType behavior
When a custom `BinaryType` is configured (other than the default `#!cpp std::vector<std::uint8_t>`), you can assign
values of that type directly to a `basic_json` instance, and they will automatically be recognized as binary values
rather than arrays:
```cpp
using custom_json = nlohmann::basic_json<
nlohmann::ordered_map, // ObjectType
std::vector, // ArrayType
std::string, // StringType
bool, // BooleanType
std::int64_t, // NumberIntegerType
std::uint64_t, // NumberUnsignedType
double, // NumberFloatType
std::allocator, // AllocatorType
nlohmann::adl_serializer,
std::vector<std::byte> // Custom BinaryType
>;
std::vector<std::byte> data{std::byte{1}, std::byte{2}, std::byte{3}};
custom_json j = data; // Creates a binary value, not an array
assert(j.is_binary());
// Round-tripping works seamlessly
auto extracted = j.get<std::vector<std::byte>>();
assert(extracted == data);
```
This automatic type detection is a convenience feature that only applies to custom (non-default) `BinaryType` configurations.
The default `nlohmann::json` continues to treat `#!cpp std::vector<std::uint8_t>` as arrays for backward compatibility.
#### Storage
Binary Arrays are stored as pointers in a `basic_json` type. That is, for any access to array values, a pointer of the
+12
View File
@@ -43,6 +43,17 @@ Strong guarantee: if an exception is thrown, there are no changes to any JSON va
Throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if a string stored inside the JSON value
is not UTF-8 encoded and `error_handler` is set to `strict`
!!! warning "Serializing untrusted input"
When serializing values that may contain invalid or untrusted UTF-8 (e.g., bytes taken directly from network
input), `dump()` throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) in the default
`strict` mode. To serialize such data without throwing, pass
[`error_handler_t::replace`](error_handler_t.md) (substitutes U+FFFD) or
[`error_handler_t::ignore`](error_handler_t.md). Callers that serialize untrusted input on a crash-sensitive path
should either choose a non-strict error handler or wrap `dump()` in a `#!cpp try`/`#!cpp catch`.
See the [FAQ](../../home/faq.md#serializing-untrusted-or-invalid-utf-8) for details.
## Complexity
Linear.
@@ -75,6 +86,7 @@ Binary values are serialized as an object containing two keys:
- [to_string](to_string.md) returns a string representation of a JSON value
- [operator<<](../operator_ltlt.md) serialize to stream
- [Serialization](../../features/serialization.md) - the serialization article
## Version history
@@ -64,6 +64,7 @@ Logarithmic in the size of the container, O(log(`size()`)).
- [emplace_back](emplace_back.md) add a value to an array
- [insert](insert.md) add values to an array/object
- [Modifying values](../../features/modifying_values.md) - the article on modifying values
## Version history
@@ -58,6 +58,7 @@ Amortized constant.
- [operator+=](operator+=.md) add a value to an array/object
- [push_back](push_back.md) add a value to an array/object
- [Modifying values](../../features/modifying_values.md) - the article on modifying values
## Version history
+1
View File
@@ -206,6 +206,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
- [clear](clear.md) clears the contents
- [insert](insert.md) add values to an array/object
- [Modifying values](../../features/modifying_values.md) - the article on modifying values
## Version history
+2 -1
View File
@@ -88,7 +88,8 @@ std::string format_as(const BasicJsonType& j)
- [dump](dump.md)
- [std::formatter<basic_json>](std_formatter.md) - the `std::format` (C++20) equivalent
- [Serialization](../../features/serialization.md) - the serialization article
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
+14 -5
View File
@@ -7,8 +7,8 @@ static basic_json from_bjdata(InputType&& i,
const bool strict = true,
const bool allow_exceptions = true);
// (2)
template<typename IteratorType>
static basic_json from_bjdata(IteratorType first, IteratorType last,
template<typename IteratorType, typename SentinelType = IteratorType>
static basic_json from_bjdata(IteratorType first, SentinelType last,
const bool strict = true,
const bool allow_exceptions = true);
```
@@ -16,7 +16,7 @@ static basic_json from_bjdata(IteratorType first, IteratorType last,
Deserializes a given input to a JSON value using the BJData (Binary JData) serialization format.
1. Reads from a compatible input.
2. Reads from an iterator range.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bjdata.md).
@@ -29,11 +29,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
## Parameters
`i` (in)
@@ -43,7 +50,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input
`last` (in)
: iterator to the end of the input
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
`strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -101,3 +108,5 @@ Linear in the size of the input.
## Version history
- Added in version 3.11.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
+14 -5
View File
@@ -7,8 +7,8 @@ static basic_json from_bson(InputType&& i,
const bool strict = true,
const bool allow_exceptions = true);
// (2)
template<typename IteratorType>
static basic_json from_bson(IteratorType first, IteratorType last,
template<typename IteratorType, typename SentinelType = IteratorType>
static basic_json from_bson(IteratorType first, SentinelType last,
const bool strict = true,
const bool allow_exceptions = true);
```
@@ -16,7 +16,7 @@ static basic_json from_bson(IteratorType first, IteratorType last,
Deserializes a given input to a JSON value using the BSON (Binary JSON) serialization format.
1. Reads from a compatible input.
2. Reads from an iterator range.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bson.md).
@@ -29,11 +29,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
## Parameters
`i` (in)
@@ -43,7 +50,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input
`last` (in)
: iterator to the end of the input
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
`strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -101,6 +108,8 @@ Linear in the size of the input.
## Version history
- Added in version 3.4.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation"
+14 -5
View File
@@ -9,8 +9,8 @@ static basic_json from_cbor(InputType&& i,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
// (2)
template<typename IteratorType>
static basic_json from_cbor(IteratorType first, IteratorType last,
template<typename IteratorType, typename SentinelType = IteratorType>
static basic_json from_cbor(IteratorType first, SentinelType last,
const bool strict = true,
const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
@@ -19,7 +19,7 @@ static basic_json from_cbor(IteratorType first, IteratorType last,
Deserializes a given input to a JSON value using the CBOR (Concise Binary Object Representation) serialization format.
1. Reads from a compatible input.
2. Reads from an iterator range.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/cbor.md).
@@ -32,11 +32,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
## Parameters
`i` (in)
@@ -46,7 +53,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input
`last` (in)
: iterator to the end of the input
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
`strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -111,6 +118,8 @@ Linear in the size of the input.
- Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0.
- Added `allow_exceptions` parameter in version 3.2.0.
- Added `tag_handler` parameter in version 3.9.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation"
@@ -7,8 +7,8 @@ static basic_json from_msgpack(InputType&& i,
const bool strict = true,
const bool allow_exceptions = true);
// (2)
template<typename IteratorType>
static basic_json from_msgpack(IteratorType first, IteratorType last,
template<typename IteratorType, typename SentinelType = IteratorType>
static basic_json from_msgpack(IteratorType first, SentinelType last,
const bool strict = true,
const bool allow_exceptions = true);
```
@@ -16,7 +16,7 @@ static basic_json from_msgpack(IteratorType first, IteratorType last,
Deserializes a given input to a JSON value using the MessagePack serialization format.
1. Reads from a compatible input.
2. Reads from an iterator range.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/messagepack.md).
@@ -29,11 +29,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
## Parameters
`i` (in)
@@ -43,7 +50,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input
`last` (in)
: iterator to the end of the input
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
`strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -103,6 +110,8 @@ Linear in the size of the input.
- Parameter `start_index` since version 2.1.1.
- Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0.
- Added `allow_exceptions` parameter in version 3.2.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation"
+14 -5
View File
@@ -7,8 +7,8 @@ static basic_json from_ubjson(InputType&& i,
const bool strict = true,
const bool allow_exceptions = true);
// (2)
template<typename IteratorType>
static basic_json from_ubjson(IteratorType first, IteratorType last,
template<typename IteratorType, typename SentinelType = IteratorType>
static basic_json from_ubjson(IteratorType first, SentinelType last,
const bool strict = true,
const bool allow_exceptions = true);
```
@@ -16,7 +16,7 @@ static basic_json from_ubjson(IteratorType first, IteratorType last,
Deserializes a given input to a JSON value using the UBJSON (Universal Binary JSON) serialization format.
1. Reads from a compatible input.
2. Reads from an iterator range.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/ubjson.md).
@@ -29,11 +29,18 @@ The exact mapping and its limitations are described on a [dedicated page](../../
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
## Parameters
`i` (in)
@@ -43,7 +50,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input
`last` (in)
: iterator to the end of the input
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
`strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -102,6 +109,8 @@ Linear in the size of the input.
- Added in version 3.1.0.
- Added `allow_exceptions` parameter in version 3.2.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation"
+8
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
@@ -155,6 +162,7 @@ overload (3).
- [get_ptr](get_ptr.md) get a pointer to the stored value
- [get_ref](get_ref.md) get a reference to the stored value
- [operator ValueType](operator_ValueType.md) get a value via implicit conversion
- [Converting values](../../features/conversions.md) - the type conversions article
## Version history
@@ -62,6 +62,7 @@ Depends on the `json_serializer<ValueType>::from_json()` implementation.
- [get](get.md) get a value (explicit conversion)
- [get_ref](get_ref.md) get a reference to the stored value
- [get_ptr](get_ptr.md) get a pointer to the stored value
- [Converting values](../../features/conversions.md) - the type conversions article
## Version history
+11
View File
@@ -46,6 +46,17 @@ for (auto& [key, val] : j_object.items())
}
```
If you need to name the type of the dereferenced element explicitly (e.g., to write a standalone function that
takes it as a parameter, or to use `items()` with `std::for_each`), use `decltype`:
```cpp
using element_type = decltype(*j_object.items().begin());
```
The per-element type (`iteration_proxy_value`) lives in the library's internal `detail` namespace and is
intentionally unspecified as a stable, named type -- `decltype` is the supported way to obtain it, but its exact
name/definition may change between versions.
## Return value
iteration proxy object wrapping the current value with an interface to use in range-based for loops
@@ -57,6 +57,7 @@ the initializer list constructor `basic_json(initializer_list_t, bool, value_t)`
- [`basic_json(initializer_list_t)`](basic_json.md) - create a JSON value from an initializer list
- [`array`](array.md) - create a JSON array value from an initializer list
- [Creating JSON values](../../features/creating_values.md) - the article on creating JSON values
## Version history
+11 -1
View File
@@ -63,7 +63,8 @@ behavior:
object will agree on the name-value mappings.
- When the names within an object are not unique, it is unspecified which one of the values for a given key will be
chosen. For instance, `#!json {"key": 2, "key": 1}` could be equal to either `#!json {"key": 1}` or
`#!json {"key": 2}`.
`#!json {"key": 2}`. To reject duplicate keys instead of silently resolving them one way or another, see
[this parsing recipe](../../features/parsing/parser_callbacks.md#recipe-rejecting-duplicate-object-keys).
- Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see
[`dump`](dump.md)) in this order. For instance, `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be stored
and serialized as `#!json {"a": 2, "b": 1}`.
@@ -93,6 +94,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
+11 -1
View File
@@ -124,6 +124,15 @@ Strong exception safety: if an exception occurs, the original value stays intact
filled with `#!json null`.
- The special value `-` is treated as a synonym for the index past the end.
!!! note "Creating intermediate levels that don't exist yet"
When the JSON pointer traverses intermediate levels that don't exist at all yet (not just a missing
leaf), each missing level is created as an array or an object depending on whether the corresponding
pointer token parses as a non-negative integer: a numeric token creates an array, a non-numeric token
creates an object. For example, on an initially `#!json null` value, `/foo/0/0/0` creates nested arrays,
while `/foo/one/one/one` creates nested objects. This is not specified by the JSON Pointer RFC; it is
this library's own, intentional disambiguation rule. See also [JSON Pointer](../../features/json_pointer.md).
## Examples
??? example "Example: (1) access specified array element"
@@ -251,5 +260,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. Added in version 1.0.0.
2. Added in version 1.0.0. Added overloads for `T* key` in version 1.1.0. Removed overloads for `T* key` (replaced by 3)
in version 3.11.0.
3. Added in version 3.11.0.
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
already supported by [`at`](at.md), [`value`](value.md), [`find`](find.md), and other lookup functions.
4. Added in version 2.0.0.
@@ -78,6 +78,7 @@ Linear in the size of the JSON value.
## See also
- [get](get.md) get a value (explicit conversion)
- [Converting values](../../features/conversions.md) - the type conversions article
## Version history
+11 -12
View File
@@ -19,10 +19,8 @@ class basic_json {
};
```
1. Compares two JSON values for inequality according to the following rules:
- The comparison always yields `#!cpp false` if (1) either operand is discarded, or (2) either operand is `NaN` and
the other operand is either `NaN` or any other number.
- Otherwise, returns the result of `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20).
1. Compares two JSON values for inequality. Returns `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20).
- This means the comparison is simply the logical negation of `operator==`, including for special values like `NaN` and `discarded`.
2. Compares a JSON value and a scalar or a scalar and a JSON value for inequality by converting the scalar to a JSON
value and comparing both JSON values according to 1.
@@ -54,13 +52,12 @@ Linear.
## Notes
!!! note "Comparing `NaN`"
!!! note "Comparing `NaN` and `discarded`"
`NaN` values are unordered within the domain of numbers.
The following comparisons all yield `#!cpp false`:
1. Comparing a `NaN` with itself.
2. Comparing a `NaN` with another `NaN`.
3. Comparing a `NaN` and any other number.
Since `operator!=` is defined as `!(a == b)`, the behavior for special values follows that of `operator==`:
- For `NaN` values: `NaN == NaN` yields `#!cpp false`, so `NaN != NaN` yields `#!cpp true`.
- For `discarded` values: `discarded == x` yields `#!cpp false` for any `x`, so `discarded != x` yields `#!cpp true`.
## Examples
@@ -94,5 +91,7 @@ Linear.
## Version history
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.13.0 to remove
special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`.
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.13.0 to remove
special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`.
+17 -7
View File
@@ -10,8 +10,8 @@ static basic_json parse(InputType&& i,
const bool ignore_trailing_commas = false);
// (2)
template<typename IteratorType>
static basic_json parse(IteratorType first, IteratorType last,
template<typename IteratorType, typename SentinelType = IteratorType>
static basic_json parse(IteratorType first, SentinelType last,
const parser_callback_t cb = nullptr,
const bool allow_exceptions = true,
const bool ignore_comments = false,
@@ -19,10 +19,11 @@ static basic_json parse(IteratorType first, IteratorType last,
```
1. Deserialize from a compatible input.
2. Deserialize from a pair of character iterators
2. Deserialize from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support)
The `value_type` of the iterator must be an integral type with size of 1, 2, or 4 bytes, which will be interpreted
respectively as UTF-8, UTF-16, and UTF-32.
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to
the iterator type with `operator!=`.
## Template parameters
@@ -34,7 +35,8 @@ static basic_json parse(IteratorType first, IteratorType last,
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters (throws if null)
- a `std::string`
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type, for instance.
@@ -42,6 +44,12 @@ static basic_json parse(IteratorType first, IteratorType last,
- a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator`
- a pair of pointers such as `ptr` and `ptr + len`
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
## Parameters
`i` (in)
@@ -66,7 +74,7 @@ static basic_json parse(IteratorType first, IteratorType last,
: iterator to the start of a character range
`last` (in)
: iterator to the end of a character range
: iterator to the end of a character range, or a sentinel value that compares equal to the end iterator with `operator!=`
## Return value
@@ -235,7 +243,9 @@ Invalid Unicode escapes and unpaired surrogates in the input are reported as
- Overload for contiguous containers (1) added in version 2.0.3.
- Ignoring comments via `ignore_comments` added in version 3.9.0.
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
- Added `ignore_trailing_commas` in version 3.12.x.
- Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation"
@@ -29,7 +29,14 @@ Discarding a value (i.e., returning `#!cpp false`) has different effects dependi
called:
- Discarded values in structured types are skipped. That is, the parser will behave as if the discarded value was never
read.
read. This holds for every value type and for both kinds of parent: a discarded element is removed from the
surrounding array, and a discarded member is removed from the surrounding object together with its key.
- Arrays and objects can be discarded either at their `parse_event_t::array_start`/`parse_event_t::object_start` event
or at their `parse_event_t::array_end`/`parse_event_t::object_end` event, and both remove the whole value. Discarding
it at the start event also means the callback is called neither for the content of the value nor for its matching end
event.
- Discarding a `parse_event_t::key` event discards the whole object member. The callback is still called for the
associated value, but its return value has no further effect.
- In case a value outside a structured type is skipped, it is replaced with `null`. This case happens if the top-level
element is skipped.
@@ -49,7 +56,7 @@ called:
## Return value
Whether the JSON value which called the function during parsing should be kept (`#!cpp true`) or not (`#!cpp false`). In
the latter case, it is either skipped completely or replaced by an empty discarded object.
the latter case, it is skipped completely, or replaced by `null` if it is the top-level value.
## Examples
@@ -68,6 +75,21 @@ the latter case, it is either skipped completely or replaced by an empty discard
--8<-- "examples/parse__string__parser_callback_t.output"
```
??? example
The example below shows where discarded values are removed. The array and the number are discarded in different
ways, but in each case the parse result contains neither the value nor its key.
```cpp
--8<-- "examples/parser_callback_t.cpp"
```
Output:
```json
--8<-- "examples/parser_callback_t.output"
```
## See also
- [parse](parse.md) deserialize from a compatible input
@@ -76,3 +98,5 @@ the latter case, it is either skipped completely or replaced by an empty discard
## Version history
- Added in version 1.0.0.
- Fixed in version 3.13.0 to also remove discarded values from a parent object; before, discarding an array or a value
stored under an object key left a discarded member behind, which made the parse result serialize to invalid JSON.
+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.
@@ -115,6 +115,7 @@ invalidates all iterators and all references.
- [emplace_back](emplace_back.md) add a value to an array
- [operator+=](operator+=.md) add a value to an array/object
- [Modifying values](../../features/modifying_values.md) - the article on modifying values
## Version history
+17 -8
View File
@@ -11,8 +11,8 @@ static bool sax_parse(InputType&& i,
const bool ignore_trailing_commas = false);
// (2)
template<class IteratorType, class SAX>
static bool sax_parse(IteratorType first, IteratorType last,
template<class IteratorType, class SAX, class SentinelType = IteratorType>
static bool sax_parse(IteratorType first, SentinelType last,
SAX* sax,
input_format_t format = input_format_t::json,
const bool strict = true,
@@ -23,10 +23,11 @@ static bool sax_parse(IteratorType first, IteratorType last,
Read from input and generate SAX events
1. Read from a compatible input.
2. Read from a pair of character iterators
2. Read from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support)
The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted
respectively as UTF-8, UTF-16, and UTF-32.
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to
the iterator type with `operator!=`.
The SAX event lister must follow the interface of [`json_sax`](../json_sax/index.md).
@@ -39,13 +40,19 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
- a `FILE` pointer
- a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of
iterators.
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
`IteratorType`
: a compatible iterator type for overload (2); a pair of character iterators whose `value_type` is an integral type
with a size of 1, 2, or 4 bytes (interpreted respectively as UTF-8, UTF-16, and UTF-32)
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for overload (2), for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
`SAX`
: a class fulfilling the SAX event listener interface; see [`json_sax`](../json_sax/index.md)
@@ -76,7 +83,7 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
: iterator to the start of a character range
`last` (in)
: iterator to the end of a character range
: iterator to the end of a character range, or a sentinel value that compares equal to the end iterator with `operator!=`
## Return value
@@ -126,7 +133,9 @@ A UTF-8 byte order mark is silently ignored.
- Added in version 3.2.0.
- Ignoring comments via `ignore_comments` added in version 3.9.0.
- Added `ignore_trailing_commas` in version 3.12.x.
- Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation"
@@ -50,7 +50,8 @@ provides `<format>`, controlled by the [`JSON_HAS_STD_FORMAT`](../macros/json_ha
- [dump](dump.md) - serialization
- [operator<<(std::ostream&)](../operator_ltlt.md) - serialize to stream
- [format_as](format_as.md) - customization point used by `fmt::format` (fmtlib)
- [Serialization](../../features/serialization.md) - the serialization article
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -18,6 +18,11 @@ JSON class into byte-sized characters during deserialization.
: the container to store strings (e.g., `std::string`). Note this container is used for keys/names in objects, see
[object_t](object_t.md).
`StringType` must have a `char`-compatible `value_type`: the library relies on UTF-8/`char`-based storage and
processing internally, so `std::wstring`, `std::u16string`, and `std::u32string` are **not** valid choices for
`StringType`. To work with wide-character data, convert it to/from UTF-8 at the boundary instead -- see the
FAQ's [wide string handling](../../home/faq.md#wide-string-handling) section for a conversion recipe.
## Notes
#### Default type
@@ -45,6 +50,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
@@ -52,6 +52,11 @@ optional, `#!cpp bjdata_version_t::draft2` by default.
Strong guarantee: if an exception is thrown, there are no changes in the JSON value.
## Exceptions
- Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size`
is false.
## Complexity
Linear in the size of the JSON value `j`.
+6 -1
View File
@@ -40,10 +40,15 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
is not an object; example: `"to serialize to BSON, top-level type must be object, but is string"`
- Throws [`out_of_range.409`](../../home/exceptions.md#jsonexceptionout_of_range409) if a key in the JSON object contains
a null byte (code point U+0000); example: `"BSON key cannot contain code point U+0000 (at byte 2)"`
- Throws [`out_of_range.412`](../../home/exceptions.md#jsonexceptionout_of_range412) if the length of a document, array,
string, or binary value exceeds the range of the 32-bit BSON length field; example:
`"BSON length 2147483661 exceeds maximum of 2147483647"`
## Complexity
Linear in the size of the JSON value `j`.
Proportional to the size of the JSON value `j` multiplied by its maximum nesting
depth, `O(n × d)`. BSON length prefixes are computed recursively before nested
values are written.
## Examples
@@ -59,6 +59,7 @@ std::string to_string(const BasicJsonType& j)
## See also
- [dump](dump.md)
- [Serialization](../../features/serialization.md) - the serialization article
## Version history
@@ -45,6 +45,11 @@ The exact mapping and its limitations are described on a [dedicated page](../../
Strong guarantee: if an exception is thrown, there are no changes in the JSON value.
## Exceptions
- Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size`
is false.
## Complexity
Linear in the size of the JSON value `j`.
@@ -21,6 +21,12 @@ a string representation of the type ([`value_t`](value_t.md)):
| array | `"array"` |
| binary | `"binary"` |
| discarded | `"discarded"` |
| invalid (corrupted value) | `"invalid"` |
!!! note "The \"invalid\" type"
The `"invalid"` return value indicates a corrupted JSON value — this can occur if an enum value falls outside the
range of valid `value_t` values. This is useful for diagnosing data corruption or internal errors.
## Exception safety
@@ -52,3 +58,4 @@ Constant.
- Part of the public API version since 2.1.0.
- Changed return value to `const char*` and added `noexcept` in version 3.0.0.
- Added support for binary type in version 3.8.0.
- Added `"invalid"` return value for corrupted JSON values in version 3.13.0.
@@ -149,6 +149,7 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value
- [insert](insert.md) add values to an array/object
- [merge_patch](merge_patch.md) applies a JSON Merge Patch
- [Modifying values](../../features/modifying_values.md) - the article on modifying values
## Version history
+5 -1
View File
@@ -17,6 +17,8 @@ ValueType value(const json_pointer& ptr,
const ValueType& default_value) const;
```
This is equivalent to Python's `dict.get(key, default)`.
1. Returns either a copy of an object's element at the specified key `key` or a given default value if no element with
key `key` exists.
@@ -184,4 +186,6 @@ changes to any JSON value.
1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version 3.11.0.
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2.
3. Added in version 2.0.2. Extended to work with arrays in version 3.12.x.
3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0, including fixing an issue where resolving
`ptr` through an array unexpectedly threw `out_of_range` instead of returning the resolved element (or
`default_value`, as documented).
+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.
@@ -38,7 +38,8 @@ When the macro is not defined, the library will define it to its default value.
Diagnostic messages can also be controlled with the CMake option
[`JSON_Diagnostics`](../../integration/cmake.md#json_diagnostics) (`OFF` by default)
which defines `JSON_DIAGNOSTICS` accordingly.
which defines `JSON_DIAGNOSTICS` accordingly. Note this only applies when building the
library from source — see the pre-installed-package caveat on that page.
## Examples
@@ -44,4 +44,4 @@ The default value is detected based on preprocessor macros such as `#!cpp __cplu
- Added in version 3.10.5.
- Added `JSON_HAS_CPP_23` in version 3.12.0.
- Added `JSON_HAS_CPP_26` in version 3.12.x.
- Added `JSON_HAS_CPP_26` in version 3.13.0.
@@ -19,6 +19,20 @@ The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_
`#!cpp __cpp_lib_experimental_filesystem`, `#!cpp __has_include(<filesystem>)`, or
`#!cpp __has_include(<experimental/filesystem>)`.
!!! info "Known compiler/stdlib exclusions"
Even when the feature-test macro indicates filesystem support is available, the library disables it on the following broken toolchains:
- **MinGW + GCC 8** — disabled entirely (broken `std::filesystem` implementation; [MinGW-w64 bug 737](https://sourceforge.net/p/mingw-w64/bugs/737/))
- **GCC (non-Clang) < 8** — disabled (no filesystem support)
- **Clang < 7** — disabled (no filesystem support)
- **MSVC < 19.14** — disabled (no filesystem support)
- **iOS < 13** — disabled (no filesystem support)
- **macOS < Catalina (10.15)** — disabled (no filesystem support)
If `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERIMENTAL_FILESYSTEM` is `0` despite `__cpp_lib_filesystem` being defined, one
of the exclusions above likely applies to your toolchain.
## Notes
- Note that older compilers or older versions of libstdc++ also require the library `stdc++fs` to be linked to for
@@ -13,6 +13,20 @@ The default value is detected based on the preprocessor macro `#!cpp __cpp_lib_r
When the macro is not defined, the library will define it to its default value.
!!! info "Known compiler/stdlib exclusions"
Even when the feature-test macro `__cpp_lib_ranges` indicates ranges support is available, the library disables it on
the following incomplete or broken toolchains:
- **GCC 11.1.0** — disabled (the shipped `<ranges>` header has a syntax error; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **libstdc++ < 11** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **Clang < 16 with libstdc++** — disabled (incomplete ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **libc++ < 160000** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **nvcc (CUDA) 12.0.x and 12.1.x** — disabled (the `enable_borrowed_range` variable-template syntax triggers a parse error
under these two toolkit versions; fixed in CUDA 12.2; [issue #3907](https://github.com/nlohmann/json/issues/3907))
If `JSON_HAS_RANGES` is `0` despite `__cpp_lib_ranges` being defined, one of the exclusions above likely applies to your toolchain.
## Examples
??? example
@@ -38,4 +38,4 @@ When the macro is not defined, the library will define it to its default value.
## Version history
- Added in version 3.12.x.
- Added in version 3.13.0.
@@ -62,6 +62,9 @@ See the examples below for the concrete generated code.
- The current implementation is limited to at most 63 member variables. If you want to serialize/deserialize types
with more than 63 member variables, you need to define the `to_json`/`from_json` functions manually.
- These macros always produce object-style (named-key) JSON, one key per member. There is no macro variant
that serializes a struct's members positionally into a JSON array; for that, write `to_json`/`from_json` by
hand, building/reading a `json::array()` of the members in order.
## Examples
@@ -63,6 +63,9 @@ See the examples below for the concrete generated code.
- The current implementation is limited to at most 63 member variables. If you want to serialize/deserialize types
with more than 63 member variables, you need to define the `to_json`/`from_json` functions manually.
- These macros always produce object-style (named-key) JSON, one key per member. There is no macro variant
that serializes a struct's members positionally into a JSON array; for that, write `to_json`/`from_json` by
hand, building/reading a `json::array()` of the members in order.
## Examples
@@ -75,4 +75,4 @@ For further information please refer to the corresponding macros without `WITH_N
## Version history
1. Added in version 3.12.x.
1. Added in version 3.13.0.
@@ -102,4 +102,4 @@ inline void from_json(const BasicJsonType& j, type& e);
## Version history
Added in version 3.12.x.
Added in version 3.13.0.
+39
View File
@@ -33,6 +33,45 @@ A UTF-8 byte order mark is silently ignored.
Invalid Unicode escapes and unpaired surrogates in the input are reported as
[`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) with a detailed message.
`operator>>` parses exactly one JSON value, so it can be called repeatedly to read a sequence of concatenated JSON
values from the same stream:
```cpp
json j1, j2;
input >> j1; // parses the first value
input >> j2; // parses the next value
```
!!! warning "A number must be followed by whitespace"
A number is only terminated by the character that follows it. That character is read from the stream to detect the
end of the number, and it is **not** put back. When a value that is a number is immediately followed by the next
value, the first character of that next value is lost:
```cpp
std::istringstream input("1true");
json j1, j2;
input >> j1; // j1 == 1
input >> j2; // throws parse_error.101: the stream now starts at "rue"
```
Separating the values with whitespace avoids this, because the character that is eaten is then the separator:
```cpp
std::istringstream input("1 true");
json j1, j2;
input >> j1; // j1 == 1
input >> j2; // j2 == true
```
Only numbers are affected. Values ending in a self-delimiting character do not read past themselves, so
`truefalse`, `[1][2]`, `{"a":1}{"b":2}`, and `"a""b"` can be read back to back without a separator.
This is tracked in [#5340](https://github.com/nlohmann/json/issues/5340).
Note that reading concatenated values does **not** work for [JSON Lines](../features/parsing/json_lines.md)
(newline-delimited JSON) input -- see that page for why and for the recommended alternative.
!!! warning "Deprecation"
This function replaces function `#!cpp std::istream& operator<<(basic_json& j, std::istream& i)` which has
@@ -56,8 +56,12 @@ Linear.
--8<-- "examples/operator_literal_json.output"
```
## See also
- [Creating JSON values](../features/creating_values.md) - the article on creating JSON values
## Version history
- 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.
+6
View File
@@ -80,6 +80,12 @@ Linear.
```json
--8<-- "examples/operator_ltlt__json_pointer.output"
```
## See also
- [dump](basic_json/dump.md) - serialize to a JSON-formatted string
- [Serialization](../features/serialization.md) - the serialization article
## Version history
1. Added in version 1.0.0. Added support for indentation character and deprecated
+6
View File
@@ -13,6 +13,12 @@ Therefore, adding object elements can yield a reallocation in which case all ite
[`end()`](basic_json/end.md) iterator) and all references to the elements are invalidated. Also, any iterator or
reference after the insertion point will point to the same index, which is now a different value.
## Complexity
[`ordered_map`](ordered_map.md) has no lookup index: every key-based object operation is a linear scan, so building or
parsing an object of `n` keys costs O(n²) rather than O(n log n). See
[`ordered_map` complexity](ordered_map.md#complexity) for the per-operation table and for measured numbers.
## Examples
??? example
+42
View File
@@ -56,6 +56,48 @@ std::equal_to<> // since C++14
- **find**
- **insert**
## Complexity
Because the elements are stored in a `std::vector` in insertion order, there is no index to look a key up by. Every
key-based operation performs a **linear scan** over the stored elements. With `n` denoting the number of elements in the
container:
| Operation | Complexity | Note |
|----------------------------------------|----------------|----------------------------------------------------------|
| **emplace** | O(n) | scans for an existing key, then appends (amortized O(1)) |
| **operator\[\]** | O(n) | delegates to **emplace** (non-const) or **at** (const) |
| **at** | O(n) | throws `#!cpp std::out_of_range` if the key is not found |
| **find** | O(n) | |
| **count** | O(n) | the result is always 0 or 1 |
| **erase(key)** | O(n) | scan, then move the remaining elements one position down |
| **erase(pos)**, **erase(first, last)** | O(n) | moves all elements after the erased range |
| **insert(value)** | O(n) | equivalent to **emplace** |
| **insert(first, last)** | O((n + m) * m) | for `m` inserted elements |
This differs from `#!cpp std::map`, where the same operations are O(log n).
!!! warning "Quadratic cost of building large objects"
Because every insertion scans all elements inserted so far, building an object of `n` distinct keys costs
**O(n²)** in total. This applies to filling an [`ordered_json`](ordered_json.md) object key by key as well as to
parsing one, since the parser inserts each key as it is read.
The cost is negligible for the object sizes typically found in configuration files or API payloads, but it grows
steeply for machine-generated objects with many thousands of keys. Measured with `-O2 -DNDEBUG` for parsing a flat
object of `n` keys, relative to `#!cpp nlohmann::json` (which uses `#!cpp std::map`):
| `n` | `json` | `ordered_json` | factor |
|--------|--------|----------------|--------|
| 2000 | 0.7 ms | 3.6 ms | 5× |
| 4000 | 0.8 ms | 14.0 ms | 19× |
| 8000 | 1.6 ms | 67.8 ms | 43× |
| 16 000 | 3.3 ms | 181.6 ms | 54× |
If key order matters for objects of that size, consider a container with a lookup index, such as
[`tsl::ordered_map`](https://github.com/Tessil/ordered-map)
([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)), as the object type -- see
[object order](../features/object_order.md).
## Examples
??? example
+40
View File
@@ -0,0 +1,40 @@
# Ecosystem
The projects below build on top of `nlohmann::json` rather than merely using it - schema validators, language
bindings, format converters, and similar building blocks. The list is not exhaustive, and is curated rather than
automatically generated. If you maintain or know of a project that belongs here,
[please let me know](mailto:mail@nlohmann.me).
For products, applications, and organizations that use the library, see [Customers](../home/customers.md) instead.
## Schema validation
- [**json-schema-validator**](https://github.com/pboettch/json-schema-validator), a JSON Schema (draft 7) validator
with human-readable error messages
## Serialization and reflection
- [**nlohmann_json_reflect**](https://github.com/1261385937/nlohmann_json_reflect), a reflection extension for
(de)serializing nested containers-in-structs-in-containers
## Encodings
- [**base-encode-decode**](https://github.com/saxonnicholls/base-encode-decode), a header-only Base64/32/16/8/4/2
(and DNA/RNA) encoding library, with an adapter that serializes binary data through `nlohmann::json`
## Language bindings and interop
- [**pybind11_json**](https://github.com/pybind/pybind11_json), a bidirectional type caster between
`nlohmann::json` and Python objects for [pybind11](https://github.com/pybind/pybind11) bindings
- [**nanobind_json**](https://github.com/ianhbell/nanobind_json), the same idea for
[nanobind](https://github.com/wjakob/nanobind) bindings
- [**nlohmann_json_qt**](https://github.com/dpurgin/nlohmann_json_qt), deserialization helpers for Qt types
(`QString`, `QUrl`, `QDateTime`, `QVector`, ...) from `nlohmann::json`
- [**vulkan2json**](https://github.com/Fadis/vulkan2json), serialization and deserialization of Vulkan API structs
## Format converters
- [**tojson**](https://github.com/mircodz/tojson), a header-only converter between YAML/XML documents and
`nlohmann::json`
- [**json2xml**](https://github.com/testillano/json2xml), a header-only converter from `nlohmann::json` to XML for
simple configuration documents
+1
View File
@@ -1,5 +1,6 @@
# Community
- [Ecosystem](ecosystem.md) - third-party projects built on top of this library
- [Code of Conduct](code_of_conduct.md) - the rules and norms of this project
- [Contribution Guidelines](contribution_guidelines.md) - guidelines how to contribute to this project
- [Governance](governance.md) - the governance model of this project
@@ -10,6 +10,10 @@ violations will result in a failed build.
Any compiler with complete C++11 support can compile the library without warnings.
Note: C++20 modules support may hit compiler-specific issues not covered by the general compiler matrix below. See [Modules](../features/modules.md#known-issues) for known issues and workarounds.
Note: Some modern features (like C++20 ranges or filesystem support) may be disabled on specific broken or incomplete toolchains even when standard feature-test macros indicate support. See [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) and [`JSON_HAS_FILESYSTEM`](../api/macros/json_has_filesystem.md) for details on known exclusions.
- [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms,
including the oldest versions known to compile the library.
@@ -62,12 +66,15 @@ violations will result in a failed build.
| Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub |
| Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| CUDA 11.0.221 (nvcc) | x86_64 | Ubuntu 20.04 LTS | GitHub |
| Clang 22.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| CUDA 11.8.0 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| CUDA 12.1.1 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| CUDA 12.6.3 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| Emscripten 4.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.8.5 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.9.3 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 5.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 6.4.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.8.5 | x86_64 | Ubuntu 20.04 LTS | GitHub |
| GNU 4.9.3 | x86_64 | Ubuntu 20.04 LTS | GitHub |
| GNU 5.5.0 | x86_64 | Ubuntu 20.04 LTS | GitHub |
| GNU 6.4.0 | x86_64 | Ubuntu 20.04 LTS | GitHub |
| GNU 7.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 8.5.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 9.3.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
@@ -84,7 +91,7 @@ violations will result in a failed build.
| GNU 15.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 16.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 16.1.0 | arm64 | Linux 6.1.100 | Cirrus CI |
| icpc (ICC) 2021.5.0 20211109 | x86_64 | Ubuntu 20.04.3 LTS | GitHub |
| icpc (ICC) 2021.10.0 20230609 | x86_64 | Ubuntu 22.04 LTS | GitHub |
| icpx (Intel oneAPI DPC++/C++) 2025.3.2 | x86_64 | Ubuntu 24.04 LTS | GitHub |
| nvc++ (NVIDIA HPC SDK) 25.5-0 | x86_64 | Ubuntu 22.04 LTS | GitHub |
| MSVC 19.0.24241.7 | x86 | Windows 8.1 | AppVeyor |
@@ -0,0 +1,47 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// a JSON text with an array and a number inside an object
auto text = R"({"IDs": [116, 943], "Width": 800})";
// discard the array when the parser reads its opening bracket
json j_array_start = json::parse(text, [](int /*depth*/, json::parse_event_t event, json& /*parsed*/)
{
return event != json::parse_event_t::array_start;
});
// discard the same array when the parser reads its closing bracket
json j_array_end = json::parse(text, [](int /*depth*/, json::parse_event_t event, json& /*parsed*/)
{
return event != json::parse_event_t::array_end;
});
// discard the number, but keep its key
json j_value = json::parse(text, [](int /*depth*/, json::parse_event_t event, json & parsed)
{
return !(event == json::parse_event_t::value && parsed == json(800));
});
// discard the key of the number
json j_key = json::parse(text, [](int /*depth*/, json::parse_event_t event, json & parsed)
{
return !(event == json::parse_event_t::key && parsed == json("Width"));
});
// discard the top-level object
json j_root = json::parse(text, [](int /*depth*/, json::parse_event_t event, json& /*parsed*/)
{
return event != json::parse_event_t::object_end;
});
// in every case, the discarded value is removed together with its key
std::cout << j_array_start << '\n'
<< j_array_end << '\n'
<< j_value << '\n'
<< j_key << '\n'
<< j_root << '\n';
}
@@ -0,0 +1,5 @@
{"Width":800}
{"Width":800}
{"IDs":[116,943]}
{"IDs":[116,943]}
null
@@ -0,0 +1,61 @@
#include <iostream>
#include <nlohmann/json.hpp>
#include <stdexcept>
#include <string>
#include <unordered_set>
#include <vector>
using json = nlohmann::json;
json parse_strict(const std::string& input)
{
// one key set per nesting depth, reused across sibling objects
std::vector<std::unordered_set<std::string>> keys;
auto reject_duplicate_keys = [&](int depth, json::parse_event_t event, json & parsed)
{
if (event == json::parse_event_t::object_start)
{
// keys of this object are reported at depth+1 (see the event table above)
const auto child_depth = static_cast<std::size_t>(depth) + 1;
if (keys.size() <= child_depth)
{
keys.resize(child_depth + 1);
}
keys[child_depth].clear();
return true;
}
if (event == json::parse_event_t::key)
{
auto& seen = keys[static_cast<std::size_t>(depth)];
const auto& key = parsed.get_ref<const std::string&>();
if (!seen.insert(key).second)
{
throw std::runtime_error("duplicate JSON object key: " + key);
}
return true;
}
return true;
};
return json::parse(input, reject_duplicate_keys);
}
int main()
{
// parsing succeeds when all keys are unique
json j = parse_strict(R"({"one": 1, "two": 2})");
std::cout << j << '\n';
// parsing throws when a key is repeated
try
{
parse_strict(R"({"one": 1, "one": 2})");
}
catch (const std::exception& e)
{
std::cout << e.what() << '\n';
}
}
@@ -0,0 +1,2 @@
{"one":1,"two":2}
duplicate JSON object key: one
+88 -2
View File
@@ -85,7 +85,7 @@ Some important things:
If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate.
There are several macros to make your life easier as long as you want to use a JSON object as serialization. The macros are following the naming pattern, and you can chose the macro based on the needed features:
There are several macros to make your life easier as long as you want to use a JSON object as serialization. The macros are following the naming pattern, and you can choose the macro based on the needed features:
- All the macros start with `NLOHMANN_DEFINE`.
- If you want a macro for the derived object, use the [`DERIVED_TYPE`](../api/macros/nlohmann_define_derived_type.md) variant, otherwise use `TYPE`.
@@ -139,7 +139,7 @@ For _derived_ classes and structs, use the following macros
```cpp
namespace ns {
struct person_derived : person {
std:string email;
std::string email;
};
NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(person_derived, person, email)
@@ -180,6 +180,49 @@ For _derived_ classes and structs, use the following macros
}
```
!!! warning "Overriding conversions for natively-supported types"
The library already provides built-in `to_json`/`from_json` conversions for STL containers such as
`std::vector`, `std::array`, and `std::map`. Defining your own free-function `to_json`/`from_json` overload
for one of these container types directly (instead of for your own type) can conflict with the built-in
overload during overload resolution, producing compiler errors ("no matching overloaded function",
"call is ambiguous") that vary by compiler and library version. If you need different conversion behavior
for a container type the library already handles, wrap it in your own type (or use `adl_serializer`
specialization, as shown [above](#how-do-i-convert-third-party-types) for `boost::optional`) instead of
trying to re-specialize `to_json`/`from_json` for the container type itself.
!!! warning "Raw C-style arrays"
Members declared as raw C-style arrays (e.g., `char buf[1024]`) do not round-trip safely through
`NLOHMANN_DEFINE_TYPE_*` macros or the default (de)serializers: `to_json` serializes any `char` array as a
JSON *string* (matching the `std::string`-constructible overload), but the `from_json` overload for
fixed-size arrays expects a JSON *array* and iterates it element-wise, which fails with a `type_error` when
given a string. Use `std::string`, `std::array<char, N>`, or a manually written `to_json`/`from_json` pair
for such members instead.
!!! note "Macros and `nlohmann::ordered_json`"
The `NLOHMANN_DEFINE_TYPE_*`/`NLOHMANN_DEFINE_DERIVED_TYPE_*` macros are generic over any `basic_json`
specialization, including `nlohmann::ordered_json`. Simply use `ordered_json` as the target type and members
are serialized in declaration order -- no separate macro or extra code is needed.
```cpp
namespace ns {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}
ns::person p{"Ned Flanders", "744 Evergreen Terrace", 60};
nlohmann::ordered_json j = p; // keys appear in declaration order: name, address, age
```
!!! note "No macro for non-default-constructible types"
There is currently no `NLOHMANN_DEFINE_TYPE_*`-style macro for types that are not
[DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). This is not an
intentional omission of documentation -- no such macro exists yet; see
[How can I use `get()` for non-default constructible/non-copyable types?](#how-can-i-use-get-for-non-default-constructiblenon-copyable-types)
for the manual pattern to use instead.
## How do I convert third-party types?
This requires a bit more advanced technique. But first, let us see how this conversion mechanism works:
@@ -270,6 +313,49 @@ namespace nlohmann {
}
```
## Why can't I convert to/from `std::any`?
`std::any` is intentionally excluded from `get<T>()`/generic conversion support, so `get<std::any>()` and
containers like `std::map<std::string, std::any>` fail to compile by design -- there is no way to know, from a
`json` value alone, which concrete type to store inside the `std::any`. To work with heterogeneous JSON values,
dispatch on the value's type manually and construct the `std::any` (or extract from it) yourself:
```cpp
std::any value_to_any(const json& j) {
if (j.is_boolean()) { return j.get<bool>(); }
if (j.is_number_integer()) { return j.get<int>(); }
if (j.is_number_float()) { return j.get<double>(); }
if (j.is_string()) { return j.get<std::string>(); }
// ... handle other types (arrays, objects) as needed for your use case
return {};
}
json any_to_json(const std::any& a) {
if (a.type() == typeid(bool)) { return std::any_cast<bool>(a); }
if (a.type() == typeid(int)) { return std::any_cast<int>(a); }
if (a.type() == typeid(double)) { return std::any_cast<double>(a); }
if (a.type() == typeid(std::string)) { return std::any_cast<std::string>(a); }
return nullptr;
}
```
## Why does serializing a `std::map`/`std::unordered_map` with non-string keys produce an array?
A `std::map`/`std::unordered_map` whose key type is not string-like (e.g., `std::map<int, std::string>`) is
serialized as a JSON *array* of 2-element `[key, value]` arrays, not as a JSON object -- JSON object keys must be
strings, so the library cannot represent an integer-keyed map as an object.
```cpp
std::map<int, std::string> m{{1, "one"}, {2, "two"}};
json j = m;
// j is [[1,"one"],[2,"two"]], not {"1":"one","2":"two"}
```
## Why does `std::wstring` convert or dump incorrectly?
The library assumes UTF-8 encoding internally, so `std::wstring` is not supported out of the box -- see the FAQ
entry on [wide string handling](../home/faq.md#wide-string-handling) for why, and for a UTF-8 conversion recipe.
## Can I write my own serializer? (Advanced use)
Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-udt.cpp) in the test suite, to see a few examples.
+1 -1
View File
@@ -11,7 +11,7 @@ Runtime assertions can be switched off by defining the preprocessor macro `NDEBU
## Change assertion behavior
The behavior of runtime assertions can be changes by defining macro [`JSON_ASSERT(x)`](../api/macros/json_assert.md)
The behavior of runtime assertions can be changed by defining macro [`JSON_ASSERT(x)`](../api/macros/json_assert.md)
before including the `json.hpp` header.
## Function with runtime assertions
@@ -116,14 +116,24 @@ The library uses the following mapping from JSON values types to BJData types ac
```
Likewise, when a JSON object in the above form is serialized using
[`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array. The
only exception is, that when the 1-dimensional vector stored in `"_ArraySize_"` contains a single integer or two
integers with one being 1, a regular 1-D optimized array is generated.
[`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array. When
the 1-dimensional vector stored in `"_ArraySize_"` contains a single integer or two integers with one being 1, a
regular 1-D optimized array is generated instead.
An object is only converted if the annotation actually describes a packed array; otherwise it is serialized as a
regular JSON object. This requires all of the following:
- `"_ArrayType_"` is one of `uint8`, `int8`, `uint16`, `int16`, `uint32`, `int32`, `uint64`, `int64`, `single`,
`double`, `char`, or `byte`,
- every entry of `"_ArraySize_"` is a non-negative integer, and their product is representable as a `std::size_t`,
- `"_ArrayData_"` holds exactly that many elements, and
- every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"` (a floating-point number for
`single` and `double`, an integer otherwise).
The current version of this library does not yet support automatic detection of and conversion from a nested JSON
array input to a BJData ND-array.
[JDataAAFmt]: https://github.com/NeuroJSON/jdata/blob/master/JData_specification.md#annotated-storage-of-n-d-arrays)
[JDataAAFmt]: https://github.com/NeuroJSON/jdata/blob/master/JData_specification.md#annotated-storage-of-n-d-arrays
!!! info "Restrictions in optimized data types for arrays and objects"
@@ -146,7 +156,7 @@ The library uses the following mapping from JSON values types to BJData types ac
suggested by the BJData documentation. In particular, this means that the serialization and the deserialization of
JSON containing binary values into BJData and back will result in a different JSON object.
[BJDataBinArr]: https://github.com/NeuroJSON/bjdata/blob/master/Binary_JData_Specification.md#optimized-binary-array)
[BJDataBinArr]: https://github.com/NeuroJSON/bjdata/blob/master/Binary_JData_Specification.md#optimized-binary-array
??? example
@@ -35,6 +35,19 @@ The library uses the following mapping from JSON values types to BSON types:
The mapping is **incomplete**, since only JSON-objects (and things contained therein) can be serialized to BSON.
Also, keys may not contain U+0000, since they are serialized a zero-terminated c-strings.
!!! warning "BSON type 0x11 interoperability"
The BSON specification defines type `0x11` as a Timestamp. This library uses marker `0x11` when serializing
`number_unsigned` values in the range `9223372036854775808..18446744073709551615`. Other BSON implementations may
therefore interpret these values as Timestamps instead of unsigned integers.
!!! info "Binary values without a subtype"
BSON requires every binary value to have a subtype. If a binary value has no subtype, this library serializes it
with the generic subtype `0x00`. After deserialization, `has_subtype()` returns `true` and `subtype()` returns `0`.
As a result, serializing and deserializing a JSON object containing such a value produces a different JSON object,
even though the binary data is unchanged.
??? example
```cpp
@@ -52,28 +65,29 @@ The library uses the following mapping from JSON values types to BSON types:
The library maps BSON record types to JSON value types as follows:
| BSON type | BSON marker byte | JSON value type |
|-----------------------|------------------|-----------------|
| double | 0x01 | number_float |
| string | 0x02 | string |
| document | 0x03 | object |
| array | 0x04 | array |
| binary | 0x05 | binary |
| undefined | 0x06 | *unsupported* |
| ObjectId | 0x07 | *unsupported* |
| boolean | 0x08 | boolean |
| UTC Date-Time | 0x09 | *unsupported* |
| null | 0x0A | null |
| Regular Expr. | 0x0B | *unsupported* |
| DB Pointer | 0x0C | *unsupported* |
| JavaScript Code | 0x0D | *unsupported* |
| Symbol | 0x0E | *unsupported* |
| JavaScript Code | 0x0F | *unsupported* |
| int32 | 0x10 | number_integer |
| uint64(Timestamp) | 0x11 | number_unsigned |
| 128-bit decimal float | 0x13 | *unsupported* |
| Max Key | 0x7F | *unsupported* |
| Min Key | 0xFF | *unsupported* |
| BSON type | BSON marker byte | JSON value type |
|--------------------------|------------------|-----------------|
| double | 0x01 | number_float |
| string | 0x02 | string |
| document | 0x03 | object |
| array | 0x04 | array |
| binary | 0x05 | binary |
| undefined | 0x06 | *unsupported* |
| ObjectId | 0x07 | *unsupported* |
| boolean | 0x08 | boolean |
| UTC Date-Time | 0x09 | *unsupported* |
| null | 0x0A | null |
| Regular Expr. | 0x0B | *unsupported* |
| DB Pointer | 0x0C | *unsupported* |
| JavaScript Code | 0x0D | *unsupported* |
| Symbol | 0x0E | *unsupported* |
| JavaScript Code w/ scope | 0x0F | *unsupported* |
| int32 | 0x10 | number_integer |
| uint64(Timestamp) | 0x11 | number_unsigned |
| int64 | 0x12 | number_integer |
| 128-bit decimal float | 0x13 | *unsupported* |
| Max Key | 0x7F | *unsupported* |
| Min Key | 0xFF | *unsupported* |
!!! warning "Incomplete mapping"
@@ -81,8 +95,19 @@ The library maps BSON record types to JSON value types as follows:
!!! note "Handling of BSON type 0x11"
BSON type 0x11 is used to represent uint64 numbers. This library treats these values purely as uint64 numbers
and does not parse them into date-related formats.
This library deserializes BSON type `0x11` (Timestamp) as a `number_unsigned` value. The 64-bit value is preserved,
but the Timestamp type information is not.
!!! warning "Lenient BSON input handling"
The BSON reader is lenient in a few areas where the BSON specification is more restrictive:
- array element keys are not checked against the required decimal sequence (`0`, `1`, `2`, ...),
- any non-zero byte is accepted as `true` for the boolean type, and
- the payload for binary subtype `0x02` is returned as-is, including its inner length prefix.
If BSON input must be validated for strict specification compliance, validate it separately before passing it to
`from_bson()`.
??? example
@@ -5,14 +5,14 @@ extremely small code sizes, fairly small message size, and extensibility without
!!! abstract "References"
- [CBOR Website](http://cbor.io) - the main source on CBOR
- [CBOR Website](http://cbor.io) - the main source on CBOR
- [CBOR Playground](http://cbor.me) - an interactive webpage to translate between JSON and CBOR
- [RFC 7049](https://tools.ietf.org/html/rfc7049) - the CBOR specification
- [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949.html) - the CBOR specification
## Serialization
The library uses the following mapping from JSON values types to CBOR types according to the CBOR specification
([RFC 7049](https://www.rfc-editor.org/rfc/rfc7049.html)):
([RFC 8949](https://www.rfc-editor.org/rfc/rfc8949.html)):
| JSON value type | value/range | CBOR type | first byte |
|-----------------|--------------------------------------------|-----------------------------------|------------|
@@ -37,22 +37,22 @@ The library uses the following mapping from JSON values types to CBOR types acco
| number_float | *any value representable by a float* | Single-Precision Float | 0xFA |
| number_float | *any value NOT representable by a float* | Double-Precision Float | 0xFB |
| string | *length*: 0..23 | UTF-8 string | 0x60..0x77 |
| string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 |
| string | *length*: 24..255 | UTF-8 string (1 byte follow) | 0x78 |
| string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 |
| string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A |
| string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B |
| array | *size*: 0..23 | array | 0x80..0x97 |
| array | *size*: 23..255 | array (1 byte follow) | 0x98 |
| array | *size*: 24..255 | array (1 byte follow) | 0x98 |
| array | *size*: 256..65535 | array (2 bytes follow) | 0x99 |
| array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A |
| array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B |
| object | *size*: 0..23 | map | 0xA0..0xB7 |
| object | *size*: 23..255 | map (1 byte follow) | 0xB8 |
| object | *size*: 24..255 | map (1 byte follow) | 0xB8 |
| object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 |
| object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA |
| object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB |
| binary | *size*: 0..23 | byte string | 0x40..0x57 |
| binary | *size*: 23..255 | byte string (1 byte follow) | 0x58 |
| binary | *size*: 24..255 | byte string (1 byte follow) | 0x58 |
| binary | *size*: 256..65535 | byte string (2 bytes follow) | 0x59 |
| binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A |
| binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B |
@@ -66,7 +66,15 @@ see "binary" cells in the table above.
!!! info "NaN/infinity handling"
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the normal JSON serialization which serializes NaN or Infinity to `null`.
`NaN`, `Infinity`, and `-Infinity` are serialized as a CBOR half-precision float (type 0xF9, 3 bytes total):
`NaN` as `0xF9 0x7E 0x00`, `Infinity` as `0xF9 0x7C 0x00`, and `-Infinity` as `0xF9 0xFC 0x00`. This behavior
differs from the normal JSON serialization which serializes NaN or Infinity to `null`.
!!! note
Prior to version 3.13.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB,
9 bytes total), because the check used to select a smaller encoding compared magnitudes with NaN, which is
always `false` and caused the intended half-precision path to be skipped.
!!! info "Unused CBOR types"
@@ -152,21 +160,25 @@ The library maps CBOR types to JSON value types as follows:
The mapping is **incomplete** in the sense that not all CBOR types can be converted to a JSON value. The following CBOR types are not supported and will yield parse errors:
- date/time (0xC0..0xC1)
- bignum (0xC2..0xC3)
- decimal fraction (0xC4)
- bigfloat (0xC5)
- expected conversions (0xD5..0xD7)
- simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7)
Tagged items (0xC0..0xDB) are not interpreted either; see the note on tagged items below.
!!! warning "Negative integer overflow"
CBOR negative integers (major type 1) are decoded as `-1 - n`. If the encoded magnitude `n` is too large for the
result to fit into `number_integer_t` (`std::int64_t` by default), parsing fails with a
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) exception rather than overflowing
silently.
!!! warning "Object keys"
CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys other than UTF-8 strings are rejected.
!!! warning "Tagged items"
Tagged items will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`. They can be stored by passing `cbor_tag_handler_t::store` to function `from_cbor`.
Tagged items (0xC0..0xDB) will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`, in which case the tag is skipped and the enclosed data item is parsed on its own. They can be stored by passing `cbor_tag_handler_t::store` to function `from_cbor`. Note that no tag is ever interpreted: for instance, a text string tagged with tag 0 (date/time) stays a string.
??? example
@@ -41,7 +41,7 @@ See [binary values](../binary_values.md) for more information.
|--------------------|-------------|--------------|-------------------|---------------|
| BJData | 53.2 % | 91.1 % | 78.1 % | 96.6 % |
| BJData (size) | 58.6 % | 92.1 % | 86.7 % | 97.4 % |
| BJData (size+tyoe) | 58.6 % | 92.1 % | 86.5 % | 97.4 % |
| BJData (size+type) | 58.6 % | 92.1 % | 86.5 % | 97.4 % |
| BSON | 85.8 % | 95.2 % | 95.8 % | 106.7 % |
| CBOR | 50.5 % | 86.3 % | 68.4 % | 88.0 % |
| MessagePack | 50.5 % | 86.0 % | 68.5 % | 87.9 % |
@@ -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
+9 -9
View File
@@ -41,7 +41,7 @@ binary.has_subtype(); // returns false
binary_with_subtype.has_subtype(); // returns true
binary_with_subtype.clear_subtype();
binary_with_subtype.has_subtype(); // returns true
binary_with_subtype.has_subtype(); // returns false
binary_with_subtype.set_subtype(42);
binary.set_subtype(23);
@@ -146,7 +146,7 @@ as an array of uint8 values. The library implements this translation.
auto v = json::to_bjdata(j);
```
`v` is a `std::vector<std::uint8t>` with the following 20 elements:
`v` is a `std::vector<std::uint8_t>` with the following 20 elements:
```c
0x7B // '{'
@@ -158,10 +158,10 @@ as an array of uint8 values. The library implements this translation.
0x7D // '}'
```
The following code uses the type and size optimization for UBJSON:
The following code uses the type and size optimization for BJData:
```cpp
// convert to UBJSON using the size and type optimization
// convert to BJData using the size and type optimization
auto v = json::to_bjdata(j, true, true);
```
@@ -178,7 +178,7 @@ as an array of uint8 values. The library implements this translation.
0xCA 0xFE 0xBA 0xBE // content
```
Note that subtype (42) is **not** serialized and that UBJSON has **no binary type**, and deserializing `v` would
Note that subtype (42) is **not** serialized and that BJData has **no binary type**, and deserializing `v` would
yield the following value:
```json
@@ -205,7 +205,7 @@ unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00
auto v = json::to_bson(j);
```
`v` is a `std::vector<std::uint8t>` with the following 22 elements:
`v` is a `std::vector<std::uint8_t>` with the following 22 elements:
```c
0x16 0x00 0x00 0x00 // number of bytes in the document
@@ -247,7 +247,7 @@ byte array.
auto v = json::to_cbor(j);
```
`v` is a `std::vector<std::uint8t>` with the following 15 elements:
`v` is a `std::vector<std::uint8_t>` with the following 15 elements:
```c
0xA1 // map(1)
@@ -291,7 +291,7 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used.
auto v = json::to_msgpack(j);
```
`v` is a `std::vector<std::uint8t>` with the following 14 elements:
`v` is a `std::vector<std::uint8_t>` with the following 14 elements:
```c
0x81 // fixmap1
@@ -331,7 +331,7 @@ as an array of uint8 values. The library implements this translation.
auto v = json::to_ubjson(j);
```
`v` is a `std::vector<std::uint8t>` with the following 20 elements:
`v` is a `std::vector<std::uint8_t>` with the following 20 elements:
```c
0x7B // '{'
+1 -1
View File
@@ -11,7 +11,7 @@ This library does not support comments *by default*. It does so for three reason
3. It is dangerous for interoperability if some libraries add comment support while others do not. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace.
However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. Combined with `ignore_trailing_commas` (also a `parse` parameter), this covers what is commonly referred to as **JSONC** (JSON with Comments, as used e.g. by Visual Studio Code's `.jsonc` files) -- comments and trailing commas, nothing more. This is a different, smaller extension than [JSON5](https://json5.org), which additionally allows unquoted keys, single-quoted strings, and other syntax changes that this library does not support.
For more information, see [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html).
+235
View File
@@ -0,0 +1,235 @@
# Converting values
A `basic_json` value stores JSON data, but most of the time you want to move that data into ordinary C++ types (an
`#!cpp int`, a `#!cpp std::string`, a `#!cpp std::vector`, or one of your own structs) and back. This page describes how
these conversions work.
## Getting values out
The [`get`](../api/basic_json/get.md) function template returns a copy of the stored value converted to the requested
type:
```cpp
json j = R"({"name": "Mary", "age": 42, "hobbies": ["hiking", "reading"]})"_json;
auto name = j["name"].get<std::string>(); // "Mary"
auto age = j["age"].get<int>(); // 42
auto hobbies = j["hobbies"].get<std::vector<std::string>>(); // {"hiking", "reading"}
```
!!! note "Getting a string without quotes"
A frequent point of confusion: use [`get`](../api/basic_json/get.md), **not** [`dump`](serialization.md), to read a
string value. `#!cpp j["name"].get<std::string>()` yields `#!cpp Mary`, whereas `#!cpp j["name"].dump()` yields the
JSON text `#!cpp "Mary"` (**with** quotes), because `dump` always produces a JSON text.
Alternatively, [`get_to`](../api/basic_json/get_to.md) writes into an existing variable and deduces the target type,
which avoids repeating it:
??? example
```cpp
--8<-- "examples/get_to.cpp"
```
Output:
```json
--8<-- "examples/get_to.output"
```
The library already knows how to convert to and from the scalar types and the STL containers (such as
`#!cpp std::vector`, `#!cpp std::map`, `#!cpp std::array`, `#!cpp std::optional`, and many more). Converting a JSON
object back to a `#!cpp std::map` or a JSON array back to a `#!cpp std::vector` therefore works without any extra code:
```cpp
json j = {{"one", 1}, {"two", 2}};
auto m = j.get<std::map<std::string, int>>(); // {{"one", 1}, {"two", 2}}
```
`#!cpp std::pair` and `#!cpp std::tuple` are also supported, converting positionally to and from a JSON array:
```cpp
json j = {1.0, "hello", 42};
auto t = j.get<std::tuple<double, std::string, int>>(); // {1.0, "hello", 42}
```
!!! warning "Serializing a `std::pair`/`std::tuple` whose every element is a string-keyed pair"
When *every* element of a `#!cpp std::pair` or `#!cpp std::tuple` is itself a two-element array whose first
element is a string (for example `#!cpp std::pair<std::string, int>`), serializing it produces a JSON **object**
instead of the expected array:
```cpp
using kv = std::pair<std::string, int>;
json j = std::pair<kv, kv>{{"a", 1}, {"b", 2}}; // {"a":1,"b":2}, not [["a",1],["b",2]]
```
This is a consequence of the [brace-initializer object-detection rule](creating_values.md): the same rule that
lets `#!cpp json{{"a", 1}, {"b", 2}}` create an object also fires here. The resulting object cannot be read back
into the original type (`#!cpp get<std::pair<kv, kv>>()` throws [`type_error.302`](../home/exceptions.md#jsonexceptiontype_error302)),
and duplicate keys collapse into one, losing elements. This only affects `#!cpp std::pair`/`#!cpp std::tuple`
themselves; a `#!cpp std::vector<std::pair<std::string, int>>`, or a pair/tuple with at least one element that is
not a string-keyed pair, serializes to an array as expected. To force an array, build one explicitly from the
elements with [`array`](../api/basic_json/array.md):
```cpp
std::pair<kv, kv> p{{"a", 1}, {"b", 2}};
json a = json::array({p.first, p.second}); // [["a",1],["b",2]]
```
!!! info "Extracting references into a tuple"
A tuple type may also hold references (e.g. `#!cpp std::tuple<double&, std::string&>`) to avoid copying: `get`
then returns a tuple of references pointing directly at the elements stored inside the `basic_json` array,
rather than a tuple of copies:
```cpp
json j = {1.0, "hello"};
auto refs = j.get<std::tuple<double&, std::string&>>();
std::get<1>(refs) = "world"; // modifies j[1] in place
```
A referenced element must name the type the library actually *stores* — one of [`boolean_t`](../api/basic_json/boolean_t.md),
[`number_integer_t`](../api/basic_json/number_integer_t.md), [`number_unsigned_t`](../api/basic_json/number_unsigned_t.md),
[`number_float_t`](../api/basic_json/number_float_t.md), [`string_t`](../api/basic_json/string_t.md),
[`binary_t`](../api/basic_json/binary_t.md), [`array_t`](../api/basic_json/array_t.md), or
[`object_t`](../api/basic_json/object_t.md). There is nothing else to refer to, so a reference to any other type is a
compile error even when a conversion would exist: `#!cpp std::tuple<int&>` is rejected, because the library stores a
`#!cpp number_integer_t` (`#!cpp std::int64_t` by default) and not an `#!cpp int`. This restriction applies only to
reference elements — a plain `#!cpp std::tuple<int>` converts by value as usual.
## Implicit conversions
By default, a JSON value implicitly converts to a compatible C++ type, so the explicit `get` call can often be omitted:
```cpp
json j = "Hello";
std::string s = j; // implicit conversion, same as j.get<std::string>()
```
Implicit conversions are convenient but can be surprising (for example, in overload resolution or with `auto`). They can
be disabled by defining [`JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md) to `#!cpp 0`,
which forces the explicit `get` form and can catch unintended conversions at compile time.
!!! warning "Conversions do not range-check numbers"
Just like C++ itself, the `get` family performs numeric conversions without range checks — retrieving a
floating-point value as an integer truncates it, and narrowing conversions may overflow. See
[number conversion](types/number_handling.md#number-conversion) for details and how to guard against it.
!!! warning "std::optional direct construction from JSON null throws"
Constructing or assigning `std::optional<T>` directly from a JSON value does not correctly produce
`std::nullopt` for a JSON `null`:
```cpp
json j_null;
std::optional<std::string> opt = j_null; // ❌ throws type_error 302
```
This is due to C++ language rules: `std::optional<T>` has its own converting constructor that is chosen over
`basic_json::operator T()` when both are viable. Use `get<std::optional<T>>()` or `get_to()` instead:
```cpp
auto opt = j_null.get<std::optional<std::string>>(); // ✅ std::nullopt
j_null.get_to(opt); // ✅ std::nullopt
```
!!! warning "`static_cast` and `get<std::optional<T>>()` are not guaranteed equivalent"
`operator ValueType()` (used by `static_cast` and implicit conversions) intentionally excludes
`std::optional<T>` from delegating to `get<T>()`, to avoid a constructor ambiguity with
`std::optional<T>`'s own converting constructor from `basic_json`. As a result,
`static_cast<std::optional<T>>(json_value)` goes through `std::optional<T>`'s own converting
constructor rather than through `get<std::optional<T>>()`, which can behave differently -- for example,
with a custom `adl_serializer<std::optional<T>>` specialization. Prefer `get<std::optional<T>>()`/`get_to()`
over `static_cast` for optional types.
!!! warning "Converting to a fixed-size destination does not check the array size"
Some destination types have a size that is fixed by their C++ type rather than by the JSON value:
`#!cpp std::pair<A, B>`, `#!cpp std::tuple<Ts...>`, `#!cpp std::array<T, N>`, C arrays `#!cpp T[N]`, and
`#!cpp std::map`/`#!cpp std::unordered_map` with a non-string key type (which is read from an array of
two-element arrays). All of them read exactly as many elements as they need via
[`at`](../api/basic_json/at.md) and **never compare the JSON array's size to that number**. The two
mismatch directions therefore behave differently:
- The JSON array has **too many** elements: the surplus is **silently discarded**, and no exception is
thrown.
- The JSON array has **too few** elements: `at` throws
[`out_of_range.401`](../home/exceptions.md#jsonexceptionout_of_range401) for the first missing index --
an out-of-range error, not a [`type_error`](../home/exceptions.md#type-errors), even though the cause
is a shape mismatch.
```cpp
json j = {1, 2, 3, 4, 5};
auto a = j.get<std::array<int, 3>>(); // {1, 2, 3} -- elements 4 and 5 silently dropped
auto p = j.get<std::pair<int, int>>(); // (1, 2) -- elements 3, 4, and 5 silently dropped
json k = {1};
auto q = k.get<std::pair<int, int>>(); // ❌ throws out_of_range.401
```
If a size mismatch is an error in your application, check the size yourself before converting.
## Omitting a field when serializing `std::optional`
By default, `to_json` for `std::optional<T>` writes either the value or `#!json null` -- there is no built-in way
to make a field disappear from the serialized object entirely when the `std::optional` is `std::nullopt`. Because
a specialization of `adl_serializer<std::optional<T>>` only controls how the *value* is converted (it cannot
prevent the containing object's `to_json` from inserting the key in the first place), omission has to be
implemented in the *containing* type's `to_json`:
```cpp
struct person {
std::string name;
std::optional<int> age;
};
void to_json(json& j, const person& p) {
j = json{{"name", p.name}};
if (p.age) {
j["age"] = *p.age; // key is only inserted when the optional has a value
}
}
```
## Putting values in
The reverse direction works the same way: assigning or constructing a `json` from a C++ value converts it to JSON.
```cpp
std::vector<int> numbers = {1, 2, 3};
json j = numbers; // [1,2,3]
```
!!! info "Constructing from a C++20 range view"
A `json` array can also be constructed directly from a C++20 range view (`std::ranges::view`), such as the result
of `std::views::filter` or `std::views::transform` -- no intermediate container is needed:
```cpp
std::vector<int> nums{1, 2, 37, 42, 21};
auto filtered = nums | std::views::filter([](int i) { return i > 10; });
json j(filtered); // [37,42,21]
```
This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due
to incomplete C++20 ranges support there.
## Your own types
The conversions above are built in for standard types. To make the same syntax work for **your own** types, provide
`to_json`/`from_json` functions (or use one of the convenience macros). This is described in detail on the
[arbitrary types conversions](arbitrary_types.md) page. Enums can be mapped to strings as described in
[specializing enum conversion](enum_conversion.md).
## See also
- [`get`](../api/basic_json/get.md) - get a copy converted to a given type
- [`get_to`](../api/basic_json/get_to.md) - convert into an existing variable
- [`get_ref`](../api/basic_json/get_ref.md) / [`get_ptr`](../api/basic_json/get_ptr.md) - access the stored value without copying
- [Arbitrary types conversions](arbitrary_types.md) - support your own types
- [`JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md) - toggle implicit conversions
@@ -0,0 +1,103 @@
# Creating JSON values
There are several ways to create a JSON value in memory. This page gives an overview; to read a value from JSON text
instead, see [parsing](parsing/index.md).
## From C++ values
Any value of a supported C++ type can be assigned to or used to construct a `json`:
```cpp
json j_number = 42;
json j_float = 3.141;
json j_string = "Hello";
json j_boolean = true;
json j_null = nullptr;
json j_vector = std::vector<int>{1, 2, 3}; // array
```
See [converting values](conversions.md) for the full set of supported types.
## With initializer lists
Objects and arrays can be written concisely with brace-enclosed initializer lists:
```cpp
// an array
json array = {1, 2, 3, 4};
// an object (a list of key/value pairs)
json object = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"list", {1, 0, 2}},
{"object", {{"currency", "USD"}, {"value", 42.99}}}
};
```
The library decides between an array and an object based on the content: a list whose elements are all two-element lists
with a string as the first element is treated as an object, everything else as an array.
!!! warning "Ambiguous cases: `#!cpp {}` vs. `#!cpp []`"
Because the same `#!cpp {}` syntax is used for both arrays and objects, some cases are ambiguous. To force a
particular type, use the explicit factory functions [`json::array`](../api/basic_json/array.md) and
[`json::object`](../api/basic_json/object.md):
```cpp
json empty_array_explicit = json::array(); // []
json empty_object_explicit = json::object(); // {}
// a JSON array with one object, not an object with one member
json array_of_objects = json::array({{"key", "value"}}); // [{"key":"value"}]
```
Related to this, single-element brace initialization such as `#!cpp json j{value};` wraps the element in a
single-element **array** by default, and its behavior even differs between compilers. See the
[FAQ](../home/faq.md#brace-initialization-yields-arrays) for details and the opt-in
[`JSON_BRACE_INIT_COPY_SEMANTICS`](../api/macros/json_brace_init_copy_semantics.md) macro.
## Building incrementally
A value can also be built up piece by piece. Accessing a non-existing object key or array index with
[`operator[]`](element_access/unchecked_access.md) creates the element on the fly:
```cpp
json j; // null
j["answer"]["everything"] = 42; // becomes an object
j["list"] = {1, 0, 2};
j["list"].push_back(3); // [1,0,2,3]
```
See [modifying values](modifying_values.md) for [`push_back`](../api/basic_json/push_back.md),
[`emplace`](../api/basic_json/emplace.md), and related functions.
## With the `_json` literal
The `_json` [user-defined literal](../api/operator_literal_json.md) parses a string at the call site and is a
convenient way to write a JSON value inline:
??? example
```cpp
--8<-- "examples/operator_literal_json.cpp"
```
Output:
```json
--8<-- "examples/operator_literal_json.output"
```
Note this **parses** the string, so `#!cpp "42"_json` is the number `#!cpp 42`, whereas `#!cpp json("42")` is the JSON
string `#!json "42"`.
## See also
- [`basic_json` constructors](../api/basic_json/basic_json.md) - all ways to construct a value
- [`array`](../api/basic_json/array.md) / [`object`](../api/basic_json/object.md) - force array or object type
- [`operator""_json`](../api/operator_literal_json.md) - the `_json` literal
- [Converting values](conversions.md) - which C++ types can be used
- [Parsing](parsing/index.md) - create a value from JSON text
@@ -29,7 +29,7 @@ otherwise.
| `#!cpp j.at("hobbies").at(0)` | `#!json "hiking"` |
| `#!cpp j.at("hobbies").at(1)` | `#!json "reading"` |
The return value is a reference, so it can be modified by the original value.
The return value is a reference, so it can be used to modify the original value.
??? example "Write access"
@@ -62,7 +62,7 @@ non-existing, an exception is thrown.
[json.exception.out_of_range.401] array index 3 is out of range
```
When you [extended diagnostic messages](../../home/exceptions.md#extended-diagnostic-messages) are enabled by
When [extended diagnostic messages](../../home/exceptions.md#extended-diagnostic-messages) are enabled by
defining [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md), the exception further gives information where
the key or index is missing or out of range.
@@ -4,7 +4,8 @@
In many situations, such as configuration files, missing values are not exceptional, but may be treated as if a default
value was present. For this case, use [`value(key, default_value)`](../../api/basic_json/value.md) which takes the key
you want to access and a default value in case there is no value stored with that key.
you want to access and a default value in case there is no value stored with that key. This is equivalent to Python's
`dict.get(key, default)`.
## Example
@@ -41,7 +42,7 @@ you want to access and a default value in case there is no value stored with tha
The value function is a template, and the return type of the function is determined by the type of the provided
default value unless otherwise specified. This can have unexpected effects. In the example below, we store a 64-bit
unsigned integer. We get exactly that value when using [`operator[]`](../../api/basic_json/operator[].md). However,
when we call `value` and provide `#!c 0` as default value, then `#!c -1` is returned. The occurs, because `#!c 0`
when we call `value` and provide `#!c 0` as default value, then `#!c -1` is returned. This occurs, because `#!c 0`
has type `#!c int` which overflows when handling the value `#!c 18446744073709551615`.
To address this issue, either provide a correctly typed default value or use the template parameter to specify the
@@ -102,6 +102,20 @@ that the passed index is the new maximal index. Intermediate values are filled w
`operator[]` can only be used with objects (with a string argument) or with arrays (with a numeric argument). For
other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error305) is thrown.
## Performance: reserving array capacity
There is no public `reserve(count)` member on `basic_json` for pre-allocating array capacity. If you are building
a large array incrementally (e.g., via repeated `push_back()`) and know its final size ahead of time, you can
reserve capacity via `get_ref()` to access the underlying `array_t` directly:
```cpp
json j = json::array();
j.get_ref<json::array_t&>().reserve(1000);
for (int i = 0; i < 1000; ++i) {
j.push_back(i);
}
```
## Summary
| scenario | non-const value | const value |
+53
View File
@@ -0,0 +1,53 @@
# Features
This section describes the features of the library in detail. If you are new to the library, the pages below are
roughly ordered along a typical workflow: create or parse a value, access and modify it, convert it to and from your own
C++ types, and finally serialize it again.
## Creating and reading values
- [Creating JSON values](creating_values.md) — build values from literals, initializer lists, and STL containers, and
understand the `#!cpp {}` vs. `#!cpp []` ambiguity.
- [Parsing](parsing/index.md) — read a JSON value from a string, file, or stream, including
[JSON Lines](parsing/json_lines.md), [callbacks](parsing/parser_callbacks.md), the
[SAX interface](parsing/sax_interface.md), and [error handling](parsing/parse_exceptions.md).
- [Comments](comments.md) and [trailing commas](trailing_commas.md) — opt-in relaxations of the JSON grammar.
## Accessing and modifying values
- [Element access](element_access/index.md) — unchecked ([`operator[]`](element_access/unchecked_access.md)),
checked ([`at`](element_access/checked_access.md)), and access with a
[default value](element_access/default_value.md).
- [JSON Pointer](json_pointer.md) — address values deep inside a document with [RFC 6901](https://tools.ietf.org/html/rfc6901) pointers.
- [Iterators](iterators.md) — traverse arrays and objects.
- [Modifying values](modifying_values.md) — add, update, merge, and remove elements.
- [JSON Patch and Diff](json_patch.md) and [JSON Merge Patch](merge_patch.md) — apply and compute structured changes.
## Converting to and from C++ types
- [Converting values](conversions.md) — get values out with [`get`](../api/basic_json/get.md)/[`get_to`](../api/basic_json/get_to.md),
and understand implicit conversions.
- [Arbitrary types conversions](arbitrary_types.md) — teach the library about your own structs and classes.
- [Specializing enum conversion](enum_conversion.md) — map enums to strings instead of integers.
## Serializing values
- [Serialization](serialization.md) — turn a value back into JSON text with [`dump`](../api/basic_json/dump.md),
including pretty-printing and handling of non-ASCII and invalid UTF-8.
- [Binary formats](binary_formats/index.md) — encode values more compactly as
[BJData](binary_formats/bjdata.md), [BSON](binary_formats/bson.md), [CBOR](binary_formats/cbor.md),
[MessagePack](binary_formats/messagepack.md), or [UBJSON](binary_formats/ubjson.md).
- [Binary values](binary_values.md) — store and exchange raw byte sequences.
## How values are stored and configured
- [Types](types/index.md) and [number handling](types/number_handling.md) — how JSON types map to C++ types and how
numbers are treated.
- [Object order](object_order.md) — keep insertion order with [`ordered_json`](../api/ordered_json.md).
- [Runtime assertions](assertions.md), [supported macros](macros.md), the [`nlohmann` namespace](namespace.md), and
[C++ modules](modules.md) — build-time and runtime configuration.
!!! tip "Looking for a specific function?"
This section gives conceptual overviews. For the precise signature, parameters, and return value of a function, see
the [API Documentation](../api/basic_json/index.md).
+1 -1
View File
@@ -130,7 +130,7 @@ for (auto& [key, val] : j_object.items())
### Iterating strings and binary values
Note that "value" means a JSON value in this setting, not values stored in the underlying containers. That is, `*begin()` returns the complete string or binary array and is also safe the underlying string or binary array is empty.
Note that "value" means a JSON value in this setting, not values stored in the underlying containers. That is, `*begin()` returns the complete string or binary array and is also safe if the underlying string or binary array is empty.
??? example

Some files were not shown because too many files have changed in this diff Show More