Compare commits

...
Author SHA1 Message Date
Niels Lohmann 48188b4569 Fix inaccuracies in the documentation
- version history: json_base_class_t (3.11.3), JSON_HAS_CPP_11 (3.10.0),
  JSON_HAS_RANGES exclusions, define-type macros, ABI tags
- releases: 3.12.0 raised the minimum CMake version
- from_*: the (ptr, len) overloads are deleted, not removed, in 4.0.0
- contains/count/find: document the deleted integral overloads
- add JSON_HAS_RANGE_VIEW_CONVERSION and list the JSON_HAS_* macros in
  the macro overview
- mention BON8 and error_handler where binary formats are listed
- broken links, outdated URLs, warning count, Hunter v0.26.12
- copy_markdown_source hook: expand snippets in the Markdown copies

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-10 13:34:47 +02:00
Niels Lohmann 6a28560c87 Clean up CI, CMake, Makefile, and Bazel files
- CMakeLists.txt: avoid VERSION_GREATER_EQUAL, which CMake < 3.7 lacks
- ci.cmake: test JSON_DisableTupleReferenceConversion in ci_cmake_flags,
  remove unused variables and unreachable per-compiler targets, look up
  Clang tools consistently, forward CMAKE_CXX_FLAGS to ci_module_cpp20,
  format json_literals.hpp and remove backups in ci_test_amalgamation
- BUILD.bazel: add json_literals.hpp to the single-header target
- workflows: format json_literals.hpp before copying it, drop the obsolete
  natvis --version plumbing, name natvis and macro_builder in failure
  messages, drop the duplicate amalgamation job, install Valgrind only
  where needed, republish docs on version bumps, fix stale names
- Makefile: complete .PHONY and help, check-amalgamation always restores
  the checked-in files, natvis uses its own venv, macro_builder_check
  installs astyle, clean removes the fuzzer binaries
- remove tools/amalgamate/config_json_view.json (json_view.hpp is not on
  develop yet)

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-10 13:27:26 +02:00
Niels Lohmann fc32fb6aed Clean up README, contribution guide, and repository metadata
- REUSE.toml: fix the Hedley path and SPDX id (CC0-1.0), mark the docset
  icons as the public-domain JSON logo
- CITATION.cff: v3.12.0 was released on 2025-04-11
- FILES.md: list all workflows, describe the Meson option defaults
- README: ctest -LE, table of contents, typos, stale Android/MinGW advice,
  moved links, merge duplicate Thanks entries, list the analysis tools
  used in CI
- CONTRIBUTING: iterative parser, json_literals.hpp is generated, links
- .gitignore: backups and release outputs; .gitattributes: mark
  generated files
