Compare commits

..
Author SHA1 Message Date
Niels Lohmann a32f61eb98 Fix update() and merge_patch() when the argument is *this or one of its members (#5678) 2026-09-30 23:04:57 +02:00
Niels Lohmann 1d675cdb46 Fix CI jobs that check less than they claim; move arm64 to GitHub (#5733)
* Fix the ci_cmake_flags wiring so every option is checked

The CMake 3.31.6 flag list referred to itself before it was defined,
so only JSON_BuildTests was checked with that version. The targets for
the CMake running the build ("_2") were created but never added to
ci_cmake_flags, and the three versions shared one build directory.
JSON_StrictNulHandling was not in the list at all.

Use the 3.5.0 list for 3.31.6, add JSON_StrictNulHandling, and create
one ci_cmake_flag_<flag> target per option for the running CMake with
its own build directory. Also use the function parameter in the
COMMENT, refresh the stale version comment, and let ci_clean remove
the downloaded cmake-<version> directories instead of the long-gone
cmake-3.5.0-Darwin64.

Part of #5715

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

* Fix ci_test_clang_libcxx_cxx* jobs silently building without warnings

CMake only seeds CMAKE_CXX_FLAGS from the CXXFLAGS environment variable
when the cache entry is unset, so the explicit -DCMAKE_CXX_FLAGS="-stdlib=libc++"
argument made it ignore CXXFLAGS="${CLANG_CXXFLAGS}" entirely. The six
ci_test_standards_clang (..., libcxx) jobs therefore compiled without
-Weverything/-Werror while their libstdc++ siblings did use them.

Pass -stdlib=libc++ through the same CXXFLAGS value instead of a separate
-D argument, and give the target its own build directory
(build_clang_libcxx_cxx${CXX_STANDARD}) so it no longer shares a CMake
cache with the libstdc++ variant. Suppress the resulting
-Wthread-safety-negative finding from libc++'s std::mutex annotations,
which fires on doctest's reporters in this translation unit only.

Part of #5715

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

* Remove the no-op AppVeyor with_win_header job

The with_win_header matrix entry patched Windows.h into
single_include/nlohmann/json.hpp before building, but JSON_MultipleHeaders
has defaulted to ON since #3532 (2022-06), so CMakeLists.txt points the
tests at include/ and the patched single header is never compiled. The
job has been a no-op VS2015 build since then.

Windows.h coverage already exists through tests/src/unit-windows_h.cpp
(#3631), which runs in every MSVC job. Delete the dead matrix entry and
its before_build steps, and cite unit-windows_h.cpp from the QA page.

Part of #5715

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

* Remove unused ci_oclint and ci_pvs_studio targets

No workflow invokes ci_oclint, ci_pvs_studio, or their tool discovery.
ci_oclint also had a side effect on every JSON_CI configure: it copied
the single header into src_single/all.cpp and added an add_executable()
for it without EXCLUDE_FROM_ALL, so a plain build compiled a 1.2 MB
translation unit that only that unused target consumed. ci_pvs_studio
duplicates the Makefile's pvs_studio target, which is kept.

Also drop the duplicate --check-level=exhaustive flag passed twice to
the same ci_cppcheck invocation.

Part of #5715

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

* Stop Dependabot from proposing astyle bumps

astyle is deliberately pinned at 3.4.13 because newer versions reformat
unrelated lines and this version defines the formatting that
check_amalgamation.yml enforces. Without an ignore rule, Dependabot
keeps opening PRs for every new astyle release (most recently #4580,
#4942, #5445, #5448), each of which fails the amalgamation check and
gets closed unmerged.

Part of #5715

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

* Move Linux arm64 CI from dead Cirrus CI to ubuntu-24.04-arm

Cirrus CI stopped reporting check runs on develop sometime after
d10879bca (2026-05-26); every commit since has only github-actions
check runs, so .cirrus.yml silently lost its only consumer while
README.md, FILES.md and the QA page kept advertising the coverage.

Add a ci_test_arm64 job to ubuntu.yml using the same pinned
actions/checkout and lukka/get-cmake actions as the other jobs, on the
native ubuntu-24.04-arm runner, with a step that confirms uname -m
reports aarch64. Delete .cirrus.yml and its README badge and FILES.md
section, and update the QA page's arm64 row.

Part of #5715

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

* Make scan-build fail on findings and drop irrelevant checkers (#5715 item 4a)

ci_clang_analyze ran scan-build without --status-bugs, so the job
passed whenever the ninja build succeeded, no matter what the
analyzer found ("No bugs found" in a green run gave no signal either
way). It is also missing --use-analyzer=${CLANG_TOOL}, so scan-build
picks whichever clang happens to be first on PATH inside the
silkeh/clang:dev container instead of the one this file already
selected and versioned.

Add --status-bugs and --use-analyzer=${CLANG_TOOL} to the scan-build
invocation. While here, drop the osx.*, webkit.*, fuchsia.*, and
optin.mpi.* checkers from CLANG_ANALYZER_CHECKS: none of them apply
to this portable C++ library, and leaving them enabled only adds
noise once the job can actually fail on a finding.

The job is currently clean (0 bugs), so this alone does not surface
any new finding; it only makes the existing "no bugs found" result
authoritative. This is 4a of 3 independent steps in #5715 item 4;
4b (Infer) and 4c (IWYU) still need their existing findings triaged
before --fail-on-issue/-Xiwyu --error can be added, and are handled
in separate commits.

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

* Deduplicate the amalgamation/format check's file set and add BUILD.bazel (#5715 item 5)

The amalgamation/format check existed three times with three different
file sets: the Makefile's pretty/check-amalgamation, the pull_request-only
check_amalgamation.yml workflow, and the ci_test_amalgamation CMake target
that also runs on direct pushes to develop/master/release/*. The CMake
target's glob was a strict subset of the workflow's (missing the
docs/mkdocs/docs/examples/*.hpp headers, tests/abi/, tests/cmake_*/project/,
tests/cuda_example/, tests/fmt_formatter/, and tests/module_cpp20/), and it
never checked BUILD.bazel at all, so a misformatted file in any of those
paths, or a stale BUILD.bazel, could reach develop through a direct push
even though the PR-only workflow would have caught it.

Make ci_test_amalgamation glob the same roots (docs/mkdocs/docs/examples,
include, tests) and extensions (*.hpp, *.cpp, *.cu) as check_amalgamation.yml,
excluding tests/thirdparty/ and tests/abi/include/nlohmann/ the same way, and
regenerate and diff BUILD.bazel next to json.hpp/json_fwd.hpp. Also add
docs/mkdocs/docs/examples/*.hpp to the Makefile's pretty/pretty_format
targets, which were missing the four custom_*_type.hpp example headers, and
drop the stale "called by Travis" comment on check-amalgamation (Travis is
gone; nothing currently calls that Makefile target from CI).

Leaves the workflow itself untouched: it deliberately runs amalgamate.py
from a fresh develop checkout so a PR cannot change the tool that checks it.

Overlaps #5610 and #5621, which each add a new amalgamated header and touch
the same INDENT_FILES/ci_test_amalgamation/check_amalgamation.yml hunks.

Verified with `make check-amalgamation` on this branch: clean, no diff.
#5715 item 5.

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

* Download prebuilt CMake binaries on Linux x86_64 instead of building from source (#5715 item 6)

ci_get_cmake() downloaded the source tarball of CMake 3.5.0, 3.31.6, and
4.0.0 and compiled each one completely (including CMake's own test
helpers) with -DCMAKE_POLICY_VERSION_MINIMUM=3.5 as a workaround for
building old CMake with a newer one. On CI this made the
ci_cmake_options (ci_cmake_flags) job take about 11 minutes, most of it
spent building CMake itself, even though Kitware has published
ready-to-run Linux x86_64 archives for all three of these releases
since 3.20 (lowercase platform name).

On Linux x86_64, download and unpack the prebuilt
cmake-<version>-linux-x86_64.tar.gz archive instead and point the
existing ${var} output at its bin/cmake, skipping the configure/build
steps and CMAKE_POLICY_VERSION_MINIMUM entirely. Keep the previous
source build as a fallback for any other platform (macOS, Linux
aarch64), since Kitware does not publish binaries for every
CMake/platform combination this project might build on.

Verify the downloaded archive against Kitware's own published checksum
before unpacking it: download cmake-<version>-SHA-256.txt alongside the
archive and run `sha256sum -c` on the matching line. A CI job that wgets
and untars a binary from a release page with no integrity check is a
supply-chain gap; Kitware has published this file for every release
since 3.20, so checking it costs one extra download and one grep.

As a separate, mechanical change: the ci_cmake_options job's container
only needed to stay on ubuntu:focal for the source build's
libssl-dev dependency and its own aging toolchain; now that the
Linux/x86_64 path never compiles CMake, drop libssl-dev from its apt
install line and move the job to ubuntu:24.04 (Ubuntu 20.04 left
standard support in May 2025). ci_clean already removes the
cmake-3.5.0/cmake-3.31.6/cmake-4.0.0 directories from the #5715 item 3
fix, and the prebuilt path reuses those same directory names, so no
further cleanup changes are needed.

Overlaps #5598, which edits the same ci_cmake_options matrix line in
ubuntu.yml; a rebase may be needed once that lands.

Verified locally: `cmake -S . -B build -DJSON_CI=On` configures cleanly
on macOS/arm64 (source-build fallback branch) and on Linux/x86_64 in an
ubuntu:24.04 Docker container (47 `ci_cmake_flag_*` targets generated,
one built and run successfully); `.github/workflows/ubuntu.yml` still
parses as valid YAML; downloaded the real v3.31.6 Linux x86_64 archive
and SHA-256 file from Kitware and confirmed the `grep | sha256sum -c`
pipeline both accepts the genuine file and is anchored to the exact
filename (not a prefix match).

CI must confirm: the prebuilt-binary path actually runs on the
ubuntu-latest/ubuntu:24.04 x86_64 runner, all `ci_cmake_options`
entries still pass with the new container's GCC, and the job's
runtime drops from roughly 11 minutes.

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

* Make Infer fail on findings, with a type-level baseline for the ~174 pre-existing ones (#5715 item 4b)

ci_infer ran `infer run` without --fail-on-issue, so the job passed
regardless of what Pulse found; the last recorded run (35829411620,
commit 1054b2097) logged "Found 174 issues" and still went green.
report.txt was also never uploaded, so the full finding list was only
ever visible in the truncated 5-issue console excerpt.

Add a repository-root .inferconfig (auto-discovered by Infer; passing
--project-root on the `infer run` invocation makes sure it is found
even though the analysis runs from build/build_infer) that sets
fail-on-issue and disables the six PULSE issue types that made up all
174 findings in that run: PULSE_UNNECESSARY_COPY_ASSIGNMENT (129),
PULSE_UNNECESSARY_COPY (22), PULSE_UNNECESSARY_COPY_INTERMEDIATE (15),
PULSE_RESOURCE_LEAK (5), PULSE_CONST_REFABLE (2), and
PULSE_UNNECESSARY_COPY_OPTIONAL (1).

This is a deliberate, narrower fix than "triage and fix everything in
this PR": the visible sample is entirely doctest-macro copies in test
code (for example tests/src/unit-algorithms.cpp:141 and
tests/src/unit-bjdata.cpp:3706), but 169 of the 174 findings were never
uploaded anywhere and this PR cannot respectably claim to have fixed
issues it never saw, including the resource-leak and const-refable
ones that are the most likely to be genuine bugs. Disabling by issue
type is a coarser baseline than a per-finding one (Infer has no
built-in per-finding baseline short of the two-run `infer reportdiff`
workflow, which this repository does not have the CI infrastructure
for), but it has the same effect today: the job goes from always green
to green-only-when-clean-of-everything-else, so CI now fails the
moment a *new* issue type appears, and report.txt is uploaded as a
workflow artifact on every run (including failures) so the six
disabled types can be triaged and re-enabled incrementally in follow-up
PRs.

#5715 item 4b. 4a (scan-build) and 4c (IWYU) are handled in separate
commits.

Verified: .inferconfig parses as JSON, ubuntu.yml still parses as
YAML. Infer itself is not available in this environment (v1.3.0 tar.xz
requires a Linux x86_64 runner), so CI must confirm that `infer run
--project-root ... -- make` picks up .inferconfig, that fail-on-issue
takes effect, and that the six disabled types actually suppress the
existing findings without also hiding an unrelated new one.

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

* Fix IWYU findings for json.hpp/json_fwd.hpp/ordered_map.hpp and make CI fail on new ones (#5715 item 4c)

ci_single_binaries ran IWYU via CMake's CXX_INCLUDE_WHAT_YOU_USE launcher
property, which only printed "Warning: include-what-you-use reported
diagnostics" without failing the build: CMake's own __run_co_compile
wrapper does not propagate the launched tool's exit code, so even
`-Xiwyu --error` could never fail `cmake --build` this way. Verified
this empirically by injecting a deliberately-unused #include and
confirming the build still exited 0.

Fix the findings from the last recorded run (issue #5715 item 4, log
35829411620):
- ordered_map.hpp: add <new> (placement new) and
  nlohmann/detail/abi_macros.hpp; drop <memory> (std::allocator is
  still visible transitively via <vector>, confirmed by full local and
  containerized test suite runs).
- json_fwd.hpp: drop <memory> (same reasoning). Keep every forward
  declaration IWYU wanted removed (adl_serializer, basic_json,
  json_pointer, ordered_map): this file's only job is to forward-declare
  them for downstream users, so "nothing in this TU uses them" is
  expected, not a real finding. Mark each with `// IWYU pragma: keep`.
- json.hpp: add <cmath>, <cstdint>, <set>, <type_traits>,
  <unordered_map>, and the detail/abi_macros.hpp, detail/input/json_sax.hpp,
  detail/meta/detected.hpp, thirdparty/hedley/hedley.hpp includes IWYU
  says it needs. Do NOT remove adl_serializer.hpp,
  detail/conversions/from_json.hpp, detail/conversions/to_json.hpp,
  detail/macro_unscope.hpp, or ordered_map.hpp as IWYU suggests: nothing
  else in include/nlohmann includes adl_serializer.hpp or
  ordered_map.hpp, so basic_json<>'s own default template arguments
  (JSONSerializer = adl_serializer, and ordered_json = basic_json<ordered_map>)
  would lose their complete type; detail/macro_unscope.hpp is what
  undoes the JSON_* macros detail/macro_scope.hpp defines earlier in
  this same file, and removing it leaks those macros into every
  translation unit that includes <nlohmann/json.hpp>. Verified by
  actually removing them in a scratch test: the header still "compiles"
  stand-alone but ordered_json and every macro-using translation unit
  break. Marked each `// IWYU pragma: keep`.

Enforce it with `iwyu_tool` (ships with IWYU, e.g. as /usr/bin/iwyu_tool
on Debian/Ubuntu) instead of relying on the launcher property: it reads
compile_commands.json (now exported project-wide under JSON_CI) and
does return a real exit code for its own analysis, independent of
CMake's wrapper. ci_single_binaries now runs it over every
src_single/*.cpp with `-Xiwyu --error`, so a *new* finding fails CI.

json.hpp itself is excluded from that hard gate: even after every fix
above, IWYU's suggestion for one remaining symbol (a container
`swap, operator!=` used somewhere via a templated comparator) is not
deterministic — repeated, otherwise-identical containerized runs
reported <set>, then <unordered_map>, then <map> as "the" header to
add/remove for the exact same source. Gating a whole CI job on a
nondeterministic suggestion would make ci_single_binaries flaky rather
than informative, so json.hpp keeps the existing informational warning
(still shown during its normal compile) without failing the build on
it. Every other one of the ~50 single-header checks is included in the
hard gate.

#5715 item 4c. 4a (scan-build) and 4b (Infer) are separate commits.

Verified: full local ctest suite (129/129) and the ci_single_binaries
target itself both green in a containerized silkeh/clang:dev run
(matching the actual CI job) after this fix; a deliberately-reintroduced
unused #include in ordered_map.hpp was confirmed to fail
`cmake --build ... --target ci_single_binaries` (exit 2) with this
change, and to pass without it, on the same container/IWYU version CI
uses. `make check-amalgamation` is clean. Compiled with Clang and GCC
at -std=c++11/14/17/20 locally with no new warnings.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 22:49:24 +02:00
Niels Lohmann c261578431 Deduplicate binary reader/writer helpers and fix stale comments (#5730)
* Fix stale and missing comments in binary_writer

The doc block of write_number() ended up above the byte_swap() helpers
added in #5286, about 80 lines from the function. It was also a plain
comment that Doxygen skips, said "write a number to output input", and
left BON8 out of the big-endian formats. Move it back onto
write_number() as a /*! block and fix the text.

write_bson() documented "@pre j.type() == value_t::object", but it
throws type_error.317 for every other type, and to_bson() relies on
that. Document the exception instead.

Explain why the CBOR binary subtype is always written with a 0xD8..0xDB
head and never in the one-byte tag form: binary_reader with
cbor_tag_handler_t::store only keeps those heads as a subtype, so
switching to write_cbor_head() would break round trips for subtypes
0..23.

Also fix the grammar of the to_char_type comment. Comments only; no
change in behavior, API or ABI.

Part of #5710

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

* Merge the duplicated UBJSON/BJData integer marker ladders

write_number_with_ubjson_prefix() (unsigned and signed overloads) and
ubjson_prefix() (number_integer and number_unsigned cases) each picked
the UBJSON/BJData integer marker (i, U, I, u, l, m, L, M, H) with their
own independent if/else ladder, and the values beyond 64 bits were
handled by a second, tag-dispatched pair of ladders. An optimized
container announces the marker of its first element via ubjson_prefix()
and then writes every element through write_number_with_ubjson_prefix(),
so the two had to be kept in lockstep by hand across four call sites.

Replace all of that with one ubjson_integer_prefix() built on
value_in_range_of<T>, and one write_ubjson_integer_payload() that
writes the value (or, for 'H', the decimal digits) for a given marker.
write_number_with_ubjson_prefix() and ubjson_prefix() keep their
signatures and now just call these two helpers.

Behavior, the public API and the ABI are unchanged. Verified with a
new regression test covering scalars and $-optimized arrays/objects at
every int8/uint8/int16/uint16/int32/uint32/int64/uint64 boundary for
to_ubjson/to_bjdata (both use_size/use_type settings), and by diffing
to_ubjson/to_bjdata output before and after over the json_test_data
corpus (bit-identical).

Part of #5710

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

* Remove dead get_char parameters in binary_reader

The non-recursive rewrite of the binary readers (#5505, #5506, #5507)
left parse_cbor_internal()'s and parse_ubjson_internal()'s get_char
parameters dead: parse_cbor_internal() has one caller and it always
passes true, and parse_ubjson_internal() has one caller and it always
uses the true default. Both parameters, and the @param docs describing
the "reuse the last character" mode they used to select, no longer
correspond to anything.

Drop both parameters, initialise fetch/prefix unconditionally, and
update the two call sites in sax_parse(). parse_cbor_value()'s and
get_ubjson_string()'s own get_char parameters are unrelated and are
left alone; both still have a false caller.

Also delete a stray `@return whether a valid MessagePack value was
passed to the SAX parser` doxygen block that sits directly above
parse_msgpack_value()'s real doc comment, a leftover of the same
rewrite.

Behavior, the public API and the ABI are unchanged; these are private
members of detail::binary_reader. Verified by compiling with
-Wunused-parameter and running unit-cbor, unit-ubjson, unit-bjdata and
unit-msgpack (offline, against the stubbed test_data.hpp).

Part of #5711

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

* Share the IEEE half-precision decoder between CBOR and BJData

binary_reader had two ~45-line copies of the IEEE 754 half-precision
decoder: CBOR's case 0xF9 and BJData's case 'h'. Once formatting is
normalised, the two blocks were identical except for the byte order
used to assemble the 16-bit half (CBOR is big endian, BJData is little
endian). Any future change to half-float decoding had to be made and
kept in sync in both places.

Add one get_half_float(format, little_endian) helper that does the two
get()/unexpect_eof() reads, assembles the half in the requested byte
order, decodes it per RFC 8949 Appendix D, and calls sax->number_float.
Both cases now just call it with their byte order; the BJData case
keeps its bjdata-only guard.

Behavior, the public API and the ABI are unchanged. Verified with a
scratch probe comparing the old and new decoders bit-for-bit (NaN by
isnan()) over all 65536 wire byte pairs, in both formats, and by
running unit-cbor and unit-bjdata (offline, against the stubbed
test_data.hpp).

Part of #5711

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

* Deduplicate the MessagePack unsigned-integer writer ladder

The number_integer (non-negative branch) and number_unsigned cases in
write_msgpack() each held their own copy of the fixint/uint8/16/32/64
ladder, kept in lockstep only by a comment ("we used the code from the
value_t::number_unsigned case here"). Both copies mixed union members:
the signed copy compared number_unsigned but wrote number_integer, and
vice versa.

Extract write_msgpack_unsigned(std::uint64_t), mirroring how
write_cbor_head() already avoids the same duplication for CBOR, and
call it from both cases. Each case now reads only its own active
union member. Output bytes are unchanged for the default 64-bit
number types.

#5710 item 3

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

* Unify float marker selection and fix the long double compile error

Four formats picked between a float32 and float64 marker through four
different helper styles: dummy-argument overloads for CBOR and
MessagePack, an std::is_same template for BON8, and a runtime if-chain
on input_format_t for write_compact_float(). With number_float_t set
to long double, to_cbor, to_msgpack and to_ubjson failed inside the
library with "call to 'get_cbor_float_prefix' is ambiguous", while
to_bson kept working because write_bson_double() takes a plain double.

Change write_compact_float() to take the two marker bytes directly
(each of its three callers already knows them at compile time) instead
of an input_format_t it only forwarded, and delete the now-unused
get_cbor_float_prefix(), get_msgpack_float_prefix(),
get_bon8_float_prefix() and get_compact_float_prefix() helpers. Turn
the two get_ubjson_float_prefix() overloads into one template. Both
write_compact_float() and get_ubjson_float_prefix() now report an
unsupported number_float_t with a static_assert naming the requirement,
rather than an ambiguous-overload error; the assert lives in the
function body, not the class scope, so to_bson with long double is
unaffected.

Verified with a probe basic_json<..., long double>: to_bson still
compiles and round-trips, while to_cbor/to_msgpack/to_ubjson now fail
to compile with the new static_assert message.

This changes the text of an existing compile error for users with an
unsupported number_float_t (documented as a public-API-visible change
in #5710).

#5710 item 1

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

* Deduplicate the BJData ndarray writer's dtype dispatch and drop <map>

write_bjdata_ndarray() built a 12-entry std::map<string_t, CharType> on
every call just to translate the _ArrayType_ name to a dtype marker
(the only reason binary_writer.hpp included <map>), then mapped dtype
to C++ type twice more: once as a switch for the range-check pass and
once as a separate if/else chain for the write pass, with nothing
checking that the two agreed. The caller also ran three at() lookups,
and the callee called value.at(key) about ten more times for the same
three members.

Replace the map with bjdata_ndarray_type_marker(), a plain string
comparison chain (a C++11 constexpr function cannot contain a switch,
so this mirrors binary_reader's own static table style). Replace the
switch/if-chain pair with one write_bjdata_ndarray_elements() that
switches on dtype once and calls a per-type helper -
write_bjdata_ndarray_element<T>() for the eight integer dtypes and
write_bjdata_ndarray_float_element() for 'd' - with a dry_run flag
selecting the range check or the actual write, so the two passes can
no longer disagree on the type. _ArrayType_, _ArraySize_ and
_ArrayData_ are now looked up once into references, and the four
header marker bytes ('[', '$', '#') are written through to_char_type()
like the rest of the UBJSON/BJData writer.

The 'd' (single-precision) rule is left exactly as before, since #5707
is expected to change it separately.

Verified byte-for-byte identical output before/after for every dtype
(including the Draft 2/Draft 3 'byte' fallback and the use_count/
use_type combinations) via a standalone probe, plus round-tripping
through from_bjdata().

Overlaps #5707, which is expected to touch the 'd' dtype case, and
#5518, which is expected to move the write_bjdata_ndarray() call site.

#5710 item 4

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

* Assert that write_bson_document() consumes every calc_bson_sizes() entry

calc_bson_sizes() and write_bson_document() are a hand-synchronized
pair of passes over the same object/array tree, introduced by #5553:
the size pass appends to nested_sizes in visiting order, and the write
pass consumes the table by position with nested_sizes[next_size++].
Nothing checked that the write pass consumed the whole table. If a
future change touched only one of the two passes - for example to skip
or reject an entry - every later size prefix in the document would be
silently wrong.

Add JSON_ASSERT(next_size == nested_sizes.size()) where
write_bson_document() returns, so such a future drift between the two
passes is caught immediately (JSON_ASSERT expands to nothing in
release builds using assert(), and the fuzzers/tests already build
with it enabled). The two passes agree today, so this changes nothing
observable; it only guards against the risk described in #5710 item 5.

Extracting a shared stepper for the two passes (the second half of the
proposed change) is left for a follow-up: it only saves ~30 lines and
the issue asks for it only if the result reads clearly, which needs
more room to get right than a mechanical cleanup pass allows.

#5710 item 5

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

* Make the BJData lookup tables static functions instead of members

binary_reader held bjd_optimized_type_markers and bjd_types_map as
non-static const members (12 string_t objects for the type-name table),
built and destroyed on every from_cbor/from_msgpack/from_bson/
from_ubjson/from_bon8/from_bjdata call even though only from_bjdata
ever reads them. They also needed the #define/decltype/#undef
workaround from #3637 and two NOLINTNEXTLINE suppressions, and
binary_writer already carries the same two lists in another form
(is_bjdata_excluded_type_marker() and a local std::map in
write_bjdata_ndarray(), the latter removed by the item-4 commit), so
the excluded-marker lists could drift apart.

Replace bjd_optimized_type_markers with static constexpr
is_bjd_excluded_optimized_type(char_int_type), using the same ||-chain
as binary_writer's is_bjdata_excluded_type_marker(). Replace
bjd_types_map with a non-constexpr static bjd_type_name(char_int_type)
switch returning nullptr for an unknown marker (a C++11 constexpr
function cannot contain a switch). Delete both
JSON_BINARY_READER_MAKE_* macros, the bjd_type pair alias, the
NOLINTNEXTLINE suppressions, detail::make_array() (no longer used
anywhere), and the now-unused <algorithm> and <array> includes.

Update the two call sites (the ND-array excluded-type check and the
_ArrayType_ lookup) accordingly, and replace unit-bjdata.cpp's
"LUT arrays are sorted" section, which only checked the two tables'
internal ordering, with a check of all 12 type names and all 8
excluded markers against both new functions.

#5711 item 1

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

* Read CBOR's 1/2/4/8-byte argument through one helper

parse_cbor_internal() hand-wrote the same "read a 1/2/4/8-byte
big-endian unsigned integer" ladder four times over:
- twice for tag numbers 0xD8-0xDB, once in the tag_handler::ignore
  branch and once, nearly identically, in the ::store branch (~90
  lines to read one integer);
- twice more for container lengths, once for array heads 0x98-0x9B and
  once for map heads 0xB8-0xBB, where the 1/2-byte forms called
  enter_array()/enter_object() directly and the 4/8-byte forms
  additionally went through get_cbor_container_size().

Add get_cbor_argument(std::uint64_t&), reading the width selected by
current & 0x1F via the same get_number() calls as before (so EOF is
reported exactly as before), and route all four sites through it:
- 0xD8-0xDB now read the argument once per branch instead of switching
  on `current` a second time; behavior split cleanly from embedded tags
  0xC0-0xD7 (tag value in the head, no argument to read), which is now
  its own case block that no longer has to fall into the ::store
  switch's "default" case to reach the same tag_pending = true; return
  true; outcome.
- 0x98-0x9B and 0xB8-0xBB collapse into one case block each, always
  going through get_cbor_container_size() (harmless for 1/2-byte
  lengths, which already always fit).

Verified byte-for-byte identical behavior before/after with a
standalone probe covering embedded and multi-byte tags under all three
tag_handler_t settings, a tag over a byte string (subtype path),
truncated tag/length arguments of every width, and array/map lengths
of every width, including the out_of_range.408 "excessive size" case:
same exceptions, same messages, same chars_read, same successful
results.

Left the string/byte-string length ladders in get_cbor_string()/
get_cbor_binary() untouched, as noted in #5711 item 2, since #5325 is
expected to touch them separately.

Overlaps #5601 (adds a branch right above the embedded-tag case) and
#5607 (touches the integer cases 0x18-0x1B, which share this ladder's
shape in separate hunks).

#5711 item 2

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

* Add leave_container() to match enter_container()

Every container is opened through enter_container(), whose docs
promise that a check placed there runs before every start event. The
close side had no equivalent: the same
"container_stack.pop_back(); dispatch to end_object() or end_array()"
sequence was written out separately in BSON, CBOR, MessagePack,
UBJSON/BJData and BON8, each copying the pattern of keeping an
is_object flag around the pop_back() that would otherwise invalidate
a reference to it. A check needed on close would have had to be added
in five places, and a sixth copy could go unnoticed.

Add leave_container() next to enter_container(), doing the same
pop-then-dispatch, and replace the five sites with it. Each site keeps
its own surrounding logic (BSON's check_bson_document_size() call
before popping, MessagePack's is_object copy used again below,
UBJSON/BJData's remaining-container handling after popping, BON8's
top used again below); only the repeated pop/dispatch line pair is
now shared.

Verified all six binary-format unit suites and unit-regression2's
deep-nesting tests (dependent count/reuse count and the bjdata ndarray
depth cases) still pass, compiled with -Wall -Wextra and ASan/UBSan.

Overlaps #5601, which is expected to add a sixth close site in its own
skip loop; that site can route through leave_container() too once it
lands.

#5711 item 4

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

* Stop passing the input format to sax_parse() when the reader already has it

binary_reader's constructor stores the format in the input_format
member, and sax_parse(format, sax_, strict, tag_handler) took the same
value again purely to dispatch on it. Every in-tree caller passed the
same value both times (all 16 from_cbor/from_msgpack/from_ubjson/
from_bjdata/from_bon8/from_bson call sites in json.hpp, and the three
public basic_json::sax_parse() overloads), so nothing was broken
today, but a caller of the detail class directly (only reachable via
JSON_PRIVATE_UNLESS_TESTED, as unit-bjdata.cpp already does) could
pass a mismatched pair - say bjdata to the constructor and ubjson to
sax_parse - and dispatch on one format while applying the other
format's rules; the default-constructed input_format_t::json reader
would additionally hit JSON_ASSERT(false) in exception_message() on
its first error.

Add sax_parse(json_sax_t*, bool, cbor_tag_handler_t) forwarding to the
existing overload with the stored input_format, and switch every
caller to it: the 16 from_*() sites (keeping their
`// cppcheck-suppress[accessMoved]` comments) and the three
basic_json::sax_parse() overloads, all of which already had the format
available from their own `format` parameter. The four-argument overload
is kept for anyone still calling it, now with
JSON_ASSERT(format == input_format) so a mismatch fails immediately
in a debug build (assert-enabled binaries, including the fuzzers and
test suite) instead of misbehaving; verified with a probe that
constructs a reader for one format and calls the explicit overload
with another, which aborts on that assertion as expected.

Removing or asserting against the constructor's input_format_t::json
default, which would affect direct detail users, is left as a separate
decision per #5711 item 5.

Overlaps #5601, which is expected to add an AllowRecovery template
parameter to sax_parse() and touch these same call sites in json.hpp.

#5711 item 5

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

* Deduplicate UBJSON/BJData signed-count handling, drop dead ndarray checks

get_ubjson_size_value()'s 'i'/'I'/'l'/'L' cases each read a differently
sized signed integer and then repeated the same "reject negative with
error 113" check; only 'L' additionally checked value_in_range_of for
the out_of_range.408 case. Any change to that error path had to be
made four times.

Add get_ubjson_signed_count<SignedType>(std::size_t&), doing the read,
the negative check and the range check once, and route all four
markers through it. The range check is a no-op for 'i'/'I'/'l' (their
values always fit std::size_t) and only live for 'L' on a 32-bit
std::size_t target, matching today's behavior exactly.

In the ndarray dimension-product loop, the preceding loop already
returns early on any zero dimension and result starts at 1, so `i > 0`
in the pre-multiplication overflow check was always true, and
`result == 0` in the post-multiplication check could not be reached
either: two positive factors whose product does not overflow (as the
pre-check already guarantees) cannot be zero. Drop the dead `i > 0 &&`
and narrow the post-check to `result == npos`, the one case the
pre-check cannot rule out (an exact, non-overflowing match with the
sentinel reserved for unknown-size containers), with a comment
explaining why.

Verified byte-for-byte identical behavior before/after with a
standalone probe covering negative counts for every marker, a matching
positive count, and ndarray inputs, plus the full unit-ubjson and
unit-bjdata suites (same assertion counts as before this change).

Overlaps #5601 (rewrites the four parse_error calls and the overflow
checks touched here) and #5607/#5707 (touch neighboring lines in the
same functions).

#5711 item 6

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

* Drop redundant format parameter and dummy float argument (review)

binary_reader::sax_parse(format, ...) only ever had to equal the format
given to the constructor, which it asserted. With every caller already
on the format-less overload, remove the four-argument overload and
dispatch on the stored input_format directly. binary_reader is a
detail class, so this is not a public API change.

get_ubjson_float_prefix() took a value only to deduce its type; make
the type an explicit template argument instead.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 22:48:32 +02:00
Niels Lohmann 35802e78d6 Remove dead Makefile targets; document macro_builder; tidy serve_header (#5735)
* Remove dead doctest help entry and pretty_format target from Makefile

The top-level Makefile still carried three leftovers:

- The help text listed a "doctest" target that was removed in #4560,
  so "make doctest" fails with "No rule to make target". The example
  check now runs as "make check_output -C docs".
- "pretty_format" ran clang-format on all sources, but .clang-format
  was deleted in #4573, so the target reformatted everything in the
  default LLVM style, against the Artistic Style formatting that
  "make pretty" applies and CI enforces.
- "clean" removed benchmarks/files/numbers/*.json, a directory that no
  longer exists since the benchmarks moved to tests/benchmarks (#3462).

Only maintainer tooling changes; the library is not affected.

Part of #5717

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

* Document tools/macro_builder and tidy up serve_header.py

tools/macro_builder generates the NLOHMANN_JSON_EXPAND,
NLOHMANN_JSON_GET_MACRO and NLOHMANN_JSON_PASTE* macros in
macro_scope.hpp, but nothing referred to it. Add a README that explains
what it generates, how to run it and where the output goes, and which
dependent tables (NLOHMANN_JSON_DOUBLE_PASTE, NLOHMANN_JSON_TYPE_BODY)
are maintained by hand. Point to it from a comment above
NLOHMANN_JSON_EXPAND. The generator itself is unchanged; following the
README reproduces the header byte for byte.

In serve_header.py, drop the LGTM suppression (LGTM.com shut down in
2022), replace the """.""" placeholder docstrings with real ones, and
import socket and ssl at module level. DualStackServer.server_bind uses
socket, which was only imported under __main__; when the module was
imported instead, the NameError was swallowed and IPV6_V6ONLY was not
cleared.

The header change is a comment only; behavior, API and ABI are
unchanged.

Part of #5717

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

* Hash every release_files artifact, not a hardcoded subset

The `release` target signed and copied json_fwd.hpp into release_files
alongside json.hpp, but the shasum line that writes hashes.txt only
listed json.hpp, include.zip and json.tar.xz. Users could not verify
the published json_fwd.hpp against hashes.txt.

Hash every file in release_files except the .asc signatures instead
of naming files by hand, so a newly shipped header (such as the
json_literals.hpp that #5610 adds to this target) cannot be missed
again.

Only affects the generated hashes.txt release artifact; the library
itself is unaffected.

Overlaps #5610, which touches the same lines to add json_literals.hpp
to the release target.

#5717 item 1

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

* Remove the broken fuzz_testing* Makefile targets

fuzz_testing and fuzz_testing_{bon8,bson,cbor,msgpack,ubjson} seeded
fuzz-testing/testcases from tests/data, which was removed in dbf1a1f41
(2020) when the test data moved to the external json_test_data repo.
The find command found nothing, but the pipeline's exit status was
that of xargs, so the recipe still reported success with an empty
corpus, and the printed afl-fuzz command would refuse to start.

The recipes were also six near-identical copies with unquoted -name
patterns, used the legacy CXX=afl-clang++, and fuzzing-start/stop were
missing from both the help output and .PHONY. tests/fuzzing.md already
documents the working flow (download json_test_data, then
`make -C tests fuzzers`), so replace the six broken targets and their
help lines with a single pointer to that document instead of trying
to keep six copies of a fragile shell pipeline in sync.

This does not affect OSS-Fuzz, which builds through tests/Makefile.

Overlaps #5621, which adds a seventh copy of the same broken line for
fuzz_testing_json_view.

#5717 item 2

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

* Remove stale Travis comment above check-amalgamation

check-amalgamation carried "Note: this target is called by Travis",
left over from before the project switched off Travis CI. The prior
Makefile cleanup commit removed the other stale Travis-era leftovers
(the doctest help entry, pretty_format, and the benchmarks/ path in
clean) but missed this comment.

#5717 item 4

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

* Fix stale install/usage instructions in the vendored amalgamate README

tools/amalgamate/README.md is the unmodified upstream text and no
longer matches how the tool is used here:

- It named a Bitbucket origin that no longer exists; CHANGES.md
  already tracks the GitHub mirror commit this copy is based on.
- It asked for Python 2.7, but CI and the Makefile run the script
  with python3.
- It told readers to run ./test.sh (not vendored) and install to
  /usr/local/bin; in this repository the tool runs through
  `make amalgamate`.
- Its usage synopsis showed `-v` taking no argument, but the script's
  own argparser requires `choices=["yes", "no"]`, so that form fails
  with "argument -v/--verbose: expected one argument". The Makefile
  calls it as `--verbose=yes`.
- It pointed at test/source.c.json and test/include.h.json, which are
  not vendored; the configs actually used are config_json.json and
  config_json_fwd.json.

Rewrote only the Installing and Using sections to match; left the
"Here be dragons" caveats and the rest of the vendored code untouched
to avoid diverging further from upstream.

Overlaps #5615, which edits amalgamate.py, this README and CHANGES.md.

#5717 item 6

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

* Derive generate_natvis.py's ABI tag list and version from abi_macros.hpp

generate_natvis.py hard-coded abi_tags = ['_diag', '_ldvcmp', '_dp',
'_bics', '_psp', '_snul'] and required --version on the command line.
The source of truth is include/nlohmann/detail/abi_macros.hpp: the
NLOHMANN_JSON_ABI_TAG_* defines, the argument order of
NLOHMANN_JSON_ABI_TAGS_CONCAT, and NLOHMANN_JSON_VERSION_MAJOR/MINOR/
PATCH. Nothing checked that the copies stayed in sync, and they have
drifted apart before: _dp was added in #4517 but missed here until
#5544, and 3.11.3 shipped json_abi_v3_11_2 namespaces (#4340).

Parse the tag list (in NLOHMANN_JSON_ABI_TAGS_CONCAT order) and the
version from abi_macros.hpp instead of hard-coding them. Make
--version optional (falling back to the parsed version) and default
the output directory to the repository root the script lives in.

Add a "natvis" Makefile target that runs the script, and extend
check-amalgamation to regenerate nlohmann_json.natvis and fail on a
diff, the same way it already does for the amalgamated headers and
BUILD.bazel. Wire the same regeneration into check_amalgamation.yml,
using the tool copy checked out from develop (as the workflow already
does for amalgamate.py) and installing jinja2 from
tools/generate_natvis/requirements.txt. Update the tool's README to
say it must be re-run after adding an ABI tag or bumping the version.

Verified: a run against develop produces no diff (with either the
default or an explicit --version 3.12.0); adding a dummy
NLOHMANN_JSON_ABI_TAG_* without a matching #define makes the script
fail loudly instead of silently omitting the tag; xmllint --noout
passes on the regenerated file; and running the script from a
directory other than the one being checked (simulating the workflow's
separate tool checkout) against this repository root also produces no
diff.

Overlaps #5600, which added _ekmo to the same hand-written abi_tags
line and regenerated the file.

#5717 item 3

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

* Strip the leading "./" find(1) prefix from release hashes.txt entries

bc6e7db72 (#5717 item 1) switched the release target's shasum line from
naming files by hand to $$(find . -type f -not -name '*.asc' | sort),
so a newly shipped header is hashed automatically. Run from inside
release_files, that find prints paths as "./json.hpp" instead of
"json.hpp", so hashes.txt lists "./json.hpp" etc. instead of the plain
filenames it always used. shasum -c still verifies "./json.hpp" fine,
but it is a needless cosmetic regression for anyone reading the file
or matching it against release notes.

Strip the "./" prefix with sed before sorting, keeping the filenames
exactly as before while still hashing every artifact automatically.

Review fix for #5717 item 1 (PR #5735).

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

* Fix check_amalgamation.yml: pass --version to generate_natvis.py

bff45f111 (#5717 item 3) made --version optional in
tools/generate_natvis/generate_natvis.py and wired the workflow's new
"Regenerate nlohmann_json.natvis" step to call it without --version,
relying on the script deriving the version from abi_macros.hpp itself.

But NATVIS_TOOL_DIR is checked out from develop, the same way TOOL_DIR
already is for amalgamate.py, precisely so an in-flight PR's tooling
changes cannot mark themselves clean. Until this PR (or an equivalent)
merges to develop, that checkout is the old generate_natvis.py, whose
--version argument is still required=True. The new step's invocation
of "generate_natvis.py $MAIN_DIR" (no --version) then fails argparse
on this PR's own CI run with "the following arguments are required:
--version", before the check ever gets to compare output.

Extract the version from $MAIN_DIR's own abi_macros.hpp in the
workflow and always pass it as --version. That satisfies the old
script's required argument and is accepted as an explicit override by
the new one, so the step behaves the same whether NATVIS_TOOL_DIR holds
the pre- or post-merge tool, and stays correct for later PRs that bump
the version.

Verified by running the workflow step's shell logic locally against
both the pre-#5717 generate_natvis.py (checked out at 633de8e44) and
the new one: both produce the identical nlohmann_json.natvis as the
committed file.

Review fix for #5717 item 3 (PR #5735).

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

* Extend tools/macro_builder to also generate DOUBLE_PASTE and TYPE_BODY

tools/macro_builder only emitted NLOHMANN_JSON_EXPAND..PASTE64, so two
other tables that scale with the same max_args stayed hand-maintained
with nothing checking them: NLOHMANN_JSON_DOUBLE_PASTE (added by hand
in #4563 for the *_WITH_NAMES macros) and the 64-slot dispatch table of
NLOHMANN_JSON_TYPE_BODY (the #4041 zero-member/one-or-more-member
switch). Both tables pass one macro name per slot to the same
NLOHMANN_JSON_GET_MACRO dispatch as PASTE, so they can drift out of
sync with max_args exactly the way _dp did in the ABI tag list fixed
by #5544.

Extend main.cpp with build_double_paste_code() (same recursive-doubling
shape as build_paste_code(), but DOUBLE_PASTE consumes two arguments
per member, so an even slot index falls back to the next lower odd
DOUBLE_PASTE<N>) and build_type_body_table() (max_args - 1 MEMBERS
slots and one trailing EMPTY slot, 8 per line, matching how it is
written by hand today). Add a "type_body" argument that selects the
TYPE_BODY block, since it lives at a separate location in
macro_scope.hpp from the EXPAND..DOUBLE_PASTE63 block; plain invocation
is unchanged apart from covering the extended range. No longer emit
the tool's old trailing blank line, so its output is directly diffable
without post-processing.

Verified with c++ -std=c++11: running the tool (with and without
"type_body") and piping the raw output through the pinned astyle
reproduces both blocks of the current macro_scope.hpp byte for byte.
tests/src/unit-udt_macro.cpp (all NLOHMANN_DEFINE_TYPE_*/_WITH_NAMES/
zero-member variants) passes unchanged under -std=c++11 and -std=c++17
with -fsanitize=address,undefined.

Add a "macro_builder_check" Makefile target that builds main.cpp,
regenerates both blocks into a scratch directory inside the repository
(astyle's --project lookup needs the target files under the same tree
as .astylerc, unlike an external /tmp directory), and diffs them
against the corresponding ranges of macro_scope.hpp; wire it into
check-amalgamation next to the natvis check. Wire the same regeneration
into check_amalgamation.yml, splicing the (still unindented) generated
blocks back into the PR's own macro_scope.hpp before the existing
astyle/amalgamation step runs, so that step's own tree-wide astyle
pass both indents them and folds any drift into the amalgamation
patch/diff the workflow already produces.

Unlike amalgamate.py and generate_natvis.py, this step builds
tools/macro_builder/main.cpp from the pull request's own checkout
($MAIN_DIR) rather than a separate checkout of tools/ at develop: this
tool has no independent source of truth to regenerate against (its
README documents that it must reproduce macro_scope.hpp byte for
byte), so a develop-pinned copy would only reproduce the
generate_natvis.py trap fixed in a previous commit on this branch,
where a PR that teaches the tool to cover more of the file fails its
own CI until that PR merges and updates the develop copy.

Add tools/macro_builder/README.md documentation for both new tables
and the two-invocation usage, and a short pointer comment above
NLOHMANN_JSON_TYPE_BODY (the EXPAND pointer already covered the first
block; extended its wording to include DOUBLE_PASTE63).

Closes #5717 item 5 in full, completing what the documentation-only
"Document tools/macro_builder..." commit already on this branch left
open (that commit's README/pointer-comment half stands; it also covers
item 7).

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 22:21:27 +02:00
Niels Lohmann 791cd88dfc Fix raw-TeX formulas and other documentation infrastructure debt (#5736)
* Fix math formulas rendering as raw TeX in the published docs

The privacy plugin self-hosts MathJax 2.7.0 but drops its
?config=TeX-MML-AM_CHTML query string, so the rehosted script loads no
input jax and the 10 formulas across 6 pages render as raw TeX to
readers. Remove pymdownx.arithmatex and the MathJax extra_javascript
entry, and rewrite the formulas in plain HTML (<sup>, <i>) instead.
This also drops a nine-year-old third-party script from every page.

Part of #5718

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

* Fix publish_documentation triggers and persist unneeded git credentials

publish_documentation.yml only triggered on docs/mkdocs/** pushes, but
the site also embeds .github/CODE_OF_CONDUCT.md, CONTRIBUTING.md,
SECURITY.md, cmake/{clang,gcc}_flags.cmake, .clang-tidy,
tools/astyle/.astylerc and tests/fmt_formatter/project/main.cpp via
pymdownx.snippets, so changes to those files never republished the
site. Extend the path filter to cover them, and switch runs-on from
the long-pinned ubuntu-22.04 to ubuntu-latest to match
ci_test_documentation.

Also add persist-credentials: false to the checkouts in ci_icpx and
ci_nvhpc (ubuntu.yml) and msvc-vs2026/msvc-arm64 (windows.yml), none
of which pushes with git, matching every other checkout in these
workflows.

Part of #5718

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

* Fix example build: broken debug echo, deprecations hidden for everything

docs/Makefile's debug echo used a space instead of a comma in
$(call cxx_standard ...), so it always printed an empty standard.
Every example was also compiled with -Wno-deprecated-declarations,
which would silently hide an accidental deprecated-API call in any of
them. Factor the duplicated compile flags into EXAMPLE_CPPFLAGS/
EXAMPLE_WARNFLAGS, build with -Werror=deprecated-declarations by
default, and only allow the three examples that intentionally
document deprecated API (the DEPRECATED_EXAMPLES list) to suppress it.

Part of #5718

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

* Fix check_structure.py NOLINT parsing and an off-by-one report line

`line.strip("<!-- NOLINT")` followed by `.strip(" -->")` strips any of
the characters in those sets from both ends, not a literal prefix; it
only happened to work for "Examples". A NOLINT'd section name
starting with N, O, L, I or T (e.g. "Notes", "Template parameters",
"Iterator invalidation", "Literals") was silently mangled, so the
suppression did not apply and the checker could report a spurious
missing/misordered section. Parse the comment with a regex instead.
The same fragile strip() pattern was used for heading text; replace it
with a plain prefix slice. Also fix the admonition_title report, which
used the 0-based line index while every other report in the file uses
lineno+1.

Part of #5718

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

* Fix docset README's non-existent make target and stale fallback URL

The README told readers to run `make nlohmann_json.docset`, but the
Makefile's targets are `all`, `JSON_for_Modern_C++.docset` and
`install_docset_zeal`; the documented command has failed with "No
rule to make target" since #2967 (2021). Point the README at the real
target and folder name. Info.plist's DashDocSetFallbackURL also still
pointed at the old nlohmann.github.io/json/ URL instead of the
canonical https://json.nlohmann.me/ from mkdocs.yml's site_url.

Leave list_missing_pages/list_removed_paths alone: they may become
redundant once #5638's check_docset() lands, which is a follow-up.

Part of #5718

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

* Remove two leftover Doxygen-era .link files from the examples directory

parse__iterator_pair.link and parse__pointers.link each held only a
Wandbox "online" permalink from the old Doxygen docs. #3071 deleted
every other .link file in 2021; these two came in through a parallel
PR (#3100) and were never referenced by any page, script or config.

Part of #5718

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

* Fix MacPorts CMake example to include its own snippet files

The MacPorts "Example: CMake" block included
integration/homebrew/example.cpp and
integration/homebrew/CMakeLists.txt instead of the MacPorts files
right next to it, a copy-paste slip from the Homebrew section. Nothing
referenced integration/macports/CMakeLists.txt as a result. The page
rendered correctly only because the homebrew, macports and
vcpkg/CMakeLists.txt snippets are byte-identical, so a future edit to
the MacPorts files would not have shown up on the page.

Part of #5718 item 6

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

* Do not persist git credentials in publish_documentation's checkout

The checkout step in publish_documentation.yml left the default
persist-credentials: true, so GITHUB_TOKEN stayed writable in
.git/config for the rest of the job (zizmor's artipacked finding). The
Deploy documentation step authenticates through its own github_token
input to peaceiris/actions-gh-pages and does not push with the
checked-out credentials, so persist-credentials: false is safe here,
matching every other checkout in the workflow set.

Overlaps #5638, which edits this same checkout step (adds
fetch-depth: 0); expect a rebase conflict there.

Part of #5718 item 2

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

* Replace list_missing_pages/list_removed_paths with a comm(1)-based diff

The docset Makefile's list_missing_pages ran one sqlite3 query per
mkdocs page, and list_removed_paths nested a loop over all mkdocs pages
inside a loop over all docset index paths (O(n*m) shell iteration).
Issue #5718 item 5 suggested removing or reducing these targets once
#5638's check_docset() lands, but that PR is still open and covers only
API pages and macros, not the full page set these targets check.
Replace the loops with two sorted path lists (DOCSET_PAGE_PATHS from
mkdocs' markdown sources, DOCSET_INDEX_PATHS from the built docset
index) compared with a single comm(1) call each, verified to produce
output identical to the old loops against the current docSet.dsidx.

The sed expression used '#' as its delimiter, which GNU Make reads as
a comment character even inside a variable assignment, truncating the
line and orphaning the closing paren of $(shell ...) ("unterminated
call to function 'shell': missing ')'"). Use '@' as the delimiter
instead.

Part of #5718 item 5

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 22:15:20 +02:00
Niels Lohmann 7d7055ec50 Fix stack overflow converting deep values between specializations (#5723)
* Fix stack overflow converting deep values between specializations

Constructing a basic_json from another specialization (json to
ordered_json or back, also via get<ordered_json>()) converted every
container with its range constructor, which calls the converting
constructor for each element. The call stack therefore grew with every
nesting level, and a value nested some 30,000 levels deep overflowed it.

The conversion now bounds its descent the way the copy constructor does
since #5387: the first 128 levels are converted exactly as before, and
below that convert_iteratively() finishes the value with an explicit
stack. It builds each container bottom-up from its converted elements
with the container's range constructor, so member order and keys that
become equal are handled as before, and it gives a value its type only
once its container exists, so an exception leaves nothing behind that
cannot be destroyed. Parents (JSON_DIAGNOSTICS) and positions
(JSON_DIAGNOSTIC_POSITIONS) are set for every value.

Converting a null value no longer resets its positions: the constructor
assigned null to a value that already was null, which swapped in the
positions of the temporary.

Fixes #5650.

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

* Explain why converting null keeps positions and why next is a reference

Review feedback on #5723 (gregmarr): clarify in comments that the
converting constructor has already copied the positions of val, which
the null case keeps like every other case, and that next must be a
reference into pending so that ++next advances the stored iterator.

Comments only; no code change.

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

* Refer to recursion_depth_limit() in the convert_structured() docs

The comment still named nesting_depth_limit, which #5637 removed on
develop in favor of detail::recursion_depth_limit().

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

* Advance the pending iterator through pending.back() and shorten the null comment

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 21:36:04 +02:00
Niels Lohmann 3b6ae43c53 Add JSON_DISABLE_TUPLE_REFERENCE_CONVERSION to fix std::tuple conversions (#5598)
* Add JSON_DISABLE_TUPLE_REFERENCE_CONVERSION to fix std::tuple conversions

basic_json can be constructed from std::tuple<json&>, which it turns into
a one-element array. Because of this, std::tuple picks its converting
constructor that converts the whole source tuple instead of the
element-wise one. As a result, std::tuple<const json&> built from
std::forward_as_tuple(j) binds to a temporary (a compile error with libc++,
a dangling reference with other standard libraries), and std::tuple<json>
built the same way holds [j] instead of a copy of j.

The new opt-in macro JSON_DISABLE_TUPLE_REFERENCE_CONVERSION (CMake option
JSON_DisableTupleReferenceConversion) removes the conversion from a
one-element tuple holding a reference to the same basic_json type, so
std::tuple converts element-wise. It is off by default, so existing
behavior is unchanged. It does not change any function body and therefore
is not part of the ABI tag.

Fixes #2226

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

* Convert one-element tuples to arrays on every compiler

to_json for std::tuple assigns a braced list, j = { std::get<Idx>(t)... }.
With a single element that is itself a basic_json, Apple clang 15 and 16
treat j = {x} as a copy of x, so std::tuple<json>{true} became true
instead of [true]. The macOS jobs (Xcode 15.1, 16.1) failed the new
checks in unit-disable-tuple-reference-conversion and unit-regression2.

The one-element overload that already handles
JSON_BRACE_INIT_COPY_SEMANTICS builds the array (or object, for a
[string, value] element) explicitly, the same way the initializer-list
constructor does. Use it unconditionally. The output is unchanged on
compilers that already wrapped the element.

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

* Skip json reference tuple tests on clang < 4 and GCC < 5

ci_test_compilers_gcc_old (4.8) and ci_test_compilers_clang (3.4) could
not compile the new tuple tests. Creating a std::tuple of basic_json
references, e.g. std::forward_as_tuple(j), makes these compilers
instantiate basic_json's conversion operator for libstdc++'s internal
tuple bases, which fails hard. This happens with and without
JSON_DISABLE_TUPLE_REFERENCE_CONVERSION, so it is a limitation of these
compilers, not of the new option.

Tested with the CI images: clang 3.4 to 3.9 and GCC 4.8 and 4.9 fail,
clang 4, 5, and 6 and GCC 5 and 6 compile all cases. Skip only the
checks that create such tuples; the is_constructible checks still run.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 20:53:56 +02:00
367 changed files with 4755 additions and 36196 deletions
-17
View File
@@ -1,17 +0,0 @@
arm_container:
image: gcc:latest
check_task:
check_script:
# the gcc image ships an outdated CMake, so fetch a recent prebuilt binary
# instead of compiling CMake from source
- wget -q https://github.com/Kitware/CMake/releases/download/v4.3.4/cmake-4.3.4-linux-aarch64.tar.gz
- tar xfz cmake-4.3.4-linux-aarch64.tar.gz
- export PATH="$(pwd)/cmake-4.3.4-linux-aarch64/bin:$PATH"
- cmake --version
- mkdir build
- cd build
- cmake .. -DJSON_FastTests=ON
- make -j4
- cd tests
- ctest -j4
+4
View File
@@ -24,6 +24,10 @@ updates:
interval: daily
cooldown:
default-days: 7
ignore:
# astyle is deliberately pinned (see tools/astyle/requirements.txt): newer versions
# reformat the code, and the pinned version defines the formatting CI enforces
- dependency-name: astyle
- package-ecosystem: pip
directory: /tools/generate_natvis
-11
View File
@@ -30,14 +30,6 @@ environment:
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
platform: x86
name: with_win_header
CXX_FLAGS: "/W4 /WX"
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Release
platform: x86
@@ -74,9 +66,6 @@ install:
- if "%platform%"=="x86" set GENERATOR_PLATFORM=Win32
before_build:
# for with_win_header build, inject the inclusion of Windows.h to the single-header library
- ps: if ($env:name -Eq "with_win_header") { $header_path = "single_include\nlohmann\json.hpp" }
- ps: if ($env:name -Eq "with_win_header") { "#include <Windows.h>`n" + (Get-Content $header_path | Out-String) | Set-Content $header_path }
- cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On "%CMAKE_OPTIONS%"
build_script:
-18
View File
@@ -45,24 +45,6 @@ labels:
- label: "aspect: binary formats"
title: "(?i)(bson|cbor|msgpack|messagepack|ubjson|bjdata|bon8|binary format)"
- label: "aspect: json_view"
files:
- "include/nlohmann/json_view\\.hpp"
- "include/nlohmann/detail/view/.*"
- "single_include/nlohmann/json_view\\.hpp"
- "tests/src/unit-json_view.*"
- "tests/src/fuzzer-(parse_json_view|json_view_image)\\.cpp"
- "tests/benchmarks/json_view/.*"
- "tools/amalgamate/config_json_view\\.json"
- "docs/mkdocs/docs/features/json_view\\.md"
- "docs/mkdocs/docs/api/basic_json_(document|view)/.*"
- "docs/mkdocs/docs/api/(ordered_)?json_(editable_)?(document|view)\\.md"
- "docs/mkdocs/docs/examples/(basic_json_(document|view)__|(ordered_)?json_(editable_)?(document|view)).*"
- "tests/benchmarks/src/benchmarks_view\\.cpp"
- label: "aspect: json_view"
title: "(?i)(json_view|json_document|zero-copy)"
- label: "python"
files:
- "\\.py$"
+57 -4
View File
@@ -35,6 +35,7 @@ jobs:
MAIN_DIR: ${{ github.workspace }}/main
INCLUDE_DIR: ${{ github.workspace }}/main/single_include/nlohmann
TOOL_DIR: ${{ github.workspace }}/tools/tools/amalgamate
NATVIS_TOOL_DIR: ${{ github.workspace }}/tools/tools/generate_natvis
steps:
- name: Harden Runner
@@ -61,6 +62,48 @@ jobs:
python3 -mvenv venv
venv/bin/pip3 install -r $MAIN_DIR/tools/astyle/requirements.txt
- name: Install generate_natvis dependencies
run: pip3 install -r $NATVIS_TOOL_DIR/requirements.txt
- name: Regenerate the tools/macro_builder tables in macro_scope.hpp
run: |
cd $MAIN_DIR
# Built from this PR's own tools/macro_builder/main.cpp, not a
# develop checkout: unlike amalgamate.py and generate_natvis.py,
# this tool has no other source of truth to check against (its
# own README documents that it must reproduce macro_scope.hpp
# byte for byte), so there is nothing to gain from checking out a
# separate copy, and doing so would make this step fail on a PR
# that adds support for a new dispatch table until that PR itself
# merges to develop, the same way generate_natvis.py's --version
# requirement briefly did.
TMPDIR=$(mktemp -d ./macro_builder_check.XXXXXX)
c++ -std=c++11 tools/macro_builder/main.cpp -o "$TMPDIR/macro_builder"
"$TMPDIR/macro_builder" > "$TMPDIR/paste.hpp"
"$TMPDIR/macro_builder" type_body > "$TMPDIR/type_body.hpp"
# Splice the (still unindented) generated blocks back into
# macro_scope.hpp; the astyle pass below indents their
# continuation lines the same way it does for the rest of
# include/, so a correctly regenerated file comes out unchanged.
awk -v newfile="$TMPDIR/paste.hpp" '
BEGIN { while ((getline line < newfile) > 0) { new = new line "\n" } }
/^#define NLOHMANN_JSON_EXPAND\( x \) x$/ { printf "%s", new; skip=1 }
skip && /^#define NLOHMANN_JSON_DOUBLE_PASTE63\(/ { skip=0; next }
skip { next }
{ print }
' include/nlohmann/detail/macro_scope.hpp > "$TMPDIR/macro_scope_1.hpp"
awk -v newfile="$TMPDIR/type_body.hpp" '
BEGIN { while ((getline line < newfile) > 0) { new = new line "\n" } }
/^#define NLOHMANN_JSON_TYPE_BODY\(Prefix, \.\.\.\)/ { printf "%s", new; skip=1 }
skip && /^[[:space:]]*NLOHMANN_JSON_TYPE_BODY_SENTINEL\)\)$/ { skip=0; next }
skip { next }
{ print }
' "$TMPDIR/macro_scope_1.hpp" > "$TMPDIR/macro_scope_2.hpp"
mv "$TMPDIR/macro_scope_2.hpp" include/nlohmann/detail/macro_scope.hpp
rm -rf "$TMPDIR"
- name: Regenerate amalgamation, formatting, and BUILD.bazel
run: |
cd $MAIN_DIR
@@ -68,15 +111,12 @@ jobs:
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 .
cp include/nlohmann/json_literals.hpp $INCLUDE_DIR/json_literals.hpp
# the configuration of json_view.hpp comes with the pull request until
# it is on develop; the tool itself is still develop's
python3 $TOOL_DIR/amalgamate.py -c $MAIN_DIR/tools/amalgamate/config_json_view.json -s .
# the header list of the Bazel "json" target must match the files in include/
cmake -P cmake/scripts/gen_bazel_build_file.cmake
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
$INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp $INCLUDE_DIR/json_view.hpp
$INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp
# fail loudly if a directory is renamed or removed: find would only warn
# about the missing path and silently drop its files from the check
@@ -91,6 +131,19 @@ jobs:
${{ 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: Regenerate nlohmann_json.natvis
run: |
cd $MAIN_DIR
# Pass --version explicitly so this step also works with the tool
# copy from develop before this repository's own generate_natvis.py
# learns to derive the version itself: the older script requires
# --version, and the newer one accepts it as an explicit override.
ABI_MACROS=include/nlohmann/detail/abi_macros.hpp
VERSION_MAJOR=$(grep -m1 'define NLOHMANN_JSON_VERSION_MAJOR' $ABI_MACROS | grep -o '[0-9]\+')
VERSION_MINOR=$(grep -m1 'define NLOHMANN_JSON_VERSION_MINOR' $ABI_MACROS | grep -o '[0-9]\+')
VERSION_PATCH=$(grep -m1 'define NLOHMANN_JSON_VERSION_PATCH' $ABI_MACROS | grep -o '[0-9]\+')
python3 $NATVIS_TOOL_DIR/generate_natvis.py --version "$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH" $MAIN_DIR
- name: Build patch and check for differences
id: diff
run: |
@@ -1,78 +0,0 @@
name: "json_view benchmarks"
# On demand only: runs the comparison of json_view with yyjson, simdjson, and
# Boost.JSON (tests/benchmarks/json_view/compare.py) on GitHub-hosted runners,
# for numbers from x86-64 and AArch64 Linux. It runs when started by hand, or
# when a pull request gets the label "benchmark" (on both architectures, with
# GCC and the default settings). Shared runners are noisy: the results show
# where json_view stands, but published numbers need a quiet machine (see
# tests/benchmarks/json_view/README.md).
on:
pull_request:
types: [labeled]
workflow_dispatch:
inputs:
runner:
description: "Runner image"
type: choice
options:
- ubuntu-24.04
- ubuntu-24.04-arm
default: ubuntu-24.04
compiler:
description: "Compiler"
type: choice
options:
- g++
- clang++
default: g++
native:
description: "Compile for the runner's CPU (-march=native)"
type: boolean
default: false
rounds:
description: "Rounds of bench_view"
type: number
default: 30
permissions:
contents: read
jobs:
compare:
if: github.event_name == 'workflow_dispatch' || github.event.label.name == 'benchmark'
strategy:
matrix:
runner: ${{ fromJSON(github.event_name == 'workflow_dispatch' && format('["{0}"]', inputs.runner) || '["ubuntu-24.04", "ubuntu-24.04-arm"]') }}
runs-on: ${{ matrix.runner }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Download test data
run: |
cmake -S . -B build -DJSON_BuildTests=On
cmake --build build --target download_test_data
- name: Run the comparison
env:
CXX: ${{ inputs.compiler || 'g++' }}
CC: ${{ inputs.compiler == 'clang++' && 'clang' || 'gcc' }}
ROUNDS: ${{ inputs.rounds || 30 }}
NATIVE: ${{ inputs.native && '--native' || '' }}
run: python3 tests/benchmarks/json_view/compare.py --data build/test_files --download --rounds "$ROUNDS" $NATIVE
- name: Summary
run: cat tests/benchmarks/json_view/results/*.md >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: json_view-benchmarks-${{ matrix.runner }}-${{ inputs.compiler || 'g++' }}
path: tests/benchmarks/json_view/results/
+13 -1
View File
@@ -7,6 +7,16 @@ on:
- develop
paths:
- docs/mkdocs/**
# the site also embeds these files via pymdownx.snippets
# (mkdocs.yml sets restrict_base_path: false for this)
- .clang-tidy
- .github/CODE_OF_CONDUCT.md
- .github/CONTRIBUTING.md
- .github/SECURITY.md
- cmake/clang_flags.cmake
- cmake/gcc_flags.cmake
- tests/fmt_formatter/project/main.cpp
- tools/astyle/.astylerc
workflow_dispatch:
# we don't want to have concurrent jobs, and we don't want to cancel running jobs to avoid broken publications
@@ -23,7 +33,7 @@ jobs:
contents: write
if: github.repository == 'nlohmann/json'
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
@@ -31,6 +41,8 @@ jobs:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install virtual environment
run: make install_venv -C docs/mkdocs
+32 -3
View File
@@ -52,6 +52,13 @@ jobs:
run: cmake -S . -B build -DJSON_CI=On
- name: Build
run: cmake --build build --target ci_infer
- name: Archive Infer report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: infer-report
path: ${{ github.workspace }}/build/build_infer/infer-out/report.txt
if-no-files-found: ignore
ci_static_analysis_ubuntu:
runs-on: ubuntu-latest
@@ -97,13 +104,13 @@ jobs:
ci_cmake_options:
runs-on: ubuntu-latest
container: ubuntu:focal
container: ubuntu:24.04
strategy:
matrix:
target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local]
target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local]
steps:
- name: Install build-essential
run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev
run: apt-get update ; apt-get install -y build-essential unzip wget git
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
@@ -346,6 +353,8 @@ jobs:
container: intel/oneapi-hpckit:latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
@@ -358,6 +367,8 @@ jobs:
container: nvcr.io/nvidia/nvhpc:25.5-devel-cuda12.9-ubuntu22.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Run CMake
@@ -403,3 +414,21 @@ jobs:
run: cmake -S . -B build -DJSON_CI=On
- name: Build
run: cmake --build build --target ${{ matrix.target }}
# Native Linux ARM64 runner with the latest GCC. The ubuntu-24.04-arm label is
# only available for public repositories.
ci_test_arm64:
runs-on: ubuntu-24.04-arm
container: gcc:latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Check that the job runs natively on arm64
run: uname -m && test "$(uname -m)" = aarch64
- name: Run CMake
run: cmake -S . -B build -DJSON_CI=On
- name: Build
run: cmake --build build --target ci_test_compiler_default
+4
View File
@@ -87,6 +87,8 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Set extra CXX_FLAGS for latest std_version
@@ -123,6 +125,8 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run CMake (Release)
run: cmake -S . -B build -G "Visual Studio 18 2026" -A ARM64 -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX"
if: matrix.build_type == 'Release'
+12
View File
@@ -0,0 +1,12 @@
{
"_comment": "Used by the ci_infer CMake target (#5715 item 4b). fail-on-issue makes CI fail on Infer findings; disable-issue-type is a type-level baseline for the ~174 pre-existing findings (all PULSE_UNNECESSARY_COPY*/PULSE_RESOURCE_LEAK/PULSE_CONST_REFABLE, mostly in test code) triaged in run https://github.com/nlohmann/json/actions/runs/35829411620 on commit 1054b2097, so CI fails only on a NEW issue type. Remove an entry here once its findings have been fixed or explicitly accepted.",
"fail-on-issue": true,
"disable-issue-type": [
"PULSE_UNNECESSARY_COPY_ASSIGNMENT",
"PULSE_UNNECESSARY_COPY",
"PULSE_UNNECESSARY_COPY_INTERMEDIATE",
"PULSE_UNNECESSARY_COPY_OPTIONAL",
"PULSE_RESOURCE_LEAK",
"PULSE_CONST_REFABLE"
]
}
-26
View File
@@ -20,13 +20,11 @@ cc_library(
hdrs = [
"include/nlohmann/adl_serializer.hpp",
"include/nlohmann/byte_container_with_subtype.hpp",
"include/nlohmann/detail/abi_config.hpp",
"include/nlohmann/detail/abi_macros.hpp",
"include/nlohmann/detail/bit_ops.hpp",
"include/nlohmann/detail/conversions/from_json.hpp",
"include/nlohmann/detail/conversions/to_chars.hpp",
"include/nlohmann/detail/conversions/to_json.hpp",
"include/nlohmann/detail/conversions/zmij.hpp",
"include/nlohmann/detail/exceptions.hpp",
"include/nlohmann/detail/hash.hpp",
"include/nlohmann/detail/input/binary_reader.hpp",
@@ -67,32 +65,9 @@ cc_library(
"include/nlohmann/detail/string_escape.hpp",
"include/nlohmann/detail/string_utils.hpp",
"include/nlohmann/detail/value_t.hpp",
"include/nlohmann/detail/view/builder.hpp",
"include/nlohmann/detail/view/compare.hpp",
"include/nlohmann/detail/view/document_data.hpp",
"include/nlohmann/detail/view/edit.hpp",
"include/nlohmann/detail/view/edit_storage.hpp",
"include/nlohmann/detail/view/errors.hpp",
"include/nlohmann/detail/view/image.hpp",
"include/nlohmann/detail/view/input.hpp",
"include/nlohmann/detail/view/iterator.hpp",
"include/nlohmann/detail/view/lookup.hpp",
"include/nlohmann/detail/view/macro_scope.hpp",
"include/nlohmann/detail/view/macro_unscope.hpp",
"include/nlohmann/detail/view/materialize.hpp",
"include/nlohmann/detail/view/node.hpp",
"include/nlohmann/detail/view/number.hpp",
"include/nlohmann/detail/view/object_index.hpp",
"include/nlohmann/detail/view/pointer.hpp",
"include/nlohmann/detail/view/scan.hpp",
"include/nlohmann/detail/view/serializer.hpp",
"include/nlohmann/detail/view/simd.hpp",
"include/nlohmann/detail/view/string_ref.hpp",
"include/nlohmann/detail/view/value.hpp",
"include/nlohmann/json.hpp",
"include/nlohmann/json_fwd.hpp",
"include/nlohmann/json_literals.hpp",
"include/nlohmann/json_view.hpp",
"include/nlohmann/ordered_map.hpp",
"include/nlohmann/thirdparty/hedley/hedley.hpp",
"include/nlohmann/thirdparty/hedley/hedley_undef.hpp",
@@ -105,7 +80,6 @@ cc_library(
name = "singleheader-json",
hdrs = [
"single_include/nlohmann/json.hpp",
"single_include/nlohmann/json_view.hpp",
],
includes = ["single_include"],
visibility = ["//visibility:public"],
+6
View File
@@ -55,6 +55,7 @@ option(JSON_Diagnostic_Positions "Enable diagnostic positions." OFF)
option(JSON_GlobalUDLs "Place user-defined string literals in the global namespace." ON)
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
option(JSON_DisableEnumSerialization "Disable default integer enum serialization." OFF)
option(JSON_DisableTupleReferenceConversion "Disable conversion from a one-element tuple of a JSON reference." OFF)
option(JSON_LegacyDiscardedValueComparison "Enable legacy discarded value comparison." OFF)
option(JSON_Install "Install CMake targets during install step." ${MAIN_PROJECT})
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." ON)
@@ -101,6 +102,10 @@ if (JSON_DisableEnumSerialization)
message(STATUS "Enum integer serialization is disabled (JSON_DISABLE_ENUM_SERIALIZATION=1)")
endif()
if (JSON_DisableTupleReferenceConversion)
message(STATUS "Tuple reference conversion is disabled (JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1)")
endif()
if (JSON_LegacyDiscardedValueComparison)
message(STATUS "Legacy discarded value comparison enabled (JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1)")
endif()
@@ -143,6 +148,7 @@ target_compile_definitions(
$<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:JSON_USE_GLOBAL_UDLS=0>
$<$<NOT:$<BOOL:${JSON_ImplicitConversions}>>:JSON_USE_IMPLICIT_CONVERSIONS=0>
$<$<BOOL:${JSON_DisableEnumSerialization}>:JSON_DISABLE_ENUM_SERIALIZATION=1>
$<$<BOOL:${JSON_DisableTupleReferenceConversion}>:JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1>
$<$<BOOL:${JSON_Diagnostics}>:JSON_DIAGNOSTICS=1>
$<$<BOOL:${JSON_Diagnostic_Positions}>:JSON_DIAGNOSTIC_POSITIONS=1>
$<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1>
-11
View File
@@ -33,17 +33,6 @@ Further documentation:
> [!IMPORTANT]
> The folder `.github/workflows` is predetermined by GitHub.
### `.cirrus.yml`
Configuration file for the pipeline at [Cirrus CI](https://cirrus-ci.com/github/nlohmann/json).
Further documentation:
- [Writing tasks](https://cirrus-ci.org/guide/writing-tasks/)
> [!IMPORTANT]
> The filename `.cirrus.yml` and position (root of the repository) are predetermined by Cirrus CI.
### `.github/external_ci/appveyor.yml`
Configuration for the pipelines at [AppVeyor](https://ci.appveyor.com/project/nlohmann/json).
+36 -106
View File
@@ -1,4 +1,4 @@
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis macro_builder_check
##########################################################################
# configuration
@@ -23,7 +23,9 @@ AMALGAMATED_FILE=single_include/nlohmann/json.hpp
AMALGAMATED_FWD_FILE=single_include/nlohmann/json_fwd.hpp
# json_literals.hpp only includes <nlohmann/json.hpp>, so it is copied verbatim
AMALGAMATED_LITERALS_FILE=single_include/nlohmann/json_literals.hpp
AMALGAMATED_VIEW_FILE=single_include/nlohmann/json_view.hpp
# the header with the argument-counting macros generated by tools/macro_builder
MACRO_SCOPE_HPP=include/nlohmann/detail/macro_scope.hpp
##########################################################################
@@ -32,19 +34,14 @@ AMALGAMATED_VIEW_FILE=single_include/nlohmann/json_view.hpp
# main target
all:
@echo "amalgamate - amalgamate files single_include/nlohmann/json{,_fwd,_literals,_view}.hpp from the include/nlohmann sources"
@echo "amalgamate - amalgamate files single_include/nlohmann/json{,_fwd,_literals}.hpp from the include/nlohmann sources"
@echo "BUILD.bazel - regenerate the Bazel BUILD file from the include/nlohmann sources"
@echo "ChangeLog.md - generate ChangeLog file"
@echo "check-amalgamation - check whether sources have been amalgamated and BUILD.bazel is up to date"
@echo "clean - remove built files"
@echo "doctest - compile example files and check their output"
@echo "fuzz_testing - prepare fuzz testing of the JSON parser"
@echo "fuzz_testing_bon8 - prepare fuzz testing of the BON8 parser"
@echo "fuzz_testing_bson - prepare fuzz testing of the BSON parser"
@echo "fuzz_testing_cbor - prepare fuzz testing of the CBOR parser"
@echo "fuzz_testing_json_view - prepare fuzz testing of the json_document/json_view parser"
@echo "fuzz_testing_msgpack - prepare fuzz testing of the MessagePack parser"
@echo "fuzz_testing_ubjson - prepare fuzz testing of the UBJSON parser"
@echo "fuzzing - see tests/fuzzing.md for how to build and run the fuzzers"
@echo "macro_builder_check - check that macro_scope.hpp matches tools/macro_builder's output"
@echo "natvis - regenerate nlohmann_json.natvis from the current ABI tags and version"
@echo "pretty - beautify code with Artistic Style"
@echo "run_benchmarks - build and run benchmarks"
@echo "update_hedley - download Hedley and regenerate hedley.hpp / hedley_undef.hpp"
@@ -63,82 +60,6 @@ run_benchmarks:
cd cmake-build-benchmarks ; ./json_benchmarks
##########################################################################
# fuzzing
##########################################################################
# the overall fuzz testing target
fuzz_testing:
rm -fr fuzz-testing
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
$(MAKE) parse_afl_fuzzer -C tests CXX=afl-clang++
mv tests/parse_afl_fuzzer fuzz-testing/fuzzer
find tests/data/json_tests -size -5k -name *json | xargs -I{} cp "{}" fuzz-testing/testcases
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
fuzz_testing_bon8:
rm -fr fuzz-testing
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
$(MAKE) parse_bon8_fuzzer -C tests CXX=afl-clang++
mv tests/parse_bon8_fuzzer fuzz-testing/fuzzer
find tests/data -size -5k -name *.bon8 | xargs -I{} cp "{}" fuzz-testing/testcases
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
fuzz_testing_bson:
rm -fr fuzz-testing
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
$(MAKE) parse_bson_fuzzer -C tests CXX=afl-clang++
mv tests/parse_bson_fuzzer fuzz-testing/fuzzer
find tests/data -size -5k -name *.bson | xargs -I{} cp "{}" fuzz-testing/testcases
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
fuzz_testing_cbor:
rm -fr fuzz-testing
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
$(MAKE) parse_cbor_fuzzer -C tests CXX=afl-clang++
mv tests/parse_cbor_fuzzer fuzz-testing/fuzzer
find tests/data -size -5k -name *.cbor | xargs -I{} cp "{}" fuzz-testing/testcases
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
fuzz_testing_json_view:
rm -fr fuzz-testing
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
$(MAKE) parse_json_view_fuzzer -C tests CXX=afl-clang++
mv tests/parse_json_view_fuzzer fuzz-testing/fuzzer
find tests/data/json_tests -size -5k -name *json | xargs -I{} cp "{}" fuzz-testing/testcases
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
fuzz_testing_msgpack:
rm -fr fuzz-testing
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
$(MAKE) parse_msgpack_fuzzer -C tests CXX=afl-clang++
mv tests/parse_msgpack_fuzzer fuzz-testing/fuzzer
find tests/data -size -5k -name *.msgpack | xargs -I{} cp "{}" fuzz-testing/testcases
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
fuzz_testing_ubjson:
rm -fr fuzz-testing
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
$(MAKE) parse_ubjson_fuzzer -C tests CXX=afl-clang++
mv tests/parse_ubjson_fuzzer fuzz-testing/fuzzer
find tests/data -size -5k -name *.ubjson | xargs -I{} cp "{}" fuzz-testing/testcases
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
fuzzing-start:
afl-fuzz -S fuzzer1 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
afl-fuzz -S fuzzer2 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
afl-fuzz -S fuzzer3 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
afl-fuzz -S fuzzer4 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
afl-fuzz -S fuzzer5 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
afl-fuzz -S fuzzer6 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
afl-fuzz -S fuzzer7 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
afl-fuzz -M fuzzer0 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer
fuzzing-stop:
-killall fuzzer
-killall afl-fuzz
##########################################################################
# Static analysis
##########################################################################
@@ -166,14 +87,10 @@ install_astyle:
# call the Artistic Style pretty printer on all source files
pretty: install_astyle
$(ASTYLE) --project=tools/astyle/.astylerc $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_VIEW_FILE) docs/mkdocs/docs/examples/*.cpp
# call the Clang-Format on all source files
pretty_format:
for FILE in $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) docs/mkdocs/docs/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done
$(ASTYLE) --project=tools/astyle/.astylerc $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) docs/mkdocs/docs/examples/*.cpp docs/mkdocs/docs/examples/*.hpp
# create single header files and pretty print
amalgamate: $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_VIEW_FILE)
amalgamate: $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE)
$(MAKE) pretty
# call the amalgamation tool for json.hpp
@@ -188,30 +105,46 @@ $(AMALGAMATED_FWD_FILE): $(SRCS)
$(AMALGAMATED_LITERALS_FILE): include/nlohmann/json_literals.hpp
cp include/nlohmann/json_literals.hpp $(AMALGAMATED_LITERALS_FILE)
# call the amalgamation tool for json_view.hpp (keeps including json.hpp)
$(AMALGAMATED_VIEW_FILE): $(SRCS)
tools/amalgamate/amalgamate.py -c tools/amalgamate/config_json_view.json -s . --verbose=yes
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
natvis:
python3 tools/generate_natvis/generate_natvis.py .
# regenerate the two tools/macro_builder blocks of $(MACRO_SCOPE_HPP) (see its README.md) and diff against the
# checked-in header; phony, because it never writes $(MACRO_SCOPE_HPP) itself
macro_builder_check:
@set -e; \
TMPDIR=$$(mktemp -d ./macro_builder_check.XXXXXX); \
trap 'rm -rf "$$TMPDIR"' EXIT; \
$(CXX) -std=c++11 tools/macro_builder/main.cpp -o "$$TMPDIR/macro_builder"; \
"$$TMPDIR/macro_builder" > "$$TMPDIR/paste.hpp"; \
"$$TMPDIR/macro_builder" type_body > "$$TMPDIR/type_body.hpp"; \
$(ASTYLE) --project=tools/astyle/.astylerc --suffix=none --quiet "$$TMPDIR/paste.hpp" "$$TMPDIR/type_body.hpp"; \
sed -n '/^#define NLOHMANN_JSON_EXPAND( x ) x$$/,/^#define NLOHMANN_JSON_DOUBLE_PASTE63(/p' $(MACRO_SCOPE_HPP) > "$$TMPDIR/paste_actual.hpp"; \
sed -n '/^#define NLOHMANN_JSON_TYPE_BODY(Prefix, \.\.\.)/,/^ NLOHMANN_JSON_TYPE_BODY_SENTINEL))$$/p' $(MACRO_SCOPE_HPP) > "$$TMPDIR/type_body_actual.hpp"; \
diff "$$TMPDIR/paste.hpp" "$$TMPDIR/paste_actual.hpp" || (echo "===================================================================\n $(MACRO_SCOPE_HPP) (NLOHMANN_JSON_EXPAND..NLOHMANN_JSON_DOUBLE_PASTE63) is out of date!\n Regenerate it, see tools/macro_builder/README.md.\n===================================================================" ; exit 1); \
diff "$$TMPDIR/type_body.hpp" "$$TMPDIR/type_body_actual.hpp" || (echo "===================================================================\n $(MACRO_SCOPE_HPP) (NLOHMANN_JSON_TYPE_BODY) is out of date!\n Regenerate it, see tools/macro_builder/README.md.\n===================================================================" ; exit 1)
# check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources
# Note: this target is called by Travis
check-amalgamation:
@mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~
@mv $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_FWD_FILE)~
@mv $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_LITERALS_FILE)~
@mv $(AMALGAMATED_VIEW_FILE) $(AMALGAMATED_VIEW_FILE)~
@$(MAKE) amalgamate
@diff $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) ; false)
@diff $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_FWD_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FWD_FILE)~ $(AMALGAMATED_FWD_FILE) ; false)
@diff $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_LITERALS_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_LITERALS_FILE)~ $(AMALGAMATED_LITERALS_FILE) ; false)
@diff $(AMALGAMATED_VIEW_FILE) $(AMALGAMATED_VIEW_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_VIEW_FILE)~ $(AMALGAMATED_VIEW_FILE) ; false)
@mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE)
@mv $(AMALGAMATED_FWD_FILE)~ $(AMALGAMATED_FWD_FILE)
@mv $(AMALGAMATED_LITERALS_FILE)~ $(AMALGAMATED_LITERALS_FILE)
@mv $(AMALGAMATED_VIEW_FILE)~ $(AMALGAMATED_VIEW_FILE)
@mv BUILD.bazel BUILD.bazel~
@$(MAKE) BUILD.bazel
@diff BUILD.bazel BUILD.bazel~ || (echo "===================================================================\n BUILD.bazel is out of date! Please run 'make BUILD.bazel'.\n===================================================================" ; mv BUILD.bazel~ BUILD.bazel ; false)
@mv BUILD.bazel~ BUILD.bazel
@mv nlohmann_json.natvis nlohmann_json.natvis~
@$(MAKE) natvis
@diff nlohmann_json.natvis nlohmann_json.natvis~ || (echo "===================================================================\n nlohmann_json.natvis is out of date! Please run 'make natvis'.\n===================================================================" ; mv nlohmann_json.natvis~ nlohmann_json.natvis ; false)
@mv nlohmann_json.natvis~ nlohmann_json.natvis
@$(MAKE) macro_builder_check
# generate the Bazel BUILD file; phony, because a removed header would not trigger a rebuild
BUILD.bazel:
@@ -248,7 +181,7 @@ json.tar.xz:
# We use `-X` to make the resulting ZIP file reproducible, see
# <https://content.pivotal.io/blog/barriers-to-deterministic-reproducible-zip-files>.
include.zip: BUILD.bazel
zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_VIEW_FILE) BUILD.bazel MODULE.bazel meson.build LICENSE.MIT
zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) BUILD.bazel MODULE.bazel meson.build LICENSE.MIT
# Create the files for a release and add signatures and hashes.
release: include.zip json.tar.xz
@@ -258,14 +191,12 @@ release: include.zip json.tar.xz
gpg --armor --detach-sig $(AMALGAMATED_FILE)
gpg --armor --detach-sig $(AMALGAMATED_FWD_FILE)
gpg --armor --detach-sig $(AMALGAMATED_LITERALS_FILE)
gpg --armor --detach-sig $(AMALGAMATED_VIEW_FILE)
gpg --armor --detach-sig json.tar.xz
cp $(AMALGAMATED_FILE) release_files
cp $(AMALGAMATED_FWD_FILE) release_files
cp $(AMALGAMATED_LITERALS_FILE) release_files
cp $(AMALGAMATED_VIEW_FILE) release_files
mv $(AMALGAMATED_FILE).asc $(AMALGAMATED_FWD_FILE).asc $(AMALGAMATED_LITERALS_FILE).asc $(AMALGAMATED_VIEW_FILE).asc json.tar.xz json.tar.xz.asc include.zip include.zip.asc release_files
cd release_files ; shasum -a 256 json.hpp json_view.hpp include.zip json.tar.xz > hashes.txt
mv $(AMALGAMATED_FILE).asc $(AMALGAMATED_FWD_FILE).asc $(AMALGAMATED_LITERALS_FILE).asc json.tar.xz json.tar.xz.asc include.zip include.zip.asc release_files
cd release_files ; shasum -a 256 $$(find . -type f -not -name '*.asc' | sed 's|^\./||' | sort) > hashes.txt
##########################################################################
@@ -275,7 +206,6 @@ release: include.zip json.tar.xz
# clean up
clean:
rm -fr fuzz fuzz-testing *.dSYM tests/*.dSYM
rm -fr benchmarks/files/numbers/*.json
rm -fr cmake-build-benchmarks fuzz-testing cmake-build-pvs-studio release_files
$(MAKE) clean -Cdocs
+1 -13
View File
@@ -7,7 +7,6 @@
[![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://app.codacy.com/gh/nlohmann/json/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Cirrus CI](https://api.cirrus-ci.com/github/nlohmann/json.svg)](https://cirrus-ci.com/github/nlohmann/json)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7)
[![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://json.nlohmann.me)
@@ -1189,14 +1188,6 @@ binary.set_subtype(0x10);
auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE
```
### Zero-copy views
Header `<nlohmann/json_view.hpp>` adds `json_document`/`json_view`, a read-only, non-owning way to look at a parsed
JSON text: parsing builds a flat index (16 bytes per value) instead of a tree, strings and numbers stay in the source
text, and `materialize()` builds a `json` value for a subtree only when you actually need one. See
[Zero-copy JSON views](https://json.nlohmann.me/features/json_view/) for the details, including which inputs are
borrowed and which are copied.
## Customers
The library is used in multiple projects, applications, operating systems, etc. The list below is not exhaustive, but the result of an internet search. If you know further customers of the library, please let me know, see [contact](#contact).
@@ -1401,12 +1392,9 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
- The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright &copy; 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>
- The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright &copy; 2009 [Florian Loitsch](https://florian.loitsch.com/)
- The class contains a port of the shortest double-to-decimal conversion of [Żmij](https://github.com/vitaut/zmij) by Victor Zverovich, which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright &copy; 2025 [Victor Zverovich](https://github.com/vitaut)
- The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
- The class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
- The class contains an adapted version of the Eisel-Lemire algorithm, its table of powers of five, and its digit comparison for long numbers from [fast_float](https://github.com/fastfloat/fast_float) by Daniel Lemire and contributors, which is available under the [MIT License](https://opensource.org/licenses/MIT) (used here), the Apache 2.0 License, and the Boost Software License. Copyright &copy; 2021 The fast_float authors
- The view's parser (`<nlohmann/json_view.hpp>`) contains techniques and code adapted from [yyjson](https://github.com/ibireme/yyjson) by YaoYuan, which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above): table-driven decoding of `\u` escapes and fixed-offset unrolled checks.
- The view's parser (`<nlohmann/json_view.hpp>`) validates non-ASCII strings with the vector UTF-8 check of [simdjson](https://github.com/simdjson/simdjson) by Daniel Lemire, Geoff Langdale, John Keiser, and contributors (its "lookup4" algorithm and tables, after J. Keiser and D. Lemire, "Validating UTF-8 In Less Than One Instruction Per Byte", 2021), which is available under the [MIT License](https://opensource.org/licenses/MIT) (used here) and the Apache 2.0 License. Copyright &copy; 2018-2025 The simdjson authors
- The class contains an adapted version of the Eisel-Lemire algorithm and its table of powers of five from [fast_float](https://github.com/fastfloat/fast_float) by Daniel Lemire and contributors, which is available under the [MIT License](https://opensource.org/licenses/MIT) (used here), the Apache 2.0 License, and the Boost Software License. Copyright &copy; 2021 The fast_float authors
<img align="right" src="https://git.fsfe.org/reuse/reuse-ci/raw/branch/master/reuse-horizontal.png" alt="REUSE Software">
+135 -99
View File
@@ -40,6 +40,14 @@ execute_process(COMMAND ${IWYU_TOOL} --version OUTPUT_VARIABLE IWYU_TOOL_VERSION
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" IWYU_TOOL_VERSION "${IWYU_TOOL_VERSION}")
message(STATUS "🔖 include-what-you-use ${IWYU_TOOL_VERSION} (${IWYU_TOOL})")
# CMake's CXX_INCLUDE_WHAT_YOU_USE launcher runs IWYU during the normal compile step (useful to see
# diagnostics inline), but CMake's own __run_co_compile wrapper does not propagate the launched
# tool's exit code to the build, so IWYU's own "-Xiwyu --error" cannot fail that step (verified: a
# deliberately-unused #include in a header still lets `cmake --build` finish with exit code 0).
# iwyu_tool.py, which ships with IWYU, reads compile_commands.json and does return a non-zero exit
# code for any analyzed file with findings; ci_single_binaries uses it to actually fail on findings.
find_program(IWYU_TOOL_PY NAMES iwyu_tool iwyu_tool.py iwyu-tool)
find_program(INFER_TOOL NAMES infer)
execute_process(COMMAND ${INFER_TOOL} --version OUTPUT_VARIABLE INFER_TOOL_VERSION ERROR_VARIABLE INFER_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" INFER_TOOL_VERSION "${INFER_TOOL_VERSION}")
@@ -55,12 +63,6 @@ execute_process(COMMAND ${NINJA_TOOL} --version OUTPUT_VARIABLE NINJA_TOOL_VERSI
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" NINJA_TOOL_VERSION "${NINJA_TOOL_VERSION}")
message(STATUS "🔖 Ninja ${NINJA_TOOL_VERSION} (${NINJA_TOOL})")
find_program(OCLINT_TOOL NAMES oclint-json-compilation-database)
find_program(OCLINT_VERSION_TOOL NAMES oclint)
execute_process(COMMAND ${OCLINT_VERSION_TOOL} --version OUTPUT_VARIABLE OCLINT_TOOL_VERSION ERROR_VARIABLE OCLINT_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" OCLINT_TOOL_VERSION "${OCLINT_TOOL_VERSION}")
message(STATUS "🔖 OCLint ${OCLINT_TOOL_VERSION} (${OCLINT_TOOL})")
find_program(VALGRIND_TOOL NAMES valgrind)
execute_process(COMMAND ${VALGRIND_TOOL} --version OUTPUT_VARIABLE VALGRIND_TOOL_VERSION ERROR_VARIABLE VALGRIND_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" VALGRIND_TOOL_VERSION "${VALGRIND_TOOL_VERSION}")
@@ -128,16 +130,16 @@ foreach(CXX_STANDARD 11 14 17 20 23 26)
COMMENT "Compile and test with Clang for C++${CXX_STANDARD}"
)
# pass -stdlib=libc++ through CXXFLAGS: an explicit -DCMAKE_CXX_FLAGS would make CMake ignore CXXFLAGS
add_custom_target(ci_test_clang_libcxx_cxx${CXX_STANDARD}
COMMAND CXX=${CLANG_TOOL} CXXFLAGS="${CLANG_CXXFLAGS}" ${CMAKE_COMMAND}
COMMAND CXX=${CLANG_TOOL} CXXFLAGS="${CLANG_CXXFLAGS};-stdlib=libc++" ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON
-DJSON_TestStandards=${CXX_STANDARD}
-DCMAKE_CXX_FLAGS="-stdlib=libc++"
-DCMAKE_EXE_LINKER_FLAGS="-lc++abi"
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD}
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD}
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_libcxx_cxx${CXX_STANDARD}
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_libcxx_cxx${CXX_STANDARD}
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_libcxx_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with Clang for C++${CXX_STANDARD} (libc++)"
)
endforeach()
@@ -276,6 +278,20 @@ add_custom_target(ci_test_disableenumserialization
COMMENT "Compile and test with enum serialization disabled"
)
###############################################################################
# Disable conversion from a one-element tuple of a JSON reference.
###############################################################################
add_custom_target(ci_test_disabletuplereferenceconversion
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_DisableTupleReferenceConversion=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion
COMMAND cd ${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with tuple reference conversion disabled"
)
###############################################################################
# Skip the multiple-inclusion library version check.
###############################################################################
@@ -362,22 +378,29 @@ add_custom_target(ci_test_clang_sanitizer
# Check if header is amalgamated and sources are properly indented.
###############################################################################
# Same file set as .github/workflows/check_amalgamation.yml, so a direct push to develop/master/release/*
# (which only this CMake target checks, not the pull_request-only workflow) is held to the same standard.
file(GLOB_RECURSE INDENT_FILES
${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp
${PROJECT_SOURCE_DIR}/tests/src/*.cpp
${PROJECT_SOURCE_DIR}/tests/src/*.hpp
${PROJECT_SOURCE_DIR}/tests/benchmarks/src/benchmarks.cpp
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.hpp
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cpp
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cu
${PROJECT_SOURCE_DIR}/include/*.hpp
${PROJECT_SOURCE_DIR}/include/*.cpp
${PROJECT_SOURCE_DIR}/include/*.cu
${PROJECT_SOURCE_DIR}/tests/*.hpp
${PROJECT_SOURCE_DIR}/tests/*.cpp
${PROJECT_SOURCE_DIR}/tests/*.cu
)
list(FILTER INDENT_FILES EXCLUDE REGEX "/tests/thirdparty/|/tests/abi/include/nlohmann/")
set(include_dir ${PROJECT_SOURCE_DIR}/single_include/nlohmann)
set(tool_dir ${PROJECT_SOURCE_DIR}/tools/amalgamate)
add_custom_target(ci_test_amalgamation
COMMAND rm -fr ${include_dir}/json.hpp~ ${include_dir}/json_fwd.hpp~ ${include_dir}/json_literals.hpp~ ${include_dir}/json_view.hpp~
COMMAND rm -fr ${include_dir}/json.hpp~ ${include_dir}/json_fwd.hpp~ ${include_dir}/json_literals.hpp~
COMMAND cp ${include_dir}/json.hpp ${include_dir}/json.hpp~
COMMAND cp ${include_dir}/json_fwd.hpp ${include_dir}/json_fwd.hpp~
COMMAND cp ${include_dir}/json_literals.hpp ${include_dir}/json_literals.hpp~
COMMAND cp ${include_dir}/json_view.hpp ${include_dir}/json_view.hpp~
COMMAND cp ${PROJECT_SOURCE_DIR}/BUILD.bazel ${PROJECT_SOURCE_DIR}/BUILD.bazel~
COMMAND ${Python3_EXECUTABLE} -mvenv venv_astyle
COMMAND venv_astyle/bin/pip3 --quiet install -r ${CMAKE_SOURCE_DIR}/tools/astyle/requirements.txt
@@ -386,19 +409,19 @@ add_custom_target(ci_test_amalgamation
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json.json -s .
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_fwd.json -s .
COMMAND cp ${PROJECT_SOURCE_DIR}/include/nlohmann/json_literals.hpp ${include_dir}/json_literals.hpp
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_view.json -s .
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp ${include_dir}/json_view.hpp
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp
COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/scripts/gen_bazel_build_file.cmake
COMMAND diff ${include_dir}/json.hpp~ ${include_dir}/json.hpp
COMMAND diff ${include_dir}/json_fwd.hpp~ ${include_dir}/json_fwd.hpp
COMMAND diff ${include_dir}/json_literals.hpp~ ${include_dir}/json_literals.hpp
COMMAND diff ${include_dir}/json_view.hpp~ ${include_dir}/json_view.hpp
COMMAND diff ${PROJECT_SOURCE_DIR}/BUILD.bazel~ ${PROJECT_SOURCE_DIR}/BUILD.bazel
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=orig ${INDENT_FILES}
COMMAND for FILE in `find . -name '*.orig'`\; do false \; done
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Check amalgamation and indentation"
COMMENT "Check amalgamation, formatting, and BUILD.bazel"
)
###############################################################################
@@ -433,14 +456,14 @@ add_custom_target(ci_test_valgrind
# Check code with Clang Static Analyzer.
###############################################################################
set(CLANG_ANALYZER_CHECKS "fuchsia.HandleChecker,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,optin.cplusplus.UninitializedObject,optin.cplusplus.VirtualCall,optin.mpi.MPI-Checker,optin.osx.OSObjectCStyleCast,optin.osx.cocoa.localizability.EmptyLocalizationContextChecker,optin.osx.cocoa.localizability.NonLocalizedStringChecker,optin.performance.GCDAntipattern,optin.performance.Padding,optin.portability.UnixAPI,security.FloatLoopCounter,security.insecureAPI.DeprecatedOrUnsafeBufferHandling,security.insecureAPI.bcmp,security.insecureAPI.bcopy,security.insecureAPI.bzero,security.insecureAPI.rand,security.insecureAPI.strcpy,valist.CopyToSelf,valist.Uninitialized,valist.Unterminated,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,core.CallAndMessage,core.DivideZero,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.VLASize,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.PlacementNew,cplusplus.PureVirtualCall,deadcode.DeadStores,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,osx.API,osx.MIG,osx.NumberObjectConversion,osx.OSObjectRetainCount,osx.ObjCProperty,osx.SecKeychainAPI,osx.cocoa.AtSync,osx.cocoa.AutoreleaseWrite,osx.cocoa.ClassRelease,osx.cocoa.Dealloc,osx.cocoa.IncompatibleMethodTypes,osx.cocoa.Loops,osx.cocoa.MissingSuperCall,osx.cocoa.NSAutoreleasePool,osx.cocoa.NSError,osx.cocoa.NilArg,osx.cocoa.NonNilReturnValue,osx.cocoa.ObjCGenerics,osx.cocoa.RetainCount,osx.cocoa.RunLoopAutoreleaseLeak,osx.cocoa.SelfInit,osx.cocoa.SuperDealloc,osx.cocoa.UnusedIvars,osx.cocoa.VariadicMethodTypes,osx.coreFoundation.CFError,osx.coreFoundation.CFNumber,osx.coreFoundation.CFRetainRelease,osx.coreFoundation.containers.OutOfBounds,osx.coreFoundation.containers.PointerSizedValues,security.insecureAPI.UncheckedReturn,security.insecureAPI.decodeValueOfObjCType,security.insecureAPI.getpw,security.insecureAPI.gets,security.insecureAPI.mkstemp,security.insecureAPI.mktemp,security.insecureAPI.vfork,unix.API,unix.Malloc,unix.MallocSizeof,unix.MismatchedDeallocator,unix.Vfork,unix.cstring.BadSizeArg,unix.cstring.NullArg")
set(CLANG_ANALYZER_CHECKS "nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,optin.cplusplus.UninitializedObject,optin.cplusplus.VirtualCall,optin.performance.Padding,optin.portability.UnixAPI,security.FloatLoopCounter,security.insecureAPI.DeprecatedOrUnsafeBufferHandling,security.insecureAPI.bcmp,security.insecureAPI.bcopy,security.insecureAPI.bzero,security.insecureAPI.rand,security.insecureAPI.strcpy,valist.CopyToSelf,valist.Uninitialized,valist.Unterminated,core.CallAndMessage,core.DivideZero,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.VLASize,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.PlacementNew,cplusplus.PureVirtualCall,deadcode.DeadStores,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,security.insecureAPI.UncheckedReturn,security.insecureAPI.decodeValueOfObjCType,security.insecureAPI.getpw,security.insecureAPI.gets,security.insecureAPI.mkstemp,security.insecureAPI.mktemp,security.insecureAPI.vfork,unix.API,unix.Malloc,unix.MallocSizeof,unix.MismatchedDeallocator,unix.Vfork,unix.cstring.BadSizeArg,unix.cstring.NullArg")
add_custom_target(ci_clang_analyze
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_analyze
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_analyze && ${SCAN_BUILD_TOOL} -enable-checker ${CLANG_ANALYZER_CHECKS} --use-c++=${CLANG_TOOL} -analyze-headers -o ${PROJECT_BINARY_DIR}/report ninja
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_analyze && ${SCAN_BUILD_TOOL} -enable-checker ${CLANG_ANALYZER_CHECKS} --use-c++=${CLANG_TOOL} --use-analyzer=${CLANG_TOOL} -analyze-headers --status-bugs -o ${PROJECT_BINARY_DIR}/report ninja
COMMENT "Check code with Clang Analyzer"
)
@@ -456,7 +479,7 @@ add_custom_target(ci_cppcheck
COMMAND venv_cppcheck/bin/cppcheck --enable=warning --check-level=exhaustive --inline-suppr --inconclusive --force
--std=c++11 ${PROJECT_SOURCE_DIR}/include/nlohmann/json.hpp -I ${CMAKE_SOURCE_DIR}/include
--error-exitcode=1 --relative-paths=${PROJECT_SOURCE_DIR} -j ${N} --include=default_defines.hpp
--cppcheck-build-dir=cppcheck --check-level=exhaustive
--cppcheck-build-dir=cppcheck
-UJSON_CATCH_USER -UJSON_TRY_USER -UJSON_ASSERT -UJSON_INTERNAL_CATCH -UJSON_THROW
-DJSON_HAS_CPP_11 -UJSON_HAS_CPP_14 -UJSON_HAS_CPP_17 -UJSON_HAS_CPP_20 -UJSON_HAS_THREE_WAY_COMPARISON
COMMENT "Check code with Cppcheck"
@@ -474,34 +497,6 @@ add_custom_target(ci_cpplint
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
###############################################################################
# Check code with OCLint.
###############################################################################
file(COPY ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp DESTINATION ${PROJECT_BINARY_DIR}/src_single)
file(RENAME ${PROJECT_BINARY_DIR}/src_single/json.hpp ${PROJECT_BINARY_DIR}/src_single/all.cpp)
file(APPEND "${PROJECT_BINARY_DIR}/src_single/all.cpp" "\n\nint main()\n{}\n")
add_executable(single_all ${PROJECT_BINARY_DIR}/src_single/all.cpp)
target_compile_features(single_all PRIVATE cxx_std_11)
add_custom_target(ci_oclint
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DJSON_BuildTests=OFF -DJSON_CI=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_oclint
COMMAND ${OCLINT_TOOL} -i ${PROJECT_BINARY_DIR}/build_oclint/src_single/all.cpp -p ${PROJECT_BINARY_DIR}/build_oclint --
-report-type html -enable-global-analysis --max-priority-1=0 --max-priority-2=1000 --max-priority-3=2000
--disable-rule=MultipleUnaryOperator
--disable-rule=DoubleNegative
--disable-rule=ShortVariableName
--disable-rule=GotoStatement
--disable-rule=LongLine
-o ${PROJECT_BINARY_DIR}/build_oclint/oclint_report.html
COMMENT "Check code with OCLint"
)
###############################################################################
# Check code with Clang-Tidy.
###############################################################################
@@ -516,29 +511,16 @@ add_custom_target(ci_clang_tidy
COMMENT "Check code with Clang-Tidy"
)
###############################################################################
# Check code with PVS-Studio Analyzer <https://www.viva64.com/en/pvs-studio/>.
###############################################################################
add_custom_target(ci_pvs_studio
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DJSON_BuildTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_pvs_studio
COMMAND cd ${PROJECT_BINARY_DIR}/build_pvs_studio && ${PVS_STUDIO_ANALYZER_TOOL} analyze -j 10
COMMAND cd ${PROJECT_BINARY_DIR}/build_pvs_studio && ${PLOG_CONVERTER_TOOL} -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
COMMENT "Check code with PVS Studio"
)
###############################################################################
# Check code with Infer <https://fbinfer.com> static analyzer.
###############################################################################
# .inferconfig (repository root) pins --fail-on-issue and the currently-triaged issue types that
# are disabled until they are addressed separately; see #5715 item 4b.
add_custom_target(ci_infer
COMMAND mkdir -p ${PROJECT_BINARY_DIR}/build_infer
COMMAND cd ${PROJECT_BINARY_DIR}/build_infer && ${INFER_TOOL} compile -- ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${PROJECT_SOURCE_DIR} -DJSON_BuildTests=ON
COMMAND cd ${PROJECT_BINARY_DIR}/build_infer && ${INFER_TOOL} run -- make
COMMAND cd ${PROJECT_BINARY_DIR}/build_infer && ${INFER_TOOL} run --project-root ${PROJECT_SOURCE_DIR} -- make
COMMENT "Check code with Infer"
)
@@ -594,7 +576,13 @@ add_custom_target(ci_reproducible_tests
# be compiled individually.
###############################################################################
set(iwyu_path_and_options ${IWYU_TOOL} -Xiwyu --max_line_length=300)
set(iwyu_options -Xiwyu --error -Xiwyu --max_line_length=300)
set(iwyu_path_and_options ${IWYU_TOOL} ${iwyu_options})
# CMake needs to know the exact flags used to compile each src_single/*.cpp below to hand them to
# iwyu_tool.py; JSON_CI already implies a from-scratch configure, so enabling this project-wide has
# no downside here.
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
foreach(SRC_FILE ${SRC_FILES})
# get relative path of the header file
@@ -609,14 +597,34 @@ foreach(SRC_FILE ${SRC_FILES})
target_include_directories(single_${RELATIVE_SRC_FILE} PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_features(single_${RELATIVE_SRC_FILE} PRIVATE cxx_std_11)
set_property(TARGET single_${RELATIVE_SRC_FILE} PROPERTY CXX_INCLUDE_WHAT_YOU_USE "${iwyu_path_and_options}")
# remember binary for ci_single_binaries target
# remember binary for ci_single_binaries
list(APPEND single_binaries single_${RELATIVE_SRC_FILE})
# json.hpp pulls together the whole library behind heavily templated, SFINAE-based code, and
# IWYU's suggestion for its one truly ambiguous symbol (a container-comparison "swap,
# operator!=") is not deterministic between runs (observed <set>, <unordered_map>, and <map>
# for the exact same source across otherwise-identical local and containerized builds). Keep
# reporting its diagnostics (informational, via CXX_INCLUDE_WHAT_YOU_USE above) but exclude it
# from the hard gate below so a fresh IWYU/compiler combination does not fail this target on a
# nondeterministic suggestion for a header that already re-exports everything on purpose.
if(NOT RELATIVE_SRC_FILE STREQUAL "json")
list(APPEND single_binaries_tus src_single/${RELATIVE_SRC_FILE}.cpp)
endif()
endforeach()
add_custom_target(ci_single_binaries
DEPENDS ${single_binaries}
COMMENT "Check if headers are self-contained"
)
if(IWYU_TOOL_PY)
add_custom_target(ci_single_binaries
DEPENDS ${single_binaries}
COMMAND ${IWYU_TOOL_PY} -p ${PROJECT_BINARY_DIR} ${single_binaries_tus} -- ${iwyu_options}
COMMENT "Check if headers are self-contained"
)
else()
# iwyu_tool.py (ships with IWYU, e.g. as /usr/bin/iwyu_tool on Debian/Ubuntu) was not found;
# fall back to building the self-containment check without enforcing the IWYU findings.
add_custom_target(ci_single_binaries
DEPENDS ${single_binaries}
COMMENT "Check if headers are self-contained"
)
endif()
###############################################################################
# Benchmarks
@@ -638,21 +646,41 @@ add_custom_target(ci_benchmarks
# we test the project with different CMake versions:
# - CMake 3.5 (the earliest supported)
# - CMake 3.31.6 (the latest 3.x release)
# - CMake 4.0.0 (the latest release)
# - CMake 4.0.0 (the first 4.x release)
# - the CMake version running this build (usually the latest release)
function(ci_get_cmake version var)
set(${var} ${PROJECT_BINARY_DIR}/cmake-${version}/bin/cmake)
add_custom_command(
OUTPUT ${${var}}
COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}.tar.gz
COMMAND tar xfz cmake-${version}.tar.gz
COMMAND rm cmake-${version}.tar.gz
# -DCMAKE_POLICY_VERSION_MINIMUM=3.5 required to compile older CMake versions with CMake 4.0.0
COMMAND cmake -S cmake-${version} -B cmake-${version} -DCMAKE_POLICY_VERSION_MINIMUM=3.5
COMMAND cmake --build cmake-${version} --parallel 10
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Download CMake ${version}"
)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64)$")
# Kitware publishes a prebuilt Linux x86_64 archive for every release; unpacking it is far
# cheaper than compiling all of CMake (including its own test helpers) from source.
add_custom_command(
OUTPUT ${${var}}
COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}-linux-x86_64.tar.gz
COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}-SHA-256.txt
# verify the archive against Kitware's published SHA-256 sums before unpacking it
COMMAND sh -c "grep ' cmake-${version}-linux-x86_64[.]tar[.]gz$' cmake-${version}-SHA-256.txt | sha256sum -c -"
COMMAND tar xfz cmake-${version}-linux-x86_64.tar.gz
COMMAND rm cmake-${version}-linux-x86_64.tar.gz cmake-${version}-SHA-256.txt
COMMAND ${CMAKE_COMMAND} -E rm -rf cmake-${version}
COMMAND ${CMAKE_COMMAND} -E rename cmake-${version}-linux-x86_64 cmake-${version}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Download prebuilt CMake ${version}"
)
else()
# no prebuilt archive for this platform (e.g. macOS or Linux aarch64): build from source
add_custom_command(
OUTPUT ${${var}}
COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}.tar.gz
COMMAND tar xfz cmake-${version}.tar.gz
COMMAND rm cmake-${version}.tar.gz
# -DCMAKE_POLICY_VERSION_MINIMUM=3.5 required to compile older CMake versions with CMake 4.0.0
COMMAND cmake -S cmake-${version} -B cmake-${version} -DCMAKE_POLICY_VERSION_MINIMUM=3.5
COMMAND cmake --build cmake-${version} --parallel 10
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Download and build CMake ${version} from source"
)
endif()
set(${var} ${${var}} PARENT_SCOPE)
endfunction()
@@ -662,30 +690,24 @@ ci_get_cmake(4.0.0 CMAKE_4_0_0_BINARY)
# the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0
set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization
JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind)
set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_31_6})
JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind
JSON_StrictNulHandling)
set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
function(ci_add_cmake_flags_targets flag min_version)
string(TOLOWER "ci_cmake_flag_${flag}" flag_target)
string(REPLACE . _ min_version_var ${min_version})
set(cmake_binary ${CMAKE_${min_version_var}_BINARY})
add_custom_target(${flag_target}_${min_version}_2
COMMENT "Check CMake flag ${flag} (CMake ${CMAKE_VERSION})"
COMMAND ${CMAKE_COMMAND}
-Werror=dev
-D${flag}=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_${flag_target}
)
add_custom_target(${flag_target}_${min_version_var}
COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake ${min_version})"
COMMENT "Check CMake flag ${flag} (CMake ${min_version})"
COMMAND mkdir -pv ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var}
COMMAND cd ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var}
&& ${cmake_binary} -Werror=dev ${PROJECT_SOURCE_DIR} -D${flag}=ON
DEPENDS ${cmake_binary}
)
list(APPEND JSON_CMAKE_FLAG_TARGETS ${JSON_CMAKE_FLAG_TARGET} ${flag_target}_${min_version_var})
list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${flag_target} ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var})
list(APPEND JSON_CMAKE_FLAG_TARGETS ${flag_target}_${min_version_var})
list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var})
set(JSON_CMAKE_FLAG_TARGETS ${JSON_CMAKE_FLAG_TARGETS} PARENT_SCOPE)
set(JSON_CMAKE_FLAG_BUILD_DIRS ${JSON_CMAKE_FLAG_BUILD_DIRS} PARENT_SCOPE)
endfunction()
@@ -702,6 +724,20 @@ foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_4_0_0})
ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 4.0.0)
endforeach()
# check the same flags with the CMake version running this build
foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_4_0_0})
string(TOLOWER "ci_cmake_flag_${JSON_CMAKE_FLAG}" flag_target)
add_custom_target(${flag_target}
COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake ${CMAKE_VERSION})"
COMMAND ${CMAKE_COMMAND}
-Werror=dev
-D${JSON_CMAKE_FLAG}=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_${flag_target}
)
list(APPEND JSON_CMAKE_FLAG_TARGETS ${flag_target})
list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${flag_target})
endforeach()
add_custom_target(ci_cmake_flags
DEPENDS ${JSON_CMAKE_FLAG_TARGETS}
COMMENT "Check CMake flags"
@@ -860,6 +896,6 @@ add_custom_target(ci_test_build_documentation
###############################################################################
add_custom_target(ci_clean
COMMAND rm -fr ${PROJECT_BINARY_DIR}/build_* cmake-3.5.0-Darwin64 ${JSON_CMAKE_FLAG_BUILD_DIRS} ${single_binaries}
COMMAND rm -fr ${PROJECT_BINARY_DIR}/build_* ${PROJECT_BINARY_DIR}/cmake-3.5.0 ${PROJECT_BINARY_DIR}/cmake-3.31.6 ${PROJECT_BINARY_DIR}/cmake-4.0.0 ${JSON_CMAKE_FLAG_BUILD_DIRS} ${single_binaries}
COMMENT "Clean generated directories"
)
-1
View File
@@ -48,7 +48,6 @@ cc_library(
name = "singleheader-json",
hdrs = [
"single_include/nlohmann/json.hpp",
"single_include/nlohmann/json_view.hpp",
],
includes = ["single_include"],
visibility = ["//visibility:public"],
+16 -5
View File
@@ -11,20 +11,31 @@ EXAMPLES = $(wildcard mkdocs/docs/examples/*.cpp)
cxx_standard = $(lastword c++11 $(filter c++%, $(subst ., ,$1)))
# common compile flags for the stand-alone example files
EXAMPLE_CPPFLAGS = -I $(SRCDIR) -DJSON_USE_GLOBAL_UDLS=0
EXAMPLE_WARNFLAGS = -Werror=deprecated-declarations
# examples that document deprecated API and are allowed to use it
DEPRECATED_EXAMPLES = $(addprefix mkdocs/docs/examples/, \
json_pointer__operator__equal_stringtype \
json_pointer__operator__notequal_stringtype \
json_pointer__operator_string_t)
$(DEPRECATED_EXAMPLES:=.output) $(DEPRECATED_EXAMPLES:=.test): EXAMPLE_WARNFLAGS = -Wno-deprecated-declarations
# create output from a stand-alone example file
%.output: %.cpp
@echo "standard $(call cxx_standard $(<:.cpp=))"
@echo "standard $(call cxx_standard,$(<:.cpp=))"
$(MAKE) $(<:.cpp=) \
CPPFLAGS="-I $(SRCDIR) -DJSON_USE_GLOBAL_UDLS=0" \
CXXFLAGS="-std=$(call cxx_standard,$(<:.cpp=)) -Wno-deprecated-declarations"
CPPFLAGS="$(EXAMPLE_CPPFLAGS)" \
CXXFLAGS="-std=$(call cxx_standard,$(<:.cpp=)) $(EXAMPLE_WARNFLAGS)"
./$(<:.cpp=) > $@
rm $(<:.cpp=)
# compare created output with current output of the example files
%.test: %.cpp
$(MAKE) $(<:.cpp=) \
CPPFLAGS="-I $(SRCDIR) -DJSON_USE_GLOBAL_UDLS=0" \
CXXFLAGS="-std=$(call cxx_standard,$(<:.cpp=)) -Wno-deprecated-declarations"
CPPFLAGS="$(EXAMPLE_CPPFLAGS)" \
CXXFLAGS="-std=$(call cxx_standard,$(<:.cpp=)) $(EXAMPLE_WARNFLAGS)"
./$(<:.cpp=) > $@
diff $@ $(<:.cpp=.output)
rm $(<:.cpp=) $@
+1 -1
View File
@@ -13,7 +13,7 @@
<key>dashIndexFilePath</key>
<string>index.html</string>
<key>DashDocSetFallbackURL</key>
<string>https://nlohmann.github.io/json/</string>
<string>https://json.nlohmann.me/</string>
<key>isJavaScriptEnabled</key>
<true/>
</dict>
+12 -22
View File
@@ -52,35 +52,25 @@ install_docset_zeal: JSON_for_Modern_C++.docset
mkdir -p $$docset_root; \
cp -r JSON_for_Modern_C++.docset $$docset_root/
# both targets below compare the docset search index with the mkdocs page
# set. They share the same normalization (docs/foo/index.md and
# docs/foo.md both become foo/index.html, the URL mkdocs itself would
# give the page; the top-level index.md is excluded, as it is not part
# of the hand-curated docSet.sql) and use comm(1) on two sorted lists
# instead of running a sqlite3 query, or an O(n*m) nested shell loop,
# once per page.
DOCSET_INDEX_PATHS=$(shell sqlite3 docSet.dsidx "SELECT DISTINCT path FROM searchIndex" | sort)
DOCSET_PAGE_PATHS=$(shell echo '$(MKDOCS_PAGES)' | tr ' ' '\n' | grep -v '^index\.md$$' | $(SED) -E 's@/index\.md$$@/index.html@; s@\.md$$@/index.html@' | sort)
# list mkdocs pages missing from the docset index
.PHONY: list_missing_pages
list_missing_pages: docSet.dsidx
@for page in $(MKDOCS_PAGES); do \
case "$$page" in \
*/index.md) path=$${page/\/index.md/} ;; \
*) path=$${page/.md/} ;; \
esac; \
if [ "x$$page" != "xindex.md" -a "x$$(sqlite3 docSet.dsidx "SELECT COUNT(*) FROM searchIndex WHERE path='$$path/index.html'")" = "x0" ]; then \
echo $$page; \
fi \
done
@comm -23 <(echo '$(DOCSET_PAGE_PATHS)' | tr ' ' '\n') <(echo '$(DOCSET_INDEX_PATHS)' | tr ' ' '\n')
# list paths in the docset index without a corresponding mkdocs page
.PHONY: list_removed_paths
list_removed_paths: docSet.dsidx
@for path in $$(sqlite3 docSet.dsidx "SELECT path FROM searchIndex"); do \
page=$${path/\/index.html/.md}; \
page_index=$${path/index.html/index.md}; \
page_found=0; \
for p in $(MKDOCS_PAGES); do \
if [ "x$$p" = "x$$page" -o "x$$p" = "x$$page_index" ]; then \
page_found=1; \
fi \
done; \
if [ "x$$page_found" = "x0" ]; then \
echo $$path; \
fi \
done
@comm -13 <(echo '$(DOCSET_PAGE_PATHS)' | tr ' ' '\n') <(echo '$(DOCSET_INDEX_PATHS)' | tr ' ' '\n')
.PHONY: clean
clean:
+3 -2
View File
@@ -7,10 +7,11 @@ documentation browsers like [Dash](https://kapeli.com/dash), [Velocity](https://
The docset can be created with
```sh
make nlohmann_json.docset
make JSON_for_Modern_C++.docset
```
The generated folder `nlohmann_json.docset` can then be opened in the documentation browser.
The generated folder `JSON_for_Modern_C++.docset` can then be opened in the documentation browser. `make all` builds a
`JSON_for_Modern_C++.tgz` archive instead, and `make install_docset_zeal` installs the docset for Zeal directly.
A recent version is also part of the [Dash user contributions](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B).
+1 -74
View File
@@ -128,74 +128,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_ubjson', 'Func
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::value', 'Method', 'api/basic_json/value/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::value_t', 'Enum', 'api/basic_json/value_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::~basic_json', 'Method', 'api/basic_json/~basic_json/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document', 'Class', 'api/basic_json_document/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::basic_json_document', 'Constructor', 'api/basic_json_document/basic_json_document/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::accept', 'Function', 'api/basic_json_document/accept/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::erase', 'Method', 'api/basic_json_document/erase/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::insert', 'Method', 'api/basic_json_document/insert/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::is_discarded', 'Method', 'api/basic_json_document/is_discarded/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::load', 'Function', 'api/basic_json_document/load/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::memory_usage', 'Method', 'api/basic_json_document/memory_usage/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::node_count', 'Method', 'api/basic_json_document/node_count/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::owns_source', 'Method', 'api/basic_json_document/owns_source/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::parse', 'Function', 'api/basic_json_document/parse/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::parse_copy', 'Function', 'api/basic_json_document/parse_copy/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::push_back', 'Method', 'api/basic_json_document/push_back/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::read', 'Method', 'api/basic_json_document/read/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::root', 'Method', 'api/basic_json_document/root/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::save', 'Method', 'api/basic_json_document/save/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::set', 'Method', 'api/basic_json_document/set/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::shrink_to_fit', 'Method', 'api/basic_json_document/shrink_to_fit/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::source', 'Method', 'api/basic_json_document/source/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view', 'Class', 'api/basic_json_view/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::basic_json_view', 'Constructor', 'api/basic_json_view/basic_json_view/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::at', 'Method', 'api/basic_json_view/at/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::back', 'Method', 'api/basic_json_view/back/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::begin', 'Method', 'api/basic_json_view/begin/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::cbegin', 'Method', 'api/basic_json_view/cbegin/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::cend', 'Method', 'api/basic_json_view/cend/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::contains', 'Method', 'api/basic_json_view/contains/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::count', 'Method', 'api/basic_json_view/count/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::dump', 'Method', 'api/basic_json_view/dump/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::empty', 'Method', 'api/basic_json_view/empty/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::end', 'Method', 'api/basic_json_view/end/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::find', 'Method', 'api/basic_json_view/find/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::front', 'Method', 'api/basic_json_view/front/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::get', 'Method', 'api/basic_json_view/get/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::get_string', 'Method', 'api/basic_json_view/get_string/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::get_to', 'Method', 'api/basic_json_view/get_to/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_array', 'Method', 'api/basic_json_view/is_array/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_binary', 'Method', 'api/basic_json_view/is_binary/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_boolean', 'Method', 'api/basic_json_view/is_boolean/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_discarded', 'Method', 'api/basic_json_view/is_discarded/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_null', 'Method', 'api/basic_json_view/is_null/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_number', 'Method', 'api/basic_json_view/is_number/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_number_float', 'Method', 'api/basic_json_view/is_number_float/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_number_integer', 'Method', 'api/basic_json_view/is_number_integer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_number_unsigned', 'Method', 'api/basic_json_view/is_number_unsigned/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_object', 'Method', 'api/basic_json_view/is_object/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_primitive', 'Method', 'api/basic_json_view/is_primitive/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_string', 'Method', 'api/basic_json_view/is_string/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_structured', 'Method', 'api/basic_json_view/is_structured/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::items', 'Method', 'api/basic_json_view/items/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::materialize', 'Method', 'api/basic_json_view/materialize/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::number_format', 'Enum', 'api/basic_json_view/number_format/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::number_token', 'Method', 'api/basic_json_view/number_token/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::operator bool', 'Method', 'api/basic_json_view/operator_bool/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::operator<<', 'Operator', 'api/basic_json_view/operator_ltlt/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::operator[]', 'Operator', 'api/basic_json_view/operator[]/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::operator==', 'Operator', 'api/basic_json_view/operator_eq/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::operator!=', 'Operator', 'api/basic_json_view/operator_ne/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::size', 'Method', 'api/basic_json_view/size/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::source_offset', 'Method', 'api/basic_json_view/source_offset/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::type', 'Method', 'api/basic_json_view/type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::type_name', 'Method', 'api/basic_json_view/type_name/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::value', 'Method', 'api/basic_json_view/value/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json', 'Class', 'api/json/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_document', 'Class', 'api/json_document/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_editable_document', 'Class', 'api/json_editable_document/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_editable_view', 'Class', 'api/json_editable_view/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_view', 'Class', 'api/json_view/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer', 'Class', 'api/json_pointer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::back', 'Method', 'api/json_pointer/back/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::empty', 'Method', 'api/json_pointer/empty/index.html');
@@ -229,10 +162,6 @@ INSERT INTO searchIndex(name, type, path) VALUES ('operator""_json_pointer', 'Li
INSERT INTO searchIndex(name, type, path) VALUES ('operator<<', 'Operator', 'api/operator_ltlt/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('operator>>', 'Operator', 'api/operator_gtgt/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json', 'Class', 'api/ordered_json/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json_document', 'Class', 'api/ordered_json_document/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json_editable_document', 'Class', 'api/ordered_json_editable_document/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json_editable_view', 'Class', 'api/ordered_json_editable_view/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json_view', 'Class', 'api/ordered_json_view/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map', 'Class', 'api/ordered_map/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('std::hash<basic_json>', 'Class', 'api/basic_json/std_hash/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('std::swap<basic_json>', 'Function', 'api/basic_json/std_swap/index.html');
@@ -262,7 +191,6 @@ INSERT INTO searchIndex(name, type, path) VALUES ('Iterators', 'Guide', 'feature
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Merge Patch', 'Guide', 'features/merge_patch/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Patch and Diff', 'Guide', 'features/json_patch/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Pointer', 'Guide', 'features/json_pointer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Zero-copy JSON views', 'Guide', 'features/json_view/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('nlohmann Namespace', 'Guide', 'features/namespace/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Types', 'Guide', 'features/types/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Types: Number Handling', 'Guide', 'features/types/number_handling/index.html');
@@ -282,6 +210,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'a
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'api/macros/json_disable_enum_serialization/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_TUPLE_REFERENCE_CONVERSION', 'Macro', 'api/macros/json_disable_tuple_reference_conversion/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_11', 'Macro', 'api/macros/json_has_cpp_11/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_14', 'Macro', 'api/macros/json_has_cpp_11/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_17', 'Macro', 'api/macros/json_has_cpp_11/index.html');
@@ -317,5 +246,3 @@ INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM'
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MAJOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MINOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_PATCH', 'Macro', 'api/macros/nlohmann_json_version_major/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_VIEW_NO_SIMD', 'Macro', 'api/macros/json_view_no_simd/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_VIEW_USE_SSSE3', 'Macro', 'api/macros/json_view_use_ssse3/index.html');
-1
View File
@@ -219,7 +219,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
- documentation on [checked access](../../features/element_access/checked_access.md)
- [`operator[]`](operator%5B%5D.md) for unchecked access by reference
- [`value`](value.md) for access with default value
- [basic_json_view::at](../basic_json_view/at.md) - the same access on a zero-copy view
## Version history
-1
View File
@@ -58,7 +58,6 @@ Constant.
## See also
- [front](front.md) to access the first element
- [basic_json_view::back](../basic_json_view/back.md) - the same access on a zero-copy view
## Version history
@@ -159,6 +159,8 @@ basic_json(basic_json&& other) noexcept;
- `CompatibleType` is not `basic_json` (to avoid hijacking copy/move constructors),
- `CompatibleType` is not a different `basic_json` type (i.e. with different template arguments)
- `CompatibleType` is not a `basic_json` nested type (e.g., `json_pointer`, `iterator`, etc.)
- if [`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../macros/json_disable_tuple_reference_conversion.md) is defined
to `1`: `CompatibleType` is not a one-element `std::tuple` holding a reference to `basic_json`
- `json_serializer<U>` (with `U = uncvref_t<CompatibleType>`) has a `to_json(basic_json_t&, CompatibleType&&)`
method
-6
View File
@@ -37,12 +37,6 @@ Constant.
--8<-- "examples/begin.output"
```
## See also
- [end](end.md) - returns an iterator to one past the last element
- [basic_json_view::begin](../basic_json_view/begin.md) - the same iteration on a zero-copy view (in document order,
not sorted by key)
## Version history
- Added in version 1.0.0.
@@ -36,11 +36,6 @@ Constant.
--8<-- "examples/cbegin.output"
```
## See also
- [cend](cend.md) - returns a const iterator to one past the last element
- [basic_json_view::cbegin](../basic_json_view/cbegin.md) - the same iteration on a zero-copy view
## Version history
- Added in version 1.0.0.
-5
View File
@@ -36,11 +36,6 @@ Constant.
--8<-- "examples/cend.output"
```
## See also
- [cbegin](cbegin.md) - returns a const iterator to the first element
- [basic_json_view::cend](../basic_json_view/cend.md) - the same iteration on a zero-copy view
## Version history
- Added in version 1.0.0.
@@ -115,7 +115,6 @@ Logarithmic in the size of the JSON object.
- [find](find.md) find a value in an object
- [count](count.md) returns the number of occurrences of a key
- [basic_json_view::contains](../basic_json_view/contains.md) - the same check on a zero-copy view
## Version history
-1
View File
@@ -80,7 +80,6 @@ Logarithmic in the size of the JSON object.
- [find](find.md) find a value in an object
- [contains](contains.md) checks whether a key exists
- [basic_json_view::count](../basic_json_view/count.md) - the same check on a zero-copy view
## Version history
-7
View File
@@ -60,9 +60,6 @@ Linear.
## Notes
Floating-point numbers are written with the fewest digits that read back as the same value (for `#!cpp double`; see
[number handling](../../features/types/number_handling.md#number-serialization)).
Binary values are serialized as an object containing two keys:
- "bytes": an array of bytes as integers
@@ -89,8 +86,6 @@ 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
- [`basic_json_view::dump`](../basic_json_view/dump.md) the corresponding function of `basic_json_view`, serializing
directly from a flat index without building a `basic_json` value
- [Serialization](../../features/serialization.md) - the serialization article
## Version history
@@ -99,5 +94,3 @@ Binary values are serialized as an object containing two keys:
- Indentation character `indent_char`, option `ensure_ascii` and exceptions added in version 3.0.0.
- Error handlers added in version 3.4.0.
- Serialization of binary values added in version 3.8.0.
- Doubles are written with the shortest digits (Żmij instead of Grisu2) since version 3.13.0; about 0.1% of doubles are
written differently, most of them with fewer digits.
-4
View File
@@ -60,10 +60,6 @@ itself is empty which is `#!cpp false` in the case of a string.
--8<-- "examples/empty.output"
```
## See also
- [basic_json_view::empty](../basic_json_view/empty.md) - the same check on a zero-copy view
## Version history
- Added in version 1.0.0.
-5
View File
@@ -37,11 +37,6 @@ Constant.
--8<-- "examples/end.output"
```
## See also
- [begin](begin.md) - returns an iterator to the first element
- [basic_json_view::end](../basic_json_view/end.md) - the same iteration on a zero-copy view
## Version history
- Added in version 1.0.0.
-1
View File
@@ -84,7 +84,6 @@ Logarithmic in the size of the JSON object.
- [count](count.md) returns the number of occurrences of a key
- [contains](contains.md) checks whether a key exists
- [basic_json_view::find](../basic_json_view/find.md) - the same lookup on a zero-copy view
## Version history
-1
View File
@@ -51,7 +51,6 @@ Constant.
## See also
- [back](back.md) to access the last element
- [basic_json_view::front](../basic_json_view/front.md) - the same access on a zero-copy view
## Version history
-2
View File
@@ -163,8 +163,6 @@ overload (3).
- [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
- [basic_json_view::get](../basic_json_view/get.md) - the same conversion on a zero-copy view (many types are
converted without ever building a `basic_json` value)
## Version history
@@ -61,8 +61,6 @@ Constant.
## See also
- [get_ptr()](get_ptr.md) get a pointer value
- [basic_json_view::get_string](../basic_json_view/get_string.md) - the closest counterpart on a zero-copy view: a
string without a copy, but as a view rather than a reference to a value that must already exist
## Version history
@@ -67,7 +67,6 @@ Depends on the `json_serializer<ValueType>::from_json()` implementation.
- [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
- [basic_json_view::get_to](../basic_json_view/get_to.md) - the same conversion on a zero-copy view
## Version history
@@ -34,10 +34,6 @@ Constant.
--8<-- "examples/is_array.output"
```
## See also
- [basic_json_view::is_array](../basic_json_view/is_array.md) - the same check on a zero-copy view
## Version history
- Added in version 1.0.0.
@@ -34,10 +34,6 @@ Constant.
--8<-- "examples/is_binary.output"
```
## See also
- [basic_json_view::is_binary](../basic_json_view/is_binary.md) - the same check on a zero-copy view
## Version history
- Added in version 3.8.0.
@@ -34,10 +34,6 @@ Constant.
--8<-- "examples/is_boolean.output"
```
## See also
- [basic_json_view::is_boolean](../basic_json_view/is_boolean.md) - the same check on a zero-copy view
## Version history
- Added in version 1.0.0.
@@ -69,11 +69,6 @@ with `allow_exceptions` set to `#!cpp false`: a parse error then yields a discar
--8<-- "examples/is_discarded.output"
```
## See also
- [basic_json_view::is_discarded](../basic_json_view/is_discarded.md) - the corresponding check on a zero-copy view,
which is `#!cpp true` if the view refers to no value
## Version history
- Added in version 1.0.0.
@@ -34,10 +34,6 @@ Constant.
--8<-- "examples/is_null.output"
```
## See also
- [basic_json_view::is_null](../basic_json_view/is_null.md) - the same check on a zero-copy view
## Version history
- Added in version 1.0.0.
@@ -49,7 +49,6 @@ constexpr bool is_number() const noexcept
- [is_number_integer()](is_number_integer.md) check if the value is an integer or unsigned integer number
- [is_number_unsigned()](is_number_unsigned.md) check if the value is an unsigned integer number
- [is_number_float()](is_number_float.md) check if the value is a floating-point number
- [basic_json_view::is_number](../basic_json_view/is_number.md) - the same check on a zero-copy view
## Version history
@@ -40,7 +40,6 @@ Constant.
- [is_number()](is_number.md) check if the value is a number
- [is_number_integer()](is_number_integer.md) check if the value is an integer or unsigned integer number
- [is_number_unsigned()](is_number_unsigned.md) check if the value is an unsigned integer number
- [basic_json_view::is_number_float](../basic_json_view/is_number_float.md) - the same check on a zero-copy view
## Version history
@@ -40,7 +40,6 @@ Constant.
- [is_number()](is_number.md) check if the value is a number
- [is_number_unsigned()](is_number_unsigned.md) check if the value is an unsigned integer number
- [is_number_float()](is_number_float.md) check if the value is a floating-point number
- [basic_json_view::is_number_integer](../basic_json_view/is_number_integer.md) - the same check on a zero-copy view
## Version history
@@ -40,7 +40,6 @@ Constant.
- [is_number()](is_number.md) check if the value is a number
- [is_number_integer()](is_number_integer.md) check if the value is an integer or unsigned integer number
- [is_number_float()](is_number_float.md) check if the value is a floating-point number
- [basic_json_view::is_number_unsigned](../basic_json_view/is_number_unsigned.md) - the same check on a zero-copy view
## Version history
@@ -34,10 +34,6 @@ Constant.
--8<-- "examples/is_object.output"
```
## See also
- [basic_json_view::is_object](../basic_json_view/is_object.md) - the same check on a zero-copy view
## Version history
- Added in version 1.0.0.
@@ -62,7 +62,6 @@ This library extends primitive types to binary types, because binary types are r
- [is_boolean()](is_boolean.md) returns whether the JSON value is a boolean
- [is_number()](is_number.md) returns whether the JSON value is a number
- [is_binary()](is_binary.md) returns whether the JSON value is a binary array
- [basic_json_view::is_primitive](../basic_json_view/is_primitive.md) - the same check on a zero-copy view
## Version history
@@ -34,10 +34,6 @@ Constant.
--8<-- "examples/is_string.output"
```
## See also
- [basic_json_view::is_string](../basic_json_view/is_string.md) - the same check on a zero-copy view
## Version history
- Added in version 1.0.0.
@@ -57,7 +57,6 @@ Note that though strings are containers in C++, they are treated as primitive va
- [is_primitive()](is_primitive.md) returns whether JSON value is primitive
- [is_array()](is_array.md) returns whether the value is an array
- [is_object()](is_object.md) returns whether the value is an object
- [basic_json_view::is_structured](../basic_json_view/is_structured.md) - the same check on a zero-copy view
## Version history
-2
View File
@@ -99,8 +99,6 @@ When iterating over an array, `key()` will return the index of the element as st
- [begin](begin.md) returns an iterator to the first element
- [end](end.md) returns an iterator to one past the last element
- [basic_json_view::items](../basic_json_view/items.md) - the same range on a zero-copy view (`#!cpp const auto`,
not `#!cpp const auto&`: items are produced on the fly)
## Version history
@@ -37,6 +37,12 @@ Thereby, `Target` is the current object; that is, the patch is applied to the cu
Linear in the lengths of `apply_patch`.
## Notes
`apply_patch` may be `#!cpp *this` itself or refer to a value contained in `#!cpp *this` (for example, a subobject
returned by `#!cpp (*this)[key]`); it is read as it was when `merge_patch()` was called, before any modification of
`#!cpp *this`.
## Examples
??? example
@@ -61,3 +67,5 @@ Linear in the lengths of `apply_patch`.
## Version history
- Added in version 3.0.0.
- Fixed use of freed or relocated memory when `apply_patch` is `#!cpp *this` or refers to a value contained in
`#!cpp *this`, in version 3.13.0.
@@ -23,10 +23,9 @@ type to use.
## Template parameters
`NumberFloatType`
: the type to store floating-point numbers. The parser converts `#!cpp float`, `#!cpp double`, and a
`#!cpp long double` that is IEEE 754 binary64 itself and other `#!cpp long double` formats with
`#!cpp std::from_chars` or `#!cpp std::strtold`, and serialization falls back to `#!cpp std::snprintf`, so the
type must be `#!cpp float`, `#!cpp double`, or `#!cpp long double`. The
: the type to store floating-point numbers. Parsing and serialization are implemented in terms of
`#!cpp std::strtof`/`#!cpp std::strtod`/`#!cpp std::strtold` and `#!cpp std::snprintf`, so the type must be
`#!cpp float`, `#!cpp double`, or `#!cpp long double`. The
[binary formats](../../features/binary_formats/index.md) additionally require `#!cpp float` or `#!cpp double`,
because they have no encoding for `#!cpp long double`. See
[Template Parameter Requirements](../../features/types/template_parameters.md#numberfloattype).
@@ -51,7 +51,7 @@ range will yield over/underflow when used in a constructor. During deserializati
will automatically be stored as [`number_unsigned_t`](number_unsigned_t.md) or [`number_float_t`](number_float_t.md).
[RFC 8259](https://tools.ietf.org/html/rfc8259) further states:
> Note that when such software is used, numbers that are integers and are in the range $[-2^{53}+1, 2^{53}-1]$ are
> Note that when such software is used, numbers that are integers and are in the range [-2<sup>53</sup>+1, 2<sup>53</sup>-1] are
> interoperable in the sense that implementations will agree exactly on their numeric values.
As this range is a subrange of the exactly supported range [INT64_MIN, INT64_MAX], this class's integer type is
@@ -52,7 +52,7 @@ when used in a constructor. During deserialization, too large or small integer n
as [`number_integer_t`](number_integer_t.md) or [`number_float_t`](number_float_t.md).
[RFC 8259](https://tools.ietf.org/html/rfc8259) further states:
> Note that when such software is used, numbers that are integers and are in the range $[-2^{53}+1, 2^{53}-1]$ are
> Note that when such software is used, numbers that are integers and are in the range [-2<sup>53</sup>+1, 2<sup>53</sup>-1] are
> interoperable in the sense that implementations will agree exactly on their numeric values.
As this range is a subrange (when considered in conjunction with the `number_integer_t` type) of the exactly supported
@@ -257,8 +257,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
- documentation on [runtime assertions](../../features/assertions.md)
- see [`at`](at.md) for access by reference with range checking
- see [`value`](value.md) for access with default value
- [basic_json_view::operator[]](../basic_json_view/operator%5B%5D.md) - the same access on a zero-copy view (always
returns a discarded view instead of assuming undefined behavior)
## Version history
@@ -166,8 +166,6 @@ Linear.
- [operator!=](operator_ne.md) compare for inequality
- [operator<=>](operator_spaceship.md) comparison: 3-way (C++20)
- [basic_json_view::operator==](../basic_json_view/operator_eq.md) - the same comparison on a zero-copy view, without
building a `basic_json` value for it
## Version history
@@ -89,12 +89,6 @@ Linear.
--8<-- "examples/operator__notequal__nullptr_t.output"
```
## See also
- [operator==](operator_eq.md) compare for equality
- [basic_json_view::operator!=](../basic_json_view/operator_ne.md) - the same comparison on a zero-copy view, without
building a `basic_json` value for it
## Version history
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
@@ -54,7 +54,7 @@ classDiagram
## Notes
For an input with $n$ bytes, 1 is the index of the first character and $n+1$ is the index of the terminating null byte
For an input with <i>n</i> bytes, 1 is the index of the first character and <i>n</i>+1 is the index of the terminating null byte
or the end of file. This also holds true when reading a byte vector for binary formats.
## Examples
-4
View File
@@ -51,10 +51,6 @@ JSON value which is `1` in the case of a string.
--8<-- "examples/size.output"
```
## See also
- [basic_json_view::size](../basic_json_view/size.md) - the same function on a zero-copy view
## Version history
- Added in version 1.0.0.
-4
View File
@@ -47,10 +47,6 @@ Constant.
--8<-- "examples/type.output"
```
## See also
- [basic_json_view::type](../basic_json_view/type.md) - the same function on a zero-copy view
## Version history
- Added in version 1.0.0.
@@ -52,11 +52,6 @@ Constant.
--8<-- "examples/type_name.output"
```
## See also
- [type](type.md) - return the type of the JSON value
- [basic_json_view::type_name](../basic_json_view/type_name.md) - the same function on a zero-copy view
## Version history
- Added in version 1.0.0.
@@ -59,6 +59,12 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value
1. O(N*log(size() + N)), where N is the number of elements to insert.
2. O(N*log(size() + N)), where N is the number of elements to insert.
## Notes
The argument `j` (or, for overload (2), the range `[first, last)`) may be `#!cpp *this` itself or refer to a value
contained in `#!cpp *this` (for example, a subobject returned by `#!cpp (*this)[key]`); it is read as it was when
`update()` was called, before any modification of `#!cpp *this`.
## Examples
??? example
@@ -155,3 +161,5 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value
- Added in version 3.0.0.
- Added `merge_objects` parameter in 3.10.5.
- Fixed use of freed or relocated memory when the argument is `#!cpp *this` or refers to a value contained in
`#!cpp *this`, in version 3.13.0.
-1
View File
@@ -189,7 +189,6 @@ changes to any JSON value.
- see [`at`](at.md) for access by reference with range checking
- see [`operator[]`](operator%5B%5D.md) for unchecked access by reference
- [basic_json_view::value](../basic_json_view/value.md) - the same access on a zero-copy view
## Version history
@@ -1,67 +0,0 @@
# <small>nlohmann::basic_json_document::</small>accept
```cpp
template<typename InputType>
static bool accept(InputType&& input,
const bool ignore_comments = false,
const bool ignore_trailing_commas = false);
```
Checks whether the input is valid JSON, accepting and rejecting exactly what
[`BasicJsonType::accept()`](../basic_json/accept.md) does, with the same options. Unlike [`parse()`](parse.md), this
function never throws an exception for invalid input, and the returned `#!cpp bool` is the only result -- no document
is returned.
## Template parameters
`InputType`
: A compatible input; see [`parse`](parse.md#template-parameters).
## Parameters
`input` (in)
: Input to check.
`ignore_comments` (in)
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
(`#!cpp false`); (optional, `#!cpp false` by default)
`ignore_trailing_commas` (in)
: whether trailing commas in arrays or objects should be ignored and treated like whitespace (`#!cpp true`) or
yield a parse error (`#!cpp false`); (optional, `#!cpp false` by default)
## Return value
Whether the input is valid JSON.
## Exception safety
Strong guarantee: this function itself never throws for an invalid input; it can only throw what allocating the
input's own copy (for inputs that are always read into a buffer) throws.
## Complexity
Linear in the length of the input.
## Examples
??? example
```cpp
--8<-- "examples/basic_json_document__accept.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__accept.output"
```
## See also
- [parse](parse.md) - deserialize from a compatible input
- [`BasicJsonType::accept`](../basic_json/accept.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,58 +0,0 @@
# <small>nlohmann::basic_json_document::</small>basic_json_document
```cpp
// (1)
basic_json_document() = default;
// (2)
basic_json_document(basic_json_document&& other) noexcept = default;
// (3)
basic_json_document(const basic_json_document&) = delete;
```
1. Creates an empty (discarded) document: [`root()`](root.md) returns a discarded view, and
[`is_discarded()`](is_discarded.md) is `#!cpp true`.
2. Move constructor. Takes over `other`'s index and, if owned, its text; `other` is left as an empty document. Views
taken from `other` before the move remain valid, because the index is heap-allocated independently of the
`basic_json_document` object.
3. `basic_json_document` is move-only. Copying is disabled because it would either duplicate a potentially large index
and text, or leave two documents claiming to borrow the same buffer.
## Parameters
`other` (in)
: another document to move the index and text from
## Exception safety
No-throw guarantee: the default and move constructors never throw exceptions.
## Complexity
Constant, for the default and move constructors.
## Examples
??? example
The example below shows the default constructor and demonstrates that `basic_json_document` is move-only.
```cpp
--8<-- "examples/basic_json_document__basic_json_document.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__basic_json_document.output"
```
## See also
- [parse](parse.md) - deserialize from a compatible input
- [is_discarded](is_discarded.md) - return whether the last parse failed
## Version history
- Added in version 3.13.0.
@@ -1,128 +0,0 @@
# <small>nlohmann::basic_json_document::</small>erase
```cpp
// (1)
std::size_t erase(view_type object, string_view_t key);
// (2)
template<typename I>
void erase(view_type array, I idx);
// (3)
std::size_t erase(const json_pointer& ptr);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
has `erase`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
1. Removes every member of `object` whose key is `key` (see [Notes](#notes) on duplicate keys) and returns how many
were removed; `#!cpp 0` if `object` has no member with this key.
2. Removes the element at index `idx` of `array`, which must already exist (`#!cpp idx < array.size()`).
3. Removes the value the JSON pointer `ptr` refers to, relative to [`root()`](root.md), and returns how many values
were removed: the *parent* of the target must already exist, and the target itself is removed as in 1. (an object
member; `#!cpp 0` or more) or 2. (an array element; always `#!cpp 1`). `ptr` must not be empty -- [`root()`](root.md)
itself cannot be erased.
## Template parameters
`I`
: an integral type other than `#!cpp bool`, deduced (overloads taking a `#!cpp bool` or a non-integral type for
`idx` do not participate in overload resolution).
## Parameters
`object` (in)
: the object to remove a member of
`array` (in)
: the array to remove an element of
`key` (in)
: the key of the member(s) to remove
`idx` (in)
: the index of the element to remove; a negative value throws (see [Exceptions](#exceptions))
`ptr` (in)
: a JSON pointer to the value to remove, relative to `root()`
## Return value
1. the number of removed members (`#!cpp 0` if `object` had none with this `key`)
2. (nothing)
3. the number of removed values (`#!cpp 0` or more for an object member, always `#!cpp 1` for an array element)
## Exceptions
1. Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) if `object` is not an object -- the
same message [`BasicJsonType::erase`](../basic_json/erase.md) throws for the same type.
2. Throws `type_error.307` if `array` is not an array. Throws
[`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `idx` is negative, or if
`#!cpp idx >= array.size()`.
3. Throws [`out_of_range.405`](../../home/exceptions.md#jsonexceptionout_of_range405) ("JSON pointer has no parent")
if `ptr` is empty. Throws what [`at`](../basic_json_view/at.md) throws (overload 3) for resolving `ptr`'s parent.
For the last reference token itself: if the parent is an array, throws what 2. throws for an index that is out of
range, or, for a token that is not a valid array index,
[`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) (a leading `#!cpp '0'`),
[`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) (not a number),
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) (too large for `size_type`), or
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) (an empty token); otherwise (an
object, or a primitive value the pointer's parent resolves to) throws what 1. throws.
Every overload also throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view
does not belong to this document") if `object`/`array` is a [discarded](../basic_json_view/is_discarded.md) view or a
view of a *different* document (overloads 1-2 only; overload 3 always starts from this document's own
[`root()`](root.md)).
## Complexity
1. Linear in the number of members of `object`.
2. Linear in the number of elements of `array` at or after `idx` (they move one slot over).
3. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
that level or the index into the array (as [`at`](../basic_json_view/at.md)), plus the complexity of 1. or 2. for
the last token.
## Notes
!!! info "Duplicate keys"
Overload 1. removes *every* member with `key`, not just the first -- unlike [`set`](set.md), which assigns the
first occurrence and drops the rest. This is why it returns a count rather than a single view: there may be
more than one member removed, or none.
Like [`set`](set.md) and [`push_back`](push_back.md), `erase` never moves an element's *value*: a view still
referring to a removed member or element keeps showing what it last held (see [Edits](index.md#edits)) -- it just no
longer appears when `array`/`object` is read, dumped, or iterated. Removing an element of `array` (2.) does shift the
*links* to the elements after it, the same way `insert`, `set`, or `push_back` on the same array would; any iterator
already taken over `array`/`object` is invalidated by an erase, since it was walking the old layout.
## Examples
??? example
The example below drops a deprecated field and a decommissioned entry from a configuration document -- using all
three overloads -- and shows what stays intact that would not with a plain `json`/`ordered_json` value: the order
of the fields around the ones removed, and the exact spelling of a number that was never touched.
```cpp
--8<-- "examples/basic_json_document__erase.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__erase.output"
```
## See also
- [insert](insert.md) - insert an element into an array
- [set](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers to
- [push_back](push_back.md) - append to an array
- [root](root.md) - the view of the root value, the starting point of overload 3
- [`BasicJsonType::erase`](../basic_json/erase.md) - the corresponding function of `basic_json`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
## Version history
- Added in version 3.13.0.
@@ -1,118 +0,0 @@
# <small>nlohmann::</small>basic_json_document
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
template<typename BasicJsonType, bool Editable = false>
class basic_json_document;
```
A parsed JSON text, held as a flat index of its values
([16 bytes per value](../../home/architecture.md#node-index-of-json-views)) instead of a tree of `BasicJsonType` values.
Strings and numbers stay in the source text; only strings that contain escapes are decoded, into one buffer owned by
the document. [`basic_json_view`](../basic_json_view/index.md) is a read-only handle to one value of a
`basic_json_document`; [`materialize()`](../basic_json_view/materialize.md) turns a subtree back into the
`BasicJsonType` value that [`BasicJsonType::parse()`](../basic_json/parse.md) would have produced for it.
A document may **borrow** the text it was parsed from (the caller's buffer must then outlive the document) or **own**
it (a copy, or an rvalue `#!cpp std::string` that was moved in); see [`owns_source`](owns_source.md). `basic_json_document`
is move-only: copying a document would either duplicate a potentially large index and text, or leave two documents
claiming to borrow the same buffer, so it is disabled.
With `#!cpp Editable == true`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
[`insert`](insert.md), and [`erase`](erase.md) to change values in place, see [Edits](#edits) below. The source text
itself is never written; a read-only document (`#!cpp Editable == false`, the default) does not carry any of the
bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp static_assert`).
## Template parameters
`BasicJsonType`
: a specialization of [`basic_json`](../basic_json/index.md), for instance [`json`](../json.md) or
[`ordered_json`](../ordered_json.md). Only 64-bit `number_integer_t`/`number_unsigned_t` types are supported; this
is checked with a `static_assert`.
`Editable`
: whether the document supports [`set`](set.md), [`push_back`](push_back.md), [`insert`](insert.md), and
[`erase`](erase.md) (optional, `#!cpp false` by default). See [Edits](#edits) below.
## Specializations
- [**json_document**](../json_document.md) - read-only documents of the default specialization [`json`](../json.md)
- [**ordered_json_document**](../ordered_json_document.md) - read-only documents of
[`ordered_json`](../ordered_json.md)
- [**json_editable_document**](../json_editable_document.md) - editable documents of [`json`](../json.md)
- [**ordered_json_editable_document**](../ordered_json_editable_document.md) - editable documents of
[`ordered_json`](../ordered_json.md)
## Member types
- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view<BasicJsonType, Editable>`)
- **value_t** - the JSON type enumeration, see [`basic_json::value_t`](../basic_json/value_t.md)
## Member functions
- [(constructor)](basic_json_document.md)
### Parsing
- [**parse**](parse.md) (_static_) - deserialize from a compatible input, borrowing or owning it as appropriate
- [**parse_copy**](parse_copy.md) (_static_) - deserialize a copy of a compatible input
- [**accept**](accept.md) (_static_) - check whether the input is valid JSON
- [**read**](read.md) - (re-)parse into this document, reusing its memory
### Access
- [**root**](root.md) - the view of the root value
- [**is_discarded**](is_discarded.md) - return whether the last parse failed
- [**source**](source.md) - the parsed text
- [**owns_source**](owns_source.md) - return whether the document holds its own copy of the text
- [**node_count**](node_count.md) - the number of index entries (values plus object keys)
- [**memory_usage**](memory_usage.md) - the number of bytes held by the document
- [**shrink_to_fit**](shrink_to_fit.md) - release unused index capacity
### Images
- [**save**](save.md) - the document as an image that `load()` reads without parsing
- [**load**](load.md) (_static_) - read an image written by `save()`
### Edits
- [**set**](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers
to (`#!cpp Editable` documents only)
- [**push_back**](push_back.md) - append to an array (`#!cpp Editable` documents only)
- [**insert**](insert.md) - insert an element into an array before a given position (`#!cpp Editable` documents only)
- [**erase**](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
(`#!cpp Editable` documents only)
## Edits
An editable document (`#!cpp Editable == true`) can be changed after parsing, with [`set`](set.md),
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md);
[`json_editable_document`](../json_editable_document.md) and
[`ordered_json_editable_document`](../ordered_json_editable_document.md) are the corresponding specializations. A few
points apply to every edit:
- **The source text is never written**, and the parsed index never moves: every value keeps the node it was parsed
into, so [views](../basic_json_view/index.md) taken before an edit stay valid, including
[`root()`](root.md). New values (and the element sequences of an edited array/object) go to storage owned by the
document, allocated on demand.
- **A view keeps referring to the same value.** After [`set`](set.md) replaces the value a view refers to, that view
sees the new value; a view of a value that a later edit replaces or drops keeps showing what it last held. An edit
of an array or object, however, **invalidates the iterators taken over it** (its members may now live in a
different sequence), and a string obtained with [`get_string()`](../basic_json_view/get_string.md) stays valid even
as further edits happen (earlier buffers of edited text are kept alive, not overwritten).
- **Values are accepted three ways:** a [`basic_json_view`](../basic_json_view/index.md) of *any* document
(read-only or editable; it is copied, nothing is shared with the source document), a `BasicJsonType` value, or
anything `BasicJsonType` can be constructed from (numbers, strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
- [`dump()`](../basic_json_view/dump.md) writes an edited document with members in document order, new members at
the end, and, with [`number_format::source`](../basic_json_view/number_format.md), keeps the spelling of every
number that was not itself edited -- see [Editing a document](../../features/json_view.md#editing-a-document) for
why this matters.
- [`read()`](read.md) discards all edits, [`shrink_to_fit()`](shrink_to_fit.md) does not move the node index once
there are edits, and [`memory_usage()`](memory_usage.md) includes the memory edits use.
[`source_offset()`](../basic_json_view/source_offset.md) of a value introduced by an edit is
`#!cpp static_cast<std::size_t>(-1)`, the same value it reports for a decoded string.
## Version history
- Added in version 3.13.0.
@@ -1,114 +0,0 @@
# <small>nlohmann::basic_json_document::</small>insert
```cpp
template<typename I, typename V>
view_type insert(view_type array, I idx, V&& value);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
has `insert`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
Inserts `value` into `array` as a new element before position `idx`, which must not be past the end
(`#!cpp idx <= array.size()`; `#!cpp idx == array.size()` appends, like [`push_back`](push_back.md)). Unlike
[`push_back`](push_back.md), a [null](../basic_json_view/is_null.md) `array` does *not* first become an empty array:
`array` must already be an array.
`value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any* document -- read-only or
editable, and it does not have to be `array`'s own document -- which is copied so that nothing is shared with the
source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
## Template parameters
`I`
: an integral type other than `#!cpp bool`, deduced (overloads taking a `#!cpp bool` or a non-integral type for
`idx` do not participate in overload resolution).
`V`
: the type of `value`, deduced; see above for what is accepted.
## Parameters
`array` (in)
: the array to insert into
`idx` (in)
: the position to insert `value` before; a negative value throws (see [Exceptions](#exceptions))
`value` (in)
: the value to insert
## Return value
a view of the new element, now holding `value`
## Exception safety
Basic exception safety: `value` is fully encoded -- including the checks below -- into storage owned by the document
before anything already reachable from [`root()`](root.md) is touched, so a failure while encoding `value` (an
invalid argument, or `#!cpp std::bad_alloc`) leaves the document completely unchanged, other than memory allocated
for the encoding that is not reclaimed. A failure of a later allocation -- while `array` switches from its parsed
layout to a growable block, or while that block grows, see [Notes](#notes) -- can still leave `array` already
switched to that layout even though `value` itself was not inserted.
## Exceptions
Throws [`type_error.309`](../../home/exceptions.md#jsonexceptiontype_error309) if `array` is not an array -- the same
message [`BasicJsonType::insert`](../basic_json/insert.md) throws for the same type; a null `array` throws this too
(see above). Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `idx` is negative,
or if `#!cpp idx > array.size()`. Throws
[`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view does not belong to this
document") if `array` is a [discarded](../basic_json_view/is_discarded.md) view or a view of a *different* document.
Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `value` is a
[discarded](../basic_json_view/is_discarded.md) view or a [discarded](../basic_json/is_discarded.md) `BasicJsonType`
value, and [`type_error.319`](../../home/exceptions.md#jsonexceptiontype_error319) if `value` is (or contains) a
binary value -- `BasicJsonType` can hold one, but a `json_document` cannot. Throws
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if `value` is (or contains) a string that is
not valid UTF-8, with the same message [`BasicJsonType::dump()`](../basic_json/dump.md) gives for that string.
## Complexity
Linear in the number of elements of `array` at or after `idx` (they move one slot over), plus time linear in the
size of `value` to encode it into the document's storage (constant for a scalar, linear in the number of nested
values for an array or object): like [`push_back`](push_back.md), the elements of `array` move to a growable block
of links the first time it is inserted into (or [`set`](set.md)/[`push_back`](push_back.md) on), and that block
grows in amortized constant time; inserting before the end within that block still shifts every later element.
## Notes
Like [`set`](set.md) on a member or an element, `insert` never moves an existing *element's value* -- only where
`array`'s *links* to its elements live -- so a view of an existing element of `array` stays valid across an
`insert`, and keeps referring to the same element even though its index shifts. Any iterator already taken over
`array` is invalidated, since it was walking the old layout. See [Edits](index.md#edits) for what stays valid across
an edit in general.
## Examples
??? example
The example below inserts a step into the middle of a deployment plan, without touching the steps that come
after it, and shows that a view taken before the insert keeps referring to the same element even though its
index shifts -- something a plain `json`/`ordered_json` array, or its `std::vector`-based storage, has no
equivalent for.
```cpp
--8<-- "examples/basic_json_document__insert.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__insert.output"
```
## See also
- [push_back](push_back.md) - append to an array
- [erase](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
- [set](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers to
- [`BasicJsonType::insert`](../basic_json/insert.md) - the corresponding function of `basic_json`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
## Version history
- Added in version 3.13.0.
@@ -1,49 +0,0 @@
# <small>nlohmann::basic_json_document::</small>is_discarded
```cpp
bool is_discarded() const noexcept;
```
Returns whether the document holds no value, either because it was default-constructed or because the last call to
[`parse()`](parse.md), [`parse_copy()`](parse_copy.md), or [`read()`](read.md) failed with `allow_exceptions` set to
`#!cpp false`.
## Return value
`#!cpp true` if the document is discarded, `#!cpp false` otherwise.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
When the document is discarded, [`root()`](root.md) returns a discarded view (its
[`is_discarded()`](../basic_json_view/is_discarded.md) is also `#!cpp true`).
## Examples
??? example
```cpp
--8<-- "examples/basic_json_document__is_discarded.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__is_discarded.output"
```
## See also
- [parse](parse.md) - deserialize from a compatible input
- [is_discarded (basic_json_view)](../basic_json_view/is_discarded.md) - return whether a view is invalid
## Version history
- Added in version 3.13.0.
@@ -1,169 +0,0 @@
# <small>nlohmann::basic_json_document::</small>load
```cpp
// (1)
static basic_json_document load(const std::uint8_t* image, std::size_t size,
const image_check check = image_check::full);
// (2)
static basic_json_document load(const std::vector<std::uint8_t>& image,
const image_check check = image_check::full);
// (3)
static basic_json_document load(std::vector<std::uint8_t>&& image,
const image_check check = image_check::full);
```
1. Reads an image [`save()`](save.md) wrote, from a pointer and a byte count. The image is **borrowed**: `image`
must stay alive and unchanged for as long as the returned document, and any view taken from it, is used.
2. Reads an image from a `#!cpp std::vector`. Also **borrowed** -- equivalent to overload 1 called with
`#!cpp image.data()` and `#!cpp image.size()`.
3. Reads an image, keeping the vector instead of copying it: `image` is moved into the document (no copy), which
then owns it for as long as it needs the text and the decoded strings. [`owns_source()`](owns_source.md) is
`#!cpp true` afterward.
In every overload, the node index is copied into storage the document itself owns -- so that it is properly aligned,
and, for an [editable](index.md#edits) document, can be edited -- while the text and the decoded strings stay in
`image`. The hash indexes [large objects](../../features/json_view.md) use for lookup are rebuilt, exactly as after
parsing.
## Parameters
`image` (in)
: the image [`save()`](save.md) wrote (overloads 1 and 2), or one to take ownership of (overload 3)
`size` (in)
: the number of bytes at `image` (overload 1)
`check` (in)
: how thoroughly to validate `image` before trusting it; see [`image_check`](#image_check) below (optional,
`#!cpp image_check::full` by default)
## Return value
The document read from the image.
## Exception safety
Overloads 1 and 2 give the strong guarantee: `image` is only read, never written, so a thrown exception leaves the
caller's buffer untouched.
Overload 3 moves `image` into the document *before* validating it, so that a good image is kept without a copy. If
loading then fails, the partially built document -- and the vector now inside it -- is discarded along with the
exception, and `image` itself is left **empty**, not restored to what was passed in. Move a copy in instead, or
validate with overload 2 first, if the original vector must survive a failed load.
## Exceptions
On a big-endian target, throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) -- the same
exception [`save()`](save.md#exceptions) throws there, since the image format is little-endian only.
Otherwise throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
`save()` could have written, or fails the requested `check`:
| message | when |
|------------------------|------------------------------------------------------------------------------------------------------|
| `too short` | `image` is `#!cpp nullptr`, or `size` is smaller than the 64-byte header |
| `unknown format` | the header's magic bytes or version do not match, or a reserved header field is not zero |
| `sizes out of range` | the node count, text size, or decoded-string size the header describes does not fit `size`, or the `#!cpp '\0'` after the text or after the decoded strings is missing |
| `the check failed` | `check` is not `#!cpp image_check::none`, and the image fails it -- see [`image_check`](#image_check) |
!!! failure "Example messages"
```
[json.exception.parse_error.116] parse error: invalid json_document image: too short
```
```
[json.exception.parse_error.116] parse error: invalid json_document image: unknown format
```
```
[json.exception.parse_error.116] parse error: invalid json_document image: sizes out of range
```
```
[json.exception.parse_error.116] parse error: invalid json_document image: the check failed
```
## Complexity
Linear in the number of nodes, which are always copied into the document. With `#!cpp check == image_check::full`,
additionally linear in the combined length of the text and the decoded strings; `#!cpp image_check::bounds` and
`#!cpp image_check::none` do not read them.
## `image_check`
```cpp
using image_check = detail::view::image_check;
enum class image_check
{
full,
bounds,
none
};
```
How thoroughly `load()` validates `image` before trusting it.
| value | checks | guarantees |
|----------|--------------------------------------------------------------------------------------------------------------|------------|
| `full` | everything the parser itself guarantees: structure and bounds; that every string is valid UTF-8 (and, for a string still in the source text, that it contains no quote, backslash, or control character); and that every number token is well-formed and matches the value stored for it | reading and serializing a checked image is safe and always produces valid JSON, exactly as for a parsed document |
| `bounds` | structure and bounds only -- that every offset and count in the node index stays inside the image | reading and serializing stay memory-safe, but a crafted image can hold strings that are not valid UTF-8 or that serialize to invalid JSON ([`dump()`](../basic_json_view/dump.md) writes them unchanged or throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316)), and numbers whose values differ from their text |
| `none` | nothing | images from a trusted source only -- reading a damaged image is undefined behavior |
`full` is the default and the right choice for an image from anything you do not fully control -- a file, a cache
shared with other processes, a peer on the network. `bounds` skips scanning the text and the decoded strings, so it
fits a cache your own process just wrote and reads straight back, where damage would mean a bug or a hardware fault
rather than adversarial input; it still cannot crash or read out of bounds. `none` skips validation entirely and
should only be used for an image you trust as much as your own memory.
## Notes
**Lifetime.** Overloads 1 and 2 borrow `image`: it must stay alive and byte-for-byte unchanged for as long as the
returned document, and any [view](../basic_json_view/index.md) taken from it, is used -- exactly like a document
[`parse()`](parse.md) borrowed its input for. Overload 3 avoids this by keeping the vector itself; see
[`owns_source`](owns_source.md).
!!! warning "Experimental"
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
stable; `load()` already rejects an image written by a different format version with `parse_error.116`
("unknown format"). Use images to cache a document within one build of the library, or to hand one to another
process running the *same* build on the *same* (little-endian) machine -- not as a long-term storage format.
**What `image_check::bounds` does not guarantee.** A bounds-checked image can never make `load()`,
[`root()`](root.md), element access, or [`materialize()`](../basic_json_view/materialize.md) read outside the image,
so those stay safe on a damaged one. It does *not* guarantee that the image describes valid JSON: a string
that a `full` check would have rejected can make [`dump()`](../basic_json_view/dump.md) write invalid UTF-8 or invalid
JSON, or throw `type_error.316`, and a number can read back with a value that does not match how it is spelled. Reserve `bounds` for images you already trust to be well-formed, and use it
only to skip the extra scan.
## Examples
??? example "Caching a document, ownership, and a rejected image"
The example below saves a parsed document as an image, checks that `load()` reproduces the original
[`dump()`](../basic_json_view/dump.md) without parsing, and shows the difference between
`load(std::move(image))` (owned) and `load(image)` (borrowed). It then damages one byte of the image and shows
`image_check::full` rejecting it with `parse_error.116`, while `image_check::bounds` -- meant for a cache the
process already trusts -- still reads it without going out of bounds.
```cpp
--8<-- "examples/basic_json_document__load.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__load.output"
```
## See also
- [save](save.md) - write the document as an image
- [owns_source](owns_source.md) - return whether the document holds its own copy of the text
- [parse](parse.md) - deserialize from JSON text instead of an image
- [Images](../../features/json_view.md#images) - why and when to use images
## Version history
- Added in version 3.13.0.
@@ -1,50 +0,0 @@
# <small>nlohmann::basic_json_document::</small>memory_usage
```cpp
std::size_t memory_usage() const noexcept;
```
Returns the number of bytes held by the document: the node index, the decoded-string buffer (for strings that
contain escapes), and, for an owned document, its copy of the source text.
## Return value
The number of bytes the document holds, `0` for a [discarded](is_discarded.md) document.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
The exact value depends on the platform, the allocator, and the library's own layout, and may change between
versions; do not rely on it being a specific number, and do not compare it across different builds or platforms.
Compare it for the same document over time, or between documents built with the same binary, instead -- for instance
to observe the effect of [`shrink_to_fit()`](shrink_to_fit.md).
## Examples
??? example
```cpp
--8<-- "examples/basic_json_document__memory_usage.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__memory_usage.output"
```
## See also
- [node_count](node_count.md) - the number of index entries
- [shrink_to_fit](shrink_to_fit.md) - release unused index capacity
## Version history
- Added in version 3.13.0.
@@ -1,49 +0,0 @@
# <small>nlohmann::basic_json_document::</small>node_count
```cpp
std::size_t node_count() const noexcept;
```
Returns the number of entries in the document's flat index.
## Return value
The number of index entries: one per value (of any type, at any nesting depth) plus one per object key. `0` for a
[discarded](is_discarded.md) document.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
Each index entry is [16 bytes](../../home/architecture.md#node-index-of-json-views), so `#!cpp node_count() * 16` is
the size of the index itself (part, but not all, of [`memory_usage()`](memory_usage.md), which also counts decoded
strings and, for an owned document, the text).
## Examples
??? example
```cpp
--8<-- "examples/basic_json_document__node_count.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__node_count.output"
```
## See also
- [memory_usage](memory_usage.md) - the number of bytes held by the document
- [shrink_to_fit](shrink_to_fit.md) - release unused index capacity
## Version history
- Added in version 3.13.0.
@@ -1,49 +0,0 @@
# <small>nlohmann::basic_json_document::</small>owns_source
```cpp
bool owns_source() const noexcept;
```
Returns whether the document holds its own copy of the parsed text, as opposed to borrowing the caller's buffer.
## Return value
`#!cpp true` if the document owns the text returned by [`source()`](source.md), `#!cpp false` if it borrows it (or if
the document is [discarded](is_discarded.md)).
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
See the ownership table on [`parse`](parse.md#notes) for which inputs are borrowed and which are owned. A borrowed
document (`#!cpp owns_source() == false`) is only valid while the buffer it was parsed from is still alive.
## Examples
??? example
```cpp
--8<-- "examples/basic_json_document__owns_source.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__owns_source.output"
```
## See also
- [parse](parse.md) - deserialize from a compatible input
- [parse_copy](parse_copy.md) - deserialize a copy of a compatible input, always owned
- [source](source.md) - the parsed text
## Version history
- Added in version 3.13.0.
@@ -1,140 +0,0 @@
# <small>nlohmann::basic_json_document::</small>parse
```cpp
// (1)
template<typename InputType>
static basic_json_document parse(InputType&& input,
const bool allow_exceptions = true,
const bool ignore_comments = false,
const bool ignore_trailing_commas = false);
// (2)
template<typename IteratorType>
static basic_json_document parse(IteratorType first, IteratorType last,
const bool allow_exceptions = true,
const bool ignore_comments = false,
const bool ignore_trailing_commas = false);
```
1. Deserialize from a compatible input, borrowing or owning it depending on its value category and type (see Notes).
2. Deserialize from a pair of input iterators.
Both overloads accept exactly what [`BasicJsonType::parse()`](../basic_json/parse.md) accepts, with the same
`ignore_comments`/`ignore_trailing_commas` options, but build a [`basic_json_document`](index.md) (a flat index into
the input) instead of a tree of `BasicJsonType` values.
## Template parameters
`InputType`
: A compatible input, for instance:
- a `#!cpp std::string`, `#!cpp std::string_view`, or a C-style array of characters
- a pointer to a null-terminated string of single byte characters
- a container for which `#!cpp obj.data()` and `#!cpp obj.size()` give contiguous single-byte access, e.g.
`#!cpp std::vector<char>` or `#!cpp std::vector<std::uint8_t>`
- an `#!cpp std::istream` object, or anything else [`BasicJsonType::parse()`](../basic_json/parse.md) accepts
`IteratorType`
: a compatible iterator type, for instance a pair of pointers such as `ptr` and `ptr + len`, or a pair of
`#!cpp std::string::iterator`
## Parameters
`input` (in)
: Input to parse from.
`allow_exceptions` (in)
: whether to throw exceptions in case of a parse error (optional, `#!cpp true` by default)
`ignore_comments` (in)
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
(`#!cpp false`); (optional, `#!cpp false` by default)
`ignore_trailing_commas` (in)
: whether trailing commas in arrays or objects should be ignored and treated like whitespace (`#!cpp true`) or
yield a parse error (`#!cpp false`); (optional, `#!cpp false` by default)
`first` (in)
: iterator to the start of a character range
`last` (in)
: iterator to the end of a character range
## Return value
The parsed document. If `allow_exceptions` is `#!cpp false` and the input is not valid JSON, the returned document is
discarded; see [`is_discarded`](is_discarded.md).
## Exceptions
Throws the same exception [`BasicJsonType::parse()`](../basic_json/parse.md) throws for the same input and options --
the same exception id, message, and position -- because on a failing input the library's own parser is run on the
same bytes to produce the diagnostic. Additionally throws
[`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the input is 4 GiB or larger, a size
[`BasicJsonType::parse()`](../basic_json/parse.md) does not reject.
## Complexity
Linear in the length of the input.
## Notes
**Ownership.** Whether the document borrows `input` or owns a copy of it depends on its value category and type:
| `input` | ownership |
|--------------------------------------------------------------------------------------|--------------------------------------------------------------|
| lvalue byte container (`std::string`, `std::vector<char>`, ...), `std::string_view`, C string, character array | **borrowed** -- `input` must outlive the document |
| rvalue `#!cpp std::string` | **owned**, moved in without a copy |
| rvalue byte container other than `#!cpp std::string` | **owned**, copied |
| stream, wide string, or anything else read through the general input adapter | **owned**, read into a buffer (a stream is read to its end) |
For overload (2), a pair of pointers to single-byte integers (e.g. `#!cpp const char*`, `#!cpp std::uint8_t*`) is
borrowed. From C++20 on, so is any other contiguous iterator over single bytes, such as
`#!cpp std::vector<char>::iterator` or `#!cpp std::string::const_iterator`. Before C++20 these iterators cannot be
told apart from other class-type iterators, so their range is read into an owned buffer, as is any non-contiguous
range (e.g. of a `#!cpp std::list<char>`).
See [`owns_source`](owns_source.md) to check which happened after a call, and the
[feature page](../../features/json_view.md) for the reasoning.
**Numbers.** As for [`BasicJsonType::parse()`](../basic_json/parse.md), an integer literal too large for the 64-bit
integer type becomes a floating-point value.
## Examples
??? example "Example: (1) borrowed vs. owned input, and errors identical to `BasicJsonType::parse()`"
```cpp
--8<-- "examples/basic_json_document__parse.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__parse.output"
```
??? example "Example: (2) parse an iterator range (no NUL terminator required)"
```cpp
--8<-- "examples/basic_json_document__parse_iterator_pair.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__parse_iterator_pair.output"
```
## See also
- [parse_copy](parse_copy.md) - deserialize a copy of a compatible input
- [accept](accept.md) - check whether the input is valid JSON
- [read](read.md) - (re-)parse into this document, reusing its memory
- [owns_source](owns_source.md) - return whether the document holds its own copy of the text
- [load](load.md) - read a document from an image instead of parsing JSON text
- [`BasicJsonType::parse`](../basic_json/parse.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,77 +0,0 @@
# <small>nlohmann::basic_json_document::</small>parse_copy
```cpp
template<typename InputType>
static basic_json_document parse_copy(InputType&& input,
const bool allow_exceptions = true,
const bool ignore_comments = false,
const bool ignore_trailing_commas = false);
```
Deserialize from a compatible input, always taking the document's own copy of it, regardless of the value category or
type of `input`. Unlike [`parse()`](parse.md), the returned document never depends on `input` staying alive.
## Template parameters
`InputType`
: A compatible input; see [`parse`](parse.md#template-parameters).
## Parameters
`input` (in)
: Input to parse from.
`allow_exceptions` (in)
: whether to throw exceptions in case of a parse error (optional, `#!cpp true` by default)
`ignore_comments` (in)
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
(`#!cpp false`); (optional, `#!cpp false` by default)
`ignore_trailing_commas` (in)
: whether trailing commas in arrays or objects should be ignored and treated like whitespace (`#!cpp true`) or
yield a parse error (`#!cpp false`); (optional, `#!cpp false` by default)
## Return value
The parsed document, with [`owns_source()`](owns_source.md) `#!cpp true`. If `allow_exceptions` is `#!cpp false` and
the input is not valid JSON, the returned document is discarded; see [`is_discarded`](is_discarded.md).
## Exceptions
Same as [`parse`](parse.md#exceptions).
## Complexity
Linear in the length of the input.
## Notes
`parse_copy()` accepts and rejects exactly what [`parse()`](parse.md) does, and classifies numbers the same way; it
only differs in that the input is always copied rather than sometimes borrowed. Prefer [`parse()`](parse.md) when the
input's lifetime already covers the document's, since it avoids the copy for borrowed inputs.
## Examples
??? example
The example below returns a document from a function whose local buffer would otherwise not outlive it.
```cpp
--8<-- "examples/basic_json_document__parse_copy.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__parse_copy.output"
```
## See also
- [parse](parse.md) - deserialize from a compatible input, borrowing it where possible
- [owns_source](owns_source.md) - return whether the document holds its own copy of the text
## Version history
- Added in version 3.13.0.
@@ -1,102 +0,0 @@
# <small>nlohmann::basic_json_document::</small>push_back
```cpp
template<typename V>
view_type push_back(view_type array, V&& value);
```
Appends `value` as a new last element of `array`. A [null](../basic_json_view/is_null.md) `array` first becomes an
empty array, the same way [`set`](set.md) turns a null `object` into an empty object.
`value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any* document -- read-only or
editable, and it does not have to be `array`'s own document -- which is copied so that nothing is shared with the
source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
has `push_back`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
## Template parameters
`V`
: the type of `value`, deduced; see above for what is accepted.
## Parameters
`array` (in)
: the array (or null value) to append to
`value` (in)
: the value to append
## Return value
a view of the new last element of `array`, now holding `value`
## Exception safety
Basic exception safety: `value` is fully encoded -- including the checks below -- into storage owned by the document
before anything already reachable from [`root()`](root.md) is touched, so a failure while encoding `value` (an
invalid argument, or `#!cpp std::bad_alloc`) leaves the document completely unchanged, other than memory allocated
for the encoding that is not reclaimed. A failure of a later allocation -- while `array` switches from its parsed
layout to a growable block, or while that block grows, see [Notes](#notes) -- can still leave a partial effect, such
as a null `array` argument already turned into an empty array even though `value` itself was not appended.
## Exceptions
Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) if `array` is neither an array nor
null -- the same message [`BasicJsonType::push_back`](../basic_json/push_back.md) throws for the same type. Throws
[`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view does not belong to this
document") if `array` is a [discarded](../basic_json_view/is_discarded.md) view or a view of a *different* document.
Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `value` is a
[discarded](../basic_json_view/is_discarded.md) view or a [discarded](../basic_json/is_discarded.md) `BasicJsonType`
value, and [`type_error.319`](../../home/exceptions.md#jsonexceptiontype_error319) if `value` is (or contains) a
binary value -- `BasicJsonType` can hold one, but a `json_document` cannot. Throws
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if `value` is (or contains) a string that is
not valid UTF-8, with the same message [`BasicJsonType::dump()`](../basic_json/dump.md) gives for that string.
## Complexity
Amortized constant, plus time linear in the size of `value` to encode it into the document's storage (constant for
a scalar, linear in the number of nested values for an array or object): the elements of `array` move to a growable
block of links the first time it is appended to (or [`set`](set.md) on), and that block itself grows -- doubling its
capacity, so the cost of growing it amortizes to constant per element -- only once it runs out of room. See
[Notes](#notes).
## Notes
Like [`set`](set.md) on a member or an element, `push_back` never moves an existing element itself -- only where
`array`'s *links* to its elements live -- so a view of an existing element of `array` stays valid across a
`push_back`, but any iterator already taken over `array` is invalidated, since it was walking the old layout. See
[Edits](index.md#edits) for what stays valid across an edit in general.
## Examples
??? example
The example below appends records to an array one at a time, as they might arrive from a stream of events,
without ever building a `BasicJsonType` value for the array or for the records already in it, and shows that a
view taken from an earlier `push_back` still refers to the same element once later ones have run.
```cpp
--8<-- "examples/basic_json_document__push_back.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__push_back.output"
```
## See also
- [set](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers to
- [insert](insert.md) - insert an element into an array before a given position
- [erase](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
- [root](root.md) - the view of the root value
- [`BasicJsonType::push_back`](../basic_json/push_back.md) - the corresponding function of `basic_json`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
## Version history
- Added in version 3.13.0.
@@ -1,77 +0,0 @@
# <small>nlohmann::basic_json_document::</small>read
```cpp
template<typename InputType>
void read(InputType&& input,
const bool allow_exceptions = true,
const bool ignore_comments = false,
const bool ignore_trailing_commas = false);
```
(Re-)parses `input` into `#!cpp *this`, discarding the document's previous value and reusing its memory (the node
index, the decoded-string buffer, and, if applicable, the owned copy of the text) rather than allocating a fresh
document. [`parse()`](parse.md) is implemented in terms of this function, applied to a default-constructed document.
## Template parameters
`InputType`
: A compatible input; see [`parse`](parse.md#template-parameters).
## Parameters
`input` (in)
: Input to parse from.
`allow_exceptions` (in)
: whether to throw exceptions in case of a parse error (optional, `#!cpp true` by default)
`ignore_comments` (in)
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
(`#!cpp false`); (optional, `#!cpp false` by default)
`ignore_trailing_commas` (in)
: whether trailing commas in arrays or objects should be ignored and treated like whitespace (`#!cpp true`) or
yield a parse error (`#!cpp false`); (optional, `#!cpp false` by default)
## Exceptions
Same as [`parse`](parse.md#exceptions).
## Complexity
Linear in the length of the input.
## Notes
Every view taken from `#!cpp *this` before the call -- including the previous [`root()`](root.md) -- is invalidated,
whether or not the new parse succeeds; take fresh views from [`root()`](root.md) afterward.
`input` is borrowed or owned by the same rules as [`parse()`](parse.md#notes); a document can borrow on one call and
own on the next, since ownership is decided freshly each time.
## Examples
??? example
The example below parses a sequence of messages into the same document, reusing its memory instead of allocating
a new document for each one.
```cpp
--8<-- "examples/basic_json_document__read.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__read.output"
```
## See also
- [parse](parse.md) - deserialize from a compatible input
- [root](root.md) - the view of the root value
- [load](load.md) - read a document from an image instead of parsing JSON text
## Version history
- Added in version 3.13.0.
@@ -1,50 +0,0 @@
# <small>nlohmann::basic_json_document::</small>root
```cpp
view_type root() const noexcept;
```
Returns a view of the root value of the document.
## Return value
A [`view_type`](index.md#member-types) (i.e. `#!cpp basic_json_view<BasicJsonType>`) for the root value, or a
discarded view if the document is [discarded](is_discarded.md).
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
`root()` is a cheap handle into the document's index, not a copy of anything; call it as often as needed. The
returned view is valid under the same conditions as any other view of the document -- see
[Object inspection](../basic_json_view/index.md) -- in particular, it is invalidated by the next
[`read()`](read.md) or [`shrink_to_fit()`](shrink_to_fit.md) on this document.
## Examples
??? example
```cpp
--8<-- "examples/basic_json_document__root.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__root.output"
```
## See also
- [is_discarded](is_discarded.md) - return whether the last parse failed
- [materialize](../basic_json_view/materialize.md) - build the `BasicJsonType` value of a subtree
## Version history
- Added in version 3.13.0.
@@ -1,104 +0,0 @@
# <small>nlohmann::basic_json_document::</small>save
```cpp
std::vector<std::uint8_t> save() const;
```
Writes the document as an *image*: a byte buffer that [`load`](load.md) reads back without parsing. The image holds
the node index, the source text (plus, for an edited document, the number tokens edits wrote), and the decoded
strings (plus the strings edits wrote) -- everything [`root()`](root.md) needs, with nothing left to parse.
An edited document is written in its *current* state, with its values in document order, the way the library's own
parser would have produced them for that JSON text: a member [`set`](set.md) added goes at the end, an
[`erase`](erase.md)d member leaves no trace, and a float that is not finite (NaN or positive/negative infinity)
becomes null, the same substitution [`dump()`](../basic_json_view/dump.md) makes. The same document always saves to
the same bytes -- also across `BasicJsonType` and `#!cpp Editable`, since the image reflects document order and
values only, not which specialization produced them.
## Return value
The image, as a `#!cpp std::vector<std::uint8_t>`. Pass it, or a pointer to its data together with its size, to
[`load`](load.md) to read the document back.
## Exception safety
Strong guarantee: `save()` does not modify `#!cpp *this` (it is `#!cpp const`), so if it throws, the document is left
exactly as it was, and the partially built image is discarded with the exception.
## Exceptions
Throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) if the document is
[discarded](is_discarded.md) -- a default-constructed document, or one a failed [`parse()`](parse.md)/
[`read()`](read.md) with `allow_exceptions == false` left discarded.
On a big-endian target, throws `type_error.320` with a different message instead: the image format is little-endian
only (see [Notes](#notes)).
Throws [`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the node count, the text, or
the decoded strings of the image would individually reach 4 GiB -- the same 32-bit offsets
[`parse()`](parse.md#exceptions) and, for edits, [`set`](set.md)/[`push_back`](push_back.md) are already limited to.
!!! failure "Example messages"
```
[json.exception.type_error.320] cannot save a discarded json_document
```
```
[json.exception.type_error.320] json_document images need a little-endian target
```
```
[json.exception.out_of_range.416] images of 4 GiB or more are not supported by json_document
```
## Complexity
Linear in the size of the document: the number of nodes, plus the length of the text and the decoded strings that end
up in the image.
## Notes
**Format.** The image begins with a 64-byte header (the magic bytes `#!cpp "NJVI"`, a version number, the node count,
and the sizes of the text and the decoded strings, all little-endian), followed by the nodes
([16 bytes each](../../home/architecture.md#node-index-of-json-views)), the text and a `#!cpp '\0'`, and the decoded
strings and a `#!cpp '\0'`. [`load`](load.md) checks the header, and the sizes it describes, before reading anything
else -- see [`load`'s Exceptions](load.md#exceptions).
!!! warning "Experimental"
The image format is versioned but not yet stable: it may change in an incompatible way before it is declared
stable. Use images to cache a document within one build of the library, or to hand one to another process running
the *same* build on the *same* (little-endian) machine -- not as a long-term storage format. Keep the original
JSON text if you need to read a saved document back with a future library version.
**Little-endian only.** The image is written as raw little-endian bytes, with no byte-swapping. `save()` (and
[`load`](load.md)) throw `type_error.320` on a big-endian target rather than silently produce bytes a big-endian
reader could not interpret correctly.
## Examples
??? example "Caching a parsed document as an image"
The example below saves a parsed configuration as an image -- the way a service might cache one to answer later
requests without parsing the text again -- and confirms that loading it back gives exactly the same result as
parsing did, and that saving is deterministic.
```cpp
--8<-- "examples/basic_json_document__save.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__save.output"
```
## See also
- [load](load.md) - read an image written by `save()`
- [owns_source](owns_source.md) - return whether the document holds its own copy of the text
- [`basic_json_view::dump`](../basic_json_view/dump.md) - serialize the document to JSON text instead of an image
- [Images](../../features/json_view.md#images) - why and when to use images
## Version history
- Added in version 3.13.0.
@@ -1,194 +0,0 @@
# <small>nlohmann::basic_json_document::</small>set
```cpp
// (1)
template<typename V>
view_type set(view_type target, V&& value);
// (2)
template<typename V>
view_type set(view_type object, string_view_t key, V&& value);
// (3)
template<typename I, typename V>
view_type set(view_type array, I idx, V&& value);
// (4)
template<typename V>
view_type set(const json_pointer& ptr, V&& value);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
has `set`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
1. Replaces the value `target` refers to with `value`.
2. Sets the member `key` of the object `object` to `value`: assigns it if `object` already has a member with this
key -- the first one, should the key occur more than once, and the later duplicates are then dropped (see the
[Notes](#notes) below) -- or appends a new member at the end otherwise. A [null](../basic_json_view/is_null.md)
`object` first becomes an empty object.
3. Assigns `value` to the element at index `idx` of the array `array`, which must already exist (`#!cpp idx <
array.size()`).
4. Sets the value the JSON pointer `ptr` refers to, relative to [`root()`](root.md), to `value`. The *parent* of the
target must already exist: an object member is set as in 2. (added if it does not exist yet), an array element is
assigned as in 3., and a last reference token of `#!cpp "-"`, or equal to the size of the array, appends `value`
instead, exactly as [`push_back`](push_back.md) would. An empty `ptr` sets [`root()`](root.md) itself, as in 1.
In every overload, `value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any*
document -- read-only or editable, and it does not have to be `target`'s/`object`'s/`array`'s own document -- which
is copied so that nothing is shared with the source document afterward; a `BasicJsonType` value; or anything
`BasicJsonType` can be constructed from (numbers, strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
## Template parameters
`V`
: the type of `value`, deduced; see above for what is accepted.
`I`
: an integral type other than `#!cpp bool`, deduced (overloads taking a `#!cpp bool` or a non-integral type for
`idx` do not participate in overload resolution).
## Parameters
`target` (in)
: the value to replace
`object` (in)
: the object (or null value) whose member to set
`array` (in)
: the array whose element to assign
`key` (in)
: the key of the member to set
`idx` (in)
: the index of the element to assign; a negative value throws (see [Exceptions](#exceptions))
`ptr` (in)
: a JSON pointer to the value to set, relative to `root()`
`value` (in)
: the new value
## Return value
1. a view of `target`, now holding `value`
2. a view of the member `key` of `object`, now holding `value`
3. a view of the element `idx` of `array`, now holding `value`
4. a view of the value `ptr` refers to, now holding `value`
## Exception safety
Basic exception safety: `value` is fully encoded -- including the checks below -- into storage owned by the document
before anything already reachable from [`root()`](root.md) is touched, so a failure while encoding `value` (an
invalid argument, or `#!cpp std::bad_alloc`) leaves the document completely unchanged, other than memory allocated
for the encoding that is not reclaimed. A failure of a later allocation -- while an edited array or object switches
from its parsed layout to a growable block, see [Notes](#notes) -- can still leave a partial effect, such as a
[null](../basic_json_view/is_null.md) `object`/`array` argument already turned into an empty object/array even
though `value` itself was not linked in.
## Exceptions
1. Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `value` is a
[discarded](../basic_json_view/is_discarded.md) view, or a [discarded](../basic_json/is_discarded.md)
`BasicJsonType` value (e.g. `#!cpp BasicJsonType(value_t::discarded)`) -- an object or array `value`, of either
kind, is fine and is encoded as a whole subtree.
2. Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if `object` is neither an object
nor null -- the same message [`operator[]`](../basic_json_view/operator%5B%5D.md) throws for a string argument on
such a value. Throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if `key` is not
valid UTF-8, with the same message [`BasicJsonType::dump()`](../basic_json/dump.md) gives for that string.
Also throws what 1. throws for `value`.
3. Throws `type_error.305` if `array` is not an array -- the same message `operator[]` throws for a numeric argument
on such a value. Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `idx` is
negative, or if `#!cpp idx >= array.size()`. Also throws what 1. throws for `value`.
4. Throws what [`at`](../basic_json_view/at.md) throws (overload 3) for resolving `ptr`'s parent, except that a
missing object member or an array index equal to the array's size at the very last reference token is not an
error there (it becomes a new member or an appended element) instead of
[`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403)/[`out_of_range.402`](../../home/exceptions.md#jsonexceptionout_of_range402).
For the last reference token itself: if the parent is an object (or a primitive value, where it throws
`type_error.305`), throws what 2. throws; if the parent is an array, throws what 3. throws for an index that is
out of range, or, for a token that is not a valid array index,
[`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) (a leading `#!cpp '0'`),
[`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) (not a number),
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) (too large for `size_type`), or
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) (an empty token). Also throws what 1.
throws for `value`.
Every overload also throws [`type_error.319`](../../home/exceptions.md#jsonexceptiontype_error319) if `value` is (or
contains) a binary value -- `BasicJsonType` can hold one, but a `json_document` cannot -- and
[`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view does not belong to this
document") if `target`/`object`/`array` is a [discarded](../basic_json_view/is_discarded.md) view or a view of a
*different* document (overloads 1-3 only; overload 4 always starts from this document's own [`root()`](root.md)).
## Complexity
1. Linear in the size of `value` (encoding it into the document's storage): constant for a scalar, linear in the
number of nested values for an array or object. If `target` is itself an array or object that spans more than one
node in its parent's original, unedited layout, and `value` is a scalar, replacing it additionally costs time
linear in the number of elements of that parent, the *first* time -- see [Notes](#notes).
2. Linear in the number of members of `object`, to find an existing member with `key`, plus the complexity of 1. for
`value`.
3. Constant, plus the complexity of 1. for `value`.
4. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
that level or the index into the array (as [`at`](../basic_json_view/at.md)), plus the complexity of 2. or 3. for
the last token.
## Notes
!!! info "Duplicate keys"
If `object` already has more than one member with `key` (2.), the *first* one is assigned `value` and every
later member with the same key is removed -- so that a lookup, an iteration, and
[`materialize()`](../basic_json_view/materialize.md) of `object` afterward all agree on a single value for
`key`, the same way [`operator[]`](../basic_json_view/operator%5B%5D.md) already picks the first occurrence of a
duplicate key for reading. See the [Notes on duplicate keys](../basic_json_view/operator%5B%5D.md#notes) of
`operator[]`.
Setting a member (2.) or an element (3., through 4.) of an array or object whose elements have not been edited
before switches it from its parsed layout to a growable block holding links to its elements; a later
[`push_back`](push_back.md) or `set` on the same container reuses that block, growing it (amortized constant time)
only once it runs out of room. This never moves an element itself -- only where the container's *links* to its
elements live -- so a view of an element stays valid, but any iterator already taken over the container is
invalidated, since it was walking the old layout. See [Edits](index.md#edits) for what stays valid across an edit in
general.
The same switch happens, for the same reason, when overload 1. replaces a multi-node array/object value with a
scalar: the *parent's* element sequence is what has to switch to links, not `target` itself, because the parent
originally stepped over `target`'s whole subtree by its node count, which no longer applies once `target` is a
one-node scalar.
## Examples
??? example "Example: (1)/(2)/(3)/(4) replace a value, set a member, assign an element, set via a JSON pointer"
The example below edits a small configuration document -- replacing a value, adding an object member, assigning
an array element, and reaching a field through a JSON pointer -- and shows what
[`dump()`](../basic_json_view/dump.md) preserves that is lost once the same edits are made on a `BasicJsonType`
value instead: the order object members were written in, and the exact spelling of a number that was never
touched.
```cpp
--8<-- "examples/basic_json_document__set.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__set.output"
```
## See also
- [push_back](push_back.md) - append to an array
- [insert](insert.md) - insert an element into an array
- [erase](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
- [root](root.md) - the view of the root value, the starting point of overload 4
- [`basic_json_view::dump`](../basic_json_view/dump.md) - serialize the document, keeping an untouched number's
spelling with `#!cpp number_format::source`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
- [Editing a document](../../features/json_view.md#editing-a-document) - why editable documents keep the source
text's order and number spelling
## Version history
- Added in version 3.13.0.
@@ -1,58 +0,0 @@
# <small>nlohmann::basic_json_document::</small>shrink_to_fit
```cpp
void shrink_to_fit();
```
Releases capacity that is no longer needed, both of the node index and of the buffer for decoded strings (strings that
contained escape sequences), e.g. after [`read()`](read.md) replaced a large document with a much smaller one. Like
`#!cpp std::vector::shrink_to_fit()`, this is a non-binding request: the library may keep more capacity than strictly
necessary.
## Exception safety
Strong guarantee: if an exception is thrown, there are no changes to the document.
## Exceptions
May throw `#!cpp std::bad_alloc` if the reallocation fails; on exception, the document is unchanged.
## Complexity
Linear in [`node_count()`](node_count.md) plus the length of the decoded strings.
## Notes
!!! warning "Invalidates views"
Unlike moving the document, `shrink_to_fit()` **invalidates every view taken from this document before the
call**, including a previously obtained [`root()`](root.md): the node index is moved into a new, smaller
allocation, and the old one is freed. Take a fresh view from [`root()`](root.md) after calling this function.
This is unlike `#!cpp std::vector::shrink_to_fit()`, which promises nothing about validity but in practice often
leaves iterators alone when it did not need to reallocate; here, an implementation that avoids a reallocation when
possible would be an internal optimization only, not a guarantee to rely on.
## Examples
??? example
```cpp
--8<-- "examples/basic_json_document__shrink_to_fit.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__shrink_to_fit.output"
```
## See also
- [node_count](node_count.md) - the number of index entries
- [memory_usage](memory_usage.md) - the number of bytes held by the document
- [root](root.md) - the view of the root value
## Version history
- Added in version 3.13.0.
@@ -1,48 +0,0 @@
# <small>nlohmann::basic_json_document::</small>source
```cpp
view_type::string_view_t source() const noexcept;
```
Returns the parsed text, whether it is borrowed from the caller or owned by the document.
## Return value
A `#!cpp string_view_t` (`#!cpp std::string_view` on C++17 and newer) over the parsed text, or an empty one if the
document is [discarded](is_discarded.md).
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
For a borrowed document, `source()` points directly into the caller's buffer, so it is only valid while that buffer
is; see [`owns_source`](owns_source.md).
## Examples
??? example
```cpp
--8<-- "examples/basic_json_document__source.cpp"
```
Output:
```json
--8<-- "examples/basic_json_document__source.output"
```
## See also
- [owns_source](owns_source.md) - return whether the document holds its own copy of the text
- [source_offset](../basic_json_view/source_offset.md) - byte offset of a value in the source text
## Version history
- Added in version 3.13.0.
-134
View File
@@ -1,134 +0,0 @@
# <small>nlohmann::basic_json_view::</small>at
```cpp
// (1)
basic_json_view at(string_view_t key) const;
basic_json_view at(const char* key) const;
basic_json_view at(const string_t& key) const;
// (2)
basic_json_view at(size_type idx) const;
basic_json_view at(int idx) const;
// (3)
basic_json_view at(const json_pointer& ptr) const;
```
1. Returns the value of the object member with key `key` -- the first one, should the key occur more than once (see
[Notes on duplicate keys](operator[].md#notes)).
2. Returns the array element at index `idx`.
3. Returns the value a JSON pointer `ptr` refers to, starting at this value.
## Parameters
`key` (in)
: object key of the element to access
`idx` (in)
: index of the element to access
`ptr` (in)
: JSON pointer to the element to access
## Return value
1. the value of the first member with key `key`
2. the element at index `idx`
3. the value `ptr` resolves to, starting at this value
## Exception safety
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
## Exceptions
1. The function can throw the following exceptions, both with the same message as the corresponding call to
[`BasicJsonType::at`](../basic_json/at.md):
- Throws [`type_error.304`](../../home/exceptions.md#jsonexceptiontype_error304) if the value is not an object.
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if no member has key `key`.
2. The function can throw the following exceptions, both with the same message as the corresponding call to
[`BasicJsonType::at`](../basic_json/at.md):
- Throws [`type_error.304`](../../home/exceptions.md#jsonexceptiontype_error304) if the value is not an array.
- Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `#!cpp idx >= size()`.
3. The function can throw the following exceptions, all with the same message as the corresponding call to
[`BasicJsonType::at`](../basic_json/at.md):
- Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index in `ptr`
begins with `#!cpp '0'`.
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in `ptr` is
not a number.
- Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if an array index in `ptr`
is out of range.
- Throws [`out_of_range.402`](../../home/exceptions.md#jsonexceptionout_of_range402) if a reference token is
`#!cpp "-"` at an array -- `at` never inserts an element, so `#!cpp "-"` is always invalid.
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if a reference token names
an object member that does not exist.
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if `ptr` cannot be resolved
because a reference token is used on a primitive value.
None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
## Complexity
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
another, in document order, stopping at the first match. Each comparison first checks the key's length --
already known from the index, without reading the key bytes -- before comparing its content.
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
on average.
2. Linear in `idx`: elements are skipped one at a time from the first one, since they are not a fixed size in the
index (unlike `BasicJsonType`'s array, which is random-access).
3. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
that level (as 1.) or the index into the array (as 2.).
## Notes
Unlike [`operator[]`](operator[].md), which returns a [discarded](is_discarded.md) view for a missing key or an
out-of-range index, `at` always throws -- exactly as `BasicJsonType::at` does, and with the same messages, so
existing error handling written against `BasicJsonType::at` keeps working unchanged when switched to a view. This
also holds for overload 3: unlike [`operator[]`](operator[].md) with a JSON pointer, which returns a discarded view
for a missing key or an out-of-range index, `at` throws for those too (`out_of_range.403`/`out_of_range.401`).
## Examples
??? example "Example: (1)/(2) access specified element with bounds checking"
The example below reads required fields out of a service configuration with `at`, and shows that the exceptions
it throws -- for a wrong type and for a missing key -- carry the same messages
[`BasicJsonType::at`](../basic_json/at.md) would produce for the same JSON text.
```cpp
--8<-- "examples/basic_json_view__at.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__at.output"
```
??? example "Example: (3) access specified element via JSON pointer with bounds checking"
The example below shows that `at` with a JSON pointer throws exactly the exceptions, with exactly the messages,
that [`BasicJsonType::at`](../basic_json/at.md) throws for the same pointer and the same document.
```cpp
--8<-- "examples/basic_json_view__at_json_pointer.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__at_json_pointer.output"
```
## See also
- [operator[]](operator[].md) - access specified element (returns a discarded view instead of throwing)
- [front](front.md), [back](back.md) - access the first or last element
- [`BasicJsonType::at`](../basic_json/at.md) - the corresponding function of `basic_json`
- [`json_pointer`](../json_pointer/index.md) - JSON pointer type used by overload 3
## Version history
- Added in version 3.13.0.
@@ -1,64 +0,0 @@
# <small>nlohmann::basic_json_view::</small>back
```cpp
basic_json_view back() const;
```
Returns the last element of an array, the last member value of an object, or the value itself if it is primitive
(as for [`BasicJsonType::back()`](../basic_json/back.md), a primitive value is a range of one element).
## Return value
The last element or member value. For a primitive value (number, string, boolean), the value itself.
## Exception safety
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
## Exceptions
Throws [`invalid_iterator.214`](../../home/exceptions.md#jsonexceptioninvalid_iterator214) if the view is
[null](is_null.md) or [discarded](is_discarded.md), or if it is an empty array or object.
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
## Complexity
Linear in the size of the array or object: unlike [`front()`](front.md), which only ever looks at the first
element, `back()` has to walk every element to find where they end, since elements are not a fixed size in the
index.
## Notes
Unlike [`BasicJsonType::back()`](../basic_json/back.md), which has undefined behavior for an empty array or object,
`back()` throws `invalid_iterator.214` in that case -- the same way it already does for `#!json null` and for a
discarded view, where `BasicJsonType::back()` also throws.
## Examples
??? example
The example below reads only the final status of a build log with `back()`. Even though `back()` is linear in
the number of events (unlike [`front()`](front.md), which is constant), it still avoids building a
`BasicJsonType` value for the events that are not needed.
```cpp
--8<-- "examples/basic_json_view__back.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__back.output"
```
## See also
- [front](front.md) - access the first element
- [`BasicJsonType::back`](../basic_json/back.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,52 +0,0 @@
# <small>nlohmann::basic_json_view::</small>basic_json_view
```cpp
basic_json_view() noexcept = default;
```
Creates an invalid (discarded) view: [`type()`](type.md) is `#!cpp value_t::discarded`,
[`is_discarded()`](is_discarded.md) is `#!cpp true`, and `#!cpp explicit operator bool()` is `#!cpp false`.
This is the only constructor a caller can use directly. Every other view is obtained from a
[`basic_json_document`](../basic_json_document/index.md), via [`root()`](../basic_json_document/root.md) or by
navigating into a container with [`operator[]`](operator[].md), [`at`](at.md), [`front`](front.md), [`back`](back.md),
[`find`](find.md), or iteration.
## Exception safety
No-throw guarantee: this constructor never throws exceptions.
## Complexity
Constant.
## Notes
`basic_json_view` is trivially copyable (it holds two pointers), so a default-constructed view can be used as a
placeholder for "no value yet" and later be assigned a real view.
## Examples
??? example
The example below shows the default constructor and that a `basic_json_view` is a small, copyable handle.
```cpp
--8<-- "examples/basic_json_view__basic_json_view.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__basic_json_view.output"
```
## See also
- [is_discarded](is_discarded.md) - return whether the view is invalid
- [operator bool](operator_bool.md) - return whether the view refers to a value
- [root](../basic_json_document/root.md) - the view of a document's root value
## Version history
- Added in version 3.13.0.
@@ -1,61 +0,0 @@
# <small>nlohmann::basic_json_view::</small>begin
```cpp
iterator begin() const noexcept;
```
Returns an iterator to the first element of an array, or the first member value of an object, in **document order**
-- the order the values appear in the source text, not sorted by key. A primitive value iterates as a range of one
element (itself); `#!json null` and a [discarded](is_discarded.md) view iterate as an empty range.
## Return value
Iterator to the first element.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
For an object, iteration visits **every** member, including all occurrences of a duplicate key -- unlike
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), [`contains`](contains.md), and [`count`](count.md),
which all resolve to the *first* member with a given key. See the
[Notes on duplicate keys](operator[].md#notes) of `operator[]`.
Because objects are iterated in document order rather than sorted by key, the order seen here can differ from what
iterating the [`materialize()`](materialize.md)d `BasicJsonType` value would produce: a `#!cpp basic_json` object
(`std::map`-backed by default) sorts its keys, while a view does not.
## Examples
??? example
The example below iterates a log record's members with `begin()`/[`end()`](end.md) and prints them in the order
they were written. Materializing the record into a `BasicJsonType` object and iterating that would instead print
the members sorted by key.
```cpp
--8<-- "examples/basic_json_view__begin.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__begin.output"
```
## See also
- [end](end.md) - returns an iterator to one past the last element
- [cbegin](cbegin.md) - returns a const iterator to the first element
- [items](items.md) - access iterator member functions in range-based for
- [`BasicJsonType::begin`](../basic_json/begin.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,49 +0,0 @@
# <small>nlohmann::basic_json_view::</small>cbegin
```cpp
iterator cbegin() const noexcept;
```
Returns an iterator to the first element, in [document order](begin.md). Equivalent to [`begin()`](begin.md): a view
is always read-only, so `#!cpp const_iterator` and `#!cpp iterator` are the same type, and `cbegin()` exists only so
that generic code that expects a `cbegin()`/`cend()` pair works with a view too.
## Return value
Iterator to the first element; identical to what [`begin()`](begin.md) returns.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Examples
??? example
The example below sums many measurements with `std::accumulate`, using `cbegin()`/[`cend()`](cend.md) as the
range -- the same way it would for any standard container -- without ever materializing the whole array into a
`BasicJsonType` value.
```cpp
--8<-- "examples/basic_json_view__cbegin.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__cbegin.output"
```
## See also
- [begin](begin.md) - returns an iterator to the first element
- [cend](cend.md) - returns a const iterator to one past the last element
- [`BasicJsonType::cbegin`](../basic_json/cbegin.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,49 +0,0 @@
# <small>nlohmann::basic_json_view::</small>cend
```cpp
iterator cend() const noexcept;
```
Returns an iterator to one past the last element, in [document order](begin.md). Equivalent to [`end()`](end.md): a
view is always read-only, so `#!cpp const_iterator` and `#!cpp iterator` are the same type, and `cend()` exists only
so that generic code that expects a `cbegin()`/`cend()` pair works with a view too.
## Return value
Iterator one past the last element; identical to what [`end()`](end.md) returns.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Examples
??? example
The example below checks that every record of a batch is an object with `std::all_of`, using
[`cbegin()`](cbegin.md)/`cend()` as the range -- the same way it would for any standard container -- before
materializing any record of the batch.
```cpp
--8<-- "examples/basic_json_view__cend.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__cend.output"
```
## See also
- [end](end.md) - returns an iterator to one past the last element
- [cbegin](cbegin.md) - returns a const iterator to the first element
- [`BasicJsonType::cend`](../basic_json/cend.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,103 +0,0 @@
# <small>nlohmann::basic_json_view::</small>contains
```cpp
// (1)
bool contains(string_view_t key) const;
bool contains(const char* key) const;
bool contains(const string_t& key) const;
// (2)
bool contains(const json_pointer& ptr) const;
```
1. Checks whether the value is an object with a member with key `key`.
2. Checks whether a JSON pointer `ptr` can be resolved, starting at this value.
## Parameters
`key` (in)
: key value to check its existence
`ptr` (in)
: JSON pointer to check its existence
## Return value
1. `#!cpp true` if the value is an object and has a member with key `key`, `#!cpp false` otherwise
2. `#!cpp true` if `ptr` can be resolved to a value starting at this view, `#!cpp false` otherwise
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
another, in document order, stopping at the first match. Each comparison first checks the key's length -- already
known from the index, without reading the key bytes -- before comparing its content.
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
on average.
2. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
that level or the index into the array -- as for [`operator[]`](operator[].md#complexity) and
[`at`](at.md#complexity) with a JSON pointer.
## Notes
Overload 1 always returns `#!cpp false` when the value is not an object -- including a [discarded](is_discarded.md)
view.
!!! info "Postconditions"
If `#!cpp v.contains(key)` returns `#!cpp true`, then `#!cpp v[key]` is not [discarded](is_discarded.md). If
`#!cpp v.contains(ptr)` returns `#!cpp true`, then `#!cpp v[ptr]` is not discarded and `#!cpp v.at(ptr)` does not
throw.
!!! info "Overload 2 never throws"
Unlike [`BasicJsonType::contains(const json_pointer&)`](../basic_json/contains.md), which can throw for certain
malformed pointers (for instance an empty array-index reference token), overload 2 never throws: a missing key,
an out-of-range or malformed array index, a `#!cpp "-"` index, or a reference token used on a primitive all
simply make it return `#!cpp false`.
## Examples
??? example "Example: (1) check with key"
The example below counts how many of a batch of records carry an optional `retry_of` field, using `contains()`
to check without ever materializing a single record of the batch.
```cpp
--8<-- "examples/basic_json_view__contains.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__contains.output"
```
??? example "Example: (2) check with JSON pointer"
The example below checks an optional, nested field with a JSON pointer, and shows two pointers that
`#!cpp contains()` resolves to `#!cpp false` without throwing.
```cpp
--8<-- "examples/basic_json_view__contains_json_pointer.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__contains_json_pointer.output"
```
## See also
- [find](find.md) - find a value in an object
- [count](count.md) - returns the number of occurrences of a key
- [at](at.md), [operator[]](operator[].md) - resolve a JSON pointer and throw, or return a discarded view
- [`BasicJsonType::contains`](../basic_json/contains.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,68 +0,0 @@
# <small>nlohmann::basic_json_view::</small>count
```cpp
size_type count(string_view_t key) const;
size_type count(const char* key) const;
size_type count(const string_t& key) const;
```
Returns `#!cpp 1` if the value is an object with a member with key `key`, `#!cpp 0` otherwise.
## Parameters
`key` (in)
: key value of the element to count
## Return value
`#!cpp 1` if the value is an object and has a member with key `key`, `#!cpp 0` otherwise.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
another, in document order, stopping at the first match. Each comparison first checks the key's length -- already
known from the index, without reading the key bytes -- before comparing its content.
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time on
average.
## Notes
This method always returns `#!cpp 0` when the value is not an object -- including a [discarded](is_discarded.md)
view.
Unlike [`BasicJsonType::count()`](../basic_json/count.md), whose return value can in principle exceed `#!cpp 1` for
an `ObjectType` that allows multiple entries per key, `count()` here never does: it is exactly
[`contains()`](contains.md) as `#!cpp 0`/`#!cpp 1`. This holds even if the source text has a duplicate key -- see the
[Notes on duplicate keys](operator[].md#notes) of `operator[]` -- because a `#!cpp count() > 1` result would require
counting every member with a matching key, not just finding the first one.
## Examples
??? example
The example below validates that every transaction of a batch carries a mandatory `amount` field, using
`count()` before deciding whether to materialize a transaction at all.
```cpp
--8<-- "examples/basic_json_view__count.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__count.output"
```
## See also
- [find](find.md) - find a value in an object
- [contains](contains.md) - checks whether a key exists
- [`BasicJsonType::count`](../basic_json/count.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,102 +0,0 @@
# <small>nlohmann::basic_json_view::</small>dump
```cpp
string_t dump(const int indent = -1,
const char indent_char = ' ',
const bool ensure_ascii = false,
const number_format numbers = number_format::shortest) const;
```
Serializes this value (and its subtree) directly from the flat index, without ever building a `BasicJsonType` value
first. With the default `#!cpp numbers == number_format::shortest`, the result is the same string
[`BasicJsonType::dump`](../basic_json/dump.md) would produce for the value
[`BasicJsonType::parse()`](../basic_json/parse.md) builds from the same source text, called with the same `indent`,
`indent_char`, and `ensure_ascii` -- except that members of an object appear in document order rather than sorted by
key, and *every* occurrence of a repeated key is written rather than only the last one (see
[Notes on duplicate keys](operator[].md#notes)). For a `json_view` (whose `BasicJsonType` is not ordered), this means
`dump()` can print an object's members in a different order than [`materialize()`](materialize.md)`.dump()` of the
same subtree.
## Parameters
`indent` (in)
: If `indent` is nonnegative, array elements and object members are pretty-printed with that indent level. An
indent level of `0` only inserts newlines. `-1` (the default) selects the most compact representation.
`indent_char` (in)
: The character used for indentation if `indent` is greater than `0`. The default is ` ` (space).
`ensure_ascii` (in)
: If `ensure_ascii` is `#!cpp true`, all non-ASCII characters in the output are escaped with `\uXXXX` sequences, and
the result consists of ASCII characters only.
`numbers` (in)
: how to write numbers, see [`number_format`](number_format.md): `shortest` (the default) writes them the way
[`BasicJsonType::dump`](../basic_json/dump.md) would; `source` copies every number exactly as it appears in the
source text.
## Return value
string containing the serialization of this value, or `#!cpp "<discarded>"` if the view is
[discarded](is_discarded.md).
## Exception safety
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
## Exceptions
May throw `#!cpp std::bad_alloc` if allocating the output string fails. Unlike
[`BasicJsonType::dump`](../basic_json/dump.md), there is no `error_handler` parameter and no
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316): the view only ever holds text the parser
already validated as UTF-8, so there is nothing to replace or ignore.
## Complexity
Linear in the size of the output text.
## Notes
The walk over the subtree is iterative, so the nesting depth it can write is limited by available memory only, not by
the call stack -- as for [`materialize()`](materialize.md).
Strings are escaped by the same rules as [`BasicJsonType::dump`](../basic_json/dump.md). With
`#!cpp numbers == number_format::shortest`, floats are written with the library's shortest round-trip conversion,
exactly as [`BasicJsonType::dump`](../basic_json/dump.md) would (e.g. `#!cpp 1.5`, `#!cpp 100.0`, `#!cpp 1e+100`), and
integers are copied from the source text -- already canonical in JSON, so this matches their shortest form too --
except that `#!cpp -0` is written as `#!cpp 0`, the way [`BasicJsonType::parse()`](../basic_json/parse.md) reads it.
`#!cpp number_format::source` copies every number exactly as written in the source text instead, with no exception
for `#!cpp -0` -- `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0.0`, `#!cpp -0`, or all digits of an integer literal with more
digits than any number type holds (such a literal is itself classified as a float, see
[What is different](../../features/json_view.md#what-is-different)) -- something `BasicJsonType` cannot do, since
parsing already reduces every number to its parsed value.
## Examples
??? example
The example below forwards a single record out of a larger batch, and re-serializes a configuration file, both
without ever building a `BasicJsonType` value for the surrounding array or for the parts of it that were not
needed. It also shows that [`materialize()`](materialize.md)`.dump()` of the configuration sorts its keys, where
`dump()` on the view keeps the order they appear in the source text.
```cpp
--8<-- "examples/basic_json_view__dump.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__dump.output"
```
## See also
- [`number_format`](number_format.md) - how `dump()` writes numbers
- [operator<<](operator_ltlt.md) - serialize this value to a stream
- [materialize](materialize.md) - build a `BasicJsonType` value, e.g. to use `BasicJsonType::dump`'s `error_handler`
- [`BasicJsonType::dump`](../basic_json/dump.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,61 +0,0 @@
# <small>nlohmann::basic_json_view::</small>empty
```cpp
bool empty() const noexcept;
```
Checks whether [`size()`](size.md) is `0`, as [`BasicJsonType::empty()`](../basic_json/empty.md) would for the same
value.
## Return value
The return value depends on the type and is defined as follows:
| Value type | return value |
|----------------------|-----------------|
| null | `#!cpp true` |
| discarded | `#!cpp true` |
| boolean | `#!cpp false` |
| string | `#!cpp false` |
| number | `#!cpp false` |
| object | `#!cpp object_t::empty()` |
| array | `#!cpp array_t::empty()` |
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
As for [`BasicJsonType::empty()`](../basic_json/empty.md), this does not return whether a string value is empty -- it
is `#!cpp false` for any string, regardless of its length.
## Examples
??? example
The example below uses [`size()`](size.md) and `empty()` to decide whether a parsed message is worth acting on,
without materializing it into a `BasicJsonType` value.
```cpp
--8<-- "examples/basic_json_view__size_empty.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__size_empty.output"
```
## See also
- [size](size.md) - return the number of elements
- [`BasicJsonType::empty`](../basic_json/empty.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,54 +0,0 @@
# <small>nlohmann::basic_json_view::</small>end
```cpp
iterator end() const noexcept;
```
Returns an iterator to one past the last element of an array, one past the last member value of an object, in
**document order** -- see [`begin()`](begin.md). A primitive value iterates as a range of one element (itself);
`#!json null` and a [discarded](is_discarded.md) view iterate as an empty range, so `#!cpp begin() == end()` for
them.
## Return value
Iterator one past the last element.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Constant.
## Notes
`#!cpp iterator` is a forward iterator: unlike `BasicJsonType::iterator`, it cannot be decremented, so there is no
way to reach the last element by stepping back from `end()`. Use [`back()`](back.md) instead.
## Examples
??? example
The example below scans a (possibly large) array of readings for the first one over a threshold, stopping the
loop at `end()` as soon as one is found. Only the matching reading, if any, is ever materialized.
```cpp
--8<-- "examples/basic_json_view__end.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__end.output"
```
## See also
- [begin](begin.md) - returns an iterator to the first element
- [cend](cend.md) - returns a const iterator to one past the last element
- [`BasicJsonType::end`](../basic_json/end.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,65 +0,0 @@
# <small>nlohmann::basic_json_view::</small>find
```cpp
iterator find(string_view_t key) const;
iterator find(const char* key) const;
iterator find(const string_t& key) const;
```
Finds a member with key `key` -- the first one, should the key occur more than once (see
[Notes on duplicate keys](operator[].md#notes)). If the value is not an object, or no member has this key,
[`end()`](end.md) is returned.
## Parameters
`key` (in)
: key value of the element to search for
## Return value
An iterator to the member with key `key`, or [`end()`](end.md) if there is none or the value is not an object.
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
another, in document order, stopping at the first match. Each comparison first checks the key's length -- already
known from the index, without reading the key bytes -- before comparing its content.
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time on
average.
## Notes
Unlike [`BasicJsonType::find`](../basic_json/find.md), which always returns `#!cpp end()` for a non-object type, this
also does so for a [discarded](is_discarded.md) view -- there is no separate "invalid" iterator to return.
## Examples
??? example
The example below scans a batch of events for those that carry an optional `user_id` field, using `find()`
instead of [`operator[]`](operator[].md) (which would throw for the events that are not objects at all) or
[`contains()`](contains.md) followed by a second lookup. Events without a match are never materialized.
```cpp
--8<-- "examples/basic_json_view__find.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__find.output"
```
## See also
- [count](count.md) - returns the number of occurrences of a key
- [contains](contains.md) - checks whether a key exists
- [`BasicJsonType::find`](../basic_json/find.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,61 +0,0 @@
# <small>nlohmann::basic_json_view::</small>front
```cpp
basic_json_view front() const;
```
Returns the first element of an array, the first member value of an object, or the value itself if it is primitive
(as for [`BasicJsonType::front()`](../basic_json/front.md), a primitive value is a range of one element).
## Return value
The first element or member value. For a primitive value (number, string, boolean), the value itself.
## Exception safety
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
## Exceptions
Throws [`invalid_iterator.214`](../../home/exceptions.md#jsonexceptioninvalid_iterator214) if the view is
[null](is_null.md) or [discarded](is_discarded.md), or if it is an empty array or object.
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
## Complexity
Constant.
## Notes
Unlike [`BasicJsonType::front()`](../basic_json/front.md), which has undefined behavior for an empty array or
object, `front()` throws `invalid_iterator.214` in that case -- the same way it already does for `#!json null` and
for a discarded view, where `BasicJsonType::front()` also throws.
## Examples
??? example
The example below reads only the earliest entry of a build log with `front()`, without materializing the rest
of the (possibly long) log.
```cpp
--8<-- "examples/basic_json_view__front.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__front.output"
```
## See also
- [back](back.md) - access the last element
- [`BasicJsonType::front`](../basic_json/front.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
-130
View File
@@ -1,130 +0,0 @@
# <small>nlohmann::basic_json_view::</small>get
```cpp
template<typename T>
T get() const;
```
Converts the value to `T`.
For the types below, the conversion works directly on the flat index -- no `BasicJsonType` value is built for it:
- `#!cpp bool`
- arithmetic types other than `#!cpp bool` (from a number; from a boolean, as `#!cpp 0`/`#!cpp 1`, exactly as
[`BasicJsonType::get<T>()`](../basic_json/get.md) converts a boolean)
- `#!cpp std::nullptr_t`
- `#!cpp std::basic_string<char, Traits, Alloc>` (including `string_t`) -- a copy of the string
- [`string_view_t`](index.md#member-types) -- **no copy**: the returned view points into the document's
[`source()`](../basic_json_document/source.md) text, or, for a string that contains escape sequences, into the
document's own buffer of decoded strings (see [`get_string()`](get_string.md))
- `BasicJsonType` -- equivalent to [`materialize()`](materialize.md)
- `basic_json_view` -- returns `#!cpp *this`
- `#!cpp std::vector<U, A>` -- element by element, each converted with `#!cpp get<U>()`; `#!cpp
std::vector<basic_json_view>` keeps a view of every element instead of a value
- `#!cpp std::map<K, V, C, A>` and `#!cpp std::unordered_map<K, V, H, E, A>`, if `K` is constructible from a `#!cpp
(const char*, std::size_t)` pair -- member by member, each value converted with `#!cpp get<V>()`; with a repeated
key, the *last* value is kept, as [`BasicJsonType::parse()`](../basic_json/parse.md) (and
[`materialize()`](materialize.md)) does; `#!cpp std::map<std::string, basic_json_view>` keeps views of the members
instead of values
Every other `T` -- `#!cpp std::list`, `#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a
`from_json()`, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
value first (as [`BasicJsonType::parse()`](../basic_json/parse.md) would), and converted from there exactly as
[`BasicJsonType::get<T>()`](../basic_json/get.md) would convert it.
## Template parameters
`T`
: the type to convert the value to
## Return value
the value, converted to `T`
## Exception safety
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
## Exceptions
- For the directly-converted types listed above (other than `BasicJsonType` and `basic_json_view`, which never
throw): throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if the value's type does not
match `T` -- the same exception, with the same message, that [`BasicJsonType::get<T>()`](../basic_json/get.md)
throws for the same JSON type and `T`.
- For `#!cpp std::vector<U, A>`: throws `type_error.302` if the value is not an array; otherwise, whatever converting
an element to `U` throws.
- For `#!cpp std::map`/`#!cpp std::unordered_map`: throws `type_error.302` if the value is not an object; otherwise,
whatever converting a member to the mapped type throws.
- For every other `T`: whatever [`materialize().get<T>()`](../basic_json/get.md) throws -- typically `type_error.302`,
or whatever a user-provided `from_json()` throws.
None of the exceptions thrown directly by this function (the first three bullets above) carry a
[`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no `BasicJsonType` value to point at. An
exception thrown while converting through `materialize()` (the last bullet) is different: it is thrown by a real
`BasicJsonType` value, so it **does** carry a `JSON_DIAGNOSTICS` path if `BasicJsonType` was built with it enabled.
## Complexity
- `#!cpp bool`, arithmetic types, `#!cpp std::nullptr_t`, [`string_view_t`](index.md#member-types), `basic_json_view`:
constant.
- `#!cpp std::basic_string<char, Traits, Alloc>`: constant, plus one allocation and a copy of the string's bytes.
- `BasicJsonType`: linear in the size of the subtree, see [`materialize()`](materialize.md).
- `#!cpp std::vector<U, A>`: linear in the number of elements, times the complexity of converting one element to `U`.
- `#!cpp std::map`/`#!cpp std::unordered_map`: linear in the number of members for walking them, plus the container's
own insertion cost per member (logarithmic for `#!cpp std::map`, amortized constant for `#!cpp
std::unordered_map`), times the complexity of converting one member to the mapped type.
- every other `T`: linear in the size of the subtree (building the `BasicJsonType` value), plus the complexity of
[`BasicJsonType::get<T>()`](../basic_json/get.md) on it.
## Notes
!!! info "Floating-point values"
A floating-point `T` is converted from the same digits the lexer would see during `#!cpp BasicJsonType::parse()`,
using the same conversion, so the result is bit-for-bit identical to `#!cpp BasicJsonType::parse(text).get<T>()`
for the same source text.
!!! info "Duplicate keys"
`#!cpp std::map`/`#!cpp std::unordered_map` conversions keep the *last* value of a repeated key, like
[`materialize()`](materialize.md) and [`BasicJsonType::parse()`](../basic_json/parse.md) do. This is the opposite
of [`operator[]`](operator[].md)/[`at`](at.md)/[`find`](find.md)/[`contains`](contains.md), which resolve to the
*first* occurrence (see the [Notes on duplicate keys](operator[].md#notes)).
!!! info "No pointers, references, or implicit conversion"
Unlike `BasicJsonType`, `basic_json_view` has no stored value anywhere to hand out a pointer or a reference to, so
it provides neither `#!cpp get_ptr()`, `#!cpp get_ref()`, nor `#!cpp operator ValueType()`.
[`get_string()`](get_string.md) (equivalently, `#!cpp get<string_view_t>()`) is the zero-copy alternative for
strings.
## Examples
??? example
The example below reads typed fields straight into C++ variables, collects a view of every array element with
`#!cpp get<std::vector<basic_json_view>>()` instead of a value, and converts a nested object into a user type
through its `from_json()` -- which runs on a `BasicJsonType` value `materialize()` builds for just that one
member.
```cpp
--8<-- "examples/basic_json_view__get.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__get.output"
```
## See also
- [get_to](get_to.md) - convert and write into a passed value
- [get_string](get_string.md) - the string, without a copy
- [number_token](number_token.md) - a number's token text, without a copy
- [materialize](materialize.md) - build the `BasicJsonType` value of this subtree
- [`BasicJsonType::get`](../basic_json/get.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,71 +0,0 @@
# <small>nlohmann::basic_json_view::</small>get_string
```cpp
string_view_t get_string() const;
```
Returns the string value as a [`string_view_t`](index.md#member-types), without copying it.
## Return value
The string, as a [`string_view_t`](index.md#member-types) that points either into the document's
[`source()`](../basic_json_document/source.md) text (a string with no escape sequences), or into the document's own
buffer of decoded strings (a string that contains escape sequences, such as `#!json "\n"` or `#!json "\u00e9"`, which
had to be decoded once when the document was parsed).
## Exception safety
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
## Exceptions
Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if the value is not a string; example:
`"type must be string, but is array"`.
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
`JSON_DIAGNOSTICS` enabled.
## Complexity
Constant.
## Notes
`basic_json_view` has no `BasicJsonType` value stored anywhere, so unlike `BasicJsonType`, it has no `get_ref()` to
hand out a reference to a stored `string_t`. `get_string()` (equivalently, [`get<string_view_t>()`](get.md)) is the
zero-copy alternative: [`BasicJsonType::get_ref<const string_t&>()`](../basic_json/get_ref.md) is its closest
counterpart, except that it returns a view instead of a reference to a value that must already exist.
The returned [`string_view_t`](index.md#member-types) is valid exactly as long as the view that produced it -- see the
[validity rules](index.md) of `basic_json_view` -- and, for a string with no escapes, for as long as the document's
source text.
## Examples
??? example
The example below pulls one field out of a JSON text that stands in for a large API response, and shows that no
`#!cpp std::string` was allocated for it: the returned view still points inside the original buffer. A field that
contains an escape sequence cannot point into the original text -- it was decoded once into the document's own
buffer instead -- but still avoids a per-field allocation.
```cpp
--8<-- "examples/basic_json_view__get_string.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__get_string.output"
```
## See also
- [get](get.md) - convert the value to a given type (`#!cpp get<string_view_t>()` is equivalent to this function)
- [number_token](number_token.md) - a number's token text, without a copy
- [`BasicJsonType::get_ref`](../basic_json/get_ref.md) - the closest counterpart of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -1,65 +0,0 @@
# <small>nlohmann::basic_json_view::</small>get_to
```cpp
template<typename T>
T& get_to(T& v) const;
```
Converts the value to `T` and assigns it to `v`. Equivalent to
```cpp
v = get<T>();
return v;
```
## Template parameters
`T`
: the type to convert the value to
## Parameters
`v` (out)
: the variable to store the converted value in
## Return value
`v`, allowing calls to chain
## Exception safety
Strong exception safety: if an exception is thrown, `v` is not modified.
## Exceptions
Whatever [`get<T>()`](get.md) throws for the same value and `T`.
## Complexity
Whatever [`get<T>()`](get.md) has for the same `T`.
## Examples
??? example
The example below reads several fields of a service configuration directly into existing variables, then uses
the returned reference to fold the `#!cpp host`/`#!cpp port` pair into a single string in the same expression.
```cpp
--8<-- "examples/basic_json_view__get_to.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__get_to.output"
```
## See also
- [get](get.md) - convert the value to a given type
- [`BasicJsonType::get_to`](../basic_json/get_to.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.

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