- labeler: label other build systems and .github documentation
- MODULE.bazel: add the module version

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-10 13:27:25 +02:00
Niels Lohmann 07ec1a4e31 Generate the docset index and pages with Python (#5799)
Replace the hand-maintained docs/docset/docSet.sql and the bash/sed
Makefile recipe with docs/docset/generate_docset.py:

- The search index is generated from the mkdocs.yml nav and each page's
  H1 and declaration. Pages documenting several entities (e.g.
  JSON_HAS_CPP_11..26) get one entry per name; all non-API pages become
  guides. New API pages no longer need a manual entry.
- Page titles are set from the index names.
- The docset is self-contained: the mermaid loader no longer points to
  https://json.nlohmann.me/assets/..., the repository widget no longer
  queries api.github.com, remaining remote images are downloaded, and
  the build fails if any remote resource load remains.
- The CSS that hides the site navigation now uses Material's classes;
  the element selectors lost against them, so the header was shown.

check_structure.py's docset check is replaced by running the generator
in `make style_check`.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-10 12:10:11 +02:00
Niels Lohmann 74aefc3486 Move custom object key tests out of unit-cbor.cpp and unit-msgpack.cpp (#5798)
The custom object key tests from #5328 instantiate a second basic_json
specialization in unit-cbor.cpp and unit-msgpack.cpp. This pushed
unit-msgpack.cpp.obj past 65535 sections in the clang (MinGW) jobs of
the Windows workflow, and linking test-msgpack_cpp11 fails with
"relocation truncated to fit: IMAGE_REL_AMD64_REL32 against `.rdata'".

The GNU linker keeps the section an associative COMDAT section belongs
to in 16 bits (x_associated in include/coff/internal.h), although big
object files store 32 bits. In larger objects it therefore ties the
jump tables of inline functions to the wrong function and discards them
together with that function's duplicate.

Move the four tests unchanged into unit-custom-object-key-type.cpp and
document the limit in windows.yml.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-10 00:05:02 +02:00
Bas van Dijkandbvandijk 84ee12a67c Make UTF8_ACCEPT/UTF8_REJECT inline variables to avoid TU-local exposure in modules (#5797)
Signed-off-by: bvandijk <bas.van.dijk@cern.ch>
Co-authored-by: bvandijk <bas.van.dijk@cern.ch>
2026-10-09 23:38:42 +02:00
Niels Lohmann 2913e96433 Unflatten in time and memory linear in the pointer depth (#5793)
* Unflatten in time and memory linear in the pointer depth

#5443 made unflatten() decide between arrays and objects independently
of the iteration order by collecting the pointer prefixes that have a
reference token 0 below them in a std::set<std::vector<string_t>>.
Every such prefix was stored as a copy of all its reference tokens, and
get_and_create() compared whole prefix vectors at every step, so
unflattening a pointer of depth d took time and memory quadratic in d:
a 10,000-level array pointer took 18 s and 1.3 GB, a 100,000-level one
did not finish.

The prefixes are now numbered nodes of a tree, so each is stored once
and get_and_create() follows the tree token by token. The result is
unchanged, including its independence of the iteration order.

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

* Initialize prefix_tree members to satisfy -Weffc++

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

* Move prefix_tree setup and child insertion into member functions

The constructor now creates the root node, add_child() inserts a
reference token below a prefix and returns the child's number, and
find_child() looks one up for get_and_create().

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-09 17:57:31 +02:00
Niels Lohmann 44e8597701 Flatten deeply nested values without recursing per nesting level (#5792)
* Flatten deeply nested values without recursing per nesting level

json_pointer::flatten() called itself once per nesting level, so
flatten() on a value nested deeply enough exhausted the call stack.
#5547 and #5548 fixed merge_patch() and diff() from #5393, but flatten()
was left out.

flatten() now walks the value with an explicit stack and keeps the path
in one buffer that grows and shrinks with it. It has a single code path
and no depth limit: the old version built a new path string per child,
so the iterative one is no slower on shallow values and much faster on
deep ones. The output, including the order of an ordered_json result,
is unchanged.

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

* Construct flatten frames in place

Give the frame a constructor so both call sites can use emplace_back, as
suggested in the review; index starts at 0 for every frame.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-09 17:06:41 +02:00
Niels Lohmann 374dfe4f0f Keep converted object keys alive while writing UBJSON and BJData (#5791)
* Keep converted object keys alive while writing UBJSON and BJData

Since #5746, write_ubjson and write_ubjson_iterative pass each object key
to sanitize_utf8_for_write and keep the returned reference. When
object_t::key_type is not string_t but converts to it, the argument is a
temporary that is destroyed at the end of the statement, and the
function returns a reference to it in every case but a sanitized copy,
so the key bytes are read from a dead object (AddressSanitizer:
stack-use-after-scope). Default json and ordered_json are unaffected.

Bind the key to a named object_key_string_t first: a reference when
key_type is string_t, so no copy is added there, and a converted copy
otherwise. A deleted overload of sanitize_utf8_for_write for anything
other than string_t turns a recurrence into a compile error.

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

* Suppress -Wunused-member-function for the converting_key test type

converting_key::data() is only called when JSON_DIAGNOSTICS is enabled.

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

* Fix clang-tidy findings in the UBJSON/BJData converted-key fix

Suppress hicpp/modernize-use-equals-delete on the deleted
sanitize_utf8_for_write overload: it guards a private helper and must stay
private. Replace the C-style array in the new test with std::array.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-09 17:05:36 +02:00
Niels Lohmann d540750f21 Use the with_*_t aliases in the remaining tests and docs (#5790)
#5787 missed the instantiations spelled as `basic_json <` (astyle's
formatting) or ending in the CustomBaseClass argument. Convert them,
including the binary_t.md example pointed out in review.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-09 16:56:14 +02:00
Alex Prabhat Bara 69a0c1b82c Avoid allocating temporary basic_json for cbor and msgpack object keys (#5328)
* avoid allocating temporary basic_json for CBOR and MessagePack object keys

Signed-off-by: alexprabhat99 <alexpbara@gmail.com>

* add size() to the custom object key test type

UBJSON and BJData access object keys through size() and c_str()
directly, so the key type now provides both and the comment says why.

Signed-off-by: alexprabhat99 <alexpbara@gmail.com>

* address review: drop key size()/c_str(), test keys below the depth limit

Nothing in the library calls size() or c_str() on an object key, so the
test key type only keeps data(), which JSON_DIAGNOSTICS needs.

The CBOR and MessagePack custom key tests now also nest objects deeper
than detail::recursion_depth_limit(), so keys written by
write_cbor_iterative and write_msgpack_iterative are covered as well.

Signed-off-by: alexprabhat99 <alexpbara@gmail.com>

---------

Signed-off-by: alexprabhat99 <alexpbara@gmail.com>
2026-10-09 13:22:07 +02:00
Niels Lohmann d33068da73 Address review comments on the API stability docs and a test comment (#5784)
* Address review comments on #5775 and #5779

Allow new defaulted parameters and new default arguments in the API
stability rules, mention the macro opt-in, and drop the redundant
recompile advice. Describe test-diagnostics-optimized as the regression
test for the fixed #5742.

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

* Document what counts as a breaking change in the API stability rules

Spell out the 3.x compatibility rules in the roadmap: new defaulted
parameters, new default arguments, noexcept/constexpr, template
parameters, parse and dump results, accepted input, key iteration order,
iterator invalidation, implicit conversions, to_json/from_json lookup,
json_sax, value_t enumerators, and documented macros, CMake options and
headers. Also list std::hash values as not part of the public API, and
link the macro overview from the section.

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-08 17:44:34 +02:00
Niels Lohmann d8dfc0d0f9 Fix unused-result warnings in the contains and parse_error examples (#5788)
contains(json_pointer) is marked JSON_HEDLEY_WARN_UNUSED_RESULT since #5477,
and parse() has been for longer. The contains example ignored the result in
two try blocks waiting for a parse_error that contains() never throws, so
they printed nothing; print the result for those pointers instead.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-08 16:21:59 +02:00
Niels Lohmann 3d7f554927 Use the with_*_t aliases in tests, examples, and docs (#5787)
* Use the with_*_t aliases in tests, examples, and docs

Replace spelled-out basic_json<...> instantiations that only change one
or two template parameters with nlohmann::json::with_*_t (or
ordered_json::with_*_t when the object type is ordered_map). Types that
change all three number types chain with_integers_t and with_float_t.

The raw basic_json<...> spelling stays where the template parameter
list itself is the subject: the alias tests in unit-udt.cpp, explicit
instantiations, and the ordered_json/compile-time docs.

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

* Fix unit-large_json for clang and JSON_DIAGNOSTICS

Two test problems from #5781 broke CI on develop: CAPTURE(depth); trips
clang's -Wextra-semi-stmt, and the type_error.321 messages did not
account for the diagnostics path prefix.

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

* Use static_cast in unit-hash for clang-tidy

#5772 added functional casts that clang-tidy reports as C-style casts
(google-readability-casting). Also append a char instead of a
one-character string in unit-large_json.

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

* Declare the expected message prefix const in unit-large_json

Without JSON_DIAGNOSTICS the prefix was never modified, which
clang-tidy reports (misc-const-correctness).

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

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-08 16:11:16 +02:00
Suyog Verma a269794db7 Use MSVC intrinsics for full multiplication (#5782)
* Use MSVC intrinsics for full multiplication

Signed-off-by: Suyog Verma <suyogverma0057@gmail.com>

* Fix formatting in unit-class_lexer

Signed-off-by: Suyog Verma <suyogverma0057@gmail.com>

* Address review feedback

Signed-off-by: Suyog Verma <suyogverma0057@gmail.com>

---------

Signed-off-by: Suyog Verma <suyogverma0057@gmail.com>
2026-10-08 08:49:32 +02:00
107 changed files with 2503 additions and 1477 deletions

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
# generated files are collapsed in diffs and excluded from language statistics
single_include/** linguist-generated
nlohmann_json.natvis linguist-generated
+1 -1
View File
@@ -1,5 +1,5 @@
# JSON for Modern C++ was originally written by Niels Lohmann. # JSON for Modern C++ was originally written by Niels Lohmann.
# Since 2013, over 250 contributors have helped to improve the library. # Since 2013, over 400 contributors have helped to improve the library.
# This CODEOWNERS file is only to make sure that @nlohmann is requested # This CODEOWNERS file is only to make sure that @nlohmann is requested
# for a code review in case of a pull request. # for a code review in case of a pull request.
+16 -14
View File
@@ -98,7 +98,7 @@ $ ctest --test-dir build -j 10
The test suite should report: The test suite should report:
``` ```
100% tests passed, 0 tests failed out of 98 100% tests passed, 0 tests failed out of <number of tests>
``` ```
#### Add tests #### Add tests
@@ -149,14 +149,17 @@ make build -C docs/mkdocs # strict build: fails on broken links, anchor
make check_mermaid -C docs/mkdocs # checks the Mermaid diagrams (requires Node.js) make check_mermaid -C docs/mkdocs # checks the Mermaid diagrams (requires Node.js)
``` ```
A new API page also needs an entry in [`docs/docset/docSet.sql`](https://github.com/nlohmann/json/blob/develop/docs/docset/docSet.sql), The search index of the docset is generated from [`mkdocs.yml`](https://github.com/nlohmann/json/blob/develop/docs/mkdocs/mkdocs.yml)
the search index of the docset; `make build` reports missing entries. and each page's title (H1) and declaration by
[`docs/docset/generate_docset.py`](https://github.com/nlohmann/json/blob/develop/docs/docset/generate_docset.py);
`make build` reports API pages that cannot be classified.
### Amalgamate the source code ### Amalgamate the source code
The single-header files The single-header files
[`single_include/nlohmann/json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) and [`single_include/nlohmann/json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp),
[`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp) [`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp), and
[`single_include/nlohmann/json_literals.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_literals.hpp)
are **generated** from the source files in the are **generated** from the source files in the
[`include/nlohmann` directory](https://github.com/nlohmann/json/tree/develop/include/nlohmann). **Do not** edit the [`include/nlohmann` directory](https://github.com/nlohmann/json/tree/develop/include/nlohmann). **Do not** edit the
files directly; instead, modify the include/nlohmann sources and regenerate the files by executing: files directly; instead, modify the include/nlohmann sources and regenerate the files by executing:
@@ -179,7 +182,7 @@ The amalgamation check in CI fails if any of these generated files is out of dat
## Recommended documentation ## Recommended documentation
- The library’s [README file](https://github.com/nlohmann/json/blob/master/README.md) is an excellent starting point to - The library’s [README file](https://github.com/nlohmann/json/blob/develop/README.md) is an excellent starting point to
understand its functionality. understand its functionality.
- The [documentation page](https://json.nlohmann.me) is the reference documentation of the library. - The [documentation page](https://json.nlohmann.me) is the reference documentation of the library.
- [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259) is the reference for the JavaScript Object Notation (JSON) - [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259) is the reference for the JavaScript Object Notation (JSON)
@@ -218,9 +221,9 @@ feature macros then allows users to test their code against the library in the n
### Break C++11 language conformance ### Break C++11 language conformance
This library is designed to work with C++11 and later. This means that any This library is designed to work with C++11 and later. This means that any
[supported C++11 compiler](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers) should compile [supported C++11 compiler](https://github.com/nlohmann/json/blob/develop/README.md#supported-compilers) should compile
the library without problems. Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual the library without problems. Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual
Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. C++ 2013 and earlier are known not to work due to missing or incomplete C++11 support.
Please do not add features that do not work with the mentioned supported compilers. Please guard features from C++14 and Please do not add features that do not work with the mentioned supported compilers. Please guard features from C++14 and
later against the respective [`JSON_HAS_CPP_14`](https://json.nlohmann.me/api/macros/json_has_cpp_11/) macros. later against the respective [`JSON_HAS_CPP_14`](https://json.nlohmann.me/api/macros/json_has_cpp_11/) macros.
@@ -236,12 +239,11 @@ extension.
The following areas really need contribution and are always welcomed: The following areas really need contribution and are always welcomed:
- Extending the **continuous integration** toward more exotic compilers such as Android NDK, Intel's Compiler, or the - Extending the **continuous integration** toward more exotic compilers such as Android NDK, Intel's Compiler, or the
bleeding-edge versions Clang. bleeding-edge versions of Clang.
- Improving the efficiency of the **JSON parser**. The current parser is implemented as a naive recursive descent parser - Improving the efficiency of the **JSON parser**. The current parser is a hand-written iterative parser that keeps an
with hand-coded string handling. More sophisticated approaches like LALR parsers would be really appreciated. That explicit stack instead of recursing, with hand-coded string handling. Speeding up the lexer or the value construction
said, parser generators like Bison or ANTLR do not play nice with single-header files -- I really would like to keep would be appreciated. Parser generators like Bison or ANTLR do not play nice with single-header files -- I really
the parser inside the `json.hpp` header, and I am not aware of approaches similar to [`re2c`](http://re2c.org) for would like to keep the parser inside the `json.hpp` header.
parsing.
- Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency - Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency
is not everything, speed and memory consumption are very important characteristics for C++ developers, so having is not everything, speed and memory consumption are very important characteristics for C++ developers, so having
proper comparisons would be interesting. proper comparisons would be interesting.
+2 -2
View File
@@ -52,7 +52,7 @@ body:
If possible, provide a small and self-contained example that triggers If possible, provide a small and self-contained example that triggers
the bug. Please understand that we cannot analyze and debug large code the bug. Please understand that we cannot analyze and debug large code
bases. Please do not paste screenshots here. bases. Please do not paste screenshots here.
render: Shell render: cpp
- type: textarea - type: textarea
id: output id: output
attributes: attributes:
@@ -79,7 +79,7 @@ body:
description: > description: >
Which version of the library did you use? If it is a released version, Which version of the library did you use? If it is a released version,
please enter the version number (e.g., 3.12.0). Otherwise, please enter please enter the version number (e.g., 3.12.0). Otherwise, please enter
the commit hash. If you got the library from another source as the the commit hash. If you got the library from another source than the
GitHub repository (e.g., via a package manager), please also state GitHub repository (e.g., via a package manager), please also state
this. this.
validations: validations:
+11
View File
@@ -21,6 +21,17 @@ labels:
files: files:
- "cmake/.*" - "cmake/.*"
# other build systems
- label: "CMake"
files:
- "(meson\\.build|meson_options\\.txt|BUILD\\.bazel|MODULE\\.bazel|Package\\.swift)"
- label: "documentation"
files:
- ".github/ISSUE_TEMPLATE/.*"
- ".github/config\\.yml"
- ".github/(CONTRIBUTING|SECURITY|CODE_OF_CONDUCT|PULL_REQUEST_TEMPLATE)\\.md"
- label: "CI" - label: "CI"
files: files:
- ".github/workflows/.*" - ".github/workflows/.*"
+7 -13
View File
@@ -83,8 +83,7 @@ jobs:
# byte for byte), so there is nothing to gain from checking out a # 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 # 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 # that adds support for a new dispatch table until that PR itself
# merges to develop, the same way generate_natvis.py's --version # merges to develop.
# requirement briefly did.
TMPDIR=$(mktemp -d ./macro_builder_check.XXXXXX) TMPDIR=$(mktemp -d ./macro_builder_check.XXXXXX)
c++ -std=c++11 tools/macro_builder/main.cpp -o "$TMPDIR/macro_builder" c++ -std=c++11 tools/macro_builder/main.cpp -o "$TMPDIR/macro_builder"
"$TMPDIR/macro_builder" > "$TMPDIR/paste.hpp" "$TMPDIR/macro_builder" > "$TMPDIR/paste.hpp"
@@ -117,7 +116,6 @@ jobs:
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json.json -s . 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 . 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 header list of the Bazel "json" target must match the files in include/ # the header list of the Bazel "json" target must match the files in include/
cmake -P cmake/scripts/gen_bazel_build_file.cmake cmake -P cmake/scripts/gen_bazel_build_file.cmake
@@ -138,17 +136,13 @@ jobs:
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \ ${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
$(find $SOURCE_DIRS -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort) $(find $SOURCE_DIRS -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort)
# json_literals.hpp is copied verbatim from the (now formatted) include/
# directory, like `make amalgamate` does
cp include/nlohmann/json_literals.hpp $INCLUDE_DIR/json_literals.hpp
- name: Regenerate nlohmann_json.natvis - name: Regenerate nlohmann_json.natvis
run: | run: |
cd $MAIN_DIR 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]\+')
# The template is what this check verifies the committed natvis # The template is what this check verifies the committed natvis
# file against, so take it from this PR rather than from the # file against, so take it from this PR rather than from the
# develop checkout: generate_natvis.py loads the template from its # develop checkout: generate_natvis.py loads the template from its
@@ -156,7 +150,7 @@ jobs:
# template could never pass. Like the macro_builder step above, # template could never pass. Like the macro_builder step above,
# this only renders PR content in a job without credentials. # this only renders PR content in a job without credentials.
cp tools/generate_natvis/nlohmann_json.natvis.j2 $NATVIS_TOOL_DIR/ cp tools/generate_natvis/nlohmann_json.natvis.j2 $NATVIS_TOOL_DIR/
python3 $NATVIS_TOOL_DIR/generate_natvis.py --version "$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH" $MAIN_DIR python3 $NATVIS_TOOL_DIR/generate_natvis.py $MAIN_DIR
- name: Build patch and check for differences - name: Build patch and check for differences
id: diff id: diff
@@ -165,7 +159,7 @@ jobs:
mkdir -p ${{ github.workspace }}/patch mkdir -p ${{ github.workspace }}/patch
git diff --patch --no-color > ${{ github.workspace }}/patch/amalgamation.patch git diff --patch --no-color > ${{ github.workspace }}/patch/amalgamation.patch
if [ -s ${{ github.workspace }}/patch/amalgamation.patch ]; then if [ -s ${{ github.workspace }}/patch/amalgamation.patch ]; then
echo "The source code has not been amalgamated/formatted correctly or BUILD.bazel is out of date. Diff:" echo "The source code has not been amalgamated/formatted correctly, or BUILD.bazel, nlohmann_json.natvis, or the macro_builder tables in macro_scope.hpp are out of date ('make amalgamate BUILD.bazel natvis' fixes all but the tables, see tools/macro_builder/README.md). Diff:"
cat ${{ github.workspace }}/patch/amalgamation.patch cat ${{ github.workspace }}/patch/amalgamation.patch
echo "has_diff=true" >> "$GITHUB_OUTPUT" echo "has_diff=true" >> "$GITHUB_OUTPUT"
else else
@@ -96,7 +96,7 @@ jobs:
issue_number: issue_number, issue_number: issue_number,
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
body: '## 🔴 Amalgamation check failed! 🔴\nThe source code has not been amalgamated and/or formatted correctly, or `BUILD.bazel` is out of date.' body: '## 🔴 Amalgamation check failed! 🔴\nThe source code has not been amalgamated and/or formatted correctly, or `BUILD.bazel`, `nlohmann_json.natvis`, or the macro_builder tables in `macro_scope.hpp` are out of date. `make amalgamate BUILD.bazel natvis` fixes all but the tables (see `tools/macro_builder/README.md`).'
+ (hasPatch ? '\n\n📎 A ready-to-apply patch is attached to the [failed workflow run](' + runUrl + ') as the `amalgamation-patch` artifact.' + (hasPatch ? '\n\n📎 A ready-to-apply patch is attached to the [failed workflow run](' + runUrl + ') as the `amalgamation-patch` artifact.'
+ ' Download it, then apply it locally from the repository root with:' + ' Download it, then apply it locally from the repository root with:'
+ '\n\n```shell\ngit apply amalgamation.patch\n```\n\n' + '\n\n```shell\ngit apply amalgamation.patch\n```\n\n'
@@ -15,6 +15,7 @@ on:
- .github/SECURITY.md - .github/SECURITY.md
- cmake/clang_flags.cmake - cmake/clang_flags.cmake
- cmake/gcc_flags.cmake - cmake/gcc_flags.cmake
- include/nlohmann/detail/abi_macros.hpp
- tests/fmt_formatter/project/main.cpp - tests/fmt_formatter/project/main.cpp
- tools/astyle/.astylerc - tools/astyle/.astylerc
workflow_dispatch: workflow_dispatch:
+3 -2
View File
@@ -109,7 +109,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind] target: [ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind]
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
@@ -117,6 +117,7 @@ jobs:
egress-policy: audit egress-policy: audit
- name: Install Valgrind - name: Install Valgrind
if: matrix.target == 'ci_test_valgrind'
run: sudo apt-get update ; sudo apt-get install -y valgrind run: sudo apt-get update ; sudo apt-get install -y valgrind
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
@@ -279,7 +280,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Get latest CMake and ninja - name: Get latest CMake and ninja
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
- name: Set env FORCE_STDCPPFS_FLAG for clang 7 / 8 / 9 / 10 - name: Disable filesystem support (std::filesystem is unusable) for clang 7 / 8 / 9 / 10
run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV" run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV"
if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }} if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }}
- name: Run CMake - name: Run CMake
+8 -1
View File
@@ -166,6 +166,13 @@ jobs:
# link, but the binaries clang 11.0.1 and clang 18.1.8 then produce crash # link, but the binaries clang 11.0.1 and clang 18.1.8 then produce crash
# before doctest prints its first line - 39 of 102 tests on clang 18. # before doctest prints its first line - 39 of 102 tests on clang 18.
# Keep the objects small by splitting the test files instead. # Keep the objects small by splitting the test files instead.
# Objects with more than 65535 sections fail to link with "relocation
# truncated to fit: IMAGE_REL_AMD64_REL32 against `.rdata'": the MinGW
# linker stores the section an associative COMDAT section belongs to in
# 16 bits (x_associated in binutils' include/coff/internal.h), so it
# discards the jump tables of inline functions together with the wrong
# function. Each basic_json specialization a test file instantiates adds
# many sections, so test a second one in a file of its own.
- name: Run CMake - name: Run CMake
run: cmake -S . -B build ^ run: cmake -S . -B build ^
-DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" ^ -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" ^
@@ -180,7 +187,7 @@ jobs:
- name: Test - name: Test
run: cd build ; ctest -j 10 -C Debug --output-on-failure run: cd build ; ctest -j 10 -C Debug --output-on-failure
clang-cl-12: clang-cl:
runs-on: windows-2022 runs-on: windows-2022
strategy: strategy:
matrix: matrix:
+14 -1
View File
@@ -27,7 +27,6 @@
/docs/docset/JSON_for_Modern_C++.tgz /docs/docset/JSON_for_Modern_C++.tgz
/docs/docset/docSet.dsidx /docs/docset/docSet.dsidx
/docs/mkdocs/.cache/ /docs/mkdocs/.cache/
/docs/mkdocs/docs/__pycache__/
/docs/mkdocs/hooks/__pycache__/ /docs/mkdocs/hooks/__pycache__/
/docs/mkdocs/scripts/mermaid/node_modules/ /docs/mkdocs/scripts/mermaid/node_modules/
/docs/mkdocs/site/ /docs/mkdocs/site/
@@ -47,3 +46,17 @@ nlohmann_json.spdx
# Bazel-related # Bazel-related
MODULE.bazel.lock MODULE.bazel.lock
# backups left by `make check-amalgamation` or the ci_test_amalgamation target if they are interrupted
/BUILD.bazel~
/nlohmann_json.natvis~
/single_include/nlohmann/*.hpp~
/venv_astyle/
# release outputs of `make release`
/include.zip
/include.zip.asc
/json.tar.xz
/json.tar.xz.asc
/release_files/
/single_include/nlohmann/*.asc
+1
View File
@@ -81,6 +81,7 @@ cc_library(
hdrs = [ hdrs = [
"single_include/nlohmann/json.hpp", "single_include/nlohmann/json.hpp",
"single_include/nlohmann/json_fwd.hpp", "single_include/nlohmann/json_fwd.hpp",
"single_include/nlohmann/json_literals.hpp",
], ],
includes = ["single_include"], includes = ["single_include"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
+1 -1
View File
@@ -8,7 +8,7 @@ authors:
website: https://nlohmann.me website: https://nlohmann.me
title: "JSON for Modern C++" title: "JSON for Modern C++"
version: 3.12.0 version: 3.12.0
date-released: 2025-04-07 date-released: 2025-04-11
license: MIT license: MIT
repository-code: "https://github.com/nlohmann/json" repository-code: "https://github.com/nlohmann/json"
url: https://json.nlohmann.me url: https://json.nlohmann.me
+1 -1
View File
@@ -30,7 +30,7 @@ endif ()
option(NLOHMANN_JSON_BUILD_MODULES "Build C++ modules support" OFF) option(NLOHMANN_JSON_BUILD_MODULES "Build C++ modules support" OFF)
if(NLOHMANN_JSON_BUILD_MODULES) if(NLOHMANN_JSON_BUILD_MODULES)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28) if(NOT CMAKE_VERSION VERSION_LESS 3.28)
message(STATUS "Building nlohmann.json C++ module") message(STATUS "Building nlohmann.json C++ module")
add_subdirectory(src/modules) add_subdirectory(src/modules)
else() else()
+7 -4
View File
@@ -14,7 +14,7 @@ This file describes the source for supporting files; that is, files that are not
The [GitHub Actions](https://docs.github.com/en/actions) workflows that build, test, and analyze the library. Each file in this folder defines one workflow: The [GitHub Actions](https://docs.github.com/en/actions) workflows that build, test, and analyze the library. Each file in this folder defines one workflow:
- `ubuntu.yml`, `macos.yml`, `windows.yml` — build and run the test suite on Linux, macOS, and Windows. - `ubuntu.yml`, `macos.yml`, `windows.yml` — build and run the test suite on Linux, macOS, and Windows.
- `check_amalgamation.yml` — verify that the single-header amalgamation in `single_include` is up to date on pull requests. - `check_amalgamation.yml` — verify on pull requests and pushes to `develop` that the generated files (the single-header amalgamation in `single_include`, `BUILD.bazel`, and `nlohmann_json.natvis`) are up to date.
- `comment_check_amalgamation.yml` — comment on a pull request when the amalgamation check failed. - `comment_check_amalgamation.yml` — comment on a pull request when the amalgamation check failed.
- `cifuzz.yml` — run short fuzzing sessions via [OSS-Fuzz CIFuzz](https://google.github.io/oss-fuzz/getting-started/continuous-integration/) on pull requests. - `cifuzz.yml` — run short fuzzing sessions via [OSS-Fuzz CIFuzz](https://google.github.io/oss-fuzz/getting-started/continuous-integration/) on pull requests.
- `codeql-analysis.yml` — run [CodeQL](https://codeql.github.com) code scanning. - `codeql-analysis.yml` — run [CodeQL](https://codeql.github.com) code scanning.
@@ -24,7 +24,9 @@ The [GitHub Actions](https://docs.github.com/en/actions) workflows that build, t
- `dependency-review.yml` — scan dependency changes in pull requests for known vulnerabilities. - `dependency-review.yml` — scan dependency changes in pull requests for known vulnerabilities.
- `labeler.yml` — the "Pull Request Labeler" workflow (see `.github/labeler.yml`). - `labeler.yml` — the "Pull Request Labeler" workflow (see `.github/labeler.yml`).
- `stale.yml` — comment on and close stale issues and pull requests. - `stale.yml` — comment on and close stale issues and pull requests.
- `publish_documentation.yml` — build and publish the documentation on every merge to the `develop` branch. - `publish_documentation.yml` — build and publish the documentation on pushes to the `develop` branch that touch the documentation sources (or the files it embeds).
- `check_docs_links.yml` — check the links of the documentation weekly, as external links can break without any change in this repository.
- `cancel_closed_pr_runs.yml` — cancel unfinished workflow runs of a pull request once it is closed or merged.
Further documentation: Further documentation:
@@ -266,8 +268,9 @@ meson setup builddir
ninja -C builddir ninja -C builddir
``` ```
`meson_options.txt` defines the options, which mirror the CMake options that change the library's target (for example, `meson_options.txt` defines the options, which mirror the names of the CMake options that change the library's target (for example,
`-DDiagnostics=true`). Meson requires this file next to `meson.build`, so it is also part of `include.zip`. `make check_build_options` `-DDiagnostics=true`); their defaults may differ (for example, `MultipleHeaders` defaults to `false` in Meson, while
`JSON_MultipleHeaders` is `ON` in CMake). Meson requires this file next to `meson.build`, so it is also part of `include.zip`. `make check_build_options`
([`tools/check_build_options`](tools/check_build_options/README.md)) checks in CI that both files and the pkg-config files ([`tools/check_build_options`](tools/check_build_options/README.md)) checks in CI that both files and the pkg-config files
stay in sync with the CMake options. stay in sync with the CMake options.
+1
View File
@@ -1,5 +1,6 @@
module( module(
name = "nlohmann_json", name = "nlohmann_json",
version = "3.12.0",
compatibility_level = 1, compatibility_level = 1,
) )
+37 -26
View File
@@ -1,4 +1,4 @@
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis macro_builder_check check_build_options .PHONY: all amalgamate check-amalgamation check_build_options pretty install_astyle clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis macro_builder_check run_benchmarks pvs_studio serve_header reuse spdx
########################################################################## ##########################################################################
# configuration # configuration
@@ -41,12 +41,18 @@ all:
@echo "BUILD.bazel - regenerate the Bazel BUILD file 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 "ChangeLog.md - generate ChangeLog file"
@echo "check-amalgamation - check whether sources have been amalgamated and BUILD.bazel is up to date" @echo "check-amalgamation - check whether sources have been amalgamated and BUILD.bazel is up to date"
@echo "check_build_options - check that the Meson build and the pkg-config files offer the options of the CMake target"
@echo "clean - remove built files" @echo "clean - remove built files"
@echo "fuzzing - see tests/fuzzing.md for how to build and run the fuzzers" @echo "(fuzzers) - see tests/fuzzing.md, or run 'make -C tests fuzzers' to build the AFL fuzzers"
@echo "macro_builder_check - check that macro_scope.hpp matches tools/macro_builder's output" @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 "natvis - regenerate nlohmann_json.natvis from the current ABI tags and version"
@echo "pretty - beautify code with Artistic Style" @echo "pretty - beautify code with Artistic Style"
@echo "pvs_studio - run the PVS-Studio static analyzer and open the report"
@echo "release - create the release files (include.zip, json.tar.xz, single headers, signatures, hashes)"
@echo "reuse - annotate the source files with REUSE license headers and lint them"
@echo "run_benchmarks - build and run benchmarks" @echo "run_benchmarks - build and run benchmarks"
@echo "serve_header - serve the single header, re-amalgamated on demand (see tools/serve_header)"
@echo "spdx - generate the SPDX software bill of materials nlohmann_json.spdx"
@echo "update_hedley - download Hedley and regenerate hedley.hpp / hedley_undef.hpp" @echo "update_hedley - download Hedley and regenerate hedley.hpp / hedley_undef.hpp"
@echo "update_hedley_undef - rebuild hedley_undef.hpp from the JSON_HEDLEY_* #define names in hedley.hpp" @echo "update_hedley_undef - rebuild hedley_undef.hpp from the JSON_HEDLEY_* #define names in hedley.hpp"
@@ -108,13 +114,18 @@ $(AMALGAMATED_FWD_FILE): $(SRCS)
$(AMALGAMATED_LITERALS_FILE): include/nlohmann/json_literals.hpp $(AMALGAMATED_LITERALS_FILE): include/nlohmann/json_literals.hpp
cp include/nlohmann/json_literals.hpp $(AMALGAMATED_LITERALS_FILE) cp include/nlohmann/json_literals.hpp $(AMALGAMATED_LITERALS_FILE)
NATVIS_VENV=tools/generate_natvis/venv
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp # regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
# (the dependencies are installed into a virtual environment first)
natvis: natvis:
python3 tools/generate_natvis/generate_natvis.py . @test -d $(NATVIS_VENV) || python3 -mvenv $(NATVIS_VENV)
@$(NATVIS_VENV)/bin/python3 -c 'import jinja2' 2>/dev/null || $(NATVIS_VENV)/bin/pip3 install --quiet -r tools/generate_natvis/requirements.txt
$(NATVIS_VENV)/bin/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 # 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 # checked-in header; phony, because it never writes $(MACRO_SCOPE_HPP) itself
macro_builder_check: macro_builder_check: install_astyle
@set -e; \ @set -e; \
TMPDIR=$$(mktemp -d ./macro_builder_check.XXXXXX); \ TMPDIR=$$(mktemp -d ./macro_builder_check.XXXXXX); \
trap 'rm -rf "$$TMPDIR"' EXIT; \ trap 'rm -rf "$$TMPDIR"' EXIT; \
@@ -131,27 +142,27 @@ macro_builder_check:
check_build_options: check_build_options:
python3 tools/check_build_options/check_build_options.py . python3 tools/check_build_options/check_build_options.py .
# check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources # check if the single headers have been amalgamated from the nlohmann sources and if BUILD.bazel and
# nlohmann_json.natvis are up to date; all checks are run, and the checked-in files are always restored
check-amalgamation: check-amalgamation:
@mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ @status=0; \
@mv $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_FWD_FILE)~ banner() { printf '===================================================================\n %s\n===================================================================\n' "$$1"; }; \
@mv $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_LITERALS_FILE)~ for FILE in $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) BUILD.bazel nlohmann_json.natvis; do \
@$(MAKE) amalgamate mv "$$FILE" "$$FILE~" || exit 1; \
@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) done; \
@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) $(MAKE) amalgamate || status=1; \
@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) $(MAKE) BUILD.bazel || status=1; \
@mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) $(MAKE) natvis || status=1; \
@mv $(AMALGAMATED_FWD_FILE)~ $(AMALGAMATED_FWD_FILE) for FILE in $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE); do \
@mv $(AMALGAMATED_LITERALS_FILE)~ $(AMALGAMATED_LITERALS_FILE) diff "$$FILE" "$$FILE~" || { banner "$$FILE is out of date! Amalgamation required! Please read the contribution guidelines in file .github/CONTRIBUTING.md."; status=1; }; \
@mv BUILD.bazel BUILD.bazel~ done; \
@$(MAKE) BUILD.bazel diff BUILD.bazel BUILD.bazel~ || { banner "BUILD.bazel is out of date! Please run 'make BUILD.bazel'."; status=1; }; \
@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) diff nlohmann_json.natvis nlohmann_json.natvis~ || { banner "nlohmann_json.natvis is out of date! Please run 'make natvis'."; status=1; }; \
@mv BUILD.bazel~ BUILD.bazel for FILE in $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) BUILD.bazel nlohmann_json.natvis; do \
@mv nlohmann_json.natvis nlohmann_json.natvis~ mv "$$FILE~" "$$FILE"; \
@$(MAKE) natvis done; \
@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) $(MAKE) macro_builder_check || status=1; \
@mv nlohmann_json.natvis~ nlohmann_json.natvis exit $$status
@$(MAKE) macro_builder_check
# generate the Bazel BUILD file; phony, because a removed header would not trigger a rebuild # generate the Bazel BUILD file; phony, because a removed header would not trigger a rebuild
BUILD.bazel: BUILD.bazel:
@@ -212,8 +223,8 @@ release: include.zip json.tar.xz
# clean up # clean up
clean: clean:
rm -fr fuzz fuzz-testing *.dSYM tests/*.dSYM rm -fr *.dSYM tests/*.dSYM tests/parse_*_fuzzer
rm -fr cmake-build-benchmarks fuzz-testing cmake-build-pvs-studio release_files rm -fr cmake-build-benchmarks cmake-build-pvs-studio release_files
$(MAKE) clean -Cdocs $(MAKE) clean -Cdocs
+424 -446
View File
@@ -48,6 +48,7 @@
- [Pkg-config](#pkg-config) - [Pkg-config](#pkg-config)
- [License](#license) - [License](#license)
- [Contact](#contact) - [Contact](#contact)
- [Security](#security)
- [Thanks](#thanks) - [Thanks](#thanks)
- [Used third-party tools](#used-third-party-tools) - [Used third-party tools](#used-third-party-tools)
- [Notes](#notes) - [Notes](#notes)
@@ -112,9 +113,9 @@ There is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/t
## Quick reference ## Quick reference
- **Constructors** [basic_json](https://json.nlohmann.me/api/basic_json/basic_json), [array](https://json.nlohmann.me/api/basic_json/array), [binary](https://json.nlohmann.me/api/basic_json/binary), [object](https://json.nlohmann.me/api/basic_json/object) - **Constructors**: [basic_json](https://json.nlohmann.me/api/basic_json/basic_json), [array](https://json.nlohmann.me/api/basic_json/array), [binary](https://json.nlohmann.me/api/basic_json/binary), [object](https://json.nlohmann.me/api/basic_json/object)
- **Object inspection**: [type](https://json.nlohmann.me/api/basic_json/type), [operator value_t](https://json.nlohmann.me/api/basic_json/operator_value_t), [type_name](https://json.nlohmann.me/api/basic_json/type_name), [is_primitive](https://json.nlohmann.me/api/basic_json/is_primitive), [is_structured](https://json.nlohmann.me/api/basic_json/is_structured), [is_null](https://json.nlohmann.me/api/basic_json/is_null), [is_boolean](https://json.nlohmann.me/api/basic_json/is_boolean), [is_number](https://json.nlohmann.me/api/basic_json/is_number), [is_number_integer](https://json.nlohmann.me/api/basic_json/is_number_integer), [is_number_unsigned](https://json.nlohmann.me/api/basic_json/is_number_unsigned), [is_number_float](https://json.nlohmann.me/api/basic_json/is_number_float), [is_object](https://json.nlohmann.me/api/basic_json/is_object), [is_array](https://json.nlohmann.me/api/basic_json/is_array), [is_string](https://json.nlohmann.me/api/basic_json/is_string), [is_binary](https://json.nlohmann.me/api/basic_json/is_binary), [is_discarded](https://json.nlohmann.me/api/basic_json/is_discarded) - **Object inspection**: [type](https://json.nlohmann.me/api/basic_json/type), [operator value_t](https://json.nlohmann.me/api/basic_json/operator_value_t), [type_name](https://json.nlohmann.me/api/basic_json/type_name), [is_primitive](https://json.nlohmann.me/api/basic_json/is_primitive), [is_structured](https://json.nlohmann.me/api/basic_json/is_structured), [is_null](https://json.nlohmann.me/api/basic_json/is_null), [is_boolean](https://json.nlohmann.me/api/basic_json/is_boolean), [is_number](https://json.nlohmann.me/api/basic_json/is_number), [is_number_integer](https://json.nlohmann.me/api/basic_json/is_number_integer), [is_number_unsigned](https://json.nlohmann.me/api/basic_json/is_number_unsigned), [is_number_float](https://json.nlohmann.me/api/basic_json/is_number_float), [is_object](https://json.nlohmann.me/api/basic_json/is_object), [is_array](https://json.nlohmann.me/api/basic_json/is_array), [is_string](https://json.nlohmann.me/api/basic_json/is_string), [is_binary](https://json.nlohmann.me/api/basic_json/is_binary), [is_discarded](https://json.nlohmann.me/api/basic_json/is_discarded)
- **Value access**; [get](https://json.nlohmann.me/api/basic_json/get), [get_to](https://json.nlohmann.me/api/basic_json/get_to), [get_ptr](https://json.nlohmann.me/api/basic_json/get_ptr), [get_ref](https://json.nlohmann.me/api/basic_json/get_ref), [operator ValueType](https://json.nlohmann.me/api/basic_json/operator_ValueType), [get_binary](https://json.nlohmann.me/api/basic_json/get_binary) - **Value access**: [get](https://json.nlohmann.me/api/basic_json/get), [get_to](https://json.nlohmann.me/api/basic_json/get_to), [get_ptr](https://json.nlohmann.me/api/basic_json/get_ptr), [get_ref](https://json.nlohmann.me/api/basic_json/get_ref), [operator ValueType](https://json.nlohmann.me/api/basic_json/operator_ValueType), [get_binary](https://json.nlohmann.me/api/basic_json/get_binary)
- **Element access**: [at](https://json.nlohmann.me/api/basic_json/at), [operator[]](https://json.nlohmann.me/api/basic_json/operator[]), [value](https://json.nlohmann.me/api/basic_json/value), [front](https://json.nlohmann.me/api/basic_json/front), [back](https://json.nlohmann.me/api/basic_json/back) - **Element access**: [at](https://json.nlohmann.me/api/basic_json/at), [operator[]](https://json.nlohmann.me/api/basic_json/operator[]), [value](https://json.nlohmann.me/api/basic_json/value), [front](https://json.nlohmann.me/api/basic_json/front), [back](https://json.nlohmann.me/api/basic_json/back)
- **Lookup**: [find](https://json.nlohmann.me/api/basic_json/find), [count](https://json.nlohmann.me/api/basic_json/count), [contains](https://json.nlohmann.me/api/basic_json/contains) - **Lookup**: [find](https://json.nlohmann.me/api/basic_json/find), [count](https://json.nlohmann.me/api/basic_json/count), [contains](https://json.nlohmann.me/api/basic_json/contains)
- **Iterators**: [begin](https://json.nlohmann.me/api/basic_json/begin), [cbegin](https://json.nlohmann.me/api/basic_json/cbegin), [end](https://json.nlohmann.me/api/basic_json/end), [cend](https://json.nlohmann.me/api/basic_json/cend), [rbegin](https://json.nlohmann.me/api/basic_json/rbegin), [rend](https://json.nlohmann.me/api/basic_json/rend), [crbegin](https://json.nlohmann.me/api/basic_json/crbegin), [crend](https://json.nlohmann.me/api/basic_json/crend), [items](https://json.nlohmann.me/api/basic_json/items) - **Iterators**: [begin](https://json.nlohmann.me/api/basic_json/begin), [cbegin](https://json.nlohmann.me/api/basic_json/cbegin), [end](https://json.nlohmann.me/api/basic_json/end), [cend](https://json.nlohmann.me/api/basic_json/cend), [rbegin](https://json.nlohmann.me/api/basic_json/rbegin), [rend](https://json.nlohmann.me/api/basic_json/rend), [crbegin](https://json.nlohmann.me/api/basic_json/crbegin), [crend](https://json.nlohmann.me/api/basic_json/crend), [items](https://json.nlohmann.me/api/basic_json/items)
@@ -1184,7 +1185,7 @@ binary[1]; // 0xFE
binary.set_subtype(0x10); binary.set_subtype(0x10);
// serialize to MessagePack // serialize to MessagePack
auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE auto msgpack = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE
``` ```
## Customers ## Customers
@@ -1220,17 +1221,7 @@ I would be happy to learn about other compilers/versions.
Please note: Please note:
- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler. - GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler.
- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. - For GCC running on MinGW or Android, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`) may occur. Note this is not an issue with the code, but rather with the compiler or C++ standard library itself: use a recent toolchain (for Android, a current [NDK](https://developer.android.com/ndk) with the LLVM C++ library `APP_STL := c++_shared`, and for MinGW, a distribution with a complete C++11 standard library). See [this discussion](https://github.com/nlohmann/json/issues/136) for MinGW and [this discussion](https://github.com/nlohmann/json/issues/219) for the old Android NDK using `APP_STL := gnustl_static`.
```makefile
APP_STL := c++_shared
NDK_TOOLCHAIN_VERSION := clang3.6
APP_CPPFLAGS += -frtti -fexceptions
```
The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10.
- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](https://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219).
- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case. - Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case.
@@ -1437,436 +1428,416 @@ I deeply appreciate the help of the following people.
12. [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual Studio. 12. [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual Studio.
13. [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types. 13. [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types.
14. [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling. 14. [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.
15. [dariomt](https://github.com/dariomt) fixed some typos in the examples. 15. [dariomt](https://github.com/dariomt) fixed some typos in the examples and fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values.
16. [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation. 16. [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.
17. [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue. 17. [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue.
18. [Huu Nguyen](https://github.com/whoshuu) corrected a variable name in the documentation. 18. [Huu Nguyen](https://github.com/whoshuu) corrected a variable name in the documentation.
19. [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. 19. [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference.
20. [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values. 20. [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK.
21. [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. 21. [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio.
22. [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. 22. [406345](https://github.com/406345) fixed two small warnings.
23. [406345](https://github.com/406345) fixed two small warnings. 23. [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.
24. [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. 24. [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
25. [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. 25. [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers.
26. [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers. 26. [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.
27. [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. 27. [msm-](https://github.com/msm-) added support for American Fuzzy Lop.
28. [msm-](https://github.com/msm-) added support for American Fuzzy Lop. 28. [Annihil](https://github.com/Annihil) fixed an example in the README file.
29. [Annihil](https://github.com/Annihil) fixed an example in the README file. 29. [Themercee](https://github.com/Themercee) noted a wrong URL in the README file.
30. [Themercee](https://github.com/Themercee) noted a wrong URL in the README file. 30. [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`.
31. [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`. 31. [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212).
32. [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212). 32. [zewt](https://github.com/zewt) added useful notes to the README file about Android.
33. [zewt](https://github.com/zewt) added useful notes to the README file about Android. 33. [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake.
34. [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake. 34. [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files.
35. [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files. 35. [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal).
36. [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal). 36. [Mário Feroldi](https://github.com/thelostt) fixed a small typo.
37. [Mário Feroldi](https://github.com/thelostt) fixed a small typo. 37. [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
38. [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release. 38. [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
39. [Damien](https://github.com/dtoma) fixed one of the last conversion warnings. 39. [Thomas Braun](https://github.com/t-b) fixed a warning in a test case and adjusted MSVC calls in the CI.
40. [Thomas Braun](https://github.com/t-b) fixed a warning in a test case and adjusted MSVC calls in the CI. 40. [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks.
41. [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks. 41. [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.
42. [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation. 42. [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.
43. [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`. 43. [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
44. [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion. 44. [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.
45. [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix. 45. [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
46. [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. 46. [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.
47. [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function. 47. [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.
48. [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing. 48. [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.
49. [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan. 49. [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning and supported the implementation of user-defined types.
50. [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning. 50. [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check.
51. [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check. 51. [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one.
52. [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one. 52. [Daniel599](https://github.com/Daniel599) helped to get Travis to execute the tests with Clang's sanitizers and allowed to use more algorithms with the `items()` function.
53. [Daniel599](https://github.com/Daniel599) helped to get Travis to execute the tests with Clang's sanitizers. 53. [Jonathan Lee](https://github.com/vjon) fixed an example in the README file.
54. [Jonathan Lee](https://github.com/vjon) fixed an example in the README file. 54. [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types.
55. [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types. 55. [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio.
56. [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio. 56. [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example.
57. [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types. 57. [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite.
58. [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example. 58. [ukhegg](https://github.com/ukhegg) proposed an improvement for the examples section.
59. [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite. 59. [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README.
60. [ukhegg](https://github.com/ukhegg) proposed an improvement for the examples section. 60. [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s.
61. [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README. 61. [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation.
62. [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s. 62. [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings.
63. [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation. 63. [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible.
64. [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings. 64. [ftillier](https://github.com/ftillier) fixed a compiler warning.
65. [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible. 65. [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped.
66. [ftillier](https://github.com/ftillier) fixed a compiler warning. 66. [Fytch](https://github.com/Fytch) found a bug in the documentation.
67. [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped. 67. [Jay Sistar](https://github.com/Type1J) implemented a Meson build description.
68. [Fytch](https://github.com/Fytch) found a bug in the documentation. 68. [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation.
69. [Jay Sistar](https://github.com/Type1J) implemented a Meson build description. 69. [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager.
70. [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation. 70. [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`.
71. [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager. 71. [Mike Tzou](https://github.com/Chocobo1) fixed some typos.
72. [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`. 72. [amrcode](https://github.com/amrcode) noted misleading documentation about comparison of floats.
73. [Mike Tzou](https://github.com/Chocobo1) fixed some typos. 73. [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `<iostream>` with `<iosfwd>`.
74. [amrcode](https://github.com/amrcode) noted misleading documentation about comparison of floats. 74. [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library.
75. [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `<iostream>` with `<iosfwd>`. 75. [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists.
76. [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library. 76. [Greg Hurrell](https://github.com/wincent) fixed a typo.
77. [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists. 77. [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo.
78. [Greg Hurrell](https://github.com/wincent) fixed a typo. 78. [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler.
79. [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo. 79. [Markus Werle](https://github.com/daixtrose) fixed a typo.
80. [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler. 80. [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check.
81. [Markus Werle](https://github.com/daixtrose) fixed a typo. 81. [Alex](https://github.com/leha-bot) noted an error in a code sample.
82. [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check. 82. [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped to fix them.
83. [Alex](https://github.com/leha-bot) noted an error in a code sample. 83. [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams.
84. [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped to fix them. 84. [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error, fixed the compilation with MSVC 2015 in debug mode and fixed a warning.
85. [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams. 85. [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings and avoided unnecessary string copies in `find()` and `count()`.
86. [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error. 86. [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file.
87. [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings. 87. [pvleuven](https://github.com/pvleuven) helped to fix a warning in ICC.
88. [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file. 88. [Pavel](https://github.com/crea7or) helped to fix some warnings in MSVC.
89. [pvleuven](https://github.com/pvleuven) helped to fix a warning in ICC. 89. [Mitja](https://github.com/Itja) fixed some typos.
90. [Pavel](https://github.com/crea7or) helped to fix some warnings in MSVC. 90. [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links.
91. [Jamie Seward](https://github.com/jseward) avoided unnecessary string copies in `find()` and `count()`. 91. [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view and removed the dependency from `std::stringstream`.
92. [Mitja](https://github.com/Itja) fixed some typos. 92. [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings.
93. [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links. 93. [Eren Okka](https://github.com/erengy) fixed some MSVC warnings.
94. [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view. 94. [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed.
95. [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings. 95. [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README.
96. [Eren Okka](https://github.com/erengy) fixed some MSVC warnings. 96. [zerodefect](https://github.com/zerodefect) fixed a compiler warning.
97. [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed. 97. [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior.
98. [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README. 98. [mark-99](https://github.com/mark-99) helped fix an ICC error.
99. [zerodefect](https://github.com/zerodefect) fixed a compiler warning. 99. [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file.
100. [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior. 100. [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings.
101. [mark-99](https://github.com/mark-99) helped fix an ICC error. 101. [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager.
102. [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file. 102. [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise.
103. [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings. 103. [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback.
104. [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager. 104. [agrianius](https://github.com/agrianius) allowed dumping JSON to an alternative string type and added code to use alternative string implementations.
105. [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise. 105. [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake.
106. [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback. 106. [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io).
107. [agrianius](https://github.com/agrianius) allowed dumping JSON to an alternative string type. 107. [Carlos O'Ryan](https://github.com/coryan) fixed a typo.
108. [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake. 108. [James Upjohn](https://github.com/jupjohn) fixed a version number in the compilers section.
109. [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io). 109. [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration.
110. [Carlos O'Ryan](https://github.com/coryan) fixed a typo. 110. [Jan Schöppach](https://github.com/dns13) fixed a typo.
111. [James Upjohn](https://github.com/jupjohn) fixed a version number in the compilers section. 111. [martin-mfg](https://github.com/martin-mfg) fixed a typo.
112. [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration. 112. [Julius Rakow](https://github.com/juliusrakow) fixed the Meson include directory and fixed the links to [cppreference.com](https://cppreference.com).
113. [Jan Schöppach](https://github.com/dns13) fixed a typo. 113. [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases.
114. [martin-mfg](https://github.com/martin-mfg) fixed a typo. 114. [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library and fixed an issue with a double macro definition.
115. [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`. 115. [thyu](https://github.com/thyu) fixed a compiler warning.
116. [agrianius](https://github.com/agrianius) added code to use alternative string implementations. 116. [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2.
117. [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function. 117. [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library.
118. [Julius Rakow](https://github.com/juliusrakow) fixed the Meson include directory and fixed the links to [cppreference.com](https://cppreference.com). 118. [Ben Berman](https://github.com/rivertam) made some error messages more understandable.
119. [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode. 119. [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler.
120. [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases. 120. [mandreyel](https://github.com/mandreyel) fixed a compilation problem.
121. [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library. 121. [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file.
122. [thyu](https://github.com/thyu) fixed a compiler warning. 122. [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8.
123. [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2. 123. [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory.
124. [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library. 124. [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning.
125. [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition. 125. [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define an enum/JSON mapping.
126. [Ben Berman](https://github.com/rivertam) made some error messages more understandable. 126. [efp](https://github.com/efp) added line and column information to parse errors.
127. [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler. 127. [julian-becker](https://github.com/julian-becker) added BSON support.
128. [mandreyel](https://github.com/mandreyel) fixed a compilation problem. 128. [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings.
129. [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file. 129. [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version).
130. [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8. 130. [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`.
131. [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory. 131. [kjpus](https://github.com/kjpus) fixed a link in the documentation.
132. [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning. 132. [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation.
133. [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define an enum/JSON mapping. 133. [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning.
134. [efp](https://github.com/efp) added line and column information to parse errors. 134. [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC.
135. [julian-becker](https://github.com/julian-becker) added BSON support. 135. [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream.
136. [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings. 136. [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson.
137. [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version). 137. [Michael Behrns-Miller](https://github.com/moodboom) found an issue with a missing namespace.
138. [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`. 138. [Nasztanovics Ferenc](https://github.com/naszta) fixed a compilation issue with libc 2.12.
139. [kjpus](https://github.com/kjpus) fixed a link in the documentation. 139. [Andreas Schwab](https://github.com/andreas-schwab) fixed the endian conversion.
140. [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation. 140. [Mark-Dunning](https://github.com/Mark-Dunning) fixed a warning in MSVC.
141. [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning. 141. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) added `operator/` for JSON Pointers and fixed a compilation issue with MSVC.
142. [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC. 142. [John-Mark](https://github.com/johnmarkwayve) noted a missing header.
143. [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream. 143. [Vitaly Zaitsev](https://github.com/xvitaly) fixed compilation with GCC 9.0.
144. [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson. 144. [Laurent Stacul](https://github.com/stac47) fixed compilation with GCC 9.0.
145. [Michael Behrns-Miller](https://github.com/moodboom) found an issue with a missing namespace. 145. [Ivor Wanders](https://github.com/iwanders) helped to reduce the CMake requirement to version 3.1 and fixed the examples to catch exception by `const&`.
146. [Nasztanovics Ferenc](https://github.com/naszta) fixed a compilation issue with libc 2.12. 146. [njlr](https://github.com/njlr) updated the Buckaroo instructions.
147. [Andreas Schwab](https://github.com/andreas-schwab) fixed the endian conversion. 147. [Lion](https://github.com/lieff) fixed a compilation issue with GCC 7 on CentOS.
148. [Mark-Dunning](https://github.com/Mark-Dunning) fixed a warning in MSVC. 148. [Isaac Nickaein](https://github.com/nickaein) improved the integer serialization performance and implemented the `contains()` function.
149. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) added `operator/` for JSON Pointers. 149. [past-due](https://github.com/past-due) suppressed an unfixable warning.
150. [John-Mark](https://github.com/johnmarkwayve) noted a missing header. 150. [Elvis Oric](https://github.com/elvisoric) improved Meson support.
151. [Vitaly Zaitsev](https://github.com/xvitaly) fixed compilation with GCC 9.0. 151. [Matěj Plch](https://github.com/Afforix) fixed an example in the README.
152. [Laurent Stacul](https://github.com/stac47) fixed compilation with GCC 9.0. 152. [Mark Beckwith](https://github.com/wythe) fixed two typos.
153. [Ivor Wanders](https://github.com/iwanders) helped to reduce the CMake requirement to version 3.1. 153. [scinart](https://github.com/scinart) fixed a bug in the serializer.
154. [njlr](https://github.com/njlr) updated the Buckaroo instructions. 154. [Patrick Boettcher](https://github.com/pboettch) implemented `push_back()` and `pop_back()` for JSON Pointers.
155. [Lion](https://github.com/lieff) fixed a compilation issue with GCC 7 on CentOS. 155. [Bruno Oliveira](https://github.com/nicoddemus) added support for Conda.
156. [Isaac Nickaein](https://github.com/nickaein) improved the integer serialization performance and implemented the `contains()` function. 156. [Michele Caini](https://github.com/skypjack) fixed links in the README.
157. [past-due](https://github.com/past-due) suppressed an unfixable warning. 157. [Hani](https://github.com/hnkb) documented how to install the library with NuGet.
158. [Elvis Oric](https://github.com/elvisoric) improved Meson support. 158. [yann-morin-1998](https://github.com/yann-morin-1998) helped to reduce the CMake requirement to version 3.1.
159. [Matěj Plch](https://github.com/Afforix) fixed an example in the README. 159. [Konstantin Podsvirov](https://github.com/podsvirov) maintains a package for the MSYS2 software distro and fixed the MSYS2 package documentation.
160. [Mark Beckwith](https://github.com/wythe) fixed a typo. 160. [remyabel](https://github.com/remyabel2) added GNUInstallDirs to the CMake files.
161. [scinart](https://github.com/scinart) fixed a bug in the serializer. 161. [Taylor Howard](https://github.com/taylorhoward92) fixed a unit test.
162. [Patrick Boettcher](https://github.com/pboettch) implemented `push_back()` and `pop_back()` for JSON Pointers. 162. [Gabe Ron](https://github.com/Macr0Nerd) implemented the `to_string` method.
163. [Bruno Oliveira](https://github.com/nicoddemus) added support for Conda. 163. [Watal M. Iwasaki](https://github.com/heavywatal) fixed a Clang warning.
164. [Michele Caini](https://github.com/skypjack) fixed links in the README. 164. [Viktor Kirilov](https://github.com/onqtam) switched the unit tests from [Catch](https://github.com/philsquared/Catch) to [doctest](https://github.com/doctest/doctest)
165. [Hani](https://github.com/hnkb) documented how to install the library with NuGet. 165. [Juncheng E](https://github.com/ejcjason) fixed a typo.
166. [Mark Beckwith](https://github.com/wythe) fixed a typo. 166. [tete17](https://github.com/tete17) fixed a bug in the `contains` function.
167. [yann-morin-1998](https://github.com/yann-morin-1998) helped to reduce the CMake requirement to version 3.1. 167. [Xav83](https://github.com/Xav83) fixed some cppcheck warnings.
168. [Konstantin Podsvirov](https://github.com/podsvirov) maintains a package for the MSYS2 software distro. 168. [0xflotus](https://github.com/0xflotus) fixed some typos.
169. [remyabel](https://github.com/remyabel2) added GNUInstallDirs to the CMake files. 169. [Christian Deneke](https://github.com/chris0x44) added a const version of `json_pointer::back`.
170. [Taylor Howard](https://github.com/taylorhoward92) fixed a unit test. 170. [Julien Hamaide](https://github.com/crazyjul) made the `items()` function work with custom string types.
171. [Gabe Ron](https://github.com/Macr0Nerd) implemented the `to_string` method. 171. [Evan Nemerson](https://github.com/nemequ) updated fixed a bug in Hedley and updated this library accordingly.
172. [Watal M. Iwasaki](https://github.com/heavywatal) fixed a Clang warning. 172. [Florian Pigorsch](https://github.com/flopp) fixed a lot of typos.
173. [Viktor Kirilov](https://github.com/onqtam) switched the unit tests from [Catch](https://github.com/philsquared/Catch) to [doctest](https://github.com/onqtam/doctest) 173. [Camille Bégué](https://github.com/cbegue) fixed an issue in the conversion from `std::pair` and `std::tuple` to `json`.
174. [Juncheng E](https://github.com/ejcjason) fixed a typo. 174. [Anthony VH](https://github.com/AnthonyVH) fixed a compile error in an enum deserialization.
175. [tete17](https://github.com/tete17) fixed a bug in the `contains` function. 175. [Yuriy Vountesmery](https://github.com/ua-code-dragon) noted a subtle bug in a preprocessor check.
176. [Xav83](https://github.com/Xav83) fixed some cppcheck warnings. 176. [Chen](https://github.com/dota17) fixed numerous issues in the library.
177. [0xflotus](https://github.com/0xflotus) fixed some typos. 177. [Antony Kellermann](https://github.com/aokellermann) added a CI step for GCC 10.1.
178. [Christian Deneke](https://github.com/chris0x44) added a const version of `json_pointer::back`. 178. [Alex](https://github.com/gistrec) fixed an MSVC warning.
179. [Julien Hamaide](https://github.com/crazyjul) made the `items()` function work with custom string types. 179. [Rainer](https://github.com/rvjr) proposed an improvement in the floating-point serialization in CBOR.
180. [Evan Nemerson](https://github.com/nemequ) updated fixed a bug in Hedley and updated this library accordingly. 180. [Francois Chabot](https://github.com/FrancoisChabot) made performance improvements in the input adapters.
181. [Florian Pigorsch](https://github.com/flopp) fixed a lot of typos. 181. [Arthur Sonzogni](https://github.com/ArthurSonzogni) documented how the library can be included via `FetchContent`.
182. [Camille Bégué](https://github.com/cbegue) fixed an issue in the conversion from `std::pair` and `std::tuple` to `json`. 182. [Rimas Misevičius](https://github.com/rmisev) fixed an error message.
183. [Anthony VH](https://github.com/AnthonyVH) fixed a compile error in an enum deserialization. 183. [Alexander Myasnikov](https://github.com/alexandermyasnikov) fixed some examples and a link in the README.
184. [Yuriy Vountesmery](https://github.com/ua-code-dragon) noted a subtle bug in a preprocessor check. 184. [Hubert Chathi](https://github.com/uhoreg) made CMake's version config file architecture-independent.
185. [Chen](https://github.com/dota17) fixed numerous issues in the library. 185. [OmnipotentEntity](https://github.com/OmnipotentEntity) implemented the binary values for CBOR, MessagePack, BSON, and UBJSON.
186. [Antony Kellermann](https://github.com/aokellermann) added a CI step for GCC 10.1. 186. [ArtemSarmini](https://github.com/ArtemSarmini) fixed a compilation issue with GCC 10 and fixed a leak.
187. [Alex](https://github.com/gistrec) fixed an MSVC warning. 187. [Evgenii Sopov](https://github.com/sea5kg) integrated the library to the wsjcpp package manager.
188. [Rainer](https://github.com/rvjr) proposed an improvement in the floating-point serialization in CBOR. 188. [Sergey Linev](https://github.com/linev) fixed a compiler warning.
189. [Francois Chabot](https://github.com/FrancoisChabot) made performance improvements in the input adapters. 189. [Miguel Magalhães](https://github.com/magamig) fixed the year in the copyright.
190. [Arthur Sonzogni](https://github.com/ArthurSonzogni) documented how the library can be included via `FetchContent`. 190. [Alexander “weej” Jones](https://github.com/alex-weej) fixed an example in the README.
191. [Rimas Misevičius](https://github.com/rmisev) fixed an error message. 191. [Antoine Cœur](https://github.com/Coeur) fixed some typos in the documentation.
192. [Alexander Myasnikov](https://github.com/alexandermyasnikov) fixed some examples and a link in the README. 192. [jothepro](https://github.com/jothepro) updated links to the Hunter package.
193. [Hubert Chathi](https://github.com/uhoreg) made CMake's version config file architecture-independent. 193. [Dave Lee](https://github.com/kastiglione) fixed a link in the README.
194. [OmnipotentEntity](https://github.com/OmnipotentEntity) implemented the binary values for CBOR, MessagePack, BSON, and UBJSON. 194. [Joël Lamotte](https://github.com/Klaim) added instruction for using Build2's package manager.
195. [ArtemSarmini](https://github.com/ArtemSarmini) fixed a compilation issue with GCC 10 and fixed a leak. 195. [Paul Jurczak](https://github.com/pauljurczak) fixed an example in the README.
196. [Evgenii Sopov](https://github.com/sea5kg) integrated the library to the wsjcpp package manager. 196. [Carlos Gomes Martinho](https://github.com/gocarlos) updated the Conan package source.
197. [Sergey Linev](https://github.com/linev) fixed a compiler warning. 197. [Tridacnid](https://github.com/Tridacnid) improved the CMake tests.
198. [Miguel Magalhães](https://github.com/magamig) fixed the year in the copyright. 198. [Michael](https://github.com/MBalszun) fixed MSVC warnings.
199. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) fixed a compilation issue with MSVC. 199. [Quentin Barbarat](https://github.com/quentin-dev) fixed an example in the documentation.
200. [Alexander “weej” Jones](https://github.com/alex-weej) fixed an example in the README. 200. [XyFreak](https://github.com/XyFreak) fixed a compiler warning.
201. [Antoine Cœur](https://github.com/Coeur) fixed some typos in the documentation. 201. [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README and updated the links in the documentation to use HTTPS.
202. [jothepro](https://github.com/jothepro) updated links to the Hunter package. 202. [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input.
203. [Dave Lee](https://github.com/kastiglione) fixed a link in the README. 203. [AODQ](https://github.com/AODQ) fixed a compiler warning.
204. [Joël Lamotte](https://github.com/Klaim) added instruction for using Build2's package manager. 204. [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline.
205. [Paul Jurczak](https://github.com/pauljurczak) fixed an example in the README. 205. [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.
206. [Sonu Lohani](https://github.com/sonulohani) fixed a warning. 206. [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values.
207. [Carlos Gomes Martinho](https://github.com/gocarlos) updated the Conan package source. 207. [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation.
208. [Konstantin Podsvirov](https://github.com/podsvirov) fixed the MSYS2 package documentation. 208. [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes.
209. [Tridacnid](https://github.com/Tridacnid) improved the CMake tests. 209. [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`.
210. [Michael](https://github.com/MBalszun) fixed MSVC warnings. 210. [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config.
211. [Quentin Barbarat](https://github.com/quentin-dev) fixed an example in the documentation. 211. [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros.
212. [XyFreak](https://github.com/XyFreak) fixed a compiler warning. 212. [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support.
213. [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README. 213. [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`.
214. [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input. 214. [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer.
215. [AODQ](https://github.com/AODQ) fixed a compiler warning. 215. Lars Wirzenius reviewed the README file.
216. [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline. 216. [Jun Jie](https://github.com/ongjunjie) fixed a compiler path in the CMake scripts.
217. [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. 217. [Ronak Buch](https://github.com/rbuch) fixed typos in the documentation.
218. [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values. 218. [Alexander Karzhenkov](https://github.com/karzhenkov) fixed a move constructor and the Travis builds.
219. [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation. 219. [Leonardo Lima](https://github.com/leozz37) added CPM.Cmake support.
220. [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes. 220. [Joseph Blackman](https://github.com/jbzdarkid) fixed a warning.
221. [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`. 221. [Yaroslav](https://github.com/YarikTH) updated doctest and implemented unit tests.
222. [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config. 222. [Martin Stump](https://github.com/globberwops) fixed a bug in the CMake files.
223. [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. 223. [Jaakko Moisio](https://github.com/jasujm) fixed a bug in the input adapters.
224. [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support. 224. [bl-ue](https://github.com/bl-ue) fixed some Markdown issues in the README file.
225. [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`. 225. [William A. Wieselquist](https://github.com/wawiesel) fixed an example from the README.
226. [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer. 226. [abbaswasim](https://github.com/abbaswasim) fixed an example from the README.
227. Lars Wirzenius reviewed the README file. 227. [Remy Jette](https://github.com/remyjette) fixed a warning.
228. [Jun Jie](https://github.com/ongjunjie) fixed a compiler path in the CMake scripts. 228. [Fraser](https://github.com/frasermarlow) fixed the documentation.
229. [Ronak Buch](https://github.com/rbuch) fixed typos in the documentation. 229. [Ben Beasley](https://github.com/musicinmybrain) updated doctest.
230. [Alexander Karzhenkov](https://github.com/karzhenkov) fixed a move constructor and the Travis builds. 230. [Doron Behar](https://github.com/doronbehar) fixed pkg-config.pc.
231. [Leonardo Lima](https://github.com/leozz37) added CPM.Cmake support. 231. [raduteo](https://github.com/raduteo) fixed a warning.
232. [Joseph Blackman](https://github.com/jbzdarkid) fixed a warning. 232. [David Pfahler](https://github.com/theShmoo) added the possibility to compile the library without I/O support.
233. [Yaroslav](https://github.com/YarikTH) updated doctest and implemented unit tests. 233. [Morten Fyhn Amundsen](https://github.com/mortenfyhn) fixed a typo.
234. [Martin Stump](https://github.com/globberwops) fixed a bug in the CMake files. 234. [jpl-mac](https://github.com/jpl-mac) allowed treating the library as a system header in CMake.
235. [Jaakko Moisio](https://github.com/jasujm) fixed a bug in the input adapters. 235. [Jason Dsouza](https://github.com/jasmcaus) fixed the indentation of the CMake file.
236. [bl-ue](https://github.com/bl-ue) fixed some Markdown issues in the README file. 236. [offa](https://github.com/offa) added a link to Conan Center to the documentation.
237. [William A. Wieselquist](https://github.com/wawiesel) fixed an example from the README. 237. [Rafail Giavrimis](https://github.com/grafail) fixed the Google Benchmark default branch.
238. [abbaswasim](https://github.com/abbaswasim) fixed an example from the README. 238. [Louis Dionne](https://github.com/ldionne) fixed a conversion operator.
239. [Remy Jette](https://github.com/remyjette) fixed a warning. 239. [justanotheranonymoususer](https://github.com/justanotheranonymoususer) made the examples in the README more consistent.
240. [Fraser](https://github.com/frasermarlow) fixed the documentation. 240. [Finkman](https://github.com/Finkman) suppressed some `-Wfloat-equal` warnings and fixed the debug pretty-printer.
241. [Ben Beasley](https://github.com/musicinmybrain) updated doctest. 241. [Ferry Huberts](https://github.com/fhuberts) fixed `-Wswitch-enum` warnings and fixed a typo.
242. [Doron Behar](https://github.com/doronbehar) fixed pkg-config.pc. 242. [Arseniy Terekhin](https://github.com/senyai) made the GDB pretty-printer robust against unset variable names.
243. [raduteo](https://github.com/raduteo) fixed a warning. 243. [Amir Masoud Abdol](https://github.com/amirmasoudabdol) updated the Homebrew command as nlohmann/json is now in homebrew-core.
244. [David Pfahler](https://github.com/theShmoo) added the possibility to compile the library without I/O support. 244. [Hallot](https://github.com/Hallot) fixed some `-Wextra-semi-stmt warnings`.
245. [Morten Fyhn Amundsen](https://github.com/mortenfyhn) fixed a typo. 245. [Giovanni Cerretani](https://github.com/gcerretani) fixed `-Wunused` warnings on `JSON_DIAGNOSTICS` and fixed a check for `std::filesystem`.
246. [jpl-mac](https://github.com/jpl-mac) allowed treating the library as a system header in CMake. 246. [Bogdan Popescu](https://github.com/Kapeli) hosts the [docset](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for offline documentation viewers.
247. [Jason Dsouza](https://github.com/jasmcaus) fixed the indentation of the CMake file. 247. [Carl Smedstad](https://github.com/carlsmedstad) fixed an assertion error when using `JSON_DIAGNOSTICS`.
248. [offa](https://github.com/offa) added a link to Conan Center to the documentation. 248. [miikka75](https://github.com/miikka75) provided an important fix to compile C++17 code with Clang 9.
249. [TotalCaesar659](https://github.com/TotalCaesar659) updated the links in the documentation to use HTTPS. 249. [Maarten Becker](https://github.com/kernie) fixed a warning for shadowed variables.
250. [Rafail Giavrimis](https://github.com/grafail) fixed the Google Benchmark default branch. 250. [Cristi Vîjdea](https://github.com/axnsan12) fixed typos in the `operator[]` documentation.
251. [Louis Dionne](https://github.com/ldionne) fixed a conversion operator. 251. [Alex Beregszaszi](https://github.com/axic) fixed spelling mistakes in comments.
252. [justanotheranonymoususer](https://github.com/justanotheranonymoususer) made the examples in the README more consistent. 252. [Dirk Stolle](https://github.com/striezel) fixed typos in the documentation.
253. [Finkman](https://github.com/Finkman) suppressed some `-Wfloat-equal` warnings. 253. [Daniel Albuschat](https://github.com/daniel-kun) corrected the parameter name in the `parse` documentation.
254. [Ferry Huberts](https://github.com/fhuberts) fixed `-Wswitch-enum` warnings. 254. [Prince Mendiratta](https://github.com/Prince-Mendiratta) fixed a link to the FAQ.
255. [Arseniy Terekhin](https://github.com/senyai) made the GDB pretty-printer robust against unset variable names. 255. [Florian Albrechtskirchinger](https://github.com/falbrechtskirchinger) implemented `std::string_view` support for object keys and made dozens of other improvements.
256. [Amir Masoud Abdol](https://github.com/amirmasoudabdol) updated the Homebrew command as nlohmann/json is now in homebrew-core. 256. [Qianqian Fang](https://github.com/fangq) implemented the Binary JData (BJData) format.
257. [Hallot](https://github.com/Hallot) fixed some `-Wextra-semi-stmt warnings`. 257. [pketelsen](https://github.com/pketelsen) added macros `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` and `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`.
258. [Giovanni Cerretani](https://github.com/gcerretani) fixed `-Wunused` warnings on `JSON_DIAGNOSTICS`. 258. [DarkZeros](https://github.com/DarkZeros) adjusted to code to not clash with Arduino defines.
259. [Bogdan Popescu](https://github.com/Kapeli) hosts the [docset](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for offline documentation viewers. 259. [flagarde](https://github.com/flagarde) fixed the output of `meta()` for MSVC.
260. [Carl Smedstad](https://github.com/carlsmedstad) fixed an assertion error when using `JSON_DIAGNOSTICS`. 260. [Dimitris Apostolou](https://github.com/rex4539) fixed a typo.
261. [miikka75](https://github.com/miikka75) provided an important fix to compile C++17 code with Clang 9. 261. [Michael Nosthoff](https://github.com/heinemml) fixed a typo.
262. [Maarten Becker](https://github.com/kernie) fixed a warning for shadowed variables. 262. [JungHoon Lee](https://github.com/jhnlee) fixed a typo.
263. [Cristi Vîjdea](https://github.com/axnsan12) fixed typos in the `operator[]` documentation. 263. [Faruk D.](https://github.com/fdiblen) fixed the CITATION.CFF file.
264. [Alex Beregszaszi](https://github.com/axic) fixed spelling mistakes in comments. 264. [Andrea Cocito](https://github.com/puffetto) added a clarification on macro usage to the documentation.
265. [Dirk Stolle](https://github.com/striezel) fixed typos in documentation. 265. [Krzysiek Karbowiak](https://github.com/kkarbowiak) refactored the tests to use `CHECK_THROWS_WITH_AS`.
266. [Daniel Albuschat](https://github.com/daniel-kun) corrected the parameter name in the `parse` documentation. 266. [Chaoqi Zhang](https://github.com/prncoprs) fixed a typo.
267. [Prince Mendiratta](https://github.com/Prince-Mendiratta) fixed a link to the FAQ. 267. [ivanovmp](https://github.com/ivanovmp) fixed a whitespace error.
268. [Florian Albrechtskirchinger](https://github.com/falbrechtskirchinger) implemented `std::string_view` support for object keys and made dozens of other improvements. 268. [KsaNL](https://github.com/KsaNL) fixed a build error when including `<windows.h>`.
269. [Qianqian Fang](https://github.com/fangq) implemented the Binary JData (BJData) format. 269. [Andrea Pappacoda](https://github.com/Tachi107) moved `.pc` and `.cmake` files to `share` directory.
270. [pketelsen](https://github.com/pketelsen) added macros `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` and `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`. 270. [Wolf Vollprecht](https://github.com/wolfv) added the `patch_inplace` function.
271. [DarkZeros](https://github.com/DarkZeros) adjusted to code to not clash with Arduino defines. 271. [Jake Zimmerman](https://github.com/jez) highlighted common usage patterns in the README file.
272. [flagarde](https://github.com/flagarde) fixed the output of `meta()` for MSVC. 272. [NN](https://github.com/NN---) added the Visual Studio output directory to `.gitignore`.
273. [Giovanni Cerretani](https://github.com/gcerretani) fixed a check for `std::filesystem`. 273. [Romain Reignier](https://github.com/romainreignier) improved the performance of the vector output adapter.
274. [Dimitris Apostolou](https://github.com/rex4539) fixed a typo. 274. [Mike](https://github.com/Mike-Leo-Smith) fixed the `std::iterator_traits`.
275. [Ferry Huberts](https://github.com/fhuberts) fixed a typo. 275. [Richard Hozák](https://github.com/richardhozak) added macro `JSON_NO_ENUM` to disable default enum conversions.
276. [Michael Nosthoff](https://github.com/heinemml) fixed a typo. 276. [vakokako](https://github.com/vakokako) fixed tests when compiling with C++20.
277. [JungHoon Lee](https://github.com/jhnlee) fixed a typo. 277. [Alexander “weej” Jones](https://github.com/alexweej) fixed an example in the README.
278. [Faruk D.](https://github.com/fdiblen) fixed the CITATION.CFF file. 278. [Eli Schwartz](https://github.com/eli-schwartz) added more files to the `include.zip` archive.
279. [Andrea Cocito](https://github.com/puffetto) added a clarification on macro usage to the documentation. 279. [Kevin Lu](https://github.com/kevinlul) fixed a compilation issue when typedefs with certain names were present.
280. [Krzysiek Karbowiak](https://github.com/kkarbowiak) refactored the tests to use `CHECK_THROWS_WITH_AS`. 280. [Trevor Hickey](https://github.com/luxe) improved the description of an example.
281. [Chaoqi Zhang](https://github.com/prncoprs) fixed a typo. 281. [Jef LeCompte](https://github.com/jef) updated the year in the README file.
282. [ivanovmp](https://github.com/ivanovmp) fixed a whitespace error. 282. [Alexandre Hamez](https://github.com/ahamez) fixed a warning.
283. [KsaNL](https://github.com/KsaNL) fixed a build error when including `<windows.h>`. 283. [Maninderpal Badhan](https://github.com/mbadhan) fixed a typo.
284. [Andrea Pappacoda](https://github.com/Tachi107) moved `.pc` and `.cmake` files to `share` directory. 284. [kevin--](https://github.com/kevin--) added a note to an example in the README file.
285. [Wolf Vollprecht](https://github.com/wolfv) added the `patch_inplace` function. 285. [I](https://github.com/wx257osn2) fixed a typo.
286. [Jake Zimmerman](https://github.com/jez) highlighted common usage patterns in the README file. 286. [Gregorio Litenstein](https://github.com/Lord-Kamina) fixed the Clang detection.
287. [NN](https://github.com/NN---) added the Visual Studio output directory to `.gitignore`. 287. [Andreas Smas](https://github.com/andoma) added a Doozer badge.
288. [Romain Reignier](https://github.com/romainreignier) improved the performance of the vector output adapter. 288. [WanCW](https://github.com/wancw) fixed the string conversion with Clang.
289. [Mike](https://github.com/Mike-Leo-Smith) fixed the `std::iterator_traits`. 289. [zhaohuaxishi](https://github.com/zhaohuaxishi) fixed a Doxygen error.
290. [Richard Hozák](https://github.com/richardhozak) added macro `JSON_NO_ENUM` to disable default enum conversions. 290. [emvivre](https://github.com/emvivre) removed an invalid parameter from CMake.
291. [vakokako](https://github.com/vakokako) fixed tests when compiling with C++20. 291. [Tobias Hermann](https://github.com/Dobiasd) fixed a link in the README file.
292. [Alexander “weej” Jones](https://github.com/alexweej) fixed an example in the README. 292. [Michael](https://github.com/traits) fixed a warning.
293. [Eli Schwartz](https://github.com/eli-schwartz) added more files to the `include.zip` archive. 293. [Ryan Mulder](https://github.com/ryanjmulder) added `ensure_ascii` to the `dump` function.
294. [Kevin Lu](https://github.com/kevinlul) fixed a compilation issue when typedefs with certain names were present. 294. [Muri Nicanor](https://github.com/murinicanor) fixed the `sed` discovery in the Makefile.
295. [Trevor Hickey](https://github.com/luxe) improved the description of an example. 295. [David Avedissian](https://github.com/dgavedissian) implemented SFINAE-friendly `iterator_traits`.
296. [Jef LeCompte](https://github.com/jef) updated the year in the README file. 296. [AQNOUCH Mohammed](https://github.com/aqnouch) fixed a typo in the README.
297. [Alexandre Hamez](https://github.com/ahamez) fixed a warning. 297. [Gareth Sylvester-Bradley](https://github.com/garethsb) added `operator/=` and `operator/` to construct JSON pointers.
298. [Maninderpal Badhan](https://github.com/mbadhan) fixed a typo. 298. [Michael Macnair](https://github.com/mykter) added support for afl-fuzz testing.
299. [kevin--](https://github.com/kevin--) added a note to an example in the README file. 299. [Berkus Decker](https://github.com/berkus) fixed a typo in the README.
300. [I](https://github.com/wx257osn2) fixed a typo. 300. [Illia Polishchuk](https://github.com/ilqvya) improved the CMake testing.
301. [Gregorio Litenstein](https://github.com/Lord-Kamina) fixed the Clang detection. 301. [Ikko Ashimine](https://github.com/eltociear) fixed two typos.
302. [Andreas Smas](https://github.com/andoma) added a Doozer badge. 302. [Raphael Grimm](https://github.com/barcode) added the possibility to define a custom base class.
303. [WanCW](https://github.com/wancw) fixed the string conversion with Clang. 303. [tocic](https://github.com/tocic) fixed typos in the documentation.
304. [zhaohuaxishi](https://github.com/zhaohuaxishi) fixed a Doxygen error. 304. [Vertexwahn](https://github.com/Vertexwahn) added Bazel build support.
305. [emvivre](https://github.com/emvivre) removed an invalid parameter from CMake. 305. [DavidKorczynski](https://github.com/DavidKorczynski) added a CIFuzz CI GitHub action.
306. [Tobias Hermann](https://github.com/Dobiasd) fixed a link in the README file. 306. [Florian Segginger](https://github.com/floriansegginger) bumped the years in the README.
307. [Michael](https://github.com/traits) fixed a warning. 307. [haadfida](https://github.com/haadfida) cleaned up the badges of used services.
308. [Ryan Mulder](https://github.com/ryanjmulder) added `ensure_ascii` to the `dump` function. 308. [Arsen Arsenović](https://github.com/ArsenArsen) fixed a build error.
309. [Muri Nicanor](https://github.com/murinicanor) fixed the `sed` discovery in the Makefile. 309. [theevilone45](https://github.com/theevilone45) fixed a typo in a CMake file.
310. [David Avedissian](https://github.com/dgavedissian) implemented SFINAE-friendly `iterator_traits`. 310. [Sergei Trofimovich](https://github.com/trofi) fixed the custom allocator support.
311. [AQNOUCH Mohammed](https://github.com/aqnouch) fixed a typo in the README. 311. [Joyce](https://github.com/joycebrum) fixed some security issues in the GitHub workflows.
312. [Gareth Sylvester-Bradley](https://github.com/garethsb) added `operator/=` and `operator/` to construct JSON pointers. 312. [Nicolas Jakob](https://github.com/njakob) add vcpkg version badge.
313. [Michael Macnair](https://github.com/mykter) added support for afl-fuzz testing. 313. [Tomerkm](https://github.com/Tomerkm) added tests.
314. [Berkus Decker](https://github.com/berkus) fixed a typo in the README. 314. [No.](https://github.com/tusooa) fixed the use of `get<>` calls.
315. [Illia Polishchuk](https://github.com/ilqvya) improved the CMake testing. 315. [taro](https://github.com/tarolling) fixed a typo in the `CODEOWNERS` file.
316. [Ikko Ashimine](https://github.com/eltociear) fixed a typo. 316. [Felix Yan](https://github.com/felixonmars) fixed a typo in the README.
317. [Raphael Grimm](https://github.com/barcode) added the possibility to define a custom base class. 317. [HO-COOH](https://github.com/HO-COOH) fixed a parenthesis in the documentation.
318. [tocic](https://github.com/tocic) fixed typos in the documentation. 318. [miny1233](https://github.com/miny1233) fixed a parenthesis in the documentation.
319. [Vertexwahn](https://github.com/Vertexwahn) added Bazel build support. 319. [tomalakgeretkal](https://github.com/tomalakgeretkal) fixed a compilation error.
320. [Dirk Stolle](https://github.com/striezel) fixed typos in the documentation. 320. [alferov](https://github.com/ALF-ONE) fixed a compilation error and fixed a version in the documentation.
321. [DavidKorczynski](https://github.com/DavidKorczynski) added a CIFuzz CI GitHub action. 321. [Craig Scott](https://github.com/craigscott-crascit) fixed a deprecation warning in CMake.
322. [Finkman](https://github.com/Finkman) fixed the debug pretty-printer. 322. [Vyacheslav Zhdanovskiy](https://github.com/ZeronSix) added macros for serialization-only types.
323. [Florian Segginger](https://github.com/floriansegginger) bumped the years in the README. 323. [Mathieu Westphal](https://github.com/mwestphal) fixed typos.
324. [haadfida](https://github.com/haadfida) cleaned up the badges of used services. 324. [scribam](https://github.com/scribam) fixed the MinGW workflow.
325. [Arsen Arsenović](https://github.com/ArsenArsen) fixed a build error. 325. [Aleksei Sapitskii](https://github.com/aleksproger) added support for Apple's Swift Package Manager.
326. [theevilone45](https://github.com/theevilone45) fixed a typo in a CMake file. 326. [Benjamin Buch](https://github.com/bebuch) fixed the installation path in CMake.
327. [Sergei Trofimovich](https://github.com/trofi) fixed the custom allocator support. 327. [Colby Haskell](https://github.com/colbychaskell) clarified the parse error message in case a file cannot be opened.
328. [Joyce](https://github.com/joycebrum) fixed some security issues in the GitHub workflows. 328. [Juan Carlos Arevalo Baeza](https://github.com/TheJCAB) fixed the enum conversion.
329. [Nicolas Jakob](https://github.com/njakob) add vcpkg version badge. 329. [ss](https://github.com/serge-s) fixed the amalgamation call.
330. [Tomerkm](https://github.com/Tomerkm) added tests. 330. [AniketDhemare](https://github.com/AniketDhemare) fixed a version in the documentation.
331. [No.](https://github.com/tusooa) fixed the use of `get<>` calls. 331. [Philip Müller](https://github.com/philip-paul-mueller) fixed an example.
332. [taro](https://github.com/tarolling) fixed a typo in the `CODEOWNERS` file. 332. [Leila Shcheglova](https://github.com/LeilaShcheglova) fixed a warning in a test.
333. [Ikko Eltociear Ashimine](https://github.com/eltociear) fixed a typo. 333. [Alex Prabhat Bara](https://github.com/alexprabhat99) fixed a function name in the documentation.
334. [Felix Yan](https://github.com/felixonmars) fixed a typo in the README. 334. [laterlaugh](https://github.com/laterlaugh) fixed some typos.
335. [HO-COOH](https://github.com/HO-COOH) fixed a parenthesis in the documentation. 335. [Yuanhao Jia](https://github.com/MrJia1997) fixed the GDB pretty printer.
336. [Ivor Wanders](https://github.com/iwanders) fixed the examples to catch exception by `const&`. 336. [Fallen_Breath](https://github.com/Fallen-Breath) fixed an example for JSON Pointer.
337. [miny1233](https://github.com/miny1233) fixed a parenthesis in the documentation. 337. [Nikhil Idiculla](https://github.com/tsnl) fixed some typos.
338. [tomalakgeretkal](https://github.com/tomalakgeretkal) fixed a compilation error. 338. [Griffin Myers](https://github.com/gmyers18) updated the Natvis file.
339. [alferov](https://github.com/ALF-ONE) fixed a compilation error. 339. [thetimr](https://github.com/thetimr) fixed a typo in the documentation.
340. [Craig Scott](https://github.com/craigscott-crascit) fixed a deprecation warning in CMake. 340. [Balazs Erseki](https://github.com/zerocukor287) fixed a URL in the contribution guidelines.
341. [Vyacheslav Zhdanovskiy](https://github.com/ZeronSix) added macros for serialization-only types. 341. [Niccolò Iardella](https://github.com/rotolof) added `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros.
342. [Mathieu Westphal](https://github.com/mwestphal) fixed typos. 342. [Borislav Stanimirov](https://github.com/iboB) allowed overriding the CMake target name.
343. [scribam](https://github.com/scribam) fixed the MinGW workflow. 343. [Captain Crutches](https://github.com/captaincrutches) made `iterator_proxy_value` a `std::forward_iterator`.
344. [Aleksei Sapitskii](https://github.com/aleksproger) added support for Apple's Swift Package Manager. 344. [Fredrik Sandhei](https://github.com/fsandhei) added type conversion support for `std::optional`.
345. [Benjamin Buch](https://github.com/bebuch) fixed the installation path in CMake. 345. [jh96](https://github.com/jordan-hoang) added exceptions when `nullptr` is passed to `parse`.
346. [Colby Haskell](https://github.com/colbychaskell) clarified the parse error message in case a file cannot be opened. 346. [Stuart Gorman](https://github.com/StuartGorman) fixed number parsing when `EINTR` set in `errno`.
347. [Juan Carlos Arevalo Baeza](https://github.com/TheJCAB) fixed the enum conversion. 347. [Dylan Baker](https://github.com/dcbaker) generated a pkg-config file that follows the pkg-config conventions.
348. [alferov](https://github.com/ALF-ONE) fixed a version in the documentation. 348. [Tianyi Chen](https://github.com/TianyiChen) optimized the binary `get_number` implementation.
349. [ss](https://github.com/serge-s) fixed the amalgamation call. 349. [peng-wang-cn](https://github.com/peng-wang-cn) added type conversion support for multidimensional arrays.
350. [AniketDhemare](https://github.com/AniketDhemare) fixed a version in the documentation. 350. [Einars Netlis-Galejs](https://github.com/EinarsNG) added `ONLY_SERIALIZE` for `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros.
351. [Philip Müller](https://github.com/philip-paul-mueller) fixed an example. 351. [Marcel](https://github.com/mering) removed `alwayslink=True` Bazel flag.
352. [Leila Shcheglova](https://github.com/LeilaShcheglova) fixed a warning in a test. 352. [Harinath Nampally](https://github.com/hnampally) added diagnostic positions to exceptions.
353. [Alex Prabhat Bara](https://github.com/alexprabhat99) fixed a function name in the documentation. 353. [Nissim Armand Ben Danan](https://github.com/NissimBendanan) fixed `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` with an empty JSON instance.
354. [laterlaugh](https://github.com/laterlaugh) fixed some typos. 354. [Michael Valladolid](https://github.com/codenut) added support for BSON uint64 serialization/deserialization.
355. [Yuanhao Jia](https://github.com/MrJia1997) fixed the GDB pretty printer. 355. [Nikhil](https://github.com/nikhilreddydev) updated the documentation.
356. [Fallen_Breath](https://github.com/Fallen-Breath) fixed an example for JSON Pointer. 356. [Nebojša Cvetković](https://github.com/nebkat) added support for BJDATA optimized binary array type.
357. [Nikhil Idiculla](https://github.com/tsnl) fixed some typos. 357. [Sushrut Shringarputale](https://github.com/sushshring) added support for diagnostic positions.
358. [Griffin Myers](https://github.com/gmyers18) updated the Natvis file. 358. [kimci86](https://github.com/kimci86) templated to `NLOHMANN_DEFINE_TYPE` macros to also support `ordered_json`.
359. [thetimr](https://github.com/thetimr) fixed a typo in the documentation. 359. [Richard Topchii](https://github.com/richardtop) added support for VisionOS in the Swift Package Manager.
360. [Balazs Erseki](https://github.com/zerocukor287) fixed a URL in the contribution guidelines. 360. [Robert Chisholm](https://github.com/Robadob) fixed a typo.
361. [Niccolò Iardella](https://github.com/rotolof) added `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros. 361. [zjyhjqs](https://github.com/zjyhjqs) added CPack support.
362. [Borislav Stanimirov](https://github.com/iboB) allowed overriding the CMake target name. 362. [bitFiedler](https://github.com/bitFiedler) made GDB pretty printer work with Python 3.8.
363. [Captain Crutches](https://github.com/captaincrutches) made `iterator_proxy_value` a `std::forward_iterator`. 363. [Gianfranco Costamagna](https://github.com/LocutusOfBorg) fixed a compiler warning.
364. [Fredrik Sandhei](https://github.com/fsandhei) added type conversion support for `std::optional`. 364. [risa2000](https://github.com/risa2000) made `std::filesystem::path` conversion to/from UTF-8 encoded string explicit.
365. [jh96](https://github.com/jordan-hoang) added exceptions when `nullptr` is passed to `parse`. 365. [AM](https://github.com/maqnouch) fixed typos in the README.
366. [Stuart Gorman](https://github.com/StuartGorman) fixed number parsing when `EINTR` set in `errno`. 366. [dmenendez-gruposantander](https://github.com/dmenendez-gruposantander) fixed typos in the comments of the examples.
367. [Dylan Baker](https://github.com/dcbaker) generated a pkg-config file that follows the pkg-config conventions. 367. [Mihai Stan](https://github.com/mstan-xx) fixed comparisons against the literal `0`.
368. [Tianyi Chen](https://github.com/TianyiChen) optimized the binary `get_number` implementation. 368. [Matt Gumbel](https://github.com/intelmatt) fixed some `-Weffc++` warnings.
369. [peng-wang-cn](https://github.com/peng-wang-cn) added type conversion support for multidimensional arrays. 369. [vimpunk](https://github.com/vimpunk) moved a lambda out of an unevaluated context to support older compilers.
370. [Einars Netlis-Galejs](https://github.com/EinarsNG) added `ONLY_SERIALIZE` for `NLOHMANN_DEFINE_DERIVED_TYPE_*` macros. 370. [Chris Harris](https://github.com/cjh1) fixed the compilation with GCC 4.8.
371. [Marcel](https://github.com/mering) removed `alwayslink=True` Bazel flag. 371. [Palmer Dabbelt](https://github.com/palmer-dabbelt) generated and installed a pkg-config file.
372. [Harinath Nampally](https://github.com/hnampally) added diagnostic positions to exceptions. 372. [Gus Pozuelo](https://github.com/ap-viavi) made `ordered_map` compatible with GCC 5.5, Clang 3.6, and Xcode 9.
373. [Nissim Armand Ben Danan](https://github.com/NissimBendanan) fixed `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` with an empty JSON instance. 373. [AK](https://github.com/Lioncky) fixed an MSVC build error caused by the `min`/`max` macros from `windows.h`.
374. [Michael Valladolid](https://github.com/codenut) added support for BSON uint64 serialization/deserialization. 374. [Sergiu Deitsch](https://github.com/sergiud) provided a fallback for missing `char8_t` support.
375. [Nikhil](https://github.com/nikhilreddydev) updated the documentation. 375. [Xiaochuan Ye](https://github.com/XueSongTap) fixed `from_msgpack` for `std::byte` input by specializing `std::char_traits`.
376. [Nebojša Cvetković](https://github.com/nebkat) added support for BJDATA optimized binary array type. 376. [Ville Vesilehto](https://github.com/thevilledev) fixed an overflow in the BJData size calculation and rejected overflowing negative integers in CBOR.
377. [Sushrut Shringarputale](https://github.com/sushshring) added support for diagnostic positions. 377. [NmPassTHFan](https://github.com/nmpassthf) replaced the deprecated `std::is_trivial` for C++26.
378. [kimci86](https://github.com/kimci86) templated to `NLOHMANN_DEFINE_TYPE` macros to also support `ordered_json`. 378. [Chris Ever](https://github.com/chirsz-ever) added the `ignore_trailing_commas` parser option.
379. [Richard Topchii](https://github.com/richardtop) added support for VisionOS in the Swift Package Manager. 379. [Kuan-Fu Wu](https://github.com/kfwu1999) fixed the example code for `json_pointer` initialization.
380. [Robert Chisholm](https://github.com/Robadob) fixed a typo. 380. [David Kilzer](https://github.com/ddkilzer) added a missing header to the input adapters.
381. [zjyhjqs](https://github.com/zjyhjqs) added CPack support. 381. [Miko](https://github.com/mikomikotaishi) added proper C++20 module support, simplified the module API, and fixed missing exports.
382. [bitFiedler](https://github.com/bitFiedler) made GDB pretty printer work with Python 3.8. 382. [hitgirl](https://github.com/hitgil) fixed the CMake configuration when cross-compiling.
383. [Gianfranco Costamagna](https://github.com/LocutusOfBorg) fixed a compiler warning. 383. [Devon Thomas](https://github.com/ThomaDevOSU) mentioned the Artistic Style formatting in the contribution guidelines.
384. [risa2000](https://github.com/risa2000) made `std::filesystem::path` conversion to/from UTF-8 encoded string explicit. 384. [Erik Hu](https://github.com/Erikhu1) made Coveralls upload errors non-fatal in the CI.
385. [AM](https://github.com/maqnouch) fixed typos in the README. 385. [co63oc](https://github.com/co63oc) fixed typos.
386. [dmenendez-gruposantander](https://github.com/dmenendez-gruposantander) fixed typos in the comments of the examples. 386. [DmitriBogdanov](https://github.com/DmitriBogdanov) fixed broken package manager links in the documentation.
387. [Mihai Stan](https://github.com/mstan-xx) fixed comparisons against the literal `0`. 387. [Bander](https://github.com/banderzhm) improved the MSVC compatibility of the C++ modules.
388. [Matt Gumbel](https://github.com/intelmatt) fixed some `-Weffc++` warnings. 388. [Andy Choi](https://github.com/ccpong) removed an unnecessary `template` keyword before `get` in the README and the documentation.
389. [vimpunk](https://github.com/vimpunk) moved a lambda out of an unevaluated context to support older compilers. 389. [SamareshSingh](https://github.com/ssam18) fixed single-element brace initialization to copy/move instead of wrapping in an array, fixed the `WITH_DEFAULT` macros for `ordered_map`, and handled moved events in `serve_header.py`.
390. [Chris Harris](https://github.com/cjh1) fixed the compilation with GCC 4.8. 390. [Aditya](https://github.com/Lumowhisp) improved the documentation of the documentation generation.
391. [Palmer Dabbelt](https://github.com/palmer-dabbelt) generated and installed a pkg-config file. 391. [cheese1](https://github.com/cheese1) clarified the README.
392. [Gus Pozuelo](https://github.com/ap-viavi) made `ordered_map` compatible with GCC 5.5, Clang 3.6, and Xcode 9. 392. [KhloodElhossiny](https://github.com/khloodelhossiny) enabled `std::string_view` keys in `operator[]`.
393. [AK](https://github.com/Lioncky) fixed an MSVC build error caused by the `min`/`max` macros from `windows.h`. 393. [Charles Cabergs](https://github.com/cacharle) fixed a `-Wtautological-constant-out-of-range-compare` warning.
394. [Sergiu Deitsch](https://github.com/sergiud) provided a fallback for missing `char8_t` support. 394. [EALePain](https://github.com/EALePain) made the `std::tuple` conversion work with reference types such as `std::tie`.
395. [Xiaochuan Ye](https://github.com/XueSongTap) fixed `from_msgpack` for `std::byte` input by specializing `std::char_traits`. 395. [koala_oishi](https://github.com/chibi-dogs) fixed grammatical wording in the README.
396. [Ville Vesilehto](https://github.com/thevilledev) fixed an overflow in the BJData size calculation and rejected overflowing negative integers in CBOR. 396. [riccardoori11](https://github.com/riccardoori11) fixed a typo in the documentation.
397. [NmPassTHFan](https://github.com/nmpassthf) replaced the deprecated `std::is_trivial` for C++26. 397. [Swastik Bose](https://github.com/VasuBhakt) fixed the parent pointers after `update()` with `JSON_DIAGNOSTICS` and fixed the Doxygen autolinking of requirements.
398. [Chris Ever](https://github.com/chirsz-ever) added the `ignore_trailing_commas` parser option. 398. [trdesilva](https://github.com/trdesilva) added `front`, `pop_front`, and `push_front` to `json_pointer`.
399. [Kuan-Fu Wu](https://github.com/kfwu1999) fixed the example code for `json_pointer` initialization. 399. [Akhilesh Arora](https://github.com/akhilesharora) fixed an incomplete-type error with `ordered_json`.
400. [David Kilzer](https://github.com/ddkilzer) added a missing header to the input adapters. 400. [Hariom Phulre](https://github.com/hariomphulre) fixed the C++20 modules compilation with GCC.
401. [Miko](https://github.com/mikomikotaishi) added proper C++20 module support, simplified the module API, and fixed missing exports. 401. [Kirill Lokotkov](https://github.com/RUSLoker) fixed printing `long double` values.
402. [hitgirl](https://github.com/hitgil) fixed the CMake configuration when cross-compiling. 402. [George Sedov](https://github.com/radistmorse) added the `NLOHMANN_DEFINE_TYPE_*_WITH_NAMES` macros.
403. [Devon Thomas](https://github.com/ThomaDevOSU) mentioned the Artistic Style formatting in the contribution guidelines. 403. [Caillin Nugent](https://github.com/nugentcaillin) added the `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` macro.
404. [Erik Hu](https://github.com/Erikhu1) made Coveralls upload errors non-fatal in the CI. 404. [Cosmin D.](https://github.com/drcosmin) fixed `std::filesystem::path` conversions and added an MSVC workaround for `std::unique_ptr`.
405. [co63oc](https://github.com/co63oc) fixed typos. 405. [Paul Dreik](https://github.com/pauldreik) fixed a test relying on implementation-specific behavior.
406. [DmitriBogdanov](https://github.com/DmitriBogdanov) fixed broken package manager links in the documentation. 406. [Daniel Falk](https://github.com/daniel-falk) added missing copyright notices to the SBOM.
407. [Bander](https://github.com/banderzhm) improved the MSVC compatibility of the C++ modules. 407. [Federico Sfriso](https://github.com/federicosfriso05-dotcom) added support for constructing JSON values from C++20 range views.
408. [Andy Choi](https://github.com/ccpong) removed an unnecessary `template` keyword before `get` in the README and the documentation. 408. [Luke Banicevic](https://github.com/banaboi) fixed corrupt BSON output for lengths exceeding `INT32_MAX`, cleaned up the BSON writer, and improved the documentation.
409. [SamareshSingh](https://github.com/ssam18) fixed single-element brace initialization to copy/move instead of wrapping in an array, fixed the `WITH_DEFAULT` macros for `ordered_map`, and handled moved events in `serve_header.py`. 409. [Patrick Armstrong](https://github.com/Patrick10199) updated the CBOR references and the half-precision float assertions.
410. [Aditya](https://github.com/Lumowhisp) improved the documentation of the documentation generation. 410. [Yash Bavadiya](https://github.com/xevrion) added checks to all BSON reads.
411. [cheese1](https://github.com/cheese1) clarified the README. 411. [hum4nBeing](https://github.com/hum4nBeing) fixed the overflow handling of high-precision numbers in UBJSON.
412. [KhloodElhossiny](https://github.com/khloodelhossiny) enabled `std::string_view` keys in `operator[]`. 412. [tomatotomata](https://github.com/tomatotomata) added checks for reading CBOR tagged subtypes.
413. [Charles Cabergs](https://github.com/cacharle) fixed a `-Wtautological-constant-out-of-range-compare` warning. 413. [YingqiDuan](https://github.com/YingqiDuan) documented the BSON interoperability.
414. [EALePain](https://github.com/EALePain) made the `std::tuple` conversion work with reference types such as `std::tie`. 414. [KBS](https://github.com/youdie006) documented the standards compliance and the strictness of `parse()` and `operator>>`.
415. [koala_oishi](https://github.com/chibi-dogs) fixed grammatical wording in the README. 415. [Petr Bělohlávek](https://github.com/petrbel) added Clang 21 and 22 to the CI.
416. [riccardoori11](https://github.com/riccardoori11) fixed a typo in the documentation. 416. [Dmitry Rantovov](https://github.com/darkdi) fixed the placement of a CBOR documentation block.
417. [Swastik Bose](https://github.com/VasuBhakt) fixed the parent pointers after `update()` with `JSON_DIAGNOSTICS` and fixed the Doxygen autolinking of requirements. 417. [ljcjclljc](https://github.com/ljcjclljc) fixed the comparison of large unsigned integers with signed integers.
418. [trdesilva](https://github.com/trdesilva) added `front`, `pop_front`, and `push_front` to `json_pointer`. 418. [Sahil Kamate](https://github.com/sahilkamate03) fixed the handling of CBOR tags 0-5 and 21-23.
419. [Akhilesh Arora](https://github.com/akhilesharora) fixed an incomplete-type error with `ordered_json`. 419. [Krishnanand G](https://github.com/Krishnanand-G) made the UBJSON writer reject `use_type` without `use_size`.
420. [Hariom Phulre](https://github.com/hariomphulre) fixed the C++20 modules compilation with GCC. 420. [whn](https://github.com/Whning0513) documented the lenient BSON input handling and corrected the complexity of `to_bson`.
421. [Kirill Lokotkov](https://github.com/RUSLoker) fixed printing `long double` values. 421. [elix3r](https://github.com/22elix3r) fixed `update()` with `merge_objects` when merging a primitive into an object.
422. [George Sedov](https://github.com/radistmorse) added the `NLOHMANN_DEFINE_TYPE_*_WITH_NAMES` macros. 422. [Avionic Harshit](https://github.com/avionicharshit-byte) made `diff()` linear when an array shrinks.
423. [Caillin Nugent](https://github.com/nugentcaillin) added the `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` macro. 423. [Qatadaha Bin Matloob](https://github.com/qatcod) fixed comparisons between integers and floats and fixed unparsable BJData output.
424. [Cosmin D.](https://github.com/drcosmin) fixed `std::filesystem::path` conversions and added an MSVC workaround for `std::unique_ptr`. 424. [Wu Shuwen](https://github.com/dajiaohuang) removed an unused include.
425. [Paul Dreik](https://github.com/pauldreik) fixed a test relying on implementation-specific behavior.
426. [Daniel Falk](https://github.com/daniel-falk) added missing copyright notices to the SBOM.
427. [Federico Sfriso](https://github.com/federicosfriso05-dotcom) added support for constructing JSON values from C++20 range views.
428. [Luke Banicevic](https://github.com/banaboi) fixed corrupt BSON output for lengths exceeding `INT32_MAX`, cleaned up the BSON writer, and improved the documentation.
429. [Patrick Armstrong](https://github.com/Patrick10199) updated the CBOR references and the half-precision float assertions.
430. [Yash Bavadiya](https://github.com/xevrion) added checks to all BSON reads.
431. [hum4nBeing](https://github.com/hum4nBeing) fixed the overflow handling of high-precision numbers in UBJSON.
432. [tomatotomata](https://github.com/tomatotomata) added checks for reading CBOR tagged subtypes.
433. [YingqiDuan](https://github.com/YingqiDuan) documented the BSON interoperability.
434. [KBS](https://github.com/youdie006) documented the standards compliance and the strictness of `parse()` and `operator>>`.
435. [Petr Bělohlávek](https://github.com/petrbel) added Clang 21 and 22 to the CI.
436. [Dmitry Rantovov](https://github.com/darkdi) fixed the placement of a CBOR documentation block.
437. [ljcjclljc](https://github.com/ljcjclljc) fixed the comparison of large unsigned integers with signed integers.
438. [Sahil Kamate](https://github.com/sahilkamate03) fixed the handling of CBOR tags 0-5 and 21-23.
439. [Krishnanand G](https://github.com/Krishnanand-G) made the UBJSON writer reject `use_type` without `use_size`.
440. [whn](https://github.com/Whning0513) documented the lenient BSON input handling and corrected the complexity of `to_bson`.
441. [elix3r](https://github.com/22elix3r) fixed `update()` with `merge_objects` when merging a primitive into an object.
442. [Avionic Harshit](https://github.com/avionicharshit-byte) made `diff()` linear when an array shrinks.
443. [Qatadaha Bin Matloob](https://github.com/qatcod) fixed comparisons between integers and floats and fixed unparsable BJData output.
444. [Wu Shuwen](https://github.com/dajiaohuang) removed an unused include.
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
@@ -1879,21 +1850,28 @@ The library itself consists of a single header file licensed under the MIT licen
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows - [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
- [**Artistic Style**](https://astyle.sourceforge.net) for automatic source code indentation - [**Artistic Style**](https://astyle.sourceforge.net) for automatic source code indentation
- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers - [**Clang**](https://clang.llvm.org) for compilation with code sanitizers
- [**Clang-Tidy**](https://clang.llvm.org/extra/clang-tidy/) for static analysis and style checks
- [**CMake**](https://cmake.org) for build automation - [**CMake**](https://cmake.org) for build automation
- [**Codacy**](https://www.codacy.com) for further [code analysis](https://app.codacy.com/gh/nlohmann/json/dashboard) - [**Codacy**](https://www.codacy.com) for further [code analysis](https://app.codacy.com/gh/nlohmann/json/dashboard)
- [**CodeQL**](https://codeql.github.com) for code scanning
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) - [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) - [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)
- [**cppcheck**](https://cppcheck.sourceforge.io) for static analysis - [**cppcheck**](https://cppcheck.sourceforge.io) for static analysis
- [**doctest**](https://github.com/onqtam/doctest) for the unit tests - [**cpplint**](https://github.com/cpplint/cpplint) for style checks
- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md) - [**doctest**](https://github.com/doctest/doctest) for the unit tests
- [**Flawfinder**](https://dwheeler.com/flawfinder/) for static analysis
- [**GitHub Changelog Generator**](https://github.com/github-changelog-generator/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)
- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks - [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks
- [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros - [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros
- [**include-what-you-use**](https://include-what-you-use.org) to check the included headers
- [**Infer**](https://fbinfer.com) for static analysis
- [**lcov**](https://github.com/linux-test-project/lcov) to process coverage information and create an HTML view - [**lcov**](https://github.com/linux-test-project/lcov) to process coverage information and create an HTML view
- [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz - [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz
- [**Material for MkDocs**](https://squidfunk.github.io/mkdocs-material/) for the style of the documentation site - [**Material for MkDocs**](https://squidfunk.github.io/mkdocs-material/) for the style of the documentation site
- [**MkDocs**](https://www.mkdocs.org) for the documentation site - [**MkDocs**](https://www.mkdocs.org) for the documentation site
- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json)) - [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json))
- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments. - [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments.
- [**Semgrep**](https://semgrep.dev) for static analysis
- [**Valgrind**](https://valgrind.org) to check for correct memory management - [**Valgrind**](https://valgrind.org) to check for correct memory management
## Notes ## Notes
@@ -1987,10 +1965,10 @@ If the testdata is not found, several test suites will fail like this:
``` ```
=============================================================================== ===============================================================================
json/tests/src/make_test_data_available.hpp:21: json/tests/src/make_test_data_available.hpp:26:
TEST CASE: check test suite is downloaded TEST CASE: check test suite is downloaded
json/tests/src/make_test_data_available.hpp:23: FATAL ERROR: REQUIRE( utils::check_testsuite_downloaded() ) is NOT correct! json/tests/src/make_test_data_available.hpp:28: FATAL ERROR: REQUIRE( utils::check_testsuite_downloaded() ) is NOT correct!
values: REQUIRE( false ) values: REQUIRE( false )
logged: Test data not found in 'json/cmake-build-debug/json_test_data'. logged: Test data not found in 'json/cmake-build-debug/json_test_data'.
Please execute target 'download_test_data' before running this test suite. Please execute target 'download_test_data' before running this test suite.
@@ -2001,10 +1979,10 @@ json/tests/src/make_test_data_available.hpp:23: FATAL ERROR: REQUIRE( utils::che
In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure` will fail. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure` will fail. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
Some tests are requiring network to be properly execute. They are labeled as `git_required`. Please execute `ctest -LE git_required` to skip these tests. See [issue #4851](https://github.com/nlohmann/json/issues/4851) for more information. Some tests require network access to execute properly. They are labeled as `git_required`. Please execute `ctest -LE git_required` to skip these tests. See [issue #4851](https://github.com/nlohmann/json/issues/4851) for more information.
Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information. Furthermore, assertions must be switched off to ensure reproducible builds (see [discussion 4494](https://github.com/nlohmann/json/discussions/4494)). Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information. Furthermore, assertions must be switched off to ensure reproducible builds (see [discussion 4494](https://github.com/nlohmann/json/discussions/4494)).
Note you need to call `cmake -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information. Note you need to call `ctest -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information.
As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/fp-model-fp.html) then. As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/fp-model-fp.html) then.
+8 -2
View File
@@ -10,10 +10,10 @@ SPDX-FileCopyrightText = "2013-2026 Niels Lohmann <https://nlohmann.me>"
SPDX-License-Identifier = "MIT" SPDX-License-Identifier = "MIT"
[[annotations]] [[annotations]]
path = "include/nlohmann/thirdparty/hedley.hpp" path = "include/nlohmann/thirdparty/hedley/hedley.hpp"
precedence = "aggregate" precedence = "aggregate"
SPDX-FileCopyrightText = "2016-2021 Evan Nemerson <evan@nemerson.com>" SPDX-FileCopyrightText = "2016-2021 Evan Nemerson <evan@nemerson.com>"
SPDX-License-Identifier = "CC0" SPDX-License-Identifier = "CC0-1.0"
[[annotations]] [[annotations]]
path = "include/nlohmann/detail/meta/cpp_future.hpp" path = "include/nlohmann/detail/meta/cpp_future.hpp"
@@ -50,3 +50,9 @@ path = "tools/gdb_pretty_printer/**"
precedence = "aggregate" precedence = "aggregate"
SPDX-FileCopyrightText = "2020 Hannes Domani <https://github.com/ssbssa>" SPDX-FileCopyrightText = "2020 Hannes Domani <https://github.com/ssbssa>"
SPDX-License-Identifier = "MIT" SPDX-License-Identifier = "MIT"
[[annotations]]
path = "docs/docset/icon*.png"
precedence = "override"
SPDX-FileCopyrightText = "JSON logo (public domain), https://commons.wikimedia.org/wiki/File:JSON_vector_logo.svg"
SPDX-License-Identifier = "CC0-1.0"
+13 -16
View File
@@ -5,15 +5,14 @@ set(N 10)
# Needed tools. # Needed tools.
############################################################################### ###############################################################################
include(FindPython3)
find_package(Python3 COMPONENTS Interpreter) find_package(Python3 COMPONENTS Interpreter)
find_program(CLANG_TOOL NAMES clang++-HEAD clang++ clang++-22 clang++-21 clang++-20 clang++-19 clang++-18 clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11 clang++) find_program(CLANG_TOOL NAMES clang++ clang++-HEAD clang++-22 clang++-21 clang++-20 clang++-19 clang++-18 clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11)
execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION) execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}") string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}")
message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})") message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})")
find_program(CLANG_TIDY_TOOL NAMES clang-tidy-22 clang-tidy-21 clang-tidy-20 clang-tidy-19 clang-tidy-18 clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy) find_program(CLANG_TIDY_TOOL NAMES clang-tidy clang-tidy-22 clang-tidy-21 clang-tidy-20 clang-tidy-19 clang-tidy-18 clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11)
execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION) execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TIDY_TOOL_VERSION "${CLANG_TIDY_TOOL_VERSION}") string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TIDY_TOOL_VERSION "${CLANG_TIDY_TOOL_VERSION}")
message(STATUS "🔖 Clang-Tidy ${CLANG_TIDY_TOOL_VERSION} (${CLANG_TIDY_TOOL})") message(STATUS "🔖 Clang-Tidy ${CLANG_TIDY_TOOL_VERSION} (${CLANG_TIDY_TOOL})")
@@ -69,9 +68,7 @@ string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" VALGRIND_TOOL_VERSION "${VALGRIND_TOOL_V
message(STATUS "🔖 Valgrind ${VALGRIND_TOOL_VERSION} (${VALGRIND_TOOL})") message(STATUS "🔖 Valgrind ${VALGRIND_TOOL_VERSION} (${VALGRIND_TOOL})")
find_program(GENHTML_TOOL NAMES genhtml) find_program(GENHTML_TOOL NAMES genhtml)
find_program(PLOG_CONVERTER_TOOL NAMES plog-converter) find_program(SCAN_BUILD_TOOL NAMES scan-build scan-build-22 scan-build-21 scan-build-20 scan-build-19 scan-build-18 scan-build-17 scan-build-16 scan-build-15 scan-build-14 scan-build-13 scan-build-12 scan-build-11)
find_program(PVS_STUDIO_ANALYZER_TOOL NAMES pvs-studio-analyzer)
find_program(SCAN_BUILD_TOOL NAMES scan-build-15 scan-build-14 scan-build-13 scan-build-12 scan-build-11 scan-build)
# the individual source files # the individual source files
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp) file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp)
@@ -367,7 +364,7 @@ add_custom_target(ci_test_coverage
COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 --ignore-errors mismatch --ignore-errors unused COMMAND ${LCOV_TOOL} --directory . --capture --output-file json.info --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 --ignore-errors mismatch --ignore-errors unused
COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc branch_coverage=1 --ignore-errors unused COMMAND ${LCOV_TOOL} -e json.info ${SRC_FILES} --output-file json.info.filtered --rc branch_coverage=1 --ignore-errors unused
COMMAND ${CMAKE_SOURCE_DIR}/tests/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept COMMAND ${CMAKE_SOURCE_DIR}/tests/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept
COMMAND genhtml --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.filtered.noexcept COMMAND ${GENHTML_TOOL} --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.filtered.noexcept
COMMENT "Compile and test with coverage" COMMENT "Compile and test with coverage"
) )
@@ -392,8 +389,8 @@ add_custom_target(ci_test_clang_sanitizer
# Check if header is amalgamated and sources are properly indented. # 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/* # Same file set as .github/workflows/check_amalgamation.yml, so this CMake target (which can be run locally) is held
# (which only this CMake target checks, not the pull_request-only workflow) is held to the same standard. # to the same standard as the workflow (which runs for pull requests and for pushes to develop/master/release/*).
file(GLOB_RECURSE INDENT_FILES file(GLOB_RECURSE INDENT_FILES
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.hpp ${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.hpp
${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cpp ${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cpp
@@ -423,7 +420,7 @@ 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.json -s .
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_fwd.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 cp ${PROJECT_SOURCE_DIR}/include/nlohmann/json_literals.hpp ${include_dir}/json_literals.hpp
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp ${include_dir}/json_literals.hpp
COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/scripts/gen_bazel_build_file.cmake 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.hpp~ ${include_dir}/json.hpp
@@ -434,6 +431,8 @@ add_custom_target(ci_test_amalgamation
COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=orig ${INDENT_FILES} COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=orig ${INDENT_FILES}
COMMAND for FILE in `find . -name '*.orig'`\; do false \; done COMMAND for FILE in `find . -name '*.orig'`\; do false \; done
COMMAND rm -f ${include_dir}/json.hpp~ ${include_dir}/json_fwd.hpp~ ${include_dir}/json_literals.hpp~ ${PROJECT_SOURCE_DIR}/BUILD.bazel~
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Check amalgamation, formatting, and BUILD.bazel" COMMENT "Check amalgamation, formatting, and BUILD.bazel"
) )
@@ -719,7 +718,7 @@ 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 # 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 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 JSON_DisableTupleReferenceConversion JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind
JSON_StrictNulHandling JSON_StrictBinaryUTF8 JSON_DeleteDeprecatedFunctions) JSON_StrictNulHandling JSON_StrictBinaryUTF8 JSON_DeleteDeprecatedFunctions)
set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0}) 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}) set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
@@ -776,17 +775,14 @@ add_custom_target(ci_cmake_flags
# Use more installed compilers. # Use more installed compilers.
############################################################################### ###############################################################################
foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6 g++-7 g++-8 g++-9 g++-10 g++-11 clang++-3.5 clang++-3.6 clang++-3.7 clang++-3.8 clang++-3.9 clang++-4.0 clang++-5.0 clang++-6.0 clang++-7 clang++-8 clang++-9 clang++-10 clang++-11 clang++-12 clang++-13 clang++-14 clang++-15 clang++-16 clang++-17 clang++-18 clang++-19 clang++-20) foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6)
find_program(COMPILER_TOOL NAMES ${COMPILER}) find_program(COMPILER_TOOL NAMES ${COMPILER})
if (COMPILER_TOOL) if (COMPILER_TOOL)
unset(ADDITIONAL_FLAGS)
add_custom_target(ci_test_compiler_${COMPILER} add_custom_target(ci_test_compiler_${COMPILER}
COMMAND CXX=${COMPILER} ${CMAKE_COMMAND} COMMAND CXX=${COMPILER} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_BuildTests=ON -DJSON_FastTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_${COMPILER}
${ADDITIONAL_FLAGS}
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER}
COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with ${COMPILER}" COMMENT "Compile and test with ${COMPILER}"
@@ -800,7 +796,6 @@ add_custom_target(ci_test_compiler_default
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_BuildTests=ON -DJSON_FastTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_default -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_default
${ADDITIONAL_FLAGS}
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_default --parallel ${N} COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_default --parallel ${N}
COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_default && ${CMAKE_CTEST_COMMAND} --parallel ${N} -LE git_required --output-on-failure COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_default && ${CMAKE_CTEST_COMMAND} --parallel ${N} -LE git_required --output-on-failure
COMMENT "Compile and test with default C++ compiler" COMMENT "Compile and test with default C++ compiler"
@@ -825,8 +820,10 @@ add_custom_target(ci_module_cpp20
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_CI=ON -DNLOHMANN_JSON_BUILD_MODULES=ON -DJSON_Install=ON -DJSON_CI=ON -DNLOHMANN_JSON_BUILD_MODULES=ON -DJSON_Install=ON
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
-S${PROJECT_SOURCE_DIR}/tests/module_cpp20 -B${PROJECT_BINARY_DIR}/ci_module_cpp20 -S${PROJECT_SOURCE_DIR}/tests/module_cpp20 -B${PROJECT_BINARY_DIR}/ci_module_cpp20
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/ci_module_cpp20 COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/ci_module_cpp20
VERBATIM
) )
############################################################################### ###############################################################################
+1
View File
@@ -49,6 +49,7 @@ cc_library(
hdrs = [ hdrs = [
"single_include/nlohmann/json.hpp", "single_include/nlohmann/json.hpp",
"single_include/nlohmann/json_fwd.hpp", "single_include/nlohmann/json_fwd.hpp",
"single_include/nlohmann/json_literals.hpp",
], ],
includes = ["single_include"], includes = ["single_include"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
+2 -2
View File
@@ -7,12 +7,12 @@ This URL provides the most recent documentation and also applies to previous ver
functions is not removed; instead, it is marked as deprecated. functions is not removed; instead, it is marked as deprecated.
If you want to view the documentation for a specific tag or commit hash, you can generate it locally as follows (example If you want to view the documentation for a specific tag or commit hash, you can generate it locally as follows (example
using tag `v3.10.2`): using tag `v3.12.0`):
```shell ```shell
git clone https://github.com/nlohmann/json.git git clone https://github.com/nlohmann/json.git
cd json cd json
git checkout v3.10.2 git checkout v3.12.0
make install_venv serve -C docs/mkdocs make install_venv serve -C docs/mkdocs
``` ```
+11 -55
View File
@@ -1,48 +1,24 @@
SHELL=/usr/bin/env bash SHELL=/usr/bin/env bash
SED ?= $(shell which gsed 2>/dev/null || which sed) PYTHON=../mkdocs/venv/bin/python3
MKDOCS_PAGES=$(shell cd ../mkdocs/docs/ && find * -type f -name '*.md' | sort)
.PHONY: all .PHONY: all
all: JSON_for_Modern_C++.tgz all: JSON_for_Modern_C++.tgz
docSet.dsidx: docSet.sql # generate the search index (the docset target does this itself, this is
# generate index # only handy for inspecting the index)
sqlite3 docSet.dsidx <docSet.sql docSet.dsidx: generate_docset.py
$(PYTHON) generate_docset.py index docSet.dsidx
JSON_for_Modern_C++.docset: Info.plist docSet.dsidx # build the documentation and turn it into a self-contained docset
rm -fr JSON_for_Modern_C++.docset JSON_for_Modern_C++.tgz .PHONY: JSON_for_Modern_C++.docset
mkdir -p JSON_for_Modern_C++.docset/Contents/Resources/Documents/ JSON_for_Modern_C++.docset:
cp icon*.png JSON_for_Modern_C++.docset
cp Info.plist JSON_for_Modern_C++.docset/Contents
# build and copy documentation
$(MAKE) install_venv -C ../mkdocs $(MAKE) install_venv -C ../mkdocs
$(MAKE) build -C ../mkdocs $(MAKE) build -C ../mkdocs
cp -r ../mkdocs/site/* JSON_for_Modern_C++.docset/Contents/Resources/Documents $(PYTHON) generate_docset.py docset ../mkdocs/site .
# patch CSS to hide navigation items
echo -e "\n\nheader, footer, nav.md-tabs, nav.md-tabs--active, div.md-sidebar--primary, a.md-content__button { display: none; }" >> "$$(ls JSON_for_Modern_C++.docset/Contents/Resources/Documents/assets/stylesheets/main.*.min.css)"
# fix spacing
echo -e "\n\ndiv.md-sidebar div.md-sidebar--secondary, div.md-main__inner { top: 0; margin-top: 0 }" >> "$$(ls JSON_for_Modern_C++.docset/Contents/Resources/Documents/assets/stylesheets/main.*.min.css)"
# remove "JSON for Modern C++" from page titles (fallback)
find JSON_for_Modern_C++.docset/Contents/Resources/Documents -type f -exec $(SED) -i 's| - JSON for Modern C++</title>|</title>|' {} +
# replace page titles with name from index, if available
for page in $(MKDOCS_PAGES); do \
case "$$page" in \
*/index.md) path=$${page/\/index.md/} ;; \
*) path=$${page/.md/} ;; \
esac; \
title=$$(sqlite3 docSet.dsidx "SELECT name FROM searchIndex WHERE path='$$path/index.html'" | tr '\n' ',' | $(SED) -e 's/,/, /g' -e 's/, $$/\n/'); \
if [ "x$$title" != "x" ]; then \
$(SED) -i "s%<title>.*</title>%<title>$$title</title>%" "JSON_for_Modern_C++.docset/Contents/Resources/Documents/$$path/index.html"; \
fi \
done
# clean up
rm JSON_for_Modern_C++.docset/Contents/Resources/Documents/sitemap.*
# copy index
cp docSet.dsidx JSON_for_Modern_C++.docset/Contents/Resources/
.PHONY: JSON_for_Modern_C++.tgz
JSON_for_Modern_C++.tgz: JSON_for_Modern_C++.docset JSON_for_Modern_C++.tgz: JSON_for_Modern_C++.docset
tar --exclude='.DS_Store' -cvzf JSON_for_Modern_C++.tgz JSON_for_Modern_C++.docset $(PYTHON) generate_docset.py tgz .
# install docset for Zeal documentation browser (https://zealdocs.org/) # install docset for Zeal documentation browser (https://zealdocs.org/)
.PHONY: install_docset_zeal .PHONY: install_docset_zeal
@@ -52,26 +28,6 @@ install_docset_zeal: JSON_for_Modern_C++.docset
mkdir -p $$docset_root; \ mkdir -p $$docset_root; \
cp -r JSON_for_Modern_C++.docset $$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
@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
@comm -13 <(echo '$(DOCSET_PAGE_PATHS)' | tr ' ' '\n') <(echo '$(DOCSET_INDEX_PATHS)' | tr ' ' '\n')
.PHONY: clean .PHONY: clean
clean: clean:
rm -f docSet.dsidx rm -f docSet.dsidx
+3 -1
View File
@@ -4,7 +4,8 @@ The folder contains the required files to create a [docset](https://kapeli.com/d
documentation browsers like [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), or documentation browsers like [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), or
[Zeal](https://zealdocs.org). [Zeal](https://zealdocs.org).
The docset can be created with The docset (pages and search index) is generated by `generate_docset.py` from the mkdocs site and `mkdocs.yml`. It
can be created with
```sh ```sh
make JSON_for_Modern_C++.docset make JSON_for_Modern_C++.docset
@@ -12,6 +13,7 @@ make JSON_for_Modern_C++.docset
The generated folder `JSON_for_Modern_C++.docset` can then be opened in the documentation browser. `make all` builds a 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. `JSON_for_Modern_C++.tgz` archive instead, and `make install_docset_zeal` installs the docset for Zeal directly.
`make docSet.dsidx` builds only the search index.
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). 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).
-289
View File
@@ -1,289 +0,0 @@
DROP TABLE IF EXISTS searchIndex;
CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);
CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path);
-- API
INSERT INTO searchIndex(name, type, path) VALUES ('adl_serializer', 'Class', 'api/adl_serializer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('adl_serializer::from_json', 'Function', 'api/adl_serializer/from_json/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('adl_serializer::to_json', 'Function', 'api/adl_serializer/to_json/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype', 'Class', 'api/byte_container_with_subtype/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::byte_container_with_subtype', 'Constructor', 'api/byte_container_with_subtype/byte_container_with_subtype/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::clear_subtype', 'Method', 'api/byte_container_with_subtype/clear_subtype/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::has_subtype', 'Method', 'api/byte_container_with_subtype/has_subtype/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::operator!=', 'Operator', 'api/byte_container_with_subtype/operator_ne/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::operator==', 'Operator', 'api/byte_container_with_subtype/operator_eq/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::set_subtype', 'Method', 'api/byte_container_with_subtype/set_subtype/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::subtype', 'Method', 'api/byte_container_with_subtype/subtype/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json', 'Class', 'api/basic_json/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('format_as', 'Function', 'api/basic_json/format_as/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::accept', 'Function', 'api/basic_json/accept/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::array', 'Function', 'api/basic_json/array/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::array_t', 'Type', 'api/basic_json/array_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::as_base_class', 'Method', 'api/basic_json/as_base_class/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::at', 'Method', 'api/basic_json/at/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::back', 'Method', 'api/basic_json/back/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::basic_json', 'Constructor', 'api/basic_json/basic_json/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::begin', 'Method', 'api/basic_json/begin/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::binary', 'Function', 'api/basic_json/binary/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::binary_t', 'Type', 'api/basic_json/binary_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::boolean_t', 'Type', 'api/basic_json/boolean_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::cbegin', 'Method', 'api/basic_json/cbegin/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::cbor_tag_handler_t', 'Enum', 'api/basic_json/cbor_tag_handler_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::cend', 'Method', 'api/basic_json/cend/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::clear', 'Method', 'api/basic_json/clear/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::contains', 'Method', 'api/basic_json/contains/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::count', 'Method', 'api/basic_json/count/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::crbegin', 'Method', 'api/basic_json/crbegin/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::crend', 'Method', 'api/basic_json/crend/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::default_object_comparator_t', 'Type', 'api/basic_json/default_object_comparator_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::diff', 'Function', 'api/basic_json/diff/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::dump', 'Method', 'api/basic_json/dump/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::emplace', 'Method', 'api/basic_json/emplace/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::emplace_back', 'Method', 'api/basic_json/emplace_back/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::empty', 'Method', 'api/basic_json/empty/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::end', 'Method', 'api/basic_json/end/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::end_pos', 'Method', 'api/basic_json/end_pos/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::erase', 'Method', 'api/basic_json/erase/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::error_handler_t', 'Enum', 'api/basic_json/error_handler_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::exception', 'Class', 'api/basic_json/exception/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::find', 'Method', 'api/basic_json/find/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::flatten', 'Method', 'api/basic_json/flatten/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_bjdata', 'Function', 'api/basic_json/from_bjdata/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_bson', 'Function', 'api/basic_json/from_bson/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_cbor', 'Function', 'api/basic_json/from_cbor/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_msgpack', 'Function', 'api/basic_json/from_msgpack/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_bon8', 'Function', 'api/basic_json/from_bon8/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::from_ubjson', 'Function', 'api/basic_json/from_ubjson/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::front', 'Method', 'api/basic_json/front/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get', 'Method', 'api/basic_json/get/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_allocator', 'Function', 'api/basic_json/get_allocator/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_binary', 'Method', 'api/basic_json/get_binary/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_ptr', 'Method', 'api/basic_json/get_ptr/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_ref', 'Method', 'api/basic_json/get_ref/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_to', 'Method', 'api/basic_json/get_to/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::input_format_t', 'Enum', 'api/basic_json/input_format_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::insert', 'Method', 'api/basic_json/insert/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::invalid_iterator', 'Class', 'api/basic_json/invalid_iterator/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_array', 'Method', 'api/basic_json/is_array/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_binary', 'Method', 'api/basic_json/is_binary/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_boolean', 'Method', 'api/basic_json/is_boolean/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_discarded', 'Method', 'api/basic_json/is_discarded/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_null', 'Method', 'api/basic_json/is_null/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_number', 'Method', 'api/basic_json/is_number/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_number_float', 'Method', 'api/basic_json/is_number_float/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_number_integer', 'Method', 'api/basic_json/is_number_integer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_number_unsigned', 'Method', 'api/basic_json/is_number_unsigned/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_object', 'Method', 'api/basic_json/is_object/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_primitive', 'Method', 'api/basic_json/is_primitive/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_string', 'Method', 'api/basic_json/is_string/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_structured', 'Method', 'api/basic_json/is_structured/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::items', 'Method', 'api/basic_json/items/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::json_base_class_t', 'Type', 'api/basic_json/json_base_class_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::json_serializer', 'Class', 'api/basic_json/json_serializer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::max_size', 'Method', 'api/basic_json/max_size/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::merge_patch', 'Method', 'api/basic_json/merge_patch/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::meta', 'Function', 'api/basic_json/meta/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::number_float_t', 'Type', 'api/basic_json/number_float_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::number_integer_t', 'Type', 'api/basic_json/number_integer_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::number_unsigned_t', 'Type', 'api/basic_json/number_unsigned_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::object', 'Function', 'api/basic_json/object/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::object_comparator_t', 'Type', 'api/basic_json/object_comparator_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::object_t', 'Type', 'api/basic_json/object_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator ValueType', 'Operator', 'api/basic_json/operator_ValueType/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator value_t', 'Operator', 'api/basic_json/operator_value_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator[]', 'Operator', 'api/basic_json/operator[]/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator=', 'Operator', 'api/basic_json/operator=/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator+=', 'Operator', 'api/basic_json/operator+=/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator==', 'Operator', 'api/basic_json/operator_eq/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator!=', 'Operator', 'api/basic_json/operator_ne/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator<', 'Operator', 'api/basic_json/operator_lt/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator<=', 'Operator', 'api/basic_json/operator_le/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator>', 'Operator', 'api/basic_json/operator_gt/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator>=', 'Operator', 'api/basic_json/operator_ge/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::operator<=>', 'Operator', 'api/basic_json/operator_spaceship/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::out_of_range', 'Class', 'api/basic_json/out_of_range/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::other_error', 'Class', 'api/basic_json/other_error/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::parse', 'Function', 'api/basic_json/parse/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::parse_error', 'Class', 'api/basic_json/parse_error/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::parse_event_t', 'Enum', 'api/basic_json/parse_event_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::parser_callback_t', 'Type', 'api/basic_json/parser_callback_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::patch', 'Method', 'api/basic_json/patch/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::patch_inplace', 'Method', 'api/basic_json/patch_inplace/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::push_back', 'Method', 'api/basic_json/push_back/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::rbegin', 'Method', 'api/basic_json/rbegin/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::rend', 'Method', 'api/basic_json/rend/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::sax_parse', 'Function', 'api/basic_json/sax_parse/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::size', 'Method', 'api/basic_json/size/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::start_pos', 'Method', 'api/basic_json/start_pos/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::string_t', 'Type', 'api/basic_json/string_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::swap', 'Method', 'api/basic_json/swap/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::type', 'Method', 'api/basic_json/type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::type_error', 'Class', 'api/basic_json/type_error/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::type_name', 'Method', 'api/basic_json/type_name/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::unflatten', 'Method', 'api/basic_json/unflatten/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::update', 'Method', 'api/basic_json/update/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_bjdata', 'Function', 'api/basic_json/to_bjdata/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_bson', 'Function', 'api/basic_json/to_bson/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_cbor', 'Function', 'api/basic_json/to_cbor/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_msgpack', 'Function', 'api/basic_json/to_msgpack/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_bon8', 'Function', 'api/basic_json/to_bon8/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_string', 'Method', 'api/basic_json/to_string/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_ubjson', 'Function', 'api/basic_json/to_ubjson/index.html');
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::with_t', 'Type', 'api/basic_json/with_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 ('json', 'Class', 'api/json/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');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::front', 'Method', 'api/json_pointer/front/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::json_pointer', 'Constructor', 'api/json_pointer/json_pointer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator==', 'Operator', 'api/json_pointer/operator_eq/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator!=', 'Operator', 'api/json_pointer/operator_ne/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator/', 'Operator', 'api/json_pointer/operator_slash/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator/=', 'Operator', 'api/json_pointer/operator_slasheq/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator string_t', 'Operator', 'api/json_pointer/operator_string_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator<=>', 'Operator', 'api/json_pointer/operator_spaceship/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::parent_pointer', 'Method', 'api/json_pointer/parent_pointer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::pop_back', 'Method', 'api/json_pointer/pop_back/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::pop_front', 'Method', 'api/json_pointer/pop_front/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::push_back', 'Method', 'api/json_pointer/push_back/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::push_front', 'Method', 'api/json_pointer/push_front/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::string_t', 'Type', 'api/json_pointer/string_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::to_string', 'Method', 'api/json_pointer/to_string/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax', 'Class', 'api/json_sax/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::binary', 'Method', 'api/json_sax/binary/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::boolean', 'Method', 'api/json_sax/boolean/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::end_array', 'Method', 'api/json_sax/end_array/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::end_object', 'Method', 'api/json_sax/end_object/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::key', 'Method', 'api/json_sax/key/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::null', 'Method', 'api/json_sax/null/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_float', 'Method', 'api/json_sax/number_float/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_integer', 'Method', 'api/json_sax/number_integer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_unsigned', 'Method', 'api/json_sax/number_unsigned/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::parse_error', 'Method', 'api/json_sax/parse_error/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::start_array', 'Method', 'api/json_sax/start_array/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::start_object', 'Method', 'api/json_sax/start_object/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::string', 'Method', 'api/json_sax/string/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('operator""_json', 'Literal', 'api/operator_literal_json/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('operator""_json_pointer', 'Literal', 'api/operator_literal_json_pointer/index.html');
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_map', 'Class', 'api/ordered_map/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('std::formatter<basic_json>', 'Class', 'api/basic_json/std_formatter/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');
-- Features
INSERT INTO searchIndex(name, type, path) VALUES ('Arbitrary Type Conversions', 'Guide', 'features/arbitrary_types/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats', 'Guide', 'features/binary_formats/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: BJData', 'Guide', 'features/binary_formats/bjdata/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: BSON', 'Guide', 'features/binary_formats/bson/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: CBOR', 'Guide', 'features/binary_formats/cbor/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: MessagePack', 'Guide', 'features/binary_formats/messagepack/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: BON8', 'Guide', 'features/binary_formats/bon8/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Formats: UBJSON', 'Guide', 'features/binary_formats/ubjson/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Binary Values', 'Guide', 'features/binary_values/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Comments', 'Guide', 'features/comments/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Element Access', 'Guide', 'features/element_access/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Access with default value: value', 'Guide', 'features/element_access/default_value/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Checked access: at', 'Guide', 'features/element_access/checked_access/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Element Access: Unchecked access: operator[]', 'Guide', 'features/element_access/unchecked_access/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Exceptions', 'Guide', 'home/exceptions/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Migration Guide', 'Guide', 'integration/migration_guide/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: CMake', 'Guide', 'integration/cmake/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Header only', 'Guide', 'integration/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Package Managers', 'Guide', 'integration/package_managers/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Integration: Pkg-config', 'Guide', 'integration/pkg-config/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Iterators', 'Guide', 'features/iterators/index.html');
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 ('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');
INSERT INTO searchIndex(name, type, path) VALUES ('Object Order', 'Guide', 'features/object_order/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Performance', 'Guide', 'features/performance/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing', 'Guide', 'features/parsing/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: JSON Lines', 'Guide', 'features/parsing/json_lines/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Parser Callbacks', 'Guide', 'features/parsing/parser_callbacks/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Parsing and Exceptions', 'Guide', 'features/parsing/parse_exceptions/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: SAX Interface', 'Guide', 'features/parsing/sax_interface/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Untrusted Input', 'Guide', 'features/parsing/untrusted_input/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Runtime Assertions', 'Guide', 'features/assertions/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Specializing enum conversion', 'Guide', 'features/enum_conversion/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Supported Macros', 'Guide', 'features/macros/index.html');
-- Macros
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'api/macros/json_assert/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_BRACE_INIT_COPY_SEMANTICS', 'Macro', 'api/macros/json_brace_init_copy_semantics/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'api/macros/json_throw_user/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DELETE_DEPRECATED_FUNCTIONS', 'Macro', 'api/macros/json_delete_deprecated_functions/index.html');
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');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_20', 'Macro', 'api/macros/json_has_cpp_11/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_23', 'Macro', 'api/macros/json_has_cpp_11/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_26', 'Macro', 'api/macros/json_has_cpp_11/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_EXPERIMENTAL_FILESYSTEM', 'Macro', 'api/macros/json_has_filesystem/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_FILESYSTEM', 'Macro', 'api/macros/json_has_filesystem/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_RANGES', 'Macro', 'api/macros/json_has_ranges/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_STATIC_RTTI', 'Macro', 'api/macros/json_has_static_rtti/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_STD_FORMAT', 'Macro', 'api/macros/json_has_std_format/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_THREE_WAY_COMPARISON', 'Macro', 'api/macros/json_has_three_way_comparison/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NOEXCEPTION', 'Macro', 'api/macros/json_noexception/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_AUTOMATIC_UDLS', 'Macro', 'api/macros/json_no_automatic_udls/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_IO', 'Macro', 'api/macros/json_no_io/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_THREAD_LOCAL', 'Macro', 'api/macros/json_no_thread_local/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_PRECISE_STREAM_POSITION', 'Macro', 'api/macros/json_precise_stream_position/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_SKIP_LIBRARY_VERSION_CHECK', 'Macro', 'api/macros/json_skip_library_version_check/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_SKIP_UNSUPPORTED_COMPILER_CHECK', 'Macro', 'api/macros/json_skip_unsupported_compiler_check/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_STRICT_BINARY_UTF8', 'Macro', 'api/macros/json_strict_binary_utf8/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_STRICT_NUL_HANDLING', 'Macro', 'api/macros/json_strict_nul_handling/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_THROW_USER', 'Macro', 'api/macros/json_throw_user/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_TRY_USER', 'Macro', 'api/macros/json_throw_user/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro', 'api/macros/json_use_global_udls/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS', 'Macro', 'api/macros/json_use_objects_for_enum_keyed_maps/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_SIMDUTF', 'Macro', 'api/macros/json_use_simdutf/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE', 'Macro', 'api/macros/nlohmann_json_namespace/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_BEGIN', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_END', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_NO_VERSION', 'Macro', 'api/macros/nlohmann_json_namespace_no_version/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM', 'Macro', 'api/macros/nlohmann_json_serialize_enum/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM_STRICT', 'Macro', 'api/macros/nlohmann_json_serialize_enum_strict/index.html');
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');
+528
View File
@@ -0,0 +1,528 @@
#!/usr/bin/env python3
"""Generate the Dash docset search index from the mkdocs sources."""
import argparse
import glob
import hashlib
import html
import os
import re
import shutil
import sqlite3
import sys
import tarfile
import urllib.parse
import urllib.request
import yaml
HERE = os.path.dirname(os.path.abspath(__file__))
MKDOCS_YML = os.path.join(HERE, '..', 'mkdocs', 'mkdocs.yml')
PAGES = os.path.join(HERE, '..', 'mkdocs', 'docs')
# api pages whose (name, type) cannot be derived by the heuristics
OVERRIDES = {
}
DOCSET = 'JSON_for_Modern_C++.docset'
TITLE_SUFFIX = ' - JSON for Modern C++</title>'
# CSS rules appended to the stylesheet: hide navigation items and fix spacing
# hide the navigation (the documentation browser has its own); Material's class selectors would win over element
# selectors, hence the classes and !important
CSS_PATCH = (
'\n\n.md-header, .md-footer, .md-tabs, .md-sidebar--primary, .md-content__button { display: none !important; }'
'\n\n.md-sidebar--secondary, .md-main__inner { top: 0 !important; margin-top: 0 !important; }'
)
USER_AGENT = ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/124.0 Safari/537.36')
CONTENT_TYPE_EXT = {'image/svg+xml': '.svg', 'image/png': '.png', 'image/jpeg': '.jpg',
'image/gif': '.gif', 'image/webp': '.webp'}
# remote loads that are allowed to remain (URL -> reason)
ALLOWED_REMOTE = {
# Material only loads this polyfill if the browser has no ResizeObserver
'https://unpkg.com/resize-observer-polyfill': 'fallback for browsers without ResizeObserver',
}
problems = []
def problem(page, reason) -> None:
"""Record a problem; all problems are reported at the end."""
problems.append(f'generate_docset.py: {page}: {reason}')
class Loader(yaml.SafeLoader):
"""YAML loader that tolerates the custom tags used in mkdocs.yml."""
Loader.add_multi_constructor('', lambda loader, suffix, node: None)
def walk_nav(items, groups=()):
"""Yield (group titles, nav title or None, md path) for all nav leaves."""
for item in items:
if isinstance(item, str):
yield list(groups), None, item
elif isinstance(item, dict):
for title, value in item.items():
if isinstance(value, list):
yield from walk_nav(value, groups + (str(title),))
else:
yield list(groups), str(title), value
def page_path(md_path) -> str:
"""Map a markdown path to the HTML path of the rendered page."""
if md_path.endswith('/index.md'):
return md_path[:-len('index.md')] + 'index.html'
return md_path[:-len('.md')] + '/index.html'
def read_page(md_path) -> str:
"""Read a page (resolving a snippet include), return '' if it does not exist."""
try:
with open(os.path.join(PAGES, md_path), encoding='utf-8') as f:
text = f.read()
m = re.match(r'--8<-- "(.+)"\s*$', text)
if m:
with open(os.path.join(PAGES, m.group(1)), encoding='utf-8') as f:
text = f.read()
return text
except OSError:
return ''
def clean(text) -> str:
"""Strip tags and entities from a heading and normalize whitespace."""
text = text.replace('\\>', '\x00') # escaped '>' is not the end of a tag
text = html.unescape(re.sub(r'</?[a-zA-Z][^>]*>', '', text)).replace('\x00', '>')
return re.sub(r'\s+', ' ', text).strip()
def strip_fences(text) -> str:
"""Remove fenced code blocks (their lines may start with '# ')."""
return re.sub(r'^(```|~~~).*?^\1[^\n]*$', '', text, flags=re.M | re.S)
def get_h1(text):
"""Return the cleaned first H1 of a page or None."""
body = strip_fences(text)
m = re.search(r'^# (.+)$', body, flags=re.M)
if m:
return clean(m.group(1))
m = re.search(r'<h1>(.*?)</h1>', body, flags=re.S)
return clean(m.group(1)) if m else None
def split_top_level(text, seps=','):
"""Split at separators that are not nested in <>, () or []."""
parts, depth, current = [], 0, ''
for c in text:
if c in '<([':
depth += 1
elif c in '>)]':
depth -= 1
if c in seps and depth <= 0:
parts.append(current)
current = ''
else:
current += c
parts.append(current)
return [p.strip() for p in parts if p.strip()]
OPERATOR_SYMBOLS = ('<=>', '<<', '>>', '<=', '>=', '<', '>')
def api_names(h1) -> list:
"""Derive the entry names from the H1 of an api page."""
# hide the angle brackets of operators from the nesting detection
for i, sym in enumerate(OPERATOR_SYMBOLS):
h1 = h1.replace('operator' + sym, f'operator\x01{i}\x01')
names = []
for part in split_top_level(h1):
name = part.replace('\\', '').replace('nlohmann::', '')
name = re.sub(r'\x01(\d)\x01', lambda m: OPERATOR_SYMBOLS[int(m.group(1))], name)
# drop qualifiers like "operator<<(basic_json)", but keep "operator()"
if not name.endswith('operator()'):
name = re.sub(r'(?<=\w|[<>=!+\-*/\[\]])\([^()]*\)$', '', name)
if name not in names:
names.append(name)
return names
def first_cpp_block(text):
"""Return the first ```cpp block following the H1."""
m = re.search(r'^# .*?^```cpp\n(.*?)^```', text, flags=re.M | re.S)
return m.group(1) if m else None
def api_type(name, decl):
"""Determine the Dash entry type from name and declaration."""
parts = name.split('::')
last = parts[-1]
if name.startswith('operator""'):
return 'Literal'
if last.startswith('operator'):
return 'Operator'
if decl is None:
return None
if re.search(r'\benum\b', decl):
return 'Enum'
if re.search(r'^\s*(template\s*<.*>\s*)?(class|struct)\s+\w+\s*(final\b|[:{;<]|$)', decl, flags=re.M):
return 'Class'
if re.search(r'\busing\s+\w+\s*=', decl) or 'typedef' in decl:
return 'Type'
if len(parts) > 1 and last == parts[-2]:
return 'Constructor'
if last.startswith('~'):
return 'Method'
if re.search(r'\bstatic\b', decl) or len(parts) == 1 or parts[0] == 'std':
return 'Function'
return 'Method'
def macro_names(h1) -> list:
"""Split the H1 of a macro page into macro names."""
return [n.strip() for n in re.split(r'[,/]', h1) if n.strip()]
def api_entries(md_path):
"""Return the (name, type) pairs of an api page."""
if md_path in OVERRIDES:
return OVERRIDES[md_path]
if md_path == 'api/macros/index.md':
return [('Macros', 'Macro')]
text = read_page(md_path)
h1 = get_h1(text)
if not h1:
problem(md_path, 'no H1 found')
return []
if md_path.startswith('api/macros/'):
return [(n, 'Macro') for n in macro_names(h1)]
names = api_names(h1)
if not names:
problem(md_path, 'no names found')
return []
decl = first_cpp_block(text)
result = []
for name in names:
kind = api_type(name, decl)
if kind is None:
problem(md_path, f'no type determinable for {name}')
else:
result.append((name, kind))
return result
def guide_entries(nav):
"""Yield (name, type, md path) for all non-api nav pages."""
for groups, title, md_path in walk_nav(nav):
if md_path.startswith('api/') or md_path == 'index.md':
continue
if not md_path.endswith('.md'):
continue
groups = groups[1:] # drop the top-level tab
if title is None:
title = get_h1(read_page(md_path))
if not title:
problem(md_path, 'no title found')
continue
# "Parsing: Parsing Untrusted Input" -> "Parsing: Untrusted Input"
if groups and title.startswith(groups[-1] + ' ') and title[len(groups[-1]) + 1:][:1].isupper():
title = title[len(groups[-1]) + 1:]
if md_path.endswith('/index.md') and groups and title == groups[-1]:
name = ': '.join(groups)
else:
name = ': '.join(groups + [title])
yield name, 'Guide', md_path
def build_entries() -> list:
"""Return the sorted list of (name, type, path) index entries."""
nav = load_mkdocs_yml()['nav']
entries = set()
for name, kind, md_path in guide_entries(nav):
entries.add((name, kind, page_path(md_path)))
api_root = os.path.join(PAGES, 'api')
on_disk = set()
for root, _, files in os.walk(api_root):
for file in files:
if file.endswith('.md'):
rel = os.path.relpath(os.path.join(root, file), PAGES)
on_disk.add(rel.replace(os.sep, '/'))
for _, _, md_path in walk_nav(nav):
if md_path.startswith('api/') and md_path not in on_disk:
problem(md_path, 'listed in nav but missing on disk')
for md_path in sorted(on_disk):
for name, kind in api_entries(md_path):
entries.add((name, kind, page_path(md_path)))
return sorted(entries)
def write_index(entries, out) -> None:
"""Write the entries into a SQLite search index."""
if os.path.exists(out):
os.remove(out)
con = sqlite3.connect(out)
con.execute('CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT)')
con.execute('CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path)')
con.executemany('INSERT INTO searchIndex(name, type, path) VALUES (?, ?, ?)', entries)
con.commit()
con.close()
def html_files(root):
"""Yield all HTML files below root."""
for base, _, files in os.walk(root):
for file in files:
if file.endswith('.html'):
yield os.path.join(base, file)
def read(path) -> str:
with open(path, encoding='utf-8') as f:
return f.read()
def write(path, text) -> None:
with open(path, 'w', encoding='utf-8') as f:
f.write(text)
def remove_source_widget(docs) -> None:
"""Drop data-md-component=source so Material does not query api.github.com for the stars and version."""
pattern = re.compile(r'\sdata-md-component=(?:"source"|source\b)')
for path in html_files(docs):
text = read(path)
new = pattern.sub('', text)
if new != text:
write(path, new)
def patch_titles(docs, entries) -> None:
"""Strip the site name from all titles; use the index names where available."""
names = {}
for name, _, path in entries:
names.setdefault(path, []).append(name)
for file in html_files(docs):
rel = os.path.relpath(file, docs).replace(os.sep, '/')
text = read(file).replace(TITLE_SUFFIX, '</title>')
if rel in names:
title = html.escape(', '.join(names[rel]), quote=False)
text = re.sub(r'<title>.*?</title>', lambda _: f'<title>{title}</title>', text, count=1, flags=re.S)
write(file, text)
IMG_RE = re.compile(r'<img\b[^>]*>', re.I)
ATTR_RE = r'''(?:{0})\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+))'''
def attr(tag, name):
"""Return the value of an attribute in a tag or None."""
m = re.search(r'(?<![\w-])' + ATTR_RE.format(name), tag, flags=re.I)
return next(g for g in m.groups() if g is not None) if m else None
def is_remote(url) -> bool:
return re.match(r'(https?:)?//', url.strip(), flags=re.I) is not None
def download(url, docs) -> str:
"""Download url into assets/external and return the path relative to docs."""
u = urllib.parse.urlparse(url if not url.startswith('//') else 'https:' + url)
req = urllib.request.Request(u.geturl(), headers={'User-Agent': USER_AGENT})
with urllib.request.urlopen(req, timeout=20) as r:
data = r.read()
ctype = r.headers.get_content_type()
path = urllib.parse.unquote(u.path).lstrip('/')
ext = os.path.splitext(path)[1]
if u.query or not ext or path.endswith('/'):
digest = hashlib.sha1(url.encode()).hexdigest()[:12]
path = os.path.join(os.path.dirname(path), digest + CONTENT_TYPE_EXT.get(ctype, ext or '.bin'))
rel = os.path.normpath(os.path.join('assets', 'external', u.hostname, path))
out = os.path.join(docs, rel)
os.makedirs(os.path.dirname(out), exist_ok=True)
with open(out, 'wb') as f:
f.write(data)
return rel.replace(os.sep, '/')
def localize_images(docs) -> None:
"""Download remote images and rewrite their src; drop them on failure."""
cache = {}
for file in html_files(docs):
text = read(file)
def repl(m):
tag = m.group(0)
src = attr(tag, 'src')
if src is None or not is_remote(src):
return tag
if src not in cache:
try:
cache[src] = download(src, docs)
except Exception as e: # noqa: BLE001
print(f'generate_docset.py: warning: cannot download {src}: {e}', file=sys.stderr)
cache[src] = None
if cache[src] is None:
return attr(tag, 'alt') or ''
local = os.path.relpath(os.path.join(docs, cache[src]), os.path.dirname(file))
local = local.replace(os.sep, '/')
return re.sub(ATTR_RE.format('src'), lambda _: f'src="{local}"', tag, count=1, flags=re.I)
new = IMG_RE.sub(repl, text)
if new != text:
write(file, new)
def load_mkdocs_yml() -> dict:
"""Load mkdocs.yml, ignoring tags like !ENV and !!python/name."""
with open(MKDOCS_YML, encoding='utf-8') as f:
return yaml.load(f, Loader=Loader)
def localize_site_urls(docs, site_url) -> None:
"""Load assets that the theme's JavaScript references by absolute site URL from the docset.
The privacy plugin rewrites the mermaid loader to "<site_url>assets/external/unpkg.com/mermaid@11/...", so the
docset would fetch mermaid from the live site. __md_scope is the site root that Material defines in every page.
"""
pattern = re.compile(r'"' + re.escape(site_url) + r'(assets/[^"]*)"')
for base, _, files in os.walk(docs):
for file in (f for f in files if f.endswith('.js')):
path = os.path.join(base, file)
text = read(path)
new = pattern.sub(r'new URL("\1",__md_scope).href', text)
if new != text:
write(path, new)
def remote_loads(docs, site_url) -> list:
"""Return 'file: url' strings for resources that would be loaded remotely."""
found = []
cdn = re.compile(r'https://(?:unpkg\.com|cdn\.jsdelivr\.net|cdnjs\.cloudflare\.com|'
r'fonts\.googleapis\.com|fonts\.gstatic\.com)/[^\s"\'`)\\]*')
css_url = re.compile(r'url\(\s*["\']?((?:https?:)?//[^)"\']+)', re.I)
css_import = re.compile(r'@import\s+(?:url\(\s*)?["\']?((?:https?:)?//[^)"\'; ]+)', re.I)
for base, _, files in os.walk(docs):
for file in files:
path = os.path.join(base, file)
rel = os.path.relpath(path, docs)
urls = []
if file.endswith('.html'):
text = read(path)
for m in re.finditer(r'<[a-zA-Z][^>]*>', text):
tag = m.group(0)
for name in ('src', 'poster'):
v = attr(tag, name)
if v and is_remote(v):
urls.append(v)
v = attr(tag, 'srcset')
if v:
urls += [c.split()[0] for c in v.split(',') if c.strip() and is_remote(c.strip())]
if re.match(r'<link\b', tag, flags=re.I):
rel_attr = (attr(tag, 'rel') or '').lower()
v = attr(tag, 'href')
if v and is_remote(v) and re.search(r'stylesheet|icon|preload|modulepreload|manifest', rel_attr):
urls.append(v)
urls += css_url.findall(text) + css_import.findall(text)
elif file.endswith('.css'):
text = read(path)
urls += css_url.findall(text) + css_import.findall(text)
elif file.endswith('.js'):
text = read(path)
urls += cdn.findall(text)
urls += re.findall(re.escape(site_url) + r'assets/[^\s"\'`)\\]*', text)
found += [f'{rel}: {u}' for u in urls if u not in ALLOWED_REMOTE]
return found
def make_docset(site, out_dir) -> int:
entries = build_entries()
if problems:
print('\n'.join(problems), file=sys.stderr)
return 1
docset = os.path.join(out_dir, DOCSET)
docs = os.path.join(docset, 'Contents', 'Resources', 'Documents')
if os.path.exists(docset):
shutil.rmtree(docset)
shutil.copytree(site, docs)
for icon in ('icon.png', 'icon@2x.png'):
shutil.copy(os.path.join(HERE, icon), docset)
shutil.copy(os.path.join(HERE, 'Info.plist'), os.path.join(docset, 'Contents'))
write_index(entries, os.path.join(docset, 'Contents', 'Resources', 'docSet.dsidx'))
# patch CSS to hide navigation items and fix spacing
css = glob.glob(os.path.join(docs, 'assets', 'stylesheets', 'main.*.min.css'))
if len(css) != 1:
print(f'generate_docset.py: expected exactly one main.*.min.css, found {len(css)}', file=sys.stderr)
return 1
with open(css[0], 'a', encoding='utf-8') as f:
f.write(CSS_PATCH)
patch_titles(docs, entries)
remove_source_widget(docs)
for sitemap in glob.glob(os.path.join(docs, 'sitemap.*')):
os.remove(sitemap)
# make the docset self-contained
site_url = load_mkdocs_yml()['site_url']
localize_images(docs)
localize_site_urls(docs, site_url)
remote = remote_loads(docs, site_url)
if remote:
print('generate_docset.py: remote resources remain in the docset:', file=sys.stderr)
print('\n'.join(' ' + r for r in remote), file=sys.stderr)
return 1
return 0
def make_tgz(out_dir) -> int:
docset = os.path.join(out_dir, DOCSET)
if not os.path.isdir(docset):
print(f'generate_docset.py: {docset} does not exist', file=sys.stderr)
return 1
with tarfile.open(os.path.join(out_dir, 'JSON_for_Modern_C++.tgz'), 'w:gz') as tar:
tar.add(docset, arcname=DOCSET, filter=lambda i: None if os.path.basename(i.name) == '.DS_Store' else i)
return 0
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
sub = parser.add_subparsers(dest='command', required=True)
sub.add_parser('list', help='print the index entries as TSV')
p = sub.add_parser('index', help='write the SQLite search index')
p.add_argument('out')
p = sub.add_parser('docset', help='build the docset from a built mkdocs site')
p.add_argument('site_dir')
p.add_argument('out_dir')
p = sub.add_parser('tgz', help='pack the docset into a tarball')
p.add_argument('out_dir')
args = parser.parse_args()
if args.command == 'docset':
return make_docset(args.site_dir, args.out_dir)
if args.command == 'tgz':
return make_tgz(args.out_dir)
entries = build_entries()
if problems:
print('\n'.join(problems), file=sys.stderr)
return 1
if args.command == 'list':
for entry in entries:
print('\t'.join(entry))
elif args.command == 'index':
write_index(entries, args.out)
return 0
if __name__ == '__main__':
sys.exit(main())
+1
View File
@@ -17,6 +17,7 @@ build: style_check
style_check: style_check:
@cd docs ; ../venv/bin/python3 ../scripts/check_structure.py @cd docs ; ../venv/bin/python3 ../scripts/check_structure.py
@venv/bin/python3 ../docset/generate_docset.py list > /dev/null
# check that all Mermaid diagrams parse (needs Node.js) # check that all Mermaid diagrams parse (needs Node.js)
# This target is used in the CI (ci_test_documentation_mermaid). # This target is used in the CI (ci_test_documentation_mermaid).
+1 -12
View File
@@ -64,18 +64,7 @@ values of that type directly to a `basic_json` instance, and they will automatic
rather than arrays: rather than arrays:
```cpp ```cpp
using custom_json = nlohmann::basic_json< using custom_json = nlohmann::ordered_json::with_binary_t<std::vector<std::byte>>;
nlohmann::ordered_map, // ObjectType
std::vector, // ArrayType
std::string, // StringType
bool, // BooleanType
std::int64_t, // NumberIntegerType
std::uint64_t, // NumberUnsignedType
double, // NumberFloatType
std::allocator, // AllocatorType
nlohmann::adl_serializer,
std::vector<std::byte> // Custom BinaryType
>;
std::vector<std::byte> data{std::byte{1}, std::byte{2}, std::byte{3}}; std::vector<std::byte> data{std::byte{1}, std::byte{2}, std::byte{3}};
custom_json j = data; // Creates a binary value, not an array custom_json j = data; // Creates a binary value, not an array
@@ -10,6 +10,10 @@ bool contains(KeyType&& key) const;
// (3) // (3)
bool contains(const json_pointer& ptr) const; bool contains(const json_pointer& ptr) const;
// (4)
template<typename T>
bool contains(T) const = delete;
``` ```
1. Check whether an element exists in a JSON object with a key equivalent to `key`. If the element is not found or the 1. Check whether an element exists in a JSON object with a key equivalent to `key`. If the element is not found or the
@@ -17,6 +21,9 @@ bool contains(const json_pointer& ptr) const;
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and 2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type. `#!cpp typename object_comparator_t::is_transparent` denotes a type.
3. Check whether the given JSON pointer `ptr` can be resolved in the current JSON value. 3. Check whether the given JSON pointer `ptr` can be resolved in the current JSON value.
4. Deleted: this overload is only available if `T` is an integral type and is declared as deleted, so that a call with
an integer `key` (for example, `#!cpp j.contains(0)`) fails to compile. Otherwise, the integer literal `0` would convert to
a null `#!cpp const char*` and, from there, to the key type, causing undefined behavior at runtime.
## Template parameters ## Template parameters
@@ -39,6 +46,7 @@ bool contains(const json_pointer& ptr) const;
is not an object, `#!cpp false` is returned. is not an object, `#!cpp false` is returned.
2. See 1. 2. See 1.
3. `#!cpp true` if the JSON pointer can be resolved to a stored value, `#!cpp false` otherwise. 3. `#!cpp true` if the JSON pointer can be resolved to a stored value, `#!cpp false` otherwise.
4. Deleted; a call with an integral argument does not compile.
## Exception safety ## Exception safety
@@ -49,6 +57,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. The function does not throw exceptions. 1. The function does not throw exceptions.
2. The function does not throw exceptions. 2. The function does not throw exceptions.
3. The function does not throw exceptions. 3. The function does not throw exceptions.
4. Deleted; a call with an integral argument does not compile.
## Complexity ## Complexity
+7
View File
@@ -7,12 +7,19 @@ size_type count(const typename object_t::key_type& key) const;
// (2) // (2)
template<typename KeyType> template<typename KeyType>
size_type count(KeyType&& key) const; size_type count(KeyType&& key) const;
// (3)
template<typename T>
size_type count(T) const = delete;
``` ```
1. Returns the number of elements with key `key`. If `ObjectType` is the default `std::map` type, the return value will 1. Returns the number of elements with key `key`. If `ObjectType` is the default `std::map` type, the return value will
always be `0` (`key` was not found) or `1` (`key` was found). always be `0` (`key` was not found) or `1` (`key` was found).
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and 2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type. `#!cpp typename object_comparator_t::is_transparent` denotes a type.
3. Deleted: this overload is only available if `T` is an integral type and is declared as deleted, so that a call with
an integer `key` (for example, `#!cpp j.count(0)`) fails to compile. Otherwise, the integer literal `0` would convert to
a null `#!cpp const char*` and, from there, to the key type, causing undefined behavior at runtime.
## Template parameters ## Template parameters
@@ -37,8 +37,8 @@ ignore
: ignore invalid UTF-8 sequences; all valid bytes are copied to the output unchanged, and invalid bytes are dropped : ignore invalid UTF-8 sequences; all valid bytes are copied to the output unchanged, and invalid bytes are dropped
keep keep
: keep invalid UTF-8 sequences unchanged; only meaningful for the binary formats mentioned above, since [`dump`] : keep invalid UTF-8 sequences unchanged; only meaningful for the binary formats mentioned above, since
(dump.md) itself must produce text, and `keep` there writes the ill-formed bytes to the output as is, so the [`dump`](dump.md) itself must produce text, and `keep` there writes the ill-formed bytes to the output as is, so the
result is then not valid UTF-8 (but still equals the input bytes exactly, including around any well-formed result is then not valid UTF-8 (but still equals the input bytes exactly, including around any well-formed
characters, which are still escaped as usual) characters, which are still escaped as usual)
+9
View File
@@ -10,12 +10,21 @@ template<typename KeyType>
iterator find(KeyType&& key); iterator find(KeyType&& key);
template<typename KeyType> template<typename KeyType>
const_iterator find(KeyType&& key) const; const_iterator find(KeyType&& key) const;
// (3)
template<typename T>
iterator find(T) = delete;
template<typename T>
const_iterator find(T) const = delete;
``` ```
1. Finds an element in a JSON object with a key equivalent to `key`. If the element is not found or the 1. Finds an element in a JSON object with a key equivalent to `key`. If the element is not found or the
JSON value is not an object, `end()` is returned. JSON value is not an object, `end()` is returned.
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and 2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type. `#!cpp typename object_comparator_t::is_transparent` denotes a type.
3. Deleted: this overload is only available if `T` is an integral type and is declared as deleted, so that a call with
an integer `key` (for example, `#!cpp j.find(0)`) fails to compile. Otherwise, the integer literal `0` would convert to
a null `#!cpp const char*` and, from there, to the key type, causing undefined behavior at runtime.
## Template parameters ## Template parameters
@@ -124,7 +124,8 @@ Linear in the size of the input.
!!! warning "Deprecation" !!! warning "Deprecation"
- Overload (2) replaces calls to `from_bjdata` with a pointer and a length as first two parameters, which has been - Overload (2) replaces calls to `from_bjdata` with a pointer and a length as first two parameters, which has been
deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.13.0. In version 4.0.0, this overload
will be deleted (`= delete`) rather than removed. Please replace all calls like
`#!cpp from_bjdata(ptr, len, ...);` with `#!cpp from_bjdata(ptr, ptr+len, ...);`. `#!cpp from_bjdata(ptr, len, ...);` with `#!cpp from_bjdata(ptr, ptr+len, ...);`.
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
+2 -1
View File
@@ -110,7 +110,8 @@ Linear in the size of the input.
!!! warning "Deprecation" !!! warning "Deprecation"
- Overload (2) replaces calls to `from_bon8` with a pointer and a length as first two parameters, which has been - Overload (2) replaces calls to `from_bon8` with a pointer and a length as first two parameters, which has been
deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.13.0. In version 4.0.0, this overload
will be deleted (`= delete`) rather than removed. Please replace all calls like
`#!cpp from_bon8(ptr, len, ...);` with `#!cpp from_bon8(ptr, ptr+len, ...);`. `#!cpp from_bon8(ptr, len, ...);` with `#!cpp from_bon8(ptr, ptr+len, ...);`.
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
+2 -1
View File
@@ -126,7 +126,8 @@ Linear in the size of the input.
!!! warning "Deprecation" !!! warning "Deprecation"
- Overload (2) replaces calls to `from_bson` with a pointer and a length as first two parameters, which has been - Overload (2) replaces calls to `from_bson` with a pointer and a length as first two parameters, which has been
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.8.0. In version 4.0.0, this overload
will be deleted (`= delete`) rather than removed. Please replace all calls like
`#!cpp from_bson(ptr, len, ...);` with `#!cpp from_bson(ptr, ptr+len, ...);`. `#!cpp from_bson(ptr, len, ...);` with `#!cpp from_bson(ptr, ptr+len, ...);`.
- Overload (2) replaces calls to `from_bson` with a pair of iterators as their first parameter, which has been - Overload (2) replaces calls to `from_bson` with a pair of iterators as their first parameter, which has been
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
+2 -1
View File
@@ -135,7 +135,8 @@ Linear in the size of the input.
!!! warning "Deprecation" !!! warning "Deprecation"
- Overload (2) replaces calls to `from_cbor` with a pointer and a length as first two parameters, which has been - Overload (2) replaces calls to `from_cbor` with a pointer and a length as first two parameters, which has been
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.8.0. In version 4.0.0, this overload
will be deleted (`= delete`) rather than removed. Please replace all calls like
`#!cpp from_cbor(ptr, len, ...);` with `#!cpp from_cbor(ptr, ptr+len, ...);`. `#!cpp from_cbor(ptr, len, ...);` with `#!cpp from_cbor(ptr, ptr+len, ...);`.
- Overload (2) replaces calls to `from_cbor` with a pair of iterators as their first parameter, which has been - Overload (2) replaces calls to `from_cbor` with a pair of iterators as their first parameter, which has been
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
@@ -127,7 +127,8 @@ Linear in the size of the input.
!!! warning "Deprecation" !!! warning "Deprecation"
- Overload (2) replaces calls to `from_msgpack` with a pointer and a length as first two parameters, which has been - Overload (2) replaces calls to `from_msgpack` with a pointer and a length as first two parameters, which has been
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.8.0. In version 4.0.0, this overload
will be deleted (`= delete`) rather than removed. Please replace all calls like
`#!cpp from_msgpack(ptr, len, ...);` with `#!cpp from_msgpack(ptr, ptr+len, ...);`. `#!cpp from_msgpack(ptr, len, ...);` with `#!cpp from_msgpack(ptr, ptr+len, ...);`.
- Overload (2) replaces calls to `from_msgpack` with a pair of iterators as their first parameter, which has been - Overload (2) replaces calls to `from_msgpack` with a pair of iterators as their first parameter, which has been
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
@@ -125,7 +125,8 @@ Linear in the size of the input.
!!! warning "Deprecation" !!! warning "Deprecation"
- Overload (2) replaces calls to `from_ubjson` with a pointer and a length as first two parameters, which has been - Overload (2) replaces calls to `from_ubjson` with a pointer and a length as first two parameters, which has been
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.8.0. In version 4.0.0, this overload
will be deleted (`= delete`) rather than removed. Please replace all calls like
`#!cpp from_ubjson(ptr, len, ...);` with `#!cpp from_ubjson(ptr, ptr+len, ...);`. `#!cpp from_ubjson(ptr, len, ...);` with `#!cpp from_ubjson(ptr, ptr+len, ...);`.
- Overload (2) replaces calls to `from_ubjson` with a pair of iterators as their first parameter, which has been - Overload (2) replaces calls to `from_ubjson` with a pair of iterators as their first parameter, which has been
deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
@@ -62,5 +62,5 @@ same name. Hidden members remain accessible via [`as_base_class`](as_base_class.
## Version history ## Version history
- Added in version 3.12.0. - Added in version 3.11.3.
- Made a public member type in version 3.13.0; it was private before, so it could not be named outside the class. - Made a public member type in version 3.13.0; it was private before, so it could not be named outside the class.
+2 -1
View File
@@ -26,7 +26,8 @@ To store objects in C++, a type is defined by the template parameters described
`StringType` `StringType`
: the type of the keys or names (e.g., `std::string`). The comparison function `std::less<StringType>` is used to : the type of the keys or names (e.g., `std::string`). The comparison function `std::less<StringType>` is used to
order elements inside the container. order elements inside the container. `object_t::key_type` must be implicitly convertible to `string_t` (required by the
binary formats).
`AllocatorType` `AllocatorType`
: the allocator to use for objects (e.g., `std::allocator`) : the allocator to use for objects (e.g., `std::allocator`)
+1
View File
@@ -27,6 +27,7 @@ header. See also the [macro overview page](../../features/macros.md).
- [**JSON_HAS_CPP_11**<br>**JSON_HAS_CPP_14**<br>**JSON_HAS_CPP_17**<br>**JSON_HAS_CPP_20**](json_has_cpp_11.md) - set supported C++ standard - [**JSON_HAS_CPP_11**<br>**JSON_HAS_CPP_14**<br>**JSON_HAS_CPP_17**<br>**JSON_HAS_CPP_20**](json_has_cpp_11.md) - set supported C++ standard
- [**JSON_HAS_FILESYSTEM**<br>**JSON_HAS_EXPERIMENTAL_FILESYSTEM**](json_has_filesystem.md) - control `std::filesystem` support - [**JSON_HAS_FILESYSTEM**<br>**JSON_HAS_EXPERIMENTAL_FILESYSTEM**](json_has_filesystem.md) - control `std::filesystem` support
- [**JSON_HAS_RANGE_VIEW_CONVERSION**](json_has_range_view_conversion.md) - control construction from `std::ranges` views
- [**JSON_HAS_RANGES**](json_has_ranges.md) - control `std::ranges` support - [**JSON_HAS_RANGES**](json_has_ranges.md) - control `std::ranges` support
- [**JSON_HAS_STATIC_RTTI**](json_has_static_rtti.md) - control RTTI (run time type information) support - [**JSON_HAS_STATIC_RTTI**](json_has_static_rtti.md) - control RTTI (run time type information) support
- [**JSON_HAS_STD_FORMAT**](json_has_std_format.md) - control `std::format`/`std::formatter` support - [**JSON_HAS_STD_FORMAT**](json_has_std_format.md) - control `std::format`/`std::formatter` support
@@ -49,6 +49,6 @@ The default value is detected based on preprocessor macros such as `#!cpp __cplu
## Version history ## Version history
- Added in version 3.10.5. - Added in version 3.10.0.
- Added `JSON_HAS_CPP_23` in version 3.12.0. - Added `JSON_HAS_CPP_23` in version 3.12.0.
- Added `JSON_HAS_CPP_26` in version 3.13.0. - Added `JSON_HAS_CPP_26` in version 3.13.0.
@@ -0,0 +1,43 @@
# JSON_HAS_RANGE_VIEW_CONVERSION
```cpp
#define JSON_HAS_RANGE_VIEW_CONVERSION /* value */
```
This macro indicates whether a JSON array can be constructed directly from a C++20 range view (`std::ranges::view`),
such as the result of `std::views::filter` or `std::views::transform`. Possible values are `1` when supported or `0`
when unsupported.
## Default definition
The default value is `1` if [`JSON_HAS_RANGES`](json_has_ranges.md) is `1` and the compiler is not MinGW (that is,
`#!cpp __MINGW32__` is not defined), and `0` otherwise.
When the macro is not defined, the library will define it to its default value.
!!! info "Known compiler/stdlib exclusions"
- **MinGW** -- disabled, because its `std::ranges` support is incomplete ([issue #4916](https://github.com/nlohmann/json/issues/4916)).
- All toolchains for which [`JSON_HAS_RANGES`](json_has_ranges.md#default-definition) is disabled.
## Examples
??? example
The code below forces the library to disable the conversion from range views:
```cpp
#define JSON_HAS_RANGE_VIEW_CONVERSION 0
#include <nlohmann/json.hpp>
...
```
## See also
- [JSON_HAS_RANGES](json_has_ranges.md) - control `std::ranges` support
- [Constructing from a C++20 range view](../../features/conversions.md#putting-values-in) - usage of the feature
## Version history
- Added in version 3.13.0.
@@ -20,7 +20,7 @@ When the macro is not defined, the library will define it to its default value.
- **GCC 11.1.0** — disabled (the shipped `<ranges>` header has a syntax error; [issue #4440](https://github.com/nlohmann/json/issues/4440)) - **GCC 11.1.0** — disabled (the shipped `<ranges>` header has a syntax error; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **libstdc++ < 11** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440)) - **libstdc++ < 11** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **Clang < 16 with libstdc++** — disabled (incomplete ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440)) - **Clang < 16 with libstdc++** — disabled (incomplete ranges support; [issue #5161](https://github.com/nlohmann/json/issues/5161))
- **libc++ < 160000** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440)) - **libc++ < 160000** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **nvcc (CUDA) 12.0.x and 12.1.x** — disabled (the `enable_borrowed_range` variable-template syntax triggers a parse error - **nvcc (CUDA) 12.0.x and 12.1.x** — disabled (the `enable_borrowed_range` variable-template syntax triggers a parse error
under these two toolkit versions; fixed in CUDA 12.2; [issue #3907](https://github.com/nlohmann/json/issues/3907)) under these two toolkit versions; fixed in CUDA 12.2; [issue #3907](https://github.com/nlohmann/json/issues/3907))
@@ -44,9 +44,12 @@ When the macro is not defined, the library will define it to its default value.
- [JSON_HAS_CPP_11 / JSON_HAS_CPP_14 / JSON_HAS_CPP_17 / JSON_HAS_CPP_20 / JSON_HAS_CPP_23 / - [JSON_HAS_CPP_11 / JSON_HAS_CPP_14 / JSON_HAS_CPP_17 / JSON_HAS_CPP_20 / JSON_HAS_CPP_23 /
JSON_HAS_CPP_26](json_has_cpp_11.md) - set supported C++ standard JSON_HAS_CPP_26](json_has_cpp_11.md) - set supported C++ standard
- [JSON_HAS_RANGE_VIEW_CONVERSION](json_has_range_view_conversion.md) - control construction from `std::ranges` views
- [JSON_HAS_STD_FORMAT](json_has_std_format.md) - a similar feature-detection macro, for `std::format`/`std::formatter` - [JSON_HAS_STD_FORMAT](json_has_std_format.md) - a similar feature-detection macro, for `std::format`/`std::formatter`
support support
## Version history ## Version history
- Added in version 3.11.0. - Added in version 3.11.0.
- Added the exclusions for libstdc++ < 11, Clang < 16 with libstdc++, libc++ < 16, and nvcc (CUDA) 12.0.x and 12.1.x in
version 3.13.0. Before, only GCC 11.1.0 was excluded.
@@ -20,7 +20,10 @@ The macro does not affect:
- The binary readers ([`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md), - The binary readers ([`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md),
[`from_ubjson`](../basic_json/from_ubjson.md), [`from_bjdata`](../basic_json/from_bjdata.md), [`from_ubjson`](../basic_json/from_ubjson.md), [`from_bjdata`](../basic_json/from_bjdata.md),
[`from_bson`](../basic_json/from_bson.md)): none of these formats requires a decoder to reject ill-formed UTF-8, so [`from_bson`](../basic_json/from_bson.md)): none of these formats requires a decoder to reject ill-formed UTF-8, so
they always return the bytes unchanged. by default they return the bytes unchanged (`error_handler_t::keep`), independent of this macro. Pass an
`error_handler` argument explicitly to validate or sanitize the strings they read.
- [`from_bon8`](../basic_json/from_bon8.md): BON8 always validates, because the UTF-8 lead bytes mark where a string
ends.
## Default definition ## Default definition
@@ -67,7 +67,7 @@ By default, implicit conversions are enabled.
`JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`: `JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`:
```cpp ```cpp
using wjson = nlohmann::basic_json<std::map, std::vector, std::wstring>; using wjson = nlohmann::json::with_string_t<std::wstring>;
void load(const nlohmann::json& j); void load(const nlohmann::json& j);
@@ -190,3 +190,5 @@ void to_json(BasicJsonType& j, const B& b) {
4. Added in version 3.12.0. 4. Added in version 3.12.0.
5. Added in version 3.12.0. 5. Added in version 3.12.0.
6. Added in version 3.12.0. 6. Added in version 3.12.0.
All six macros were changed to allow an empty member list in version 3.13.0.
@@ -186,3 +186,6 @@ See the examples below for the concrete generated code.
1. Added in version 3.9.0. 1. Added in version 3.9.0.
2. Added in version 3.11.0. 2. Added in version 3.11.0.
3. Added in version 3.11.3. 3. Added in version 3.11.3.
All three macros were changed to work with any `basic_json` specialization (not only `nlohmann::json`) in version 3.12.0,
and to allow an empty member list in version 3.13.0.
@@ -185,3 +185,6 @@ See the examples below for the concrete generated code.
1. Added in version 3.9.0. 1. Added in version 3.9.0.
2. Added in version 3.11.0. 2. Added in version 3.11.0.
3. Added in version 3.11.3. 3. Added in version 3.11.3.
All three macros were changed to work with any `basic_json` specialization (not only `nlohmann::json`) in version 3.12.0,
and to allow an empty member list in version 3.13.0.
@@ -38,4 +38,6 @@ the library.
## Version history ## Version history
- Added in version 3.11.0. Changed inline namespace name in version 3.11.2. - Added in version 3.11.0. Changed inline namespace name in version 3.11.2. Added the ABI tag `_dp` in
version 3.12.0, and the ABI tags `_bics`, `_psp`, `_snul`, `_sbu8`, and `_ekmo` in version 3.13.0; see
[`nlohmann` Namespace](../../features/namespace.md#structure).
@@ -14,7 +14,7 @@ These macros can be used to open and close the `nlohmann` namespace. See
## Default definition ## Default definition
The default definitions open and close the `nlohmann` namespace. The precise definition of The default definitions open and close the `nlohmann` namespace. The precise definition of
[`NLOHMANN_JSON_NAMESPACE_BEGIN`] varies as described [here](../../features/namespace.md#structure). `NLOHMANN_JSON_NAMESPACE_BEGIN` varies as described [here](../../features/namespace.md#structure).
1. Default definition of `NLOHMANN_JSON_NAMESPACE_BEGIN`: 1. Default definition of `NLOHMANN_JSON_NAMESPACE_BEGIN`:
+1 -1
View File
@@ -10,7 +10,7 @@ The library parses, stores, and serializes JSON values in memory. It does not op
files (it only reads from streams or `std::FILE*` handles that the caller has already opened), does not read environment files (it only reads from streams or `std::FILE*` handles that the caller has already opened), does not read environment
variables, and does not implement cryptography or handle credentials. variables, and does not implement cryptography or handle credentials.
The primary threat is therefore **untrusted input**: JSON text or binary data (BJData, BSON, CBOR, MessagePack, UBJSON) The primary threat is therefore **untrusted input**: JSON text or binary data (BJData, BON8, BSON, CBOR, MessagePack, UBJSON)
that an attacker controls, passed to [`parse`](../api/basic_json/parse.md), [`accept`](../api/basic_json/accept.md), that an attacker controls, passed to [`parse`](../api/basic_json/parse.md), [`accept`](../api/basic_json/accept.md),
[`sax_parse`](../api/basic_json/sax_parse.md), or one of the `from_*` functions such as [`sax_parse`](../api/basic_json/sax_parse.md), or one of the `from_*` functions such as
[`from_cbor`](../api/basic_json/from_cbor.md). Such input may try to [`from_cbor`](../api/basic_json/from_cbor.md). Such input may try to
@@ -12,7 +12,7 @@ violations will result in a failed build.
Note: C++20 modules support may hit compiler-specific issues not covered by the general compiler matrix below. See [Modules](../features/modules.md#known-issues) for known issues and workarounds. Note: C++20 modules support may hit compiler-specific issues not covered by the general compiler matrix below. See [Modules](../features/modules.md#known-issues) for known issues and workarounds.
Note: Some modern features (like C++20 ranges or filesystem support) may be disabled on specific broken or incomplete toolchains even when standard feature-test macros indicate support. See [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) and [`JSON_HAS_FILESYSTEM`](../api/macros/json_has_filesystem.md) for details on known exclusions. Note: Some modern features (like C++20 ranges or filesystem support) may be disabled on specific broken or incomplete toolchains even when standard feature-test macros indicate support. See [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md), [`JSON_HAS_RANGE_VIEW_CONVERSION`](../api/macros/json_has_range_view_conversion.md), and [`JSON_HAS_FILESYSTEM`](../api/macros/json_has_filesystem.md) for details on known exclusions.
- [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms, - [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms,
including the oldest versions known to compile the library. including the oldest versions known to compile the library.
@@ -107,7 +107,7 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa
- [x] The library is compiled with all C++ language revisions (C++11, C++14, C++17, C++20, C++23, and C++26) to detect - [x] The library is compiled with all C++ language revisions (C++11, C++14, C++17, C++20, C++23, and C++26) to detect
and fix language deprecations early. and fix language deprecations early.
- [x] The library is checked for compiler warnings: - [x] The library is checked for compiler warnings:
- On Clang, `-Weverything` is used with 8 exceptions. - On Clang, `-Weverything` is used with 7 exceptions.
??? abstract "Clang warnings" ??? abstract "Clang warnings"
+23 -9
View File
@@ -36,13 +36,26 @@ work items are tracked in the [GitHub milestones](https://github.com/nlohmann/js
## API stability ## API stability
Releases follow [semantic versioning](https://semver.org): a minor or patch release of version 3.x does not break code Releases follow [semantic versioning](https://semver.org): a minor or patch release of version 3.x does not break code
that uses the public API. In particular, a 3.x release does not: that uses the public API, unless that code opts in to a change with a macro as described [below](#version-40). In
particular, a 3.x release does not:
- change the signature of a function (its parameter types, return type, number of parameters, or the const-ness of a - make breaking changes to the signature of a function: the types or order of its existing parameters, its return type,
member function); its `noexcept` or `constexpr` specifier, or the const-ness of a member function. New parameters may be added if they
- remove or rename a function or class; have a default value;
- remove or rename a function or class, or change the template parameters of a public class template;
- change which exceptions a function throws, or the [exception ids](../home/exceptions.md); - change which exceptions a function throws, or the [exception ids](../home/exceptions.md);
- change access specifiers or default arguments. - change access specifiers, or change or remove existing default arguments. New default arguments may be added;
- change the JSON type that a valid input parses to, or the text that `dump()` produces for a valid value;
- accept input that was rejected before, or reject input that was accepted before;
- change the order in which the keys of an object are iterated. The default type sorts keys, and
[`ordered_json`](../api/ordered_json.md) keeps insertion order;
- change when iterators, pointers, or references are invalidated, or the state of a moved-from `basic_json`;
- add or remove implicit conversions from `basic_json`;
- change how `to_json` and `from_json` functions are found, or the behavior of
[`adl_serializer`](../api/adl_serializer/index.md);
- add pure virtual functions to the [`json_sax`](../api/json_sax/index.md) interface;
- remove, rename, renumber, or add enumerators of `value_t`;
- remove or rename a documented macro, CMake option, CMake target, or header, or change what a documented macro does.
Exceptions to these rules, for instance when fixing a bug requires changing the exception a function throws, are Exceptions to these rules, for instance when fixing a bug requires changing the exception a function throws, are
documented in the [release notes](../home/releases.md). documented in the [release notes](../home/releases.md).
@@ -51,13 +64,14 @@ The following are **not** part of the public API and may change in any release,
- The text of exception messages returned by `what()`. Use the [exception id](../home/exceptions.md) to tell errors - The text of exception messages returned by `what()`. Use the [exception id](../home/exceptions.md) to tell errors
apart. apart.
- The ABI, including `sizeof(basic_json)` and the memory layout of its values. Recompile your code when you upgrade the - The ABI, including `sizeof(basic_json)` and the memory layout of its values. The
library. The [versioned inline namespace](../features/namespace.md) turns mixing versions into a link error. [versioned inline namespace](../features/namespace.md) turns mixing versions into a link error.
- The hash values returned by `std::hash` for `basic_json`. Numbers that compare equal still hash equally.
- Everything in namespace `nlohmann::detail`, and macros and type traits that are not documented in the - Everything in namespace `nlohmann::detail`, and macros and type traits that are not documented in the
[API reference](../api/basic_json/index.md). [API reference](../api/basic_json/index.md).
Changes that would break the public API are only added behind a macro whose default keeps the 3.x behavior, see Breaking changes are only added behind a macro whose default keeps the 3.x behavior. See [Version 4.0](#version-40) and
[Version 4.0](#version-40). the [macro overview](../features/macros.md).
## Version 4.0 ## Version 4.0
+1 -13
View File
@@ -15,19 +15,7 @@ class base_class_with_hidden_members
} }
}; };
using json = nlohmann::basic_json < using json = nlohmann::json::with_base_class_t<base_class_with_hidden_members>;
std::map,
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
std::allocator,
nlohmann::adl_serializer,
std::vector<std::uint8_t>,
base_class_with_hidden_members
>;
int main() int main()
{ {
@@ -19,25 +19,9 @@ int main()
<< j.contains("/array/1"_json_pointer) << '\n' << j.contains("/array/1"_json_pointer) << '\n'
<< j.contains("/array/-"_json_pointer) << '\n' << j.contains("/array/-"_json_pointer) << '\n'
<< j.contains("/array/4"_json_pointer) << '\n' << j.contains("/array/4"_json_pointer) << '\n'
<< j.contains("/baz"_json_pointer) << std::endl; << j.contains("/baz"_json_pointer) << '\n'
// an array index with a leading '0' is not found
try << j.contains("/array/01"_json_pointer) << '\n'
{ // an array index that is not a number is not found
// try to use an array index with leading '0' << j.contains("/array/one"_json_pointer) << std::endl;
j.contains("/array/01"_json_pointer);
}
catch (const json::parse_error& e)
{
std::cout << e.what() << '\n';
}
try
{
// try to use an array index that is not a number
j.contains("/array/one"_json_pointer);
}
catch (const json::parse_error& e)
{
std::cout << e.what() << '\n';
}
} }
@@ -5,3 +5,5 @@ true
false false
false false
false false
false
false
@@ -1,11 +1,10 @@
#include <iostream> #include <iostream>
#include <map>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "custom_array_type.hpp" #include "custom_array_type.hpp"
using custom_json = nlohmann::basic_json<std::map, custom_array_type>; using custom_json = nlohmann::json::with_array_t<custom_array_type>;
int main() int main()
{ {
@@ -1,16 +1,10 @@
#include <cstdint>
#include <iostream> #include <iostream>
#include <map>
#include <string>
#include <vector>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "custom_binary_type.hpp" #include "custom_binary_type.hpp"
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, using custom_json = nlohmann::json::with_binary_t<custom_binary_type>;
std::int64_t, std::uint64_t, double, std::allocator,
nlohmann::adl_serializer, custom_binary_type>;
int main() int main()
{ {
@@ -1,12 +1,11 @@
#include <iostream> #include <iostream>
#include <type_traits> #include <type_traits>
#include <vector>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "custom_object_type.hpp" #include "custom_object_type.hpp"
using custom_json = nlohmann::basic_json<custom_object_type, std::vector>; using custom_json = nlohmann::json::with_object_t<custom_object_type>;
int main() int main()
{ {
@@ -1,12 +1,10 @@
#include <iostream> #include <iostream>
#include <map>
#include <vector>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "custom_string_type.hpp" #include "custom_string_type.hpp"
using custom_json = nlohmann::basic_json<std::map, std::vector, custom_string_type>; using custom_json = nlohmann::json::with_string_t<custom_string_type>;
int main() int main()
{ {
+1 -1
View File
@@ -8,7 +8,7 @@ int main()
try try
{ {
// parsing input with a syntax error // parsing input with a syntax error
json::parse("[1,2,3,]"); json j = json::parse("[1,2,3,]");
} }
catch (const json::parse_error& e) catch (const json::parse_error& e)
{ {
+2 -1
View File
@@ -217,7 +217,8 @@ json j = numbers; // [1,2,3]
``` ```
This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due
to incomplete C++20 ranges support there. to incomplete C++20 ranges support there; see
[`JSON_HAS_RANGE_VIEW_CONVERSION`](../api/macros/json_has_range_view_conversion.md).
## Your own types ## Your own types
+39
View File
@@ -82,6 +82,45 @@ To override the built-in check, define `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERI
See [full documentation of `JSON_HAS_FILESYSTEM` and `JSON_HAS_EXPERIMENTAL_FILESYSTEM`](../api/macros/json_has_filesystem.md). See [full documentation of `JSON_HAS_FILESYSTEM` and `JSON_HAS_EXPERIMENTAL_FILESYSTEM`](../api/macros/json_has_filesystem.md).
## `JSON_HAS_RANGES`
The library uses `std::ranges` (and concepts) where available, for example, to parse from C++20 ranges and to
construct JSON arrays from range views. The library detects whether the standard library supports ranges and
disables the support on toolchains with an incomplete implementation. To override the built-in check, define
`JSON_HAS_RANGES` to `1` or `0`.
See [full documentation of `JSON_HAS_RANGES`](../api/macros/json_has_ranges.md).
## `JSON_HAS_RANGE_VIEW_CONVERSION`
When `JSON_HAS_RANGES` is enabled (and the compiler is not MinGW), a JSON array can be constructed directly from a C++20
range view such as `std::views::filter(...)`. To override the built-in check, define `JSON_HAS_RANGE_VIEW_CONVERSION` to
`1` or `0`.
See [full documentation of `JSON_HAS_RANGE_VIEW_CONVERSION`](../api/macros/json_has_range_view_conversion.md).
## `JSON_HAS_STATIC_RTTI`
The library detects whether the compiler supports run time type information (RTTI), which it needs, for instance, to
exclude `std::any` from the candidate types of the implicit conversion on C++17. To override the built-in check, define
`JSON_HAS_STATIC_RTTI` to `1` or `0`.
See [full documentation of `JSON_HAS_STATIC_RTTI`](../api/macros/json_has_static_rtti.md).
## `JSON_HAS_STD_FORMAT`
When compiling with C++20 and a standard library that provides `<format>`, the library provides a `std::formatter`
specialization for JSON values. To override the built-in check, define `JSON_HAS_STD_FORMAT` to `1` or `0`.
See [full documentation of `JSON_HAS_STD_FORMAT`](../api/macros/json_has_std_format.md).
## `JSON_HAS_THREE_WAY_COMPARISON`
When the compiler and standard library support 3-way comparison (the spaceship operator `<=>`), the library provides it
for JSON values. To override the built-in check, define `JSON_HAS_THREE_WAY_COMPARISON` to `1` or `0`.
See [full documentation of `JSON_HAS_THREE_WAY_COMPARISON`](../api/macros/json_has_three_way_comparison.md).
## `JSON_NOEXCEPTION` ## `JSON_NOEXCEPTION`
Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`. Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`.
+6
View File
@@ -101,3 +101,9 @@ follows:
- Introduced inline namespace (`json_v3_11_0[_abi-tag]*`) in version 3.11.0. - Introduced inline namespace (`json_v3_11_0[_abi-tag]*`) in version 3.11.0.
- Changed structure of inline namespace in version 3.11.2. - Changed structure of inline namespace in version 3.11.2.
- Added ABI tag `_dp` ([`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md)) in version 3.12.0.
- Added ABI tags `_bics` ([`JSON_BRACE_INIT_COPY_SEMANTICS`](../api/macros/json_brace_init_copy_semantics.md)), `_psp`
([`JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md)), `_snul`
([`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md)), `_sbu8`
([`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md)), and `_ekmo`
([`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md)) in version 3.13.0.
@@ -351,9 +351,8 @@ The number types can be changed with template parameters.
A `basic_json` type that uses `#!c long double` as floating-point type. A `basic_json` type that uses `#!c long double` as floating-point type.
```cpp hl_lines="2" ```cpp hl_lines="1"
using json_ld = nlohmann::basic_json<std::map, std::vector, std::string, bool, using json_ld = nlohmann::json::with_float_t<long double>;
std::int64_t, std::uint64_t, long double>;
``` ```
Note values should then be parsed with `json_ld::parse` rather than `json::parse` as the latter would parse Note values should then be parsed with `json_ld::parse` rather than `json::parse` as the latter would parse
@@ -8,6 +8,10 @@ these requirements so they do not have to be discovered by trial and error. Each
that are known to work for that parameter and the ones that do not, checked against Boost 1.83, Abseil 20250127.0, that are known to work for that parameter and the ones that do not, checked against Boost 1.83, Abseil 20250127.0,
Folly, EASTL 3.21, `ankerl::unordered_dense`, `phmap`, `gtl`, `robin_hood`, `tsl::ordered_map`, and Qt 6. Folly, EASTL 3.21, `ankerl::unordered_dense`, `phmap`, `gtl`, `robin_hood`, `tsl::ordered_map`, and Qt 6.
To change a single template parameter and keep the others, use the member alias templates
[`with_*_t`](../../api/basic_json/with_t.md); for instance, `nlohmann::json::with_float_t<long double>` is `json` with
`#!cpp long double` as [`number_float_t`](../../api/basic_json/number_float_t.md).
## How to read this page ## How to read this page
Requirements are split into two groups: Requirements are split into two groups:
@@ -143,7 +147,7 @@ struct unordered_map_object
using base_t::base_t; using base_t::base_t;
}; };
using unordered_json = nlohmann::basic_json<unordered_map_object>; using unordered_json = nlohmann::json::with_object_t<unordered_map_object>;
``` ```
Whether `#!cpp std::unordered_map` can be instantiated at all depends on the standard library: `object_t` is formed Whether `#!cpp std::unordered_map` can be instantiated at all depends on the standard library: `object_t` is formed
@@ -176,7 +180,7 @@ struct flat_hash_object
using base_t::base_t; using base_t::base_t;
}; };
using flat_hash_json = nlohmann::basic_json<flat_hash_object>; using flat_hash_json = nlohmann::json::with_object_t<flat_hash_object>;
``` ```
`absl::node_hash_map` keeps references to the mapped values valid across insertions; `absl::flat_hash_map` does not, `absl::node_hash_map` keeps references to the mapped values valid across insertions; `absl::flat_hash_map` does not,
+1 -1
View File
@@ -34,7 +34,7 @@ flowchart LR
- **JSON text** is read by an [input adapter](#input-adapters), tokenized by the lexer, and turned into SAX events by - **JSON text** is read by an [input adapter](#input-adapters), tokenized by the lexer, and turned into SAX events by
the parser. the parser.
- **Binary formats** (BJData, BSON, CBOR, MessagePack, UBJSON) are read by an input adapter and turned into the same SAX - **Binary formats** (BJData, BON8, BSON, CBOR, MessagePack, UBJSON) are read by an input adapter and turned into the same SAX
events by the `binary_reader`. events by the `binary_reader`.
- A [SAX consumer](#sax-interface) receives the events. The one used by [`parse`](../api/basic_json/parse.md) builds a - A [SAX consumer](#sax-interface) receives the events. The one used by [`parse`](../api/basic_json/parse.md) builds a
`basic_json` value tree. `basic_json` value tree.
+2 -2
View File
@@ -6,7 +6,7 @@ There are myriads of [JSON](https://json.org) libraries out there, and each may
- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. - **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.
- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [OpenSSF Best Practices](https://www.bestpractices.dev/projects/289). - **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [OpenSSF Best Practices](https://www.bestpractices.dev/projects/289).
Other aspects were not so important to us: Other aspects were not so important to us:
@@ -14,4 +14,4 @@ Other aspects were not so important to us:
- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set. - **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set.
See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information. See the [contribution guidelines](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md#please-dont) for more information.
+2 -2
View File
@@ -104,7 +104,7 @@ See [documentation of `JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) for
## Parse errors ## Parse errors
The library throws this exception when a parse error occurs. Parse errors The library throws this exception when a parse error occurs. Parse errors
can occur during the deserialization of JSON text, CBOR, MessagePack, as well can occur during the deserialization of JSON text or of one of the binary formats (BJData, BON8, BSON, CBOR, MessagePack, UBJSON), as well
as when using JSON Patch. as when using JSON Patch.
Exceptions have ids 1xx. Exceptions have ids 1xx.
@@ -190,7 +190,7 @@ This error indicates a syntax error while deserializing a JSON text. The error m
!!! tip !!! tip
- Make sure the input is correctly read. Try to write the input to standard output to check if, for instance, the input file was successfully opened. - Make sure the input is correctly read. Try to write the input to standard output to check if, for instance, the input file was successfully opened.
- Paste the input to a JSON validator like <http://jsonlint.com> or a tool like [jq](https://stedolan.github.io/jq/). - Paste the input to a JSON validator like <https://jsonlint.com> or a tool like [jq](https://jqlang.github.io/jq/).
### json.exception.parse_error.102 ### json.exception.parse_error.102
+1 -1
View File
@@ -26,7 +26,7 @@ Fixes bugs found in 3.11.3 and adds several features. All changes are backward-c
[BJData](../features/binary_formats/bjdata.md) draft 3 and unsigned 64-bit integers for [BJData](../features/binary_formats/bjdata.md) draft 3 and unsigned 64-bit integers for
[BSON](../features/binary_formats/bson.md). [BSON](../features/binary_formats/bson.md).
- Adds multidimensional C-array conversion and UTF-8 encoded `std::filesystem::path` conversions, and - Adds multidimensional C-array conversion and UTF-8 encoded `std::filesystem::path` conversions, and
lowers the minimum [CMake](../integration/cmake.md) version to allow CMake 4.0. raises the minimum [CMake](../integration/cmake.md) version to 3.5 and supports CMake 4.0.
[Full release notes](https://github.com/nlohmann/json/releases/tag/v3.12.0). [Full release notes](https://github.com/nlohmann/json/releases/tag/v3.12.0).
@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.15)
include("cmake/HunterGate.cmake") include("cmake/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.23.297.tar.gz" URL "https://github.com/cpp-pm/hunter/archive/v0.26.12.tar.gz"
SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3" SHA1 "6498c5d0dec25d7fffb2b0574ebaf265179b894d"
) )
project(json_example) project(json_example)
@@ -116,7 +116,7 @@ function to use instead.
=== "Deprecated" === "Deprecated"
```cpp ```cpp
using my_json = nlohmann::basic_json<std::map, std::vector, my_string_type>; using my_json = nlohmann::json::with_string_t<my_string_type>;
nlohmann::json_pointer<my_json> ptr("/foo/bar/1"); nlohmann::json_pointer<my_json> ptr("/foo/bar/1");
``` ```
+28 -3
View File
@@ -2,12 +2,30 @@
# Creates a `<path>.md` sibling of each HTML output (for example, # Creates a `<path>.md` sibling of each HTML output (for example,
# `features/comments/` becomes `features/comments.md`) so agents and tools can # `features/comments/` becomes `features/comments.md`) so agents and tools can
# fetch the raw Markdown directly instead of parsing rendered HTML. # fetch the raw Markdown directly instead of parsing rendered HTML. The
# `--8<-- "path"` lines of pymdownx.snippets are expanded with the extension's
# own preprocessor and the settings from mkdocs.yml, so the copies contain the
# included example code and files instead of the include directives.
import io
import os import os
import shutil
import markdown
from pymdownx.snippets import SnippetMissingError
_pages = [] _pages = []
_snippets = None
def on_config(config):
global _snippets
md = markdown.Markdown(
extensions=["pymdownx.snippets"],
extension_configs={"pymdownx.snippets": config["mdx_configs"].get("pymdownx.snippets", {})},
)
_snippets = md.preprocessors["snippet"]
_snippets.auto_append = [] # the glossary is only needed to render abbreviations
return config
def on_files(files, config): def on_files(files, config):
@@ -22,4 +40,11 @@ def on_post_build(config):
url = file.url.rstrip("/") url = file.url.rstrip("/")
target = os.path.join(site_dir, (url or "index") + ".md") target = os.path.join(site_dir, (url or "index") + ".md")
os.makedirs(os.path.dirname(target), exist_ok=True) os.makedirs(os.path.dirname(target), exist_ok=True)
shutil.copyfile(file.abs_src_path, target) with io.open(file.abs_src_path, encoding="utf-8", newline="") as source:
text = source.read()
try:
text = "\n".join(_snippets.run(text.split("\n")))
except (SnippetMissingError, OSError):
pass # keep the include directives; the regular build reports the missing file
with io.open(target, "w", encoding="utf-8", newline="") as copy:
copy.write(text)
+1 -1
View File
@@ -1,7 +1,7 @@
<!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary --> <!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary -->
*[ADL]: Argument-dependent lookup *[ADL]: Argument-dependent lookup
*[API]: Application Programming Interfaces *[API]: Application Programming Interface
*[ASCII]: American Standard Code for Information Interchange *[ASCII]: American Standard Code for Information Interchange
*[BDFL]: Benevolent Dictator for Life *[BDFL]: Benevolent Dictator for Life
*[BJData]: Binary JData *[BJData]: Binary JData
+1
View File
@@ -299,6 +299,7 @@ nav:
- 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md - 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md
- 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26': api/macros/json_has_cpp_11.md - 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26': api/macros/json_has_cpp_11.md
- 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md - 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md
- 'JSON_HAS_RANGE_VIEW_CONVERSION': api/macros/json_has_range_view_conversion.md
- 'JSON_HAS_RANGES': api/macros/json_has_ranges.md - 'JSON_HAS_RANGES': api/macros/json_has_ranges.md
- 'JSON_HAS_STATIC_RTTI': api/macros/json_has_static_rtti.md - 'JSON_HAS_STATIC_RTTI': api/macros/json_has_static_rtti.md
- 'JSON_HAS_STD_FORMAT': api/macros/json_has_std_format.md - 'JSON_HAS_STD_FORMAT': api/macros/json_has_std_format.md
-31
View File
@@ -288,36 +288,6 @@ def check_header_links() -> None:
f'link to "{match.group(0)}" does not point to a documentation page') f'link to "{match.group(0)}" does not point to a documentation page')
def check_docset() -> None:
"""Every API page and every macro has an entry in the docset index; no entry points to a missing page."""
entry_re = re.compile(r"VALUES \('((?:[^']|'')*)', '(\w+)', '([^']*)'\);")
names_by_path = {}
with open("../../docset/docSet.sql", encoding="utf-8") as sql:
for name, _, path in entry_re.findall(sql.read()):
names_by_path.setdefault(path, set()).add(name.replace("''", "'"))
def to_path(page):
if os.path.basename(page) == "index.md":
return page[:-len("index.md")] + "index.html"
return page[:-len(".md")] + "/index.html"
pages = sorted(glob.glob("**/*.md", recursive=True))
for path in sorted(set(names_by_path) - {to_path(p) for p in pages}):
report("docset/stale_entry", "../../docset/docSet.sql", f'entry "{path}" has no documentation page')
for page in (p for p in pages if p.startswith("api/")):
names = names_by_path.get(to_path(page))
if not names:
report("docset/missing_entry", page, "page has no entry in docs/docset/docSet.sql")
elif page.startswith("api/macros/") and os.path.basename(page) != "index.md":
with open(page, encoding="utf-8") as content:
text = content.read()
match = re.search(r"^# (.+)$", text, re.MULTILINE) or re.search(r"<h1>(.*?)</h1>", text, re.DOTALL)
title = re.sub(r"<[^>]+>|\s+", " ", match.group(1))
for macro in filter(None, (x.strip() for x in re.split(r"[,/]", title))):
if macro not in names:
report("docset/missing_macro", page, f'macro "{macro}" has no entry in docs/docset/docSet.sql')
if __name__ == "__main__": if __name__ == "__main__":
print(120 * "-") print(120 * "-")
check_structure() check_structure()
@@ -327,7 +297,6 @@ if __name__ == "__main__":
check_heading_levels() check_heading_levels()
check_image_alt_text() check_image_alt_text()
check_header_links() check_header_links()
check_docset()
print(120 * "-") print(120 * "-")
if warnings > 0: if warnings > 0:
+11 -2
View File
@@ -9,12 +9,15 @@
#pragma once #pragma once
#include <cstdint> // uint64_t #include <cstdint> // uint64_t
#if !defined(__SIZEOF_INT128__) && defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
#include <intrin0.h> // __umulh, _umul128
#endif
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
// Portable bit-level helpers for the number and string scanners. They use // Portable bit-level helpers for the number and string scanners. They use
// compiler builtins where available and plain C++ otherwise, so they need no // compiler builtins or platform-specific intrinsics where available and plain
// platform headers and work regardless of byte order. // C++ otherwise, so they work regardless of byte order.
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail
@@ -52,6 +55,12 @@ inline uint128_parts full_multiplication(std::uint64_t a, std::uint64_t b) noexc
__extension__ using uint128 = unsigned __int128; __extension__ using uint128 = unsigned __int128;
const uint128 r = static_cast<uint128>(a) * b; const uint128 r = static_cast<uint128>(a) * b;
return {static_cast<std::uint64_t>(r), static_cast<std::uint64_t>(r >> 64u)}; return {static_cast<std::uint64_t>(r), static_cast<std::uint64_t>(r >> 64u)};
#elif defined(_MSC_VER) && defined(_M_X64)
std::uint64_t high = 0;
const std::uint64_t low = _umul128(a, b, &high);
return {low, high};
#elif defined(_MSC_VER) && defined(_M_ARM64)
return {a * b, __umulh(a, b)};
#else #else
const std::uint64_t a_lo = a & 0xFFFFFFFFu; const std::uint64_t a_lo = a & 0xFFFFFFFFu;
const std::uint64_t a_hi = a >> 32u; const std::uint64_t a_hi = a >> 32u;
+151 -39
View File
@@ -16,8 +16,8 @@
#include <iosfwd> // ostream #include <iosfwd> // ostream
#endif // JSON_NO_IO #endif // JSON_NO_IO
#include <limits> // max #include <limits> // max
#include <map> // map
#include <numeric> // accumulate #include <numeric> // accumulate
#include <set> // set
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
#include <vector> // vector #include <vector> // vector
@@ -359,33 +359,82 @@ class json_pointer
private: private:
/*! /*!
@brief the reference token sequences that denote arrays @brief the pointer prefixes of a flattened object, and which of them denote arrays
@ref unflatten collects the pointer prefixes that have a reference token 0 @ref unflatten collects the pointer prefixes that have a reference token 0
among their children; @ref get_and_create creates arrays exactly below among their children; @ref get_and_create creates arrays exactly below
those prefixes and objects everywhere else. Deciding this up front keeps those prefixes and objects everywhere else. Deciding this up front keeps
the result independent of the order in which the flattened object is the result independent of the order in which the flattened object is
iterated, which is unspecified for some object types. iterated, which is unspecified for some object types.
The prefixes form a tree and are numbered, so each of them is stored only
once (as a node) rather than as a copy of all of its reference tokens.
*/ */
using array_parents_t = std::set<std::vector<string_t>>; struct prefix_tree
{
// children[id] maps a reference token to the number of the prefix
// extended by that token; number 0 is the empty prefix
std::vector<std::map<string_t, std::size_t>> children;
// is_array[id] is true iff some flattened key has the reference token
// 0 directly below the prefix with number id
std::vector<bool> is_array;
// start with the empty prefix only
prefix_tree()
: children(1)
, is_array(1, false)
{}
// return the number of the prefix with number id extended by
// reference_token, adding it if it is new
std::size_t add_child(std::size_t id, string_t&& reference_token)
{
if (reference_token == "0")
{
is_array[id] = true;
}
// read the number before the emplace_back below, which may
// reallocate children and invalidate the iterator
const std::size_t next = children.size();
const auto inserted = children[id].emplace(std::move(reference_token), next);
const std::size_t child = inserted.first->second;
if (inserted.second)
{
children.emplace_back();
is_array.push_back(false);
}
return child;
}
// return the number of the prefix with number id extended by
// reference_token, which must have been added before
std::size_t find_child(std::size_t id, const string_t& reference_token) const
{
const auto it = children[id].find(reference_token);
JSON_ASSERT(it != children[id].end());
return it->second;
}
};
/*! /*!
@brief create and return a reference to the pointed to value @brief create and return a reference to the pointed to value
Complexity: Linear in the number of reference tokens. Complexity: Linear in the number of reference tokens (times the logarithm
of the number of siblings for the prefix lookup).
@throw parse_error.106 if an array index begins with '0' @throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if array index is not a number @throw parse_error.109 if array index is not a number
@throw type_error.313 if value cannot be unflattened @throw type_error.313 if value cannot be unflattened
*/ */
template<typename BasicJsonType> template<typename BasicJsonType>
BasicJsonType& get_and_create(BasicJsonType& j, const array_parents_t& array_parents) const BasicJsonType& get_and_create(BasicJsonType& j, const prefix_tree& tree) const
{ {
auto* result = &j; auto* result = &j;
// the reference tokens that have been consumed so far; used to look up // the number of the prefix consumed so far; used to look up whether
// whether the value to be created below is an array or an object // the value to be created below is an array or an object
std::vector<string_t> prefix; std::size_t id = 0;
// in case no reference tokens exist, return a reference to the JSON value // in case no reference tokens exist, return a reference to the JSON value
// j which will be overwritten by a primitive value // j which will be overwritten by a primitive value
@@ -395,7 +444,7 @@ class json_pointer
{ {
case detail::value_t::null: case detail::value_t::null:
{ {
if (array_parents.find(prefix) != array_parents.end()) if (tree.is_array[id])
{ {
// some reference token below this position is 0, so the // some reference token below this position is 0, so the
// value is an array // value is an array
@@ -440,7 +489,7 @@ class json_pointer
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
} }
prefix.push_back(reference_token); id = tree.find_child(id, reference_token);
} }
return *result; return *result;
@@ -878,49 +927,74 @@ class json_pointer
@param[in,out] result the result object to insert values to @param[in,out] result the result object to insert values to
@note Empty objects or arrays are flattened to `null`. @note Empty objects or arrays are flattened to `null`.
The value is walked with an explicit stack rather than the call stack, so
arbitrarily deeply nested values can be flattened.
@sa https://github.com/nlohmann/json/issues/5393
*/ */
template<typename BasicJsonType> template<typename BasicJsonType>
static void flatten(const string_t& reference_string, static void flatten(const string_t& reference_string,
const BasicJsonType& value, const BasicJsonType& value,
BasicJsonType& result) BasicJsonType& result)
{ {
switch (value.type()) using object_const_iterator = typename BasicJsonType::object_t::const_iterator;
// an array or object being walked: the container, the array index or
// object iterator of the next child, and the length of the path of the
// container itself
struct frame
{
frame(const BasicJsonType* container_, object_const_iterator member_, const std::size_t path_length_) noexcept
: container(container_), member(std::move(member_)), path_length(path_length_)
{}
const BasicJsonType* container;
std::size_t index = 0;
object_const_iterator member;
std::size_t path_length;
};
// The containers being flattened are kept on an explicit stack, and
// every child is flattened completely before the next one, so the
// entries come out in the same order as with a recursive walk. The
// path of the value being flattened is kept in one buffer that grows
// and shrinks with the stack, rather than in a new string per level.
std::vector<frame> stack;
string_t path = reference_string;
// flatten `v`, whose path is `path`: primitives and empty containers
// are added to the result right away; other containers get a frame
const auto enter = [&stack, &path, &result](const BasicJsonType & v)
{
switch (v.type())
{ {
case detail::value_t::array: case detail::value_t::array:
{ {
if (value.m_data.m_value.array->empty()) if (v.m_data.m_value.array->empty())
{ {
// flatten empty array as null // flatten empty array as null
result[reference_string] = nullptr; result[path] = nullptr;
} }
else else
{ {
// iterate array and use index as a reference string stack.emplace_back(&v, object_const_iterator(), path.size());
for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
{
flatten(detail::concat<string_t>(reference_string, '/', std::to_string(i)),
value.m_data.m_value.array->operator[](i), result);
} }
} return;
break;
} }
case detail::value_t::object: case detail::value_t::object:
{ {
if (value.m_data.m_value.object->empty()) if (v.m_data.m_value.object->empty())
{ {
// flatten empty object as null // flatten empty object as null
result[reference_string] = nullptr; result[path] = nullptr;
} }
else else
{ {
// iterate object and use keys as reference string stack.emplace_back(&v, v.m_data.m_value.object->begin(), path.size());
for (const auto& element : *value.m_data.m_value.object)
{
flatten(detail::concat<string_t>(reference_string, '/', detail::escape(element.first)), element.second, result);
} }
} return;
break;
} }
case detail::value_t::null: case detail::value_t::null:
@@ -934,8 +1008,50 @@ class json_pointer
default: default:
{ {
// add a primitive value with its reference string // add a primitive value with its reference string
result[reference_string] = value; result[path] = v;
break; return;
}
}
};
enter(value);
while (!stack.empty())
{
// the frame is changed through stack.back(): enter() may push a
// frame, which would invalidate a reference to it
const BasicJsonType* const container = stack.back().container;
// drop the path of the previous child
path.resize(stack.back().path_length);
if (container->is_array())
{
const auto& array = *container->m_data.m_value.array;
const std::size_t i = stack.back().index;
if (i == array.size())
{
stack.pop_back();
continue;
}
// iterate array and use index as a reference string
++stack.back().index;
detail::concat_into(path, '/', detail::to_string<string_t>(i));
enter(array[i]);
}
else
{
const object_const_iterator it = stack.back().member;
if (it == container->m_data.m_value.object->end())
{
stack.pop_back();
continue;
}
// iterate object and use keys as reference string
++stack.back().member;
detail::concat_into(path, '/', detail::escape(it->first));
enter(it->second);
} }
} }
} }
@@ -963,19 +1079,15 @@ class json_pointer
// collect the pointer prefixes that have a reference token 0 among // collect the pointer prefixes that have a reference token 0 among
// their children; the values below them are arrays, all others are // their children; the values below them are arrays, all others are
// objects (see array_parents_t) // objects (see prefix_tree)
array_parents_t array_parents; prefix_tree tree;
for (const auto& element : *value.m_data.m_value.object) for (const auto& element : *value.m_data.m_value.object)
{ {
json_pointer ptr(element.first); json_pointer ptr(element.first);
std::vector<string_t> prefix; std::size_t id = 0;
for (auto& reference_token : ptr.reference_tokens) for (auto& reference_token : ptr.reference_tokens)
{ {
if (reference_token == "0") id = tree.add_child(id, std::move(reference_token));
{
array_parents.insert(prefix);
}
prefix.push_back(std::move(reference_token));
} }
} }
@@ -991,7 +1103,7 @@ class json_pointer
// that if the JSON pointer is "" (i.e., points to the whole value), // that if the JSON pointer is "" (i.e., points to the whole value),
// function get_and_create returns a reference to the result itself. // function get_and_create returns a reference to the result itself.
// An assignment will then create a primitive value. // An assignment will then create a primitive value.
json_pointer(element.first).get_and_create(result, array_parents) = element.second; json_pointer(element.first).get_and_create(result, tree) = element.second;
} }
return result; return result;
+126 -77
View File
@@ -85,6 +85,12 @@ template<typename BasicJsonType, typename CharType, typename OutputSinkType = ou
class binary_writer class binary_writer
{ {
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
/// an object key as string_t: a reference when object_t::key_type already is
/// string_t, otherwise a converted copy that outlives sanitize_utf8_for_write's result
using object_key_string_t = typename std::conditional <
std::is_same<typename BasicJsonType::object_t::key_type, string_t>::value,
const string_t&, string_t >::type;
using binary_t = typename BasicJsonType::binary_t; using binary_t = typename BasicJsonType::binary_t;
using number_float_t = typename BasicJsonType::number_float_t; using number_float_t = typename BasicJsonType::number_float_t;
@@ -244,16 +250,7 @@ class binary_writer
case value_t::string: case value_t::string:
{ {
string_t storage; write_cbor_string(*j.m_data.m_value.string, j);
const string_t& value = sanitize_utf8_for_write(*j.m_data.m_value.string, j, storage);
// step 1: write control byte and the string length
write_cbor_head(0x60, value.size());
// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(value.data()),
value.size());
break; break;
} }
@@ -316,23 +313,20 @@ class binary_writer
case value_t::object: case value_t::object:
{ {
static_assert(
std::is_convertible <
typename BasicJsonType::object_t::key_type,
string_t >::value,
"object_t::key_type must be implicitly convertible to string_t");
// step 1: write control byte and the object size // step 1: write control byte and the object size
write_cbor_head(0xA0, j.m_data.m_value.object->size()); write_cbor_head(0xA0, j.m_data.m_value.object->size());
for (const auto& el : *j.m_data.m_value.object) for (const auto& el : *j.m_data.m_value.object)
{ {
// el.first is checked here, against the object as // el.first is written directly (not via a temporary
// diagnostics context, because write_cbor(el.first) // basic_json), with the object as diagnostics context
// converts it to a temporary basic_json that would be write_cbor_string(el.first, j);
// used as the context instead; for error_handler_t::keep
// and ::replace/::ignore the recursive write_cbor(el.first)
// call below handles the key like any other string, so no
// separate check is needed here for those
if (error_handler == error_handler_t::strict)
{
check_utf8(el.first, j);
}
write_cbor(el.first);
write_cbor(el.second, depth + 1); write_cbor(el.second, depth + 1);
} }
break; break;
@@ -491,39 +485,7 @@ class binary_writer
case value_t::string: case value_t::string:
{ {
string_t storage; write_msgpack_string(*j.m_data.m_value.string, j);
const string_t& value = sanitize_utf8_for_write(*j.m_data.m_value.string, j, storage);
// step 1: write control byte and the string length
const auto N = to_msgpack_length(value.size(), j);
if (N <= 31)
{
// fixstr
write_number(static_cast<std::uint8_t>(0xA0 | N));
}
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{
// str 8
oa.write_character(to_char_type(0xD9));
write_number(static_cast<std::uint8_t>(N));
}
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{
// str 16
oa.write_character(to_char_type(0xDA));
write_number(static_cast<std::uint16_t>(N));
}
else
{
// str 32
oa.write_character(to_char_type(0xDB));
write_number(static_cast<std::uint32_t>(N));
}
// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(value.data()),
value.size());
break; break;
} }
@@ -629,19 +591,20 @@ class binary_writer
case value_t::object: case value_t::object:
{ {
static_assert(
std::is_convertible <
typename BasicJsonType::object_t::key_type,
string_t >::value,
"object_t::key_type must be implicitly convertible to string_t");
// step 1: write control byte and the object size // step 1: write control byte and the object size
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j); write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
for (const auto& el : *j.m_data.m_value.object) for (const auto& el : *j.m_data.m_value.object)
{ {
// as in write_cbor, el.first is checked here against the // as in write_cbor, el.first is written directly with the
// object as diagnostics context; the recursive call below // object as diagnostics context
// handles keep/replace/ignore like any other string write_msgpack_string(el.first, j);
if (error_handler == error_handler_t::strict)
{
check_utf8(el.first, j);
}
write_msgpack(el.first);
write_msgpack(el.second, depth + 1); write_msgpack(el.second, depth + 1);
} }
break; break;
@@ -819,8 +782,10 @@ class binary_writer
for (const auto& el : *j.m_data.m_value.object) for (const auto& el : *j.m_data.m_value.object)
{ {
// a converted key must outlive the reference returned by sanitize_utf8_for_write
const object_key_string_t key_string = el.first;
string_t storage; string_t storage;
const string_t& key = sanitize_utf8_for_write(el.first, j, storage); const string_t& key = sanitize_utf8_for_write(key_string, j, storage);
write_number_with_ubjson_prefix(key.size(), true, use_bjdata); write_number_with_ubjson_prefix(key.size(), true, use_bjdata);
oa.write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(key.data()), reinterpret_cast<const CharType*>(key.data()),
@@ -1025,13 +990,9 @@ class binary_writer
continue; continue;
} }
// el.first is checked here, against the object as diagnostics // the key is written directly (not via a temporary basic_json),
// context, like the matching check in write_cbor's object case // with the object as diagnostics context, as in write_cbor
if (error_handler == error_handler_t::strict) write_cbor_string(current.object_it->first, *current.value);
{
check_utf8(current.object_it->first, *current.value);
}
write_cbor(current.object_it->first);
const BasicJsonType* child = &(current.object_it->second); const BasicJsonType* child = &(current.object_it->second);
++stack.back().object_it; ++stack.back().object_it;
write_cbor_value_or_push(*child, stack); write_cbor_value_or_push(*child, stack);
@@ -1106,11 +1067,9 @@ class binary_writer
continue; continue;
} }
if (error_handler == error_handler_t::strict) // as in write_cbor_iterative, the key is written directly with
{ // the object as diagnostics context
check_utf8(current.object_it->first, *current.value); write_msgpack_string(current.object_it->first, *current.value);
}
write_msgpack(current.object_it->first);
const BasicJsonType* child = &(current.object_it->second); const BasicJsonType* child = &(current.object_it->second);
++stack.back().object_it; ++stack.back().object_it;
write_msgpack_value_or_push(*child, stack); write_msgpack_value_or_push(*child, stack);
@@ -1366,8 +1325,10 @@ class binary_writer
continue; continue;
} }
// a converted key must outlive the reference returned by sanitize_utf8_for_write
const object_key_string_t key_string = current.object_it->first;
string_t storage; string_t storage;
const string_t& key = sanitize_utf8_for_write(current.object_it->first, j, storage); const string_t& key = sanitize_utf8_for_write(key_string, j, storage);
write_number_with_ubjson_prefix(key.size(), true, use_bjdata); write_number_with_ubjson_prefix(key.size(), true, use_bjdata);
oa.write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(key.data()), reinterpret_cast<const CharType*>(key.data()),
@@ -1988,6 +1949,85 @@ class binary_writer
} }
} }
/*!
@brief write a CBOR text string
@a value is checked or sanitized according to @ref error_handler, with
@a context (the string value itself, or the object a key belongs to) used
as diagnostics context; this avoids converting object keys to a temporary
basic_json just to write them
@note When object_t::key_type is not string_t, @a value is a temporary
string_t converted from the key, which lives only until the end of
the caller's statement. The reference returned by
@ref sanitize_utf8_for_write may refer to it, so it must not escape
this function.
*/
void write_cbor_string(const string_t& value, const BasicJsonType& context)
{
string_t storage;
const string_t& sanitized = sanitize_utf8_for_write(value, context, storage);
// step 1: write control byte and the string length
write_cbor_head(0x60, sanitized.size());
// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(sanitized.data()),
sanitized.size());
}
/////////////
// MsgPack //
/////////////
/*!
@brief write a MessagePack str
@a value is checked or sanitized according to @ref error_handler, with
@a context used as diagnostics context, as in @ref write_cbor_string
@note As in @ref write_cbor_string, @a value may be a temporary string_t
converted from a key, so the reference returned by
@ref sanitize_utf8_for_write must not escape this function.
*/
void write_msgpack_string(const string_t& value, const BasicJsonType& context)
{
string_t storage;
const string_t& sanitized = sanitize_utf8_for_write(value, context, storage);
// step 1: write control byte and the string length
const auto N = to_msgpack_length(sanitized.size(), context);
if (N <= 31)
{
// fixstr
write_number(static_cast<std::uint8_t>(0xA0 | N));
}
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{
// str 8
oa.write_character(to_char_type(0xD9));
write_number(static_cast<std::uint8_t>(N));
}
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{
// str 16
oa.write_character(to_char_type(0xDA));
write_number(static_cast<std::uint16_t>(N));
}
else
{
// str 32
oa.write_character(to_char_type(0xDB));
write_number(static_cast<std::uint32_t>(N));
}
// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(sanitized.data()),
sanitized.size());
}
//////////// ////////////
// UBJSON // // UBJSON //
//////////// ////////////
@@ -2730,6 +2770,11 @@ class binary_writer
itself in every case but a sanitized `replace`/`ignore` one, so @a itself in every case but a sanitized `replace`/`ignore` one, so @a
storage must outlive the returned reference only then. storage must outlive the returned reference only then.
@a s must be an lvalue that outlives the returned reference. An object key
whose `key_type` is not @ref string_t must therefore first be converted
into a named string_t (see @ref object_key_string_t); the deleted overload
below enforces this at compile time.
@param[in] s the string (value or object key) to write @param[in] s the string (value or object key) to write
@param[in] context the value @a s belongs to (for diagnostics) @param[in] context the value @a s belongs to (for diagnostics)
@param[out] storage backing storage for a sanitized copy @param[out] storage backing storage for a sanitized copy
@@ -2759,6 +2804,10 @@ class binary_writer
} }
} }
/// deleted: anything but a string_t would bind a temporary that dies before the returned reference is used
template < typename T, enable_if_t < !std::is_same<T, string_t>::value, int > = 0 >
const string_t& sanitize_utf8_for_write(const T& /*s*/, const BasicJsonType& /*context*/, string_t& /*storage*/) const = delete; // NOLINT(hicpp-use-equals-delete,modernize-use-equals-delete): a private helper's guard, not part of the interface
/*! /*!
@brief write an integer in the shortest encoding @brief write an integer in the shortest encoding
+2 -2
View File
@@ -108,8 +108,8 @@ void encode_utf8(std::uint32_t cp, const Out& out)
/////////////////// ///////////////////
// UTF-8 decoder states used by decode() below // UTF-8 decoder states used by decode() below
static constexpr std::uint8_t UTF8_ACCEPT = 0; JSON_INLINE_VARIABLE constexpr std::uint8_t UTF8_ACCEPT = 0;
static constexpr std::uint8_t UTF8_REJECT = 1; JSON_INLINE_VARIABLE constexpr std::uint8_t UTF8_REJECT = 1;
/*! /*!
@brief process a byte of a UTF-8 sequence @brief process a byte of a UTF-8 sequence
+290 -120
View File
@@ -6395,8 +6395,8 @@ void encode_utf8(std::uint32_t cp, const Out& out)
/////////////////// ///////////////////
// UTF-8 decoder states used by decode() below // UTF-8 decoder states used by decode() below
static constexpr std::uint8_t UTF8_ACCEPT = 0; JSON_INLINE_VARIABLE constexpr std::uint8_t UTF8_ACCEPT = 0;
static constexpr std::uint8_t UTF8_REJECT = 1; JSON_INLINE_VARIABLE constexpr std::uint8_t UTF8_REJECT = 1;
/*! /*!
@brief process a byte of a UTF-8 sequence @brief process a byte of a UTF-8 sequence
@@ -8791,13 +8791,16 @@ NLOHMANN_JSON_NAMESPACE_END
#include <cstdint> // uint64_t #include <cstdint> // uint64_t
#if !defined(__SIZEOF_INT128__) && defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
#include <intrin0.h> // __umulh, _umul128
#endif
// #include <nlohmann/detail/abi_macros.hpp> // #include <nlohmann/detail/abi_macros.hpp>
// Portable bit-level helpers for the number and string scanners. They use // Portable bit-level helpers for the number and string scanners. They use
// compiler builtins where available and plain C++ otherwise, so they need no // compiler builtins or platform-specific intrinsics where available and plain
// platform headers and work regardless of byte order. // C++ otherwise, so they work regardless of byte order.
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail
@@ -8835,6 +8838,12 @@ inline uint128_parts full_multiplication(std::uint64_t a, std::uint64_t b) noexc
__extension__ using uint128 = unsigned __int128; __extension__ using uint128 = unsigned __int128;
const uint128 r = static_cast<uint128>(a) * b; const uint128 r = static_cast<uint128>(a) * b;
return {static_cast<std::uint64_t>(r), static_cast<std::uint64_t>(r >> 64u)}; return {static_cast<std::uint64_t>(r), static_cast<std::uint64_t>(r >> 64u)};
#elif defined(_MSC_VER) && defined(_M_X64)
std::uint64_t high = 0;
const std::uint64_t low = _umul128(a, b, &high);
return {low, high};
#elif defined(_MSC_VER) && defined(_M_ARM64)
return {a * b, __umulh(a, b)};
#else #else
const std::uint64_t a_lo = a & 0xFFFFFFFFu; const std::uint64_t a_lo = a & 0xFFFFFFFFu;
const std::uint64_t a_hi = a >> 32u; const std::uint64_t a_hi = a >> 32u;
@@ -19919,8 +19928,8 @@ NLOHMANN_JSON_NAMESPACE_END
#include <iosfwd> // ostream #include <iosfwd> // ostream
#endif // JSON_NO_IO #endif // JSON_NO_IO
#include <limits> // max #include <limits> // max
#include <map> // map
#include <numeric> // accumulate #include <numeric> // accumulate
#include <set> // set
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
#include <vector> // vector #include <vector> // vector
@@ -20268,33 +20277,82 @@ class json_pointer
private: private:
/*! /*!
@brief the reference token sequences that denote arrays @brief the pointer prefixes of a flattened object, and which of them denote arrays
@ref unflatten collects the pointer prefixes that have a reference token 0 @ref unflatten collects the pointer prefixes that have a reference token 0
among their children; @ref get_and_create creates arrays exactly below among their children; @ref get_and_create creates arrays exactly below
those prefixes and objects everywhere else. Deciding this up front keeps those prefixes and objects everywhere else. Deciding this up front keeps
the result independent of the order in which the flattened object is the result independent of the order in which the flattened object is
iterated, which is unspecified for some object types. iterated, which is unspecified for some object types.
The prefixes form a tree and are numbered, so each of them is stored only
once (as a node) rather than as a copy of all of its reference tokens.
*/ */
using array_parents_t = std::set<std::vector<string_t>>; struct prefix_tree
{
// children[id] maps a reference token to the number of the prefix
// extended by that token; number 0 is the empty prefix
std::vector<std::map<string_t, std::size_t>> children;
// is_array[id] is true iff some flattened key has the reference token
// 0 directly below the prefix with number id
std::vector<bool> is_array;
// start with the empty prefix only
prefix_tree()
: children(1)
, is_array(1, false)
{}
// return the number of the prefix with number id extended by
// reference_token, adding it if it is new
std::size_t add_child(std::size_t id, string_t&& reference_token)
{
if (reference_token == "0")
{
is_array[id] = true;
}
// read the number before the emplace_back below, which may
// reallocate children and invalidate the iterator
const std::size_t next = children.size();
const auto inserted = children[id].emplace(std::move(reference_token), next);
const std::size_t child = inserted.first->second;
if (inserted.second)
{
children.emplace_back();
is_array.push_back(false);
}
return child;
}
// return the number of the prefix with number id extended by
// reference_token, which must have been added before
std::size_t find_child(std::size_t id, const string_t& reference_token) const
{
const auto it = children[id].find(reference_token);
JSON_ASSERT(it != children[id].end());
return it->second;
}
};
/*! /*!
@brief create and return a reference to the pointed to value @brief create and return a reference to the pointed to value
Complexity: Linear in the number of reference tokens. Complexity: Linear in the number of reference tokens (times the logarithm
of the number of siblings for the prefix lookup).
@throw parse_error.106 if an array index begins with '0' @throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if array index is not a number @throw parse_error.109 if array index is not a number
@throw type_error.313 if value cannot be unflattened @throw type_error.313 if value cannot be unflattened
*/ */
template<typename BasicJsonType> template<typename BasicJsonType>
BasicJsonType& get_and_create(BasicJsonType& j, const array_parents_t& array_parents) const BasicJsonType& get_and_create(BasicJsonType& j, const prefix_tree& tree) const
{ {
auto* result = &j; auto* result = &j;
// the reference tokens that have been consumed so far; used to look up // the number of the prefix consumed so far; used to look up whether
// whether the value to be created below is an array or an object // the value to be created below is an array or an object
std::vector<string_t> prefix; std::size_t id = 0;
// in case no reference tokens exist, return a reference to the JSON value // in case no reference tokens exist, return a reference to the JSON value
// j which will be overwritten by a primitive value // j which will be overwritten by a primitive value
@@ -20304,7 +20362,7 @@ class json_pointer
{ {
case detail::value_t::null: case detail::value_t::null:
{ {
if (array_parents.find(prefix) != array_parents.end()) if (tree.is_array[id])
{ {
// some reference token below this position is 0, so the // some reference token below this position is 0, so the
// value is an array // value is an array
@@ -20349,7 +20407,7 @@ class json_pointer
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
} }
prefix.push_back(reference_token); id = tree.find_child(id, reference_token);
} }
return *result; return *result;
@@ -20787,49 +20845,74 @@ class json_pointer
@param[in,out] result the result object to insert values to @param[in,out] result the result object to insert values to
@note Empty objects or arrays are flattened to `null`. @note Empty objects or arrays are flattened to `null`.
The value is walked with an explicit stack rather than the call stack, so
arbitrarily deeply nested values can be flattened.
@sa https://github.com/nlohmann/json/issues/5393
*/ */
template<typename BasicJsonType> template<typename BasicJsonType>
static void flatten(const string_t& reference_string, static void flatten(const string_t& reference_string,
const BasicJsonType& value, const BasicJsonType& value,
BasicJsonType& result) BasicJsonType& result)
{ {
switch (value.type()) using object_const_iterator = typename BasicJsonType::object_t::const_iterator;
// an array or object being walked: the container, the array index or
// object iterator of the next child, and the length of the path of the
// container itself
struct frame
{
frame(const BasicJsonType* container_, object_const_iterator member_, const std::size_t path_length_) noexcept
: container(container_), member(std::move(member_)), path_length(path_length_)
{}
const BasicJsonType* container;
std::size_t index = 0;
object_const_iterator member;
std::size_t path_length;
};
// The containers being flattened are kept on an explicit stack, and
// every child is flattened completely before the next one, so the
// entries come out in the same order as with a recursive walk. The
// path of the value being flattened is kept in one buffer that grows
// and shrinks with the stack, rather than in a new string per level.
std::vector<frame> stack;
string_t path = reference_string;
// flatten `v`, whose path is `path`: primitives and empty containers
// are added to the result right away; other containers get a frame
const auto enter = [&stack, &path, &result](const BasicJsonType & v)
{
switch (v.type())
{ {
case detail::value_t::array: case detail::value_t::array:
{ {
if (value.m_data.m_value.array->empty()) if (v.m_data.m_value.array->empty())
{ {
// flatten empty array as null // flatten empty array as null
result[reference_string] = nullptr; result[path] = nullptr;
} }
else else
{ {
// iterate array and use index as a reference string stack.emplace_back(&v, object_const_iterator(), path.size());
for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
{
flatten(detail::concat<string_t>(reference_string, '/', std::to_string(i)),
value.m_data.m_value.array->operator[](i), result);
} }
} return;
break;
} }
case detail::value_t::object: case detail::value_t::object:
{ {
if (value.m_data.m_value.object->empty()) if (v.m_data.m_value.object->empty())
{ {
// flatten empty object as null // flatten empty object as null
result[reference_string] = nullptr; result[path] = nullptr;
} }
else else
{ {
// iterate object and use keys as reference string stack.emplace_back(&v, v.m_data.m_value.object->begin(), path.size());
for (const auto& element : *value.m_data.m_value.object)
{
flatten(detail::concat<string_t>(reference_string, '/', detail::escape(element.first)), element.second, result);
} }
} return;
break;
} }
case detail::value_t::null: case detail::value_t::null:
@@ -20843,8 +20926,50 @@ class json_pointer
default: default:
{ {
// add a primitive value with its reference string // add a primitive value with its reference string
result[reference_string] = value; result[path] = v;
break; return;
}
}
};
enter(value);
while (!stack.empty())
{
// the frame is changed through stack.back(): enter() may push a
// frame, which would invalidate a reference to it
const BasicJsonType* const container = stack.back().container;
// drop the path of the previous child
path.resize(stack.back().path_length);
if (container->is_array())
{
const auto& array = *container->m_data.m_value.array;
const std::size_t i = stack.back().index;
if (i == array.size())
{
stack.pop_back();
continue;
}
// iterate array and use index as a reference string
++stack.back().index;
detail::concat_into(path, '/', detail::to_string<string_t>(i));
enter(array[i]);
}
else
{
const object_const_iterator it = stack.back().member;
if (it == container->m_data.m_value.object->end())
{
stack.pop_back();
continue;
}
// iterate object and use keys as reference string
++stack.back().member;
detail::concat_into(path, '/', detail::escape(it->first));
enter(it->second);
} }
} }
} }
@@ -20872,19 +20997,15 @@ class json_pointer
// collect the pointer prefixes that have a reference token 0 among // collect the pointer prefixes that have a reference token 0 among
// their children; the values below them are arrays, all others are // their children; the values below them are arrays, all others are
// objects (see array_parents_t) // objects (see prefix_tree)
array_parents_t array_parents; prefix_tree tree;
for (const auto& element : *value.m_data.m_value.object) for (const auto& element : *value.m_data.m_value.object)
{ {
json_pointer ptr(element.first); json_pointer ptr(element.first);
std::vector<string_t> prefix; std::size_t id = 0;
for (auto& reference_token : ptr.reference_tokens) for (auto& reference_token : ptr.reference_tokens)
{ {
if (reference_token == "0") id = tree.add_child(id, std::move(reference_token));
{
array_parents.insert(prefix);
}
prefix.push_back(std::move(reference_token));
} }
} }
@@ -20900,7 +21021,7 @@ class json_pointer
// that if the JSON pointer is "" (i.e., points to the whole value), // that if the JSON pointer is "" (i.e., points to the whole value),
// function get_and_create returns a reference to the result itself. // function get_and_create returns a reference to the result itself.
// An assignment will then create a primitive value. // An assignment will then create a primitive value.
json_pointer(element.first).get_and_create(result, array_parents) = element.second; json_pointer(element.first).get_and_create(result, tree) = element.second;
} }
return result; return result;
@@ -21581,6 +21702,12 @@ template<typename BasicJsonType, typename CharType, typename OutputSinkType = ou
class binary_writer class binary_writer
{ {
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
/// an object key as string_t: a reference when object_t::key_type already is
/// string_t, otherwise a converted copy that outlives sanitize_utf8_for_write's result
using object_key_string_t = typename std::conditional <
std::is_same<typename BasicJsonType::object_t::key_type, string_t>::value,
const string_t&, string_t >::type;
using binary_t = typename BasicJsonType::binary_t; using binary_t = typename BasicJsonType::binary_t;
using number_float_t = typename BasicJsonType::number_float_t; using number_float_t = typename BasicJsonType::number_float_t;
@@ -21740,16 +21867,7 @@ class binary_writer
case value_t::string: case value_t::string:
{ {
string_t storage; write_cbor_string(*j.m_data.m_value.string, j);
const string_t& value = sanitize_utf8_for_write(*j.m_data.m_value.string, j, storage);
// step 1: write control byte and the string length
write_cbor_head(0x60, value.size());
// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(value.data()),
value.size());
break; break;
} }
@@ -21812,23 +21930,20 @@ class binary_writer
case value_t::object: case value_t::object:
{ {
static_assert(
std::is_convertible <
typename BasicJsonType::object_t::key_type,
string_t >::value,
"object_t::key_type must be implicitly convertible to string_t");
// step 1: write control byte and the object size // step 1: write control byte and the object size
write_cbor_head(0xA0, j.m_data.m_value.object->size()); write_cbor_head(0xA0, j.m_data.m_value.object->size());
for (const auto& el : *j.m_data.m_value.object) for (const auto& el : *j.m_data.m_value.object)
{ {
// el.first is checked here, against the object as // el.first is written directly (not via a temporary
// diagnostics context, because write_cbor(el.first) // basic_json), with the object as diagnostics context
// converts it to a temporary basic_json that would be write_cbor_string(el.first, j);
// used as the context instead; for error_handler_t::keep
// and ::replace/::ignore the recursive write_cbor(el.first)
// call below handles the key like any other string, so no
// separate check is needed here for those
if (error_handler == error_handler_t::strict)
{
check_utf8(el.first, j);
}
write_cbor(el.first);
write_cbor(el.second, depth + 1); write_cbor(el.second, depth + 1);
} }
break; break;
@@ -21987,39 +22102,7 @@ class binary_writer
case value_t::string: case value_t::string:
{ {
string_t storage; write_msgpack_string(*j.m_data.m_value.string, j);
const string_t& value = sanitize_utf8_for_write(*j.m_data.m_value.string, j, storage);
// step 1: write control byte and the string length
const auto N = to_msgpack_length(value.size(), j);
if (N <= 31)
{
// fixstr
write_number(static_cast<std::uint8_t>(0xA0 | N));
}
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{
// str 8
oa.write_character(to_char_type(0xD9));
write_number(static_cast<std::uint8_t>(N));
}
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{
// str 16
oa.write_character(to_char_type(0xDA));
write_number(static_cast<std::uint16_t>(N));
}
else
{
// str 32
oa.write_character(to_char_type(0xDB));
write_number(static_cast<std::uint32_t>(N));
}
// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(value.data()),
value.size());
break; break;
} }
@@ -22125,19 +22208,20 @@ class binary_writer
case value_t::object: case value_t::object:
{ {
static_assert(
std::is_convertible <
typename BasicJsonType::object_t::key_type,
string_t >::value,
"object_t::key_type must be implicitly convertible to string_t");
// step 1: write control byte and the object size // step 1: write control byte and the object size
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j); write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
for (const auto& el : *j.m_data.m_value.object) for (const auto& el : *j.m_data.m_value.object)
{ {
// as in write_cbor, el.first is checked here against the // as in write_cbor, el.first is written directly with the
// object as diagnostics context; the recursive call below // object as diagnostics context
// handles keep/replace/ignore like any other string write_msgpack_string(el.first, j);
if (error_handler == error_handler_t::strict)
{
check_utf8(el.first, j);
}
write_msgpack(el.first);
write_msgpack(el.second, depth + 1); write_msgpack(el.second, depth + 1);
} }
break; break;
@@ -22315,8 +22399,10 @@ class binary_writer
for (const auto& el : *j.m_data.m_value.object) for (const auto& el : *j.m_data.m_value.object)
{ {
// a converted key must outlive the reference returned by sanitize_utf8_for_write
const object_key_string_t key_string = el.first;
string_t storage; string_t storage;
const string_t& key = sanitize_utf8_for_write(el.first, j, storage); const string_t& key = sanitize_utf8_for_write(key_string, j, storage);
write_number_with_ubjson_prefix(key.size(), true, use_bjdata); write_number_with_ubjson_prefix(key.size(), true, use_bjdata);
oa.write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(key.data()), reinterpret_cast<const CharType*>(key.data()),
@@ -22521,13 +22607,9 @@ class binary_writer
continue; continue;
} }
// el.first is checked here, against the object as diagnostics // the key is written directly (not via a temporary basic_json),
// context, like the matching check in write_cbor's object case // with the object as diagnostics context, as in write_cbor
if (error_handler == error_handler_t::strict) write_cbor_string(current.object_it->first, *current.value);
{
check_utf8(current.object_it->first, *current.value);
}
write_cbor(current.object_it->first);
const BasicJsonType* child = &(current.object_it->second); const BasicJsonType* child = &(current.object_it->second);
++stack.back().object_it; ++stack.back().object_it;
write_cbor_value_or_push(*child, stack); write_cbor_value_or_push(*child, stack);
@@ -22602,11 +22684,9 @@ class binary_writer
continue; continue;
} }
if (error_handler == error_handler_t::strict) // as in write_cbor_iterative, the key is written directly with
{ // the object as diagnostics context
check_utf8(current.object_it->first, *current.value); write_msgpack_string(current.object_it->first, *current.value);
}
write_msgpack(current.object_it->first);
const BasicJsonType* child = &(current.object_it->second); const BasicJsonType* child = &(current.object_it->second);
++stack.back().object_it; ++stack.back().object_it;
write_msgpack_value_or_push(*child, stack); write_msgpack_value_or_push(*child, stack);
@@ -22862,8 +22942,10 @@ class binary_writer
continue; continue;
} }
// a converted key must outlive the reference returned by sanitize_utf8_for_write
const object_key_string_t key_string = current.object_it->first;
string_t storage; string_t storage;
const string_t& key = sanitize_utf8_for_write(current.object_it->first, j, storage); const string_t& key = sanitize_utf8_for_write(key_string, j, storage);
write_number_with_ubjson_prefix(key.size(), true, use_bjdata); write_number_with_ubjson_prefix(key.size(), true, use_bjdata);
oa.write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(key.data()), reinterpret_cast<const CharType*>(key.data()),
@@ -23484,6 +23566,85 @@ class binary_writer
} }
} }
/*!
@brief write a CBOR text string
@a value is checked or sanitized according to @ref error_handler, with
@a context (the string value itself, or the object a key belongs to) used
as diagnostics context; this avoids converting object keys to a temporary
basic_json just to write them
@note When object_t::key_type is not string_t, @a value is a temporary
string_t converted from the key, which lives only until the end of
the caller's statement. The reference returned by
@ref sanitize_utf8_for_write may refer to it, so it must not escape
this function.
*/
void write_cbor_string(const string_t& value, const BasicJsonType& context)
{
string_t storage;
const string_t& sanitized = sanitize_utf8_for_write(value, context, storage);
// step 1: write control byte and the string length
write_cbor_head(0x60, sanitized.size());
// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(sanitized.data()),
sanitized.size());
}
/////////////
// MsgPack //
/////////////
/*!
@brief write a MessagePack str
@a value is checked or sanitized according to @ref error_handler, with
@a context used as diagnostics context, as in @ref write_cbor_string
@note As in @ref write_cbor_string, @a value may be a temporary string_t
converted from a key, so the reference returned by
@ref sanitize_utf8_for_write must not escape this function.
*/
void write_msgpack_string(const string_t& value, const BasicJsonType& context)
{
string_t storage;
const string_t& sanitized = sanitize_utf8_for_write(value, context, storage);
// step 1: write control byte and the string length
const auto N = to_msgpack_length(sanitized.size(), context);
if (N <= 31)
{
// fixstr
write_number(static_cast<std::uint8_t>(0xA0 | N));
}
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{
// str 8
oa.write_character(to_char_type(0xD9));
write_number(static_cast<std::uint8_t>(N));
}
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{
// str 16
oa.write_character(to_char_type(0xDA));
write_number(static_cast<std::uint16_t>(N));
}
else
{
// str 32
oa.write_character(to_char_type(0xDB));
write_number(static_cast<std::uint32_t>(N));
}
// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(sanitized.data()),
sanitized.size());
}
//////////// ////////////
// UBJSON // // UBJSON //
//////////// ////////////
@@ -24226,6 +24387,11 @@ class binary_writer
itself in every case but a sanitized `replace`/`ignore` one, so @a itself in every case but a sanitized `replace`/`ignore` one, so @a
storage must outlive the returned reference only then. storage must outlive the returned reference only then.
@a s must be an lvalue that outlives the returned reference. An object key
whose `key_type` is not @ref string_t must therefore first be converted
into a named string_t (see @ref object_key_string_t); the deleted overload
below enforces this at compile time.
@param[in] s the string (value or object key) to write @param[in] s the string (value or object key) to write
@param[in] context the value @a s belongs to (for diagnostics) @param[in] context the value @a s belongs to (for diagnostics)
@param[out] storage backing storage for a sanitized copy @param[out] storage backing storage for a sanitized copy
@@ -24255,6 +24421,10 @@ class binary_writer
} }
} }
/// deleted: anything but a string_t would bind a temporary that dies before the returned reference is used
template < typename T, enable_if_t < !std::is_same<T, string_t>::value, int > = 0 >
const string_t& sanitize_utf8_for_write(const T& /*s*/, const BasicJsonType& /*context*/, string_t& /*storage*/) const = delete; // NOLINT(hicpp-use-equals-delete,modernize-use-equals-delete): a private helper's guard, not part of the interface
/*! /*!
@brief write an integer in the shortest encoding @brief write an integer in the shortest encoding
+2 -1
View File
@@ -138,7 +138,8 @@ json_test_set_test_options(test-disabled_exceptions
# only the #972 regression test needs thirdparty/fifo_map on its include path # only the #972 regression test needs thirdparty/fifo_map on its include path
json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include) json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include)
# GCC's false -Warray-bounds error with JSON_DIAGNOSTICS only shows up when optimizing (#5742). # Regression test for GCC's false -Warray-bounds error with JSON_DIAGNOSTICS (#5742, fixed in #5585). It only
# showed up when optimizing, so build this test with -O3 and the warning as an error.
# -O3 makes the optimizer-driven warnings of the ci_test_gcc flag set (-Winline, # -O3 makes the optimizer-driven warnings of the ci_test_gcc flag set (-Winline,
# -Wsuggest-attribute=...) fire on the library's inline functions; they are not # -Wsuggest-attribute=...) fire on the library's inline functions; they are not
# what this test checks, so turn them off for it. # what this test checks, so turn them off for it.
+75
View File
@@ -0,0 +1,75 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#pragma once
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <nlohmann/json.hpp>
namespace custom_object_key_test
{
class key
{
public:
key() = default;
key(const char* value)
: m_value(value)
{}
key(std::string value)
: m_value(std::move(value))
{}
operator std::string() const
{
return m_value;
}
// Required by JSON_DIAGNOSTICS, which reads object keys through data()
// when building the path of an exception.
const char* data() const noexcept
{
return m_value.data();
}
friend bool operator<(const key& lhs, const key& rhs)
{
return lhs.m_value < rhs.m_value;
}
private:
std::string m_value;
};
template<typename Key, typename Value, typename Compare, typename Allocator>
class object
: public std::map <
key,
Value,
std::less<key>, // NOLINT(modernize-use-transparent-functors)
typename std::allocator_traits<Allocator>::template rebind_alloc <
std::pair<const key, Value >>>
{
private:
using allocator_type =
typename std::allocator_traits<Allocator>::template rebind_alloc <
std::pair<const key, Value >>;
using base_type =
std::map<key, Value, std::less<key>, allocator_type>; // NOLINT(modernize-use-transparent-functors)
public:
using base_type::base_type;
};
using json = nlohmann::basic_json<object>;
} // namespace custom_object_key_test
+6 -48
View File
@@ -370,14 +370,7 @@ TEST_CASE("copy of a deeply nested value survives a failing allocation (#5640)")
#if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0) #if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
SECTION("std::map-backed object_t") SECTION("std::map-backed object_t")
{ {
using bad_alloc_json = nlohmann::basic_json<std::map, using bad_alloc_json = nlohmann::json::with_allocator_t<nth_alloc_fails_allocator>;
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
nth_alloc_fails_allocator>;
check_deep_copy_survives_failing_allocation<bad_alloc_json>(false); check_deep_copy_survives_failing_allocation<bad_alloc_json>(false);
check_deep_copy_survives_failing_allocation<bad_alloc_json>(true); check_deep_copy_survives_failing_allocation<bad_alloc_json>(true);
@@ -385,14 +378,7 @@ TEST_CASE("copy of a deeply nested value survives a failing allocation (#5640)")
SECTION("ordered_map-backed object_t") SECTION("ordered_map-backed object_t")
{ {
using bad_alloc_ordered_json = nlohmann::basic_json<nlohmann::ordered_map, using bad_alloc_ordered_json = nlohmann::ordered_json::with_allocator_t<nth_alloc_fails_allocator>;
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
nth_alloc_fails_allocator>;
check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(false); check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(false);
check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(true); check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(true);
@@ -450,14 +436,7 @@ struct scratch_counting_allocator : std::allocator<T>
TEST_CASE("deep copy uses the provided allocator") TEST_CASE("deep copy uses the provided allocator")
{ {
using counting_json = nlohmann::basic_json<std::map, using counting_json = nlohmann::json::with_allocator_t<scratch_counting_allocator>;
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
scratch_counting_allocator>;
// deeper than the 128 levels the copy constructor descends into, so the // deeper than the 128 levels the copy constructor descends into, so the
// innermost objects are copied by the iterative deep copy // innermost objects are copied by the iterative deep copy
@@ -516,14 +495,7 @@ TEST_CASE("converting a deeply nested value from another specialization fails cl
// the allocator in noexcept constructors, so a failing construction crashes // the allocator in noexcept constructors, so a failing construction crashes
// the program there instead of throwing std::bad_alloc. Nothing to check. // the program there instead of throwing std::bad_alloc. Nothing to check.
#if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0) #if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
using countdown_json = nlohmann::basic_json<std::map, using countdown_json = nlohmann::json::with_allocator_t<countdown_allocator>;
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
countdown_allocator>;
// deeper than the 128 levels the converting constructor descends into, so // deeper than the 128 levels the converting constructor descends into, so
// that failures land on both sides of the bound - or, built with // that failures land on both sides of the bound - or, built with
@@ -631,14 +603,7 @@ TEST_CASE("destructor performs no allocation, only deallocation")
// Since that stack could itself throw bad_alloc from inside the // Since that stack could itself throw bad_alloc from inside the
// noexcept destructor (#5135), destroy() no longer allocates anything: // noexcept destructor (#5135), destroy() no longer allocates anything:
// it only ever frees what is already there. // it only ever frees what is already there.
using counting_json = nlohmann::basic_json<std::map, using counting_json = nlohmann::json::with_allocator_t<counting_allocator>;
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
counting_allocator>;
SECTION("array") SECTION("array")
{ {
@@ -683,14 +648,7 @@ TEST_CASE("destructor performs no allocation, only deallocation")
TEST_CASE("a failed allocation leaves the value unchanged") TEST_CASE("a failed allocation leaves the value unchanged")
{ {
// create JSON type using the throwing allocator // create JSON type using the throwing allocator
using my_json = nlohmann::basic_json<std::map, using my_json = nlohmann::json::with_allocator_t<my_allocator>;
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
my_allocator>;
// Each of these creates a string, array, object, or binary value. The // Each of these creates a string, array, object, or binary value. The
// value must be created before the type is changed: otherwise, a failed // value must be created before the type is changed: otherwise, a failed
+1 -1
View File
@@ -237,7 +237,7 @@ namespace
// the binary formats as function pointers for "Binary formats with narrow number types"; // the binary formats as function pointers for "Binary formats with narrow number types";
// named functions rather than lambdas, because clang 3.5 cannot convert a lambda // named functions rather than lambdas, because clang 3.5 cannot convert a lambda
// to a function pointer in the braced initializer of the format table // to a function pointer in the braced initializer of the format table
using narrow_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int32_t, std::uint32_t, float>; using narrow_json = nlohmann::json::with_integers_t<std::int32_t, std::uint32_t>::with_float_t<float>;
using bytes = std::vector<std::uint8_t>; using bytes = std::vector<std::uint8_t>;
bytes encode_cbor(const json& j) bytes encode_cbor(const json& j)
@@ -12,7 +12,11 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#include <array>
#include <map>
#include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
namespace namespace
@@ -55,6 +59,53 @@ std::string dump_and_parse(const std::string& raw, eh error_handler)
return json::parse(json(raw).dump(-1, ' ', false, error_handler)).get<std::string>(); return json::parse(json(raw).dump(-1, ' ', false, error_handler)).get<std::string>();
} }
// an object key type that is not string_t, but converts implicitly to it;
// data() is only used when JSON_DIAGNOSTICS is enabled
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function")
class converting_key
{
public:
converting_key(const char* s) : m_value(s) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
converting_key(std::string s) : m_value(std::move(s)) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
// the conversion yields a temporary string_t
operator std::string() const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
{
return m_value;
}
// read by the exception messages when JSON_DIAGNOSTICS is enabled
const char* data() const noexcept
{
return m_value.data();
}
friend bool operator<(const converting_key& lhs, const converting_key& rhs)
{
return lhs.m_value < rhs.m_value;
}
private:
std::string m_value;
};
DOCTEST_CLANG_SUPPRESS_WARNING_POP
// ObjectType using converting_key; the Key template argument is ignored
template<typename Key, typename Value, typename Compare, typename Allocator>
class converting_key_object : public std::map<converting_key, Value, std::less<converting_key>, // NOLINT(modernize-use-transparent-functors)
typename std::allocator_traits<Allocator>::template rebind_alloc<std::pair<const converting_key, Value>>>
{
using base_type = std::map<converting_key, Value, std::less<converting_key>, // NOLINT(modernize-use-transparent-functors)
typename std::allocator_traits<Allocator>::template rebind_alloc<std::pair<const converting_key, Value>>>;
public:
using base_type::base_type;
using base_type::operator=;
};
using converting_key_json = nlohmann::basic_json<converting_key_object>;
} // namespace } // namespace
TEST_CASE("UTF-8 error_handler for the binary readers and writers") TEST_CASE("UTF-8 error_handler for the binary readers and writers")
@@ -370,3 +421,109 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
CHECK(json::from_bson(bson_bytes)["k"].get<std::string>() == ill_formed_cases()[0].bytes); CHECK(json::from_bson(bson_bytes)["k"].get<std::string>() == ill_formed_cases()[0].bytes);
} }
} }
// The UBJSON and BJData writers bind the (possibly sanitized) key to a const
// string_t&. If key_type is not string_t but converts to it, the converted
// temporary must outlive that reference; this was a use-after-scope found by
// AddressSanitizer. Keys exceed the small string optimization on purpose.
TEST_CASE("UBJSON and BJData writers with an object_t whose key_type is not string_t")
{
const std::string long_prefix(70, 'k');
SECTION("well-formed keys, every error_handler")
{
const std::string key1 = long_prefix + "-first";
const std::string key2 = long_prefix + "-second";
converting_key_json::object_t o;
o.emplace(converting_key(key1), 1);
o.emplace(converting_key(key2), "value");
const converting_key_json v(std::move(o));
json expected;
expected[key1] = 1;
expected[key2] = "value";
const std::array<std::pair<bool, bool>, 3> combos = {{{false, false}, {true, false}, {true, true}}};
for (const auto h : all_handlers())
{
CAPTURE(static_cast<int>(h))
for (const auto& combo : combos)
{
const bool use_count = combo.first;
const bool use_type = combo.second;
CAPTURE(use_count)
CAPTURE(use_type)
CHECK(json::from_ubjson(converting_key_json::to_ubjson(v, use_count, use_type, h)) == expected);
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, use_count, use_type, json::bjdata_version_t::draft2, h)) == expected);
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, use_count, use_type, json::bjdata_version_t::draft3, h)) == expected);
}
}
}
SECTION("ill-formed keys")
{
for (const auto& c : ill_formed_cases())
{
CAPTURE(c.name)
const std::string key = long_prefix + c.bytes;
converting_key_json::object_t o;
o.emplace(converting_key(key), 1);
const converting_key_json v(std::move(o));
CHECK_THROWS_AS(converting_key_json::to_ubjson(v, false, false, eh::strict), converting_key_json::type_error&);
CHECK_THROWS_AS(converting_key_json::to_bjdata(v, false, false, json::bjdata_version_t::draft2, eh::strict), converting_key_json::type_error&);
for (const auto h :
{
eh::replace, eh::ignore
})
{
CAPTURE(static_cast<int>(h))
const std::string expected = dump_and_parse(key, h);
CHECK(json::from_ubjson(converting_key_json::to_ubjson(v, false, false, h)).begin().key() == expected);
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, false, false, json::bjdata_version_t::draft2, h)).begin().key() == expected);
}
CHECK(json::from_ubjson(converting_key_json::to_ubjson(v, false, false, eh::keep)).begin().key() == key);
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, false, false, json::bjdata_version_t::draft2, eh::keep)).begin().key() == key);
}
}
SECTION("nested deeper than the recursion limit")
{
// wrap the previous value, innermost first
converting_key_json v = 42;
json expected = 42;
for (int i = 199; i >= 0; --i)
{
const std::string key = "level-" + std::to_string(i) + "-" + std::string(64, 'x');
converting_key_json::object_t o;
o.emplace(converting_key(key), std::move(v));
v = converting_key_json(std::move(o));
json e;
e[key] = std::move(expected);
expected = std::move(e);
}
for (const auto h : all_handlers())
{
CAPTURE(static_cast<int>(h))
for (const bool use_count :
{
false, true
})
{
CAPTURE(use_count)
CHECK(json::from_ubjson(converting_key_json::to_ubjson(v, use_count, false, h)) == expected);
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, use_count, false, json::bjdata_version_t::draft2, h)) == expected);
}
}
}
}
+2 -6
View File
@@ -46,9 +46,7 @@ class huge_binary_t : public std::vector<std::uint8_t>
} }
}; };
using huge_binary_json = nlohmann::basic_json < using huge_binary_json = nlohmann::json::with_binary_t<huge_binary_t>;
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
double, std::allocator, nlohmann::adl_serializer, huge_binary_t, void >;
// a string type that can be made to report a size beyond INT32_MAX without // a string type that can be made to report a size beyond INT32_MAX without
// allocating that much memory, so BSON length overflow can be tested for // allocating that much memory, so BSON length overflow can be tested for
@@ -96,9 +94,7 @@ class huge_string_t : public std::string
bool pretend_huge = false; bool pretend_huge = false;
}; };
using huge_string_json = nlohmann::basic_json < using huge_string_json = nlohmann::json::with_string_t<huge_string_t>;
std::map, std::vector, huge_string_t, bool, std::int64_t, std::uint64_t,
double, std::allocator, nlohmann::adl_serializer, std::vector<std::uint8_t>, void >;
} // namespace } // namespace
TEST_CASE("BSON") TEST_CASE("BSON")
+34 -3
View File
@@ -17,6 +17,7 @@ using nlohmann::json;
#include <cstdint> // uint32_t, uint64_t #include <cstdint> // uint32_t, uint64_t
#include <cstdlib> // strtod #include <cstdlib> // strtod
#include <cstring> // memcpy #include <cstring> // memcpy
#include <limits> // numeric_limits
#include <sstream> // stringstream #include <sstream> // stringstream
#include <string> // string #include <string> // string
#include <utility> // pair #include <utility> // pair
@@ -891,8 +892,39 @@ TEST_CASE("Eisel-Lemire float conversion")
SECTION("128-bit products and leading zeros") SECTION("128-bit products and leading zeros")
{ {
const auto check_product = [](std::uint64_t a, std::uint64_t b)
{
const auto product = nlohmann::detail::full_multiplication(a, b);
CHECK(big_from(product.high, product.low) == big_mul(big_from(0, a), big_from(0, b)));
};
const std::uint64_t max = (std::numeric_limits<std::uint64_t>::max)();
const std::array<std::pair<std::uint64_t, std::uint64_t>, 13> edge_cases =
{
{
{0, 0},
{0, 1},
{1, 1},
{1, max},
{0xFFFFFFFFu, 0x100000000u},
{0x100000000u, 0x100000000u},
{0x100000001u, 0x100000001u},
{max, max},
{max, 2},
{0xFFFFFFFF00000000u, 0x100000001u},
{0x100000001u, 0xFFFFFFFF00000000u},
{max, 1},
{2, max},
}
};
for (const auto& test : edge_cases)
{
check_product(test.first, test.second);
}
// whichever implementation the compiler gets (with or without a // whichever implementation the compiler gets (with or without a
// 128-bit integer type or a builtin) // 128-bit integer type or a builtin / intrinsic)
std::uint64_t state = 42; std::uint64_t state = 42;
for (int i = 0; i < 10000; ++i) for (int i = 0; i < 10000; ++i)
{ {
@@ -901,8 +933,7 @@ TEST_CASE("Eisel-Lemire float conversion")
state ^= state << 17u; state ^= state << 17u;
const std::uint64_t a = state; const std::uint64_t a = state;
const std::uint64_t b = (state * 0x9E3779B97F4A7C15u) >> (i % 64); const std::uint64_t b = (state * 0x9E3779B97F4A7C15u) >> (i % 64);
const auto product = nlohmann::detail::full_multiplication(a, b); check_product(a, b);
CHECK(big_from(product.high, product.low) == big_mul(big_from(0, a), big_from(0, b)));
const int k = i % 64; const int k = i % 64;
const std::uint64_t x = (std::uint64_t{1} << k) | (a & ((std::uint64_t{1} << k) - 1)); const std::uint64_t x = (std::uint64_t{1} << k) | (a & ((std::uint64_t{1} << k) - 1));
+3 -3
View File
@@ -824,7 +824,7 @@ struct unordered_object_t : std::map<Key, Value, directed_less<Key>, Allocator>
return !(lhs == rhs); return !(lhs == rhs);
} }
}; };
using unordered_json = nlohmann::basic_json<unordered_object_t>; using unordered_json = nlohmann::json::with_object_t<unordered_object_t>;
// the entries "0" to "9", enumerated in ascending or in descending order // the entries "0" to "9", enumerated in ascending or in descending order
unordered_json make_unordered_object(const bool descending) unordered_json make_unordered_object(const bool descending)
@@ -875,7 +875,7 @@ struct key_case_less
template<class Key, class Value, class /*Compare*/, class Allocator> template<class Key, class Value, class /*Compare*/, class Allocator>
using key_case_map = std::map<Key, Value, key_case_less, Allocator>; using key_case_map = std::map<Key, Value, key_case_less, Allocator>;
using key_case_json = nlohmann::basic_json<key_case_map>; using key_case_json = nlohmann::json::with_object_t<key_case_map>;
// the innermost value of a chain of single-element arrays // the innermost value of a chain of single-element arrays
template<typename Json> template<typename Json>
@@ -905,7 +905,7 @@ struct case_insensitive_less
template<class Key, class Value, class /*Compare*/, class Allocator> template<class Key, class Value, class /*Compare*/, class Allocator>
using case_insensitive_map = std::map<Key, Value, case_insensitive_less, Allocator>; using case_insensitive_map = std::map<Key, Value, case_insensitive_less, Allocator>;
using ci_json = nlohmann::basic_json<case_insensitive_map>; using ci_json = nlohmann::json::with_object_t<case_insensitive_map>;
} // namespace } // namespace
TEST_CASE("equality of objects whose entries have no fixed order") TEST_CASE("equality of objects whose entries have no fixed order")
+2 -2
View File
@@ -22,7 +22,7 @@ namespace
// std::deque has no capacity() member function, which the library only needs // std::deque has no capacity() member function, which the library only needs
// to detect a reallocation for JSON_DIAGNOSTICS // to detect a reallocation for JSON_DIAGNOSTICS
using deque_json = nlohmann::basic_json<std::map, std::deque>; using deque_json = nlohmann::json::with_array_t<std::deque>;
// a std::vector whose at() is hidden: the library performs its own bounds // a std::vector whose at() is hidden: the library performs its own bounds
// check and must not fall back to the container's checked accessor // check and must not fall back to the container's checked accessor
@@ -39,7 +39,7 @@ class vector_without_at : public std::vector<T, Allocator>
void at() = delete; void at() = delete;
}; };
using no_at_json = nlohmann::basic_json<std::map, vector_without_at>; using no_at_json = nlohmann::json::with_array_t<vector_without_at>;
} // namespace } // namespace
+2 -27
View File
@@ -400,20 +400,7 @@ class base_class_with_hidden_members
std::size_t m_size = 42; std::size_t m_size = 42;
}; };
using json_with_hidden_base_members = using json_with_hidden_base_members = nlohmann::json::with_base_class_t<base_class_with_hidden_members>;
nlohmann::basic_json <
std::map,
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
std::allocator,
nlohmann::adl_serializer,
std::vector<std::uint8_t>,
base_class_with_hidden_members
>;
TEST_CASE("JSON Node as_base_class") TEST_CASE("JSON Node as_base_class")
{ {
@@ -459,19 +446,7 @@ struct const_member_base
const int id = 7; // NOLINT(misc-non-private-member-variables-in-classes) const int id = 7; // NOLINT(misc-non-private-member-variables-in-classes)
}; };
using json_with_const_base = nlohmann::basic_json < using json_with_const_base = nlohmann::json::with_base_class_t<const_member_base>;
std::map,
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
std::allocator,
nlohmann::adl_serializer,
std::vector<std::uint8_t>,
const_member_base
>;
// build an array nested @a depth levels deep, with the innermost value 1; // build an array nested @a depth levels deep, with the innermost value 1;
// every level is constructed (never assigned), since const_member_base does // every level is constructed (never assigned), since const_member_base does
+2 -6
View File
@@ -26,15 +26,11 @@ namespace
// a BinaryType whose value type is signed: the elements must still be // a BinaryType whose value type is signed: the elements must still be
// processed as the numbers 0..255 // processed as the numbers 0..255
using char_binary_json = nlohmann::basic_json < using char_binary_json = nlohmann::json::with_binary_t<std::vector<char>>;
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
double, std::allocator, nlohmann::adl_serializer, std::vector<char>, void >;
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
// a BinaryType whose value type is not an integer type at all // a BinaryType whose value type is not an integer type at all
using byte_binary_json = nlohmann::basic_json < using byte_binary_json = nlohmann::json::with_binary_t<std::vector<std::byte>>;
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
double, std::allocator, nlohmann::adl_serializer, std::vector<std::byte>, void >;
#endif #endif
} // namespace } // namespace
+127
View File
@@ -0,0 +1,127 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
#include <cstddef>
#include <string>
#include <utility>
#include "custom_object_key_type.hpp"
// These tests instantiate a second basic_json specialization. They live in
// their own file rather than in unit-cbor.cpp and unit-msgpack.cpp to keep
// those objects below 65535 sections: the MinGW linker stores the section a
// COMDAT section is associated with in 16 bits, so it misplaces the jump
// tables of larger objects (see the clang job in windows.yml).
TEST_CASE("CBOR supports custom object key types")
{
using custom_json = custom_object_key_test::json;
using custom_key = custom_object_key_test::key;
custom_json::object_t object;
object.emplace(custom_key{"short"}, 1);
object.emplace(
custom_key{"a key longer than twenty-three characters"},
2);
const custom_json value(std::move(object));
const auto encoded = custom_json::to_cbor(value);
CHECK(nlohmann::json::from_cbor(encoded) == nlohmann::json
{
{"short", 1},
{"a key longer than twenty-three characters", 2}
});
}
TEST_CASE("CBOR supports custom object key types nested deeper than the recursion depth limit")
{
// below detail::recursion_depth_limit(), keys are written by
// write_cbor_iterative instead of write_cbor
using custom_json = custom_object_key_test::json;
using custom_key = custom_object_key_test::key;
const std::size_t depth = nlohmann::detail::recursion_depth_limit() + 10;
custom_json value = 1;
nlohmann::json expected = 1;
for (std::size_t i = 0; i < depth; ++i)
{
// alternate short keys with ones long enough to need a length byte
const std::string name = (i % 2 == 0) ? "k" + std::to_string(i)
: "a key longer than thirty-one characters " + std::to_string(i);
custom_json::object_t object;
object.emplace(custom_key{name}, std::move(value));
value = custom_json(std::move(object));
nlohmann::json::object_t expected_object;
expected_object.emplace(name, std::move(expected));
expected = nlohmann::json(std::move(expected_object));
}
const auto encoded = custom_json::to_cbor(value);
CHECK(encoded == nlohmann::json::to_cbor(expected));
CHECK(nlohmann::json::from_cbor(encoded) == expected);
}
TEST_CASE("MessagePack supports custom object key types")
{
using custom_json = custom_object_key_test::json;
using custom_key = custom_object_key_test::key;
custom_json::object_t object;
object.emplace(custom_key{"short"}, 1);
object.emplace(
custom_key{"a key longer than thirty-one characters"},
2);
const custom_json value(std::move(object));
const auto encoded = custom_json::to_msgpack(value);
CHECK(nlohmann::json::from_msgpack(encoded) == nlohmann::json
{
{"short", 1},
{"a key longer than thirty-one characters", 2}
});
}
TEST_CASE("MessagePack supports custom object key types nested deeper than the recursion depth limit")
{
// below detail::recursion_depth_limit(), keys are written by
// write_msgpack_iterative instead of write_msgpack
using custom_json = custom_object_key_test::json;
using custom_key = custom_object_key_test::key;
const std::size_t depth = nlohmann::detail::recursion_depth_limit() + 10;
custom_json value = 1;
nlohmann::json expected = 1;
for (std::size_t i = 0; i < depth; ++i)
{
// alternate short keys with ones long enough to need a length byte
const std::string name = (i % 2 == 0) ? "k" + std::to_string(i)
: "a key longer than thirty-one characters " + std::to_string(i);
custom_json::object_t object;
object.emplace(custom_key{name}, std::move(value));
value = custom_json(std::move(object));
nlohmann::json::object_t expected_object;
expected_object.emplace(name, std::move(expected));
expected = nlohmann::json(std::move(expected_object));
}
const auto encoded = custom_json::to_msgpack(value);
CHECK(encoded == nlohmann::json::to_msgpack(expected));
CHECK(nlohmann::json::from_msgpack(encoded) == expected);
}
+3 -3
View File
@@ -179,7 +179,7 @@ class no_key_compare_map
} }
}; };
using no_key_compare_json = nlohmann::basic_json<no_key_compare_map>; using no_key_compare_json = nlohmann::json::with_object_t<no_key_compare_map>;
// An ObjectType whose erase(iterator) returns void rather than the following // An ObjectType whose erase(iterator) returns void rather than the following
// iterator, as for instance Abseil's hash maps do // iterator, as for instance Abseil's hash maps do
@@ -196,7 +196,7 @@ struct void_erase_map : std::map<Key, T, Compare, Allocator>
} }
}; };
using void_erase_json = nlohmann::basic_json<void_erase_map>; using void_erase_json = nlohmann::json::with_object_t<void_erase_map>;
// wraps an iterator, but only offers the LegacyForwardIterator operations, // wraps an iterator, but only offers the LegacyForwardIterator operations,
// like the iterators of std::unordered_map and other hash maps // like the iterators of std::unordered_map and other hash maps
@@ -388,7 +388,7 @@ class forward_only_map
} }
}; };
using forward_only_json = nlohmann::basic_json<forward_only_map>; using forward_only_json = nlohmann::json::with_object_t<forward_only_map>;
} // namespace } // namespace
+3 -3
View File
@@ -157,13 +157,13 @@ TEST_CASE("hash<nlohmann::json>")
// the ends of the integer ranges, which equal floats exactly // the ends of the integer ranges, which equal floats exactly
const auto int_min = (std::numeric_limits<json::number_integer_t>::min)(); const auto int_min = (std::numeric_limits<json::number_integer_t>::min)();
const auto int_max = (std::numeric_limits<json::number_integer_t>::max)(); const auto int_max = (std::numeric_limits<json::number_integer_t>::max)();
const auto two_63 = json::number_unsigned_t(1) << 63U; const auto two_63 = static_cast<json::number_unsigned_t>(1) << 63U;
CHECK(json(int_min) == json(-9223372036854775808.0)); CHECK(json(int_min) == json(-9223372036854775808.0));
CHECK(std::hash<json> {}(json(int_min)) == std::hash<json> {}(json(-9223372036854775808.0))); CHECK(std::hash<json> {}(json(int_min)) == std::hash<json> {}(json(-9223372036854775808.0)));
CHECK(json(two_63) == json(9223372036854775808.0)); CHECK(json(two_63) == json(9223372036854775808.0));
CHECK(std::hash<json> {}(json(two_63)) == std::hash<json> {}(json(9223372036854775808.0))); CHECK(std::hash<json> {}(json(two_63)) == std::hash<json> {}(json(9223372036854775808.0)));
CHECK(json(json::number_unsigned_t(int_max)) == json(int_max)); CHECK(json(static_cast<json::number_unsigned_t>(int_max)) == json(int_max));
CHECK(std::hash<json> {}(json(json::number_unsigned_t(int_max))) == std::hash<json> {}(json(int_max))); CHECK(std::hash<json> {}(json(static_cast<json::number_unsigned_t>(int_max))) == std::hash<json> {}(json(int_max)));
} }
TEST_CASE("hash<nlohmann::ordered_json>") TEST_CASE("hash<nlohmann::ordered_json>")
+111
View File
@@ -939,3 +939,114 @@ TEST_CASE("unescaping keeps a '~' that does not start an escape sequence")
nlohmann::detail::unescape(s); nlohmann::detail::unescape(s);
CHECK(s == "~/~"); CHECK(s == "~/~");
} }
TEST_CASE("flatten of structured values")
{
SECTION("values nested too deeply for the call stack (#5393)")
{
// flatten() used to recurse once per nesting level
const std::size_t depth = 100000;
for (const bool objects :
{
false, true
})
{
CAPTURE(objects)
std::string text;
std::string path;
for (std::size_t i = 0; i < depth; ++i)
{
text += objects ? "{\"a\":" : "[";
path += objects ? "/a" : "/0";
}
text += "0";
text += std::string(depth, objects ? '}' : ']');
const auto value = json::parse(text);
const auto flat = value.flatten();
REQUIRE(flat.size() == 1);
REQUIRE(flat.begin().key().size() == path.size());
CHECK(flat.begin().key() == path);
CHECK(flat.begin().value() == 0);
// unflatten() is linear in the depth, so the value roundtrips
CHECK(flat.unflatten() == value);
}
}
SECTION("unflatten of a deeply nested pointer")
{
const std::size_t depth = 100000;
for (const bool objects :
{
false, true
})
{
CAPTURE(objects)
std::string path;
for (std::size_t i = 0; i < depth; ++i)
{
path += objects ? "/a" : "/0";
}
json flat = json::object();
flat[path] = 1;
const json value = flat.unflatten();
// walk down iteratively
std::size_t levels = 0;
const json* current = &value;
while (objects ? current->is_object() : current->is_array())
{
REQUIRE(current->size() == 1);
current = objects ? &current->at("a") : &current->at(0);
++levels;
}
CHECK(levels == depth);
CHECK(*current == 1);
}
}
SECTION("unflatten does not depend on the iteration order")
{
// the "0" key comes after its sibling in iteration order
const nlohmann::ordered_json flat_array = nlohmann::ordered_json::parse(R"({"/a/1": 2, "/a/0": 1})");
CHECK(flat_array.unflatten() == nlohmann::ordered_json::parse(R"({"a": [1, 2]})"));
const nlohmann::ordered_json flat_object = nlohmann::ordered_json::parse(R"({"/b/1": 2})");
CHECK(flat_object.unflatten() == nlohmann::ordered_json::parse(R"({"b": {"1": 2}})"));
}
SECTION("objects and arrays interleaved")
{
const json value =
{
{"a", {1, {{"b", json::array()}, {"c", json::object()}}, json::array({{{"x~/", {true, nullptr}}}})}},
{"a/b", {{"~", 1}}},
{"z", "s"}
};
const json expected =
{
{"/a/0", 1},
{"/a/1/b", nullptr},
{"/a/1/c", nullptr},
{"/a/2/0/x~0~1/0", true},
{"/a/2/0/x~0~1/1", nullptr},
{"/a~1b/~0", 1},
{"/z", "s"}
};
CHECK(value.flatten() == expected);
}
SECTION("order of the entries of an ordered_json")
{
const auto value = nlohmann::ordered_json::parse(
R"({"z":"s","a/b":{"~":1,"k":[]},"a":[1,{"c":{},"b":[]},[{"x~/":[true,null],"w":2}]]})");
const auto flat = value.flatten();
CHECK(flat.dump() ==
R"({"/z":"s","/a~1b/~0":1,"/a~1b/k":null,"/a/0":1,"/a/1/c":null,"/a/1/b":null,"/a/2/0/x~0~1/0":true,"/a/2/0/x~0~1/1":null,"/a/2/0/w":2})");
}
}
+18 -6
View File
@@ -426,7 +426,7 @@ TEST_CASE("issue #5392 - binary writers on deeply nested values")
{ {
for (std::size_t depth = 120; depth <= 140; ++depth) for (std::size_t depth = 120; depth <= 140; ++depth)
{ {
CAPTURE(depth); CAPTURE(depth)
const json array = nested_array(depth, json(7)); const json array = nested_array(depth, json(7));
CHECK(json::from_cbor(json::to_cbor(array)) == array); CHECK(json::from_cbor(json::to_cbor(array)) == array);
@@ -464,7 +464,7 @@ TEST_CASE("issue #5392 - binary writers on deeply nested values")
nlohmann::detail::recursion_depth_limit() + 1, nlohmann::detail::recursion_depth_limit() + 2 nlohmann::detail::recursion_depth_limit() + 1, nlohmann::detail::recursion_depth_limit() + 2
}) })
{ {
CAPTURE(depth); CAPTURE(depth)
const json array = nested_array(depth, json(0)); const json array = nested_array(depth, json(0));
std::vector<std::uint8_t> expected_cbor(depth, 0x81); std::vector<std::uint8_t> expected_cbor(depth, 0x81);
@@ -505,10 +505,22 @@ TEST_CASE("issue #5392 - binary writers on deeply nested values")
const json discarded_leaf(json::value_t::discarded); const json discarded_leaf(json::value_t::discarded);
const json deep_discarded = nested_array(depth, discarded_leaf); const json deep_discarded = nested_array(depth, discarded_leaf);
CHECK_THROWS_WITH_AS(json::to_cbor(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to CBOR", json::type_error); // with diagnostics, the message names the path to the discarded leaf
CHECK_THROWS_WITH_AS(json::to_msgpack(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to MessagePack", json::type_error); #if JSON_DIAGNOSTICS
CHECK_THROWS_WITH_AS(json::to_ubjson(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error); std::string path;
CHECK_THROWS_WITH_AS(json::to_bjdata(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error); for (std::size_t i = 0; i < depth; ++i)
{
path += "/0";
}
const std::string prefix = "[json.exception.type_error.321] (" + path + ") ";
#else
const std::string prefix = "[json.exception.type_error.321] ";
#endif
CHECK_THROWS_WITH_AS(json::to_cbor(deep_discarded), (prefix + "cannot serialize discarded value to CBOR").c_str(), json::type_error);
CHECK_THROWS_WITH_AS(json::to_msgpack(deep_discarded), (prefix + "cannot serialize discarded value to MessagePack").c_str(), json::type_error);
CHECK_THROWS_WITH_AS(json::to_ubjson(deep_discarded), (prefix + "cannot serialize discarded value to UBJSON").c_str(), json::type_error);
CHECK_THROWS_WITH_AS(json::to_bjdata(deep_discarded), (prefix + "cannot serialize discarded value to BJData").c_str(), json::type_error);
} }
SECTION("does not overflow the C++ stack") SECTION("does not overflow the C++ stack")
+3 -3
View File
@@ -172,7 +172,7 @@ TEST_CASE("locale-dependent test (LC_NUMERIC=de_DE)")
// a floating-point type that is not a float or a double is written // a floating-point type that is not a float or a double is written
// with snprintf, whose locale-specific decimal point and thousands // with snprintf, whose locale-specific decimal point and thousands
// separator are undone afterwards // separator are undone afterwards
using long_double_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>; using long_double_json = nlohmann::json::with_float_t<long double>;
CHECK(long_double_json(12345.5L).dump() == "12345.5"); CHECK(long_double_json(12345.5L).dump() == "12345.5");
CHECK(long_double_json(1.0L).dump() == "1.0"); CHECK(long_double_json(1.0L).dump() == "1.0");
CHECK(long_double_json(-0.25L).dump() == "-0.25"); CHECK(long_double_json(-0.25L).dump() == "-0.25");
@@ -272,7 +272,7 @@ TEST_CASE("locale changes between lexer construction and number conversion (#519
} }
text += "]"; text += "]";
using long_double_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>; using long_double_json = nlohmann::json::with_float_t<long double>;
// reference values, parsed without a locale switch // reference values, parsed without a locale switch
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr); REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
@@ -432,7 +432,7 @@ TEST_CASE("locale changes during a single dump() (#5709 item 3)")
// long double on 64-bit Arm, where it is IEEE-754 double) takes the // long double on 64-bit Arm, where it is IEEE-754 double) takes the
// locale-independent to_chars() path instead, and this test is a no-op // locale-independent to_chars() path instead, and this test is a no-op
// there. // there.
using long_double_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>; using long_double_json = nlohmann::json::with_float_t<long double>;
using ld_limits = std::numeric_limits<long_double_json::number_float_t>; using ld_limits = std::numeric_limits<long_double_json::number_float_t>;
const bool is_ieee_single_or_double = const bool is_ieee_single_or_double =
(ld_limits::is_iec559 && ld_limits::digits == 24 && ld_limits::max_exponent == 128) || (ld_limits::is_iec559 && ld_limits::digits == 24 && ld_limits::max_exponent == 128) ||
+8 -48
View File
@@ -2201,10 +2201,7 @@ struct huge_array : std::vector<T, A>
} }
}; };
using huge_array_json = nlohmann::basic_json < using huge_array_json = nlohmann::json::with_array_t<huge_array>;
std::map, huge_array, std::string, bool, std::int64_t, std::uint64_t,
double, std::allocator, nlohmann::adl_serializer,
std::vector<std::uint8_t>, void >;
TEST_CASE("MessagePack Size above uint32 for array") TEST_CASE("MessagePack Size above uint32 for array")
{ {
@@ -2249,18 +2246,7 @@ template<typename K, typename V,
} }
}; };
using huge_object_json = nlohmann::basic_json < using huge_object_json = nlohmann::json::with_object_t<huge_map>;
huge_map,
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
std::allocator,
nlohmann::adl_serializer,
std::vector<std::uint8_t>,
void >;
TEST_CASE("MessagePack Size above uint32 for object") TEST_CASE("MessagePack Size above uint32 for object")
{ {
@@ -2295,18 +2281,7 @@ struct huge_string : std::string
} }
}; };
using huge_string_json = nlohmann::basic_json < using huge_string_json = nlohmann::json::with_string_t<huge_string>;
std::map,
std::vector,
huge_string,
bool,
std::int64_t,
std::uint64_t,
double,
std::allocator,
nlohmann::adl_serializer,
std::vector<std::uint8_t>,
void >;
TEST_CASE("MessagePack Size above uint32 for string") TEST_CASE("MessagePack Size above uint32 for string")
{ {
@@ -2329,18 +2304,7 @@ struct huge_binary : std::vector<std::uint8_t>
} }
}; };
using huge_binary_json = nlohmann::basic_json < using huge_binary_json = nlohmann::json::with_binary_t<huge_binary>;
std::map,
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
std::allocator,
nlohmann::adl_serializer,
huge_binary,
void >;
TEST_CASE("MessagePack Size above uint32 for binary") TEST_CASE("MessagePack Size above uint32 for binary")
{ {
@@ -2390,14 +2354,10 @@ class beyond_uint32_string_t : public std::string
} }
}; };
using beyond_uint32_string_json = nlohmann::basic_json < using beyond_uint32_string_json = nlohmann::json::with_string_t<beyond_uint32_string_t>;
std::map, std::vector, beyond_uint32_string_t, bool, std::int64_t, std::uint64_t,
double, std::allocator, nlohmann::adl_serializer, std::vector<std::uint8_t>, void >;
#endif #endif
using beyond_uint32_binary_json = nlohmann::basic_json < using beyond_uint32_binary_json = nlohmann::json::with_binary_t<beyond_uint32_binary_t>;
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
double, std::allocator, nlohmann::adl_serializer, beyond_uint32_binary_t, void >;
} // namespace } // namespace
TEST_CASE("MessagePack lengths beyond UINT32_MAX cannot be serialized") TEST_CASE("MessagePack lengths beyond UINT32_MAX cannot be serialized")
@@ -2432,8 +2392,8 @@ TEST_CASE("MessagePack numbers use the active union member (see #5644)")
// used to read the union member that was not the active one, writing // used to read the union member that was not the active one, writing
// wrong bytes for some values; std::int64_t/std::uint64_t (the default // wrong bytes for some values; std::int64_t/std::uint64_t (the default
// types, where both members have the same width) were not affected // types, where both members have the same width) were not affected
using int32_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int32_t, std::uint64_t, double>; using int32_json = nlohmann::json::with_integers_t<std::int32_t, std::uint64_t>;
using int16_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int16_t, std::uint64_t, double>; using int16_json = nlohmann::json::with_integers_t<std::int16_t, std::uint64_t>;
SECTION("number_integer_t = std::int32_t") SECTION("number_integer_t = std::int32_t")
{ {
Loaded 100 of 107 files, more files were not shown because too many files have changed in this diff. Show more