Compare commits

..
Author SHA1 Message Date
Niels Lohmann 8418ff85b6 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>
2026-10-08 08:41:06 +02:00
162 changed files with 556 additions and 73546 deletions

No files matched your search

-81
View File
@@ -1,81 +0,0 @@
name: "Check API documentation"
on:
pull_request:
permissions:
contents: read
jobs:
check_api_docs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- name: Checkout pull request
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install clang
# Used only as a subprocess for `clang++ -E -v` system-include-path discovery in
# extract_api.py; it does not need to version-match the pinned libclang pip wheel
# below, which does the actual AST parsing. Do not "fix" this to be version-matched.
run: sudo apt-get update && sudo apt-get install -y clang
- name: Install Python dependencies
run: pip install -r tools/api_checker/requirements.txt
- name: Extract API and regenerate the committed surface file
run: |
python3 tools/api_checker/extract_api.py \
--header include/nlohmann/json.hpp \
--include include \
--output /tmp/api_snapshot.json \
--surface-output tools/api_checker/api_surface.json
- name: "Check API documentation (Phase 1: advisory)"
# Surfaces missing/broken @sa links without failing the job while the backlog from the
# initial AST-based rollout is burned down. See tools/api_checker/POLICY.md and the PR
# that introduced this workflow for the two-phase rollout plan.
continue-on-error: true
run: |
python3 tools/api_checker/check_docs.py \
--snapshot /tmp/api_snapshot.json
- name: Check macro documentation (advisory only)
# Cross-checks docs/mkdocs/docs/api/macros/ pages against #define sites. Only checks the
# documented-macro-still-exists direction; never blocks CI. See POLICY.md.
run: python3 tools/api_checker/check_macros.py
- name: Check for uncommitted API surface changes
id: diff
run: |
mkdir -p ${{ github.workspace }}/patch
git diff --patch --no-color -- tools/api_checker/api_surface.json > ${{ github.workspace }}/patch/api_surface.patch
if [ -s ${{ github.workspace }}/patch/api_surface.patch ]; then
echo "tools/api_checker/api_surface.json is out of date. Diff:"
cat ${{ github.workspace }}/patch/api_surface.patch
echo "has_diff=true" >> "$GITHUB_OUTPUT"
else
echo "has_diff=false" >> "$GITHUB_OUTPUT"
fi
# Uploaded so contributors can fix their PR with `git apply api_surface.patch`
# instead of installing libclang locally.
- name: Upload patch
if: steps.diff.outputs.has_diff == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: api-surface-patch
path: patch/api_surface.patch
- name: Fail if API surface file is not up to date
# Unlike the doc-backlog check above, this is purely mechanical regeneration with no
# backlog to phase in -- blocking from the start, matching check_amalgamation.yml's
# precedent. Contributors who add/remove/rename public API must regenerate and commit
# tools/api_checker/api_surface.json as part of their PR.
if: steps.diff.outputs.has_diff == 'true'
run: exit 1
-7
View File
@@ -166,13 +166,6 @@ 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" ^
-5
View File
@@ -3,7 +3,6 @@
*.gcno *.gcno
*.gcda *.gcda
.DS_Store .DS_Store
__pycache__/
/.idea /.idea
/cmake-build-* /cmake-build-*
@@ -46,9 +45,5 @@ venv
nlohmann_json.spdx nlohmann_json.spdx
# api_checker: ephemeral, location/doc-status-sensitive working file (not the committed
# release-tracking artifact -- see tools/api_checker/api_surface.json for that)
/tools/api_checker/api_snapshot.json
# Bazel-related # Bazel-related
MODULE.bazel.lock MODULE.bazel.lock
+1 -1
View File
@@ -104,7 +104,7 @@ Thanks everyone!
:books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/examples), or browse through the [**help pages**](https://json.nlohmann.me). :books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/examples), or browse through the [**help pages**](https://json.nlohmann.me).
:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or have a look at the [quick reference](#quick-reference) below. The public API surface is derived mechanically and checked for documentation coverage by the tooling in [`tools/api_checker/`](tools/api_checker/), whose [POLICY.md](tools/api_checker/POLICY.md) defines what counts as public API and what stability is guaranteed. :construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or have a look at the [quick reference](#quick-reference) below.
:bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as much information as possible to help us understand and reproduce your issue. :bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as much information as possible to help us understand and reproduce your issue.
-25
View File
@@ -9,13 +9,11 @@ INSERT INTO searchIndex(name, type, path) VALUES ('adl_serializer::to_json', 'Fu
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', '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::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::clear_subtype', 'Method', 'api/byte_container_with_subtype/clear_subtype/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::container_type', 'Type', 'api/byte_container_with_subtype/container_type/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::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_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::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::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 ('byte_container_with_subtype::subtype', 'Method', 'api/byte_container_with_subtype/subtype/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::subtype_type', 'Type', 'api/byte_container_with_subtype/subtype_type/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json', 'Class', 'api/basic_json/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 ('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::accept', 'Function', 'api/basic_json/accept/index.html');
@@ -28,7 +26,6 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::basic_json', 'Con
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::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', '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::binary_t', 'Type', 'api/basic_json/binary_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::bjdata_version_t', 'Enum', 'api/basic_json/bjdata_version_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::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::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::cbor_tag_handler_t', 'Enum', 'api/basic_json/cbor_tag_handler_t/index.html');
@@ -64,7 +61,6 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::get_binary', 'Met
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_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_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::get_to', 'Method', 'api/basic_json/get_to/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::initializer_list_t', 'Type', 'api/basic_json/initializer_list_t/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::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::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::invalid_iterator', 'Class', 'api/basic_json/invalid_iterator/index.html');
@@ -83,7 +79,6 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::is_string', 'Meth
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::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::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_base_class_t', 'Type', 'api/basic_json/json_base_class_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::json_sax_t', 'Type', 'api/basic_json/json_sax_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::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::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::merge_patch', 'Method', 'api/basic_json/merge_patch/index.html');
@@ -159,44 +154,24 @@ INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::string_t', 'Typ
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_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', '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::binary', 'Method', 'api/json_sax/binary/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::binary_t', 'Type', 'api/json_sax/binary_t/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::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_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::end_object', 'Method', 'api/json_sax/end_object/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::json_sax', 'Constructor', 'api/json_sax/json_sax/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::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::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_float', 'Method', 'api/json_sax/number_float/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_float_t', 'Type', 'api/json_sax/number_float_t/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_integer', 'Method', 'api/json_sax/number_integer/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_integer_t', 'Type', 'api/json_sax/number_integer_t/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::number_unsigned', 'Method', 'api/json_sax/number_unsigned/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::number_unsigned_t', 'Type', 'api/json_sax/number_unsigned_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::operator=', 'Operator', 'api/json_sax/operator=/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::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_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::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 ('json_sax::string', 'Method', 'api/json_sax/string/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::string_t', 'Type', 'api/json_sax/string_t/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('json_sax::~json_sax', 'Method', 'api/json_sax/~json_sax/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', '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""_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_ltlt/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('operator>>', 'Operator', 'api/operator_gtgt/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('operator>>', 'Operator', 'api/operator_gtgt/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json', 'Class', 'api/ordered_json/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json', '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 ('ordered_map', 'Class', 'api/ordered_map/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::Container', 'Type', 'api/ordered_map/Container/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::at', 'Method', 'api/ordered_map/at/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::count', 'Method', 'api/ordered_map/count/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::emplace', 'Method', 'api/ordered_map/emplace/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::erase', 'Method', 'api/ordered_map/erase/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::find', 'Method', 'api/ordered_map/find/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::insert', 'Method', 'api/ordered_map/insert/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::key_compare', 'Type', 'api/ordered_map/key_compare/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::operator=', 'Operator', 'api/ordered_map/operator=/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::operator[]', 'Operator', 'api/ordered_map/operator[]/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::ordered_map', 'Constructor', 'api/ordered_map/ordered_map/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map::~ordered_map', 'Method', 'api/ordered_map/~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::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::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'); INSERT INTO searchIndex(name, type, path) VALUES ('std::swap<basic_json>', 'Function', 'api/basic_json/std_swap/index.html');
@@ -475,10 +475,8 @@ basic_json(basic_json&& other) noexcept;
1. Since version 1.0.0. 1. Since version 1.0.0.
2. Since version 1.0.0. 2. Since version 1.0.0.
3. Since version 2.1.0. 3. Since version 2.1.0.
4. Since version 3.2.0. Also initializes the position reported by 4. Since version 3.2.0. Explicit for different string types if `JSON_USE_IMPLICIT_CONVERSIONS` is `0` since
[`start_pos()`](start_pos.md)/[`end_pos()`](end_pos.md) from `val` when version 3.13.0.
[`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) is enabled, since version 3.12.0. Explicit
for different string types if `JSON_USE_IMPLICIT_CONVERSIONS` is `0` since version 3.13.0.
5. Since version 1.0.0. 5. Since version 1.0.0.
6. Since version 1.0.0. 6. Since version 1.0.0.
7. Since version 1.0.0. Fixed in version 3.13.0 to also check the iterator range for binary values; before, a range 7. Since version 1.0.0. Fixed in version 3.13.0 to also check the iterator range for binary values; before, a range
+12 -1
View File
@@ -64,7 +64,18 @@ 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::ordered_json::with_binary_t<std::vector<std::byte>>; using custom_json = nlohmann::basic_json<
nlohmann::ordered_map, // ObjectType
std::vector, // ArrayType
std::string, // StringType
bool, // BooleanType
std::int64_t, // NumberIntegerType
std::uint64_t, // NumberUnsignedType
double, // NumberFloatType
std::allocator, // AllocatorType
nlohmann::adl_serializer,
std::vector<std::byte> // Custom BinaryType
>;
std::vector<std::byte> data{std::byte{1}, std::byte{2}, std::byte{3}}; 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
@@ -1,38 +0,0 @@
# <small>nlohmann::basic_json::</small>bjdata_version_t
```cpp
enum class bjdata_version_t
{
draft2,
draft3,
};
```
This enumeration is used in the [`to_bjdata`](to_bjdata.md) function to choose which draft version of
the BJData specification to encode ND-array extensions for:
draft2
: encode using the BJData Draft 2 ND-array format
draft3
: encode using the BJData Draft 3 ND-array format
## Examples
??? example
The example shows how `bjdata_version_t` selects the BJData draft used by `to_bjdata`.
```cpp
--8<-- "examples/bjdata_version_t.cpp"
```
Output:
```
--8<-- "examples/bjdata_version_t.output"
```
## Version history
- Added in version 3.12.0.
@@ -1,32 +0,0 @@
# <small>nlohmann::basic_json::</small>initializer_list_t
```cpp
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
```
The type used for the initializer-list [constructor](basic_json.md) (overload 5) and for functions
such as [`operator=`](operator=.md) that accept a braced-init-list of JSON values. Each element wraps a
`basic_json` value or something convertible to one, deferring the decision of whether the list should be
parsed as a JSON array or a JSON object to the constructor itself.
See the [constructor](basic_json.md) documentation for how `initializer_list_t` values are interpreted.
## Examples
??? example
The example shows how an `initializer_list_t` is used to construct a JSON value.
```cpp
--8<-- "examples/initializer_list_t.cpp"
```
Output:
```
--8<-- "examples/initializer_list_t.output"
```
## Version history
- Since version 1.0.0.
@@ -1,31 +0,0 @@
# <small>nlohmann::basic_json::</small>json_sax_t
```cpp
using json_sax_t = json_sax<basic_json>;
```
The [`json_sax`](../json_sax/index.md) interface bound to this `basic_json` specialization, i.e. with
`BasicJsonType` fixed to `basic_json`. Used as the SAX interface type by [`sax_parse`](sax_parse.md) and
other SAX-based parsing functions.
See [`nlohmann::json_sax`](../json_sax/index.md) for more information.
## Examples
??? example
The example shows the type `json_sax_t`.
```cpp
--8<-- "examples/json_sax_t.cpp"
```
Output:
```
--8<-- "examples/json_sax_t.output"
```
## Version history
- Added in version 3.2.0.
+1 -2
View File
@@ -26,8 +26,7 @@ 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. `object_t::key_type` must be implicitly convertible to `string_t` (required by the order elements inside the container.
binary formats).
`AllocatorType` `AllocatorType`
: the allocator to use for objects (e.g., `std::allocator`) : the allocator to use for objects (e.g., `std::allocator`)
@@ -51,5 +51,3 @@ Linear.
## Version history ## Version history
- Added in version 1.0.0. - Added in version 1.0.0.
- The `noexcept` specification was extended to also depend on
[`json_base_class_t`](json_base_class_t.md)'s move-assignment in version 3.11.3.
@@ -92,8 +92,3 @@ Linear in the size of the JSON value.
- Since version 1.0.0. - Since version 1.0.0.
- Macros `JSON_EXPLICIT`/[`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) added - Macros `JSON_EXPLICIT`/[`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) added
in version 3.9.0. in version 3.9.0.
- The exclusion of `std::any` from this conversion became conditional on
[`JSON_HAS_STATIC_RTTI`](../macros/json_has_static_rtti.md) in version 3.11.3.
- `std::optional<T>` excluded from this conversion in version 3.13.0; use
[`get<std::optional<T>>()`](get.md)/[`get_to()`](get_to.md) instead (see
[Converting values](../../features/conversions.md)).
@@ -1,32 +0,0 @@
# <small>nlohmann::byte_container_with_subtype::</small>container_type
```cpp
using container_type = BinaryType;
```
The type of the underlying binary container, forwarded from the `BinaryType` template parameter that
`byte_container_with_subtype` is instantiated with. `byte_container_with_subtype` publicly inherits from
`container_type`.
See [`basic_json::binary_t`](../basic_json/binary_t.md) for the type typically used to instantiate
`BinaryType`.
## Examples
??? example
The example shows the type `container_type`.
```cpp
--8<-- "examples/byte_container_with_subtype__container_type.cpp"
```
Output:
```
--8<-- "examples/byte_container_with_subtype__container_type.output"
```
## Version history
- Since version 3.8.0.
@@ -1,28 +0,0 @@
# <small>nlohmann::byte_container_with_subtype::</small>subtype_type
```cpp
using subtype_type = std::uint64_t;
```
The type used to store the optional binary subtype tag. See [`subtype`](subtype.md) and
[`set_subtype`](set_subtype.md).
## Examples
??? example
The example shows the type `subtype_type`.
```cpp
--8<-- "examples/byte_container_with_subtype__subtype_type.cpp"
```
Output:
```
--8<-- "examples/byte_container_with_subtype__subtype_type.output"
```
## Version history
- Since version 3.8.0.
-30
View File
@@ -1,30 +0,0 @@
# <small>nlohmann::json_sax::</small>binary_t
```cpp
using binary_t = typename BasicJsonType::binary_t;
```
The type used by the [`binary`](binary.md) callback for JSON binary values, forwarded from the
`BasicJsonType` template parameter.
See [`basic_json::binary_t`](../basic_json/binary_t.md) for more information.
## Examples
??? example
The example shows the type `binary_t` and its relation to `basic_json::binary_t`.
```cpp
--8<-- "examples/json_sax__binary_t.cpp"
```
Output:
```
--8<-- "examples/json_sax__binary_t.output"
```
## Version history
- Added in version 3.8.0.
-33
View File
@@ -1,33 +0,0 @@
# <small>nlohmann::json_sax::</small>json_sax
```cpp
// (1)
json_sax() = default;
// (2)
json_sax(const json_sax&) = default;
// (3)
json_sax(json_sax&&) noexcept = default;
```
1. Default constructor.
2. Copy constructor.
3. Move constructor.
`json_sax` is a pure abstract base class with no data members of its own, so all three constructors are
defaulted and only exist to make derived SAX consumers explicitly copyable/movable.
## Exception safety
No-throw guarantee: none of these constructors throw exceptions.
## Complexity
Constant.
<!-- NOLINT Examples -->
## Version history
- Added in version 3.2.0.
@@ -1,30 +0,0 @@
# <small>nlohmann::json_sax::</small>number_float_t
```cpp
using number_float_t = typename BasicJsonType::number_float_t;
```
The type used by the [`number_float`](number_float.md) callback for JSON floating-point numbers,
forwarded from the `BasicJsonType` template parameter.
See [`basic_json::number_float_t`](../basic_json/number_float_t.md) for more information.
## Examples
??? example
The example shows the type `number_float_t` and its relation to `basic_json::number_float_t`.
```cpp
--8<-- "examples/json_sax__number_float_t.cpp"
```
Output:
```
--8<-- "examples/json_sax__number_float_t.output"
```
## Version history
- Added in version 3.2.0.
@@ -1,30 +0,0 @@
# <small>nlohmann::json_sax::</small>number_integer_t
```cpp
using number_integer_t = typename BasicJsonType::number_integer_t;
```
The type used by the [`number_integer`](number_integer.md) callback for JSON integer numbers, forwarded
from the `BasicJsonType` template parameter.
See [`basic_json::number_integer_t`](../basic_json/number_integer_t.md) for more information.
## Examples
??? example
The example shows the type `number_integer_t` and its relation to `basic_json::number_integer_t`.
```cpp
--8<-- "examples/json_sax__number_integer_t.cpp"
```
Output:
```
--8<-- "examples/json_sax__number_integer_t.output"
```
## Version history
- Added in version 3.2.0.
@@ -1,30 +0,0 @@
# <small>nlohmann::json_sax::</small>number_unsigned_t
```cpp
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
```
The type used by the [`number_unsigned`](number_unsigned.md) callback for JSON unsigned integer numbers,
forwarded from the `BasicJsonType` template parameter.
See [`basic_json::number_unsigned_t`](../basic_json/number_unsigned_t.md) for more information.
## Examples
??? example
The example shows the type `number_unsigned_t` and its relation to `basic_json::number_unsigned_t`.
```cpp
--8<-- "examples/json_sax__number_unsigned_t.cpp"
```
Output:
```
--8<-- "examples/json_sax__number_unsigned_t.output"
```
## Version history
- Added in version 3.2.0.
@@ -1,29 +0,0 @@
# <small>nlohmann::json_sax::</small>operator=
```cpp
// (1)
json_sax& operator=(const json_sax&) = default;
// (2)
json_sax& operator=(json_sax&&) noexcept = default;
```
1. Copy assignment operator.
2. Move assignment operator.
`json_sax` is a pure abstract base class with no data members of its own, so both assignment operators
are defaulted and only exist to make derived SAX consumers explicitly copy-/move-assignable.
## Exception safety
No-throw guarantee: neither operator throws exceptions.
## Complexity
Constant.
<!-- NOLINT Examples -->
## Version history
- Added in version 3.2.0.
-30
View File
@@ -1,30 +0,0 @@
# <small>nlohmann::json_sax::</small>string_t
```cpp
using string_t = typename BasicJsonType::string_t;
```
The type used by the [`string`](string.md) and [`key`](key.md) callbacks for JSON strings and object
keys, forwarded from the `BasicJsonType` template parameter.
See [`basic_json::string_t`](../basic_json/string_t.md) for more information.
## Examples
??? example
The example shows the type `string_t` and its relation to `basic_json::string_t`.
```cpp
--8<-- "examples/json_sax__string_t.cpp"
```
Output:
```
--8<-- "examples/json_sax__string_t.output"
```
## Version history
- Added in version 3.2.0.
@@ -1,22 +0,0 @@
# <small>nlohmann::json_sax::</small>~json_sax
```cpp
virtual ~json_sax() = default;
```
Destructor. Virtual to allow proper destruction of derived SAX consumer classes through a
pointer/reference to `json_sax`.
## Exception safety
No-throw guarantee: this destructor never throws exceptions.
## Complexity
Constant.
<!-- NOLINT Examples -->
## Version history
- Added in version 3.2.0.
@@ -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::json::with_string_t<std::wstring>; using wjson = nlohmann::basic_json<std::map, std::vector, std::wstring>;
void load(const nlohmann::json& j); void load(const nlohmann::json& j);
+4 -4
View File
@@ -8,16 +8,16 @@ This type preserves the insertion order of object keys.
## Iterator invalidation ## Iterator invalidation
The type is based on [`ordered_map`](ordered_map/index.md) which in turn uses a `std::vector` to store object elements. The type is based on [`ordered_map`](ordered_map.md) which in turn uses a `std::vector` to store object elements.
Therefore, adding object elements can yield a reallocation in which case all iterators (including the Therefore, adding object elements can yield a reallocation in which case all iterators (including the
[`end()`](basic_json/end.md) iterator) and all references to the elements are invalidated. Also, any iterator or [`end()`](basic_json/end.md) iterator) and all references to the elements are invalidated. Also, any iterator or
reference after the insertion point will point to the same index, which is now a different value. reference after the insertion point will point to the same index, which is now a different value.
## Complexity ## Complexity
[`ordered_map`](ordered_map/index.md) has no lookup index: every key-based object operation is a linear scan, so building or [`ordered_map`](ordered_map.md) has no lookup index: every key-based object operation is a linear scan, so building or
parsing an object of `n` keys costs O(n²) rather than O(n log n). See parsing an object of `n` keys costs O(n²) rather than O(n log n). See
[`ordered_map` complexity](ordered_map/index.md#complexity) for the per-operation table and for measured numbers. [`ordered_map` complexity](ordered_map.md#complexity) for the per-operation table and for measured numbers.
## Examples ## Examples
@@ -37,7 +37,7 @@ parsing an object of `n` keys costs O(n²) rather than O(n log n). See
## See also ## See also
- [ordered_map](ordered_map/index.md) - [ordered_map](ordered_map.md)
- [Object Order](../features/object_order.md) - [Object Order](../features/object_order.md)
## Version history ## Version history
@@ -6,7 +6,7 @@ template<class Key, class T, class IgnoredLess = std::less<Key>,
struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>; struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>;
``` ```
A minimal map-like container that preserves insertion order for use within [`nlohmann::ordered_json`](../ordered_json.md) A minimal map-like container that preserves insertion order for use within [`nlohmann::ordered_json`](ordered_json.md)
(`nlohmann::basic_json<ordered_map>`). (`nlohmann::basic_json<ordered_map>`).
## Template parameters ## Template parameters
@@ -30,19 +30,19 @@ case all iterators (including the `end()` iterator) and all references to the el
When the storage grows, the keys are copied and the mapped values are moved to the new storage. A plain `std::vector` When the storage grows, the keys are copied and the mapped values are moved to the new storage. A plain `std::vector`
would copy the whole elements instead, because their `#!cpp const` keys make them not nothrow move constructible; for would copy the whole elements instead, because their `#!cpp const` keys make them not nothrow move constructible; for
[`ordered_json`](../ordered_json.md), this would be a deep copy of every nested value. The values are only copied if [`ordered_json`](ordered_json.md), this would be a deep copy of every nested value. The values are only copied if
`T` is not default constructible or not nothrow move assignable. `T` is not default constructible or not nothrow move assignable.
## Member types ## Member types
- **key_type** - key type (`Key`) - **key_type** - key type (`Key`)
- **mapped_type** - mapped type (`T`) - **mapped_type** - mapped type (`T`)
- [**Container**](Container.md) - base container type (`#!cpp std::vector<std::pair<const Key, T>, Allocator>`) - **Container** - base container type (`#!cpp std::vector<std::pair<const Key, T>, Allocator>`)
- **iterator** - **iterator**
- **const_iterator** - **const_iterator**
- **size_type** - **size_type**
- **value_type** - **value_type**
- [**key_compare**](key_compare.md) - key comparison function - **key_compare** - key comparison function
```cpp ```cpp
std::equal_to<Key> // until C++14 std::equal_to<Key> // until C++14
@@ -51,16 +51,15 @@ std::equal_to<> // since C++14
## Member functions ## Member functions
- [(constructor)](ordered_map.md) - (constructor)
- [(destructor)](~ordered_map.md) - (destructor)
- [**operator=**](operator=.md) - **emplace**
- [**emplace**](emplace.md) - **operator\[\]**
- [**operator\[\]**](operator[].md) - **at**
- [**at**](at.md) - **erase**
- [**erase**](erase.md) - **count**
- [**count**](count.md) - **find**
- [**find**](find.md) - **insert**
- [**insert**](insert.md)
## Exception safety ## Exception safety
@@ -90,7 +89,7 @@ This differs from `#!cpp std::map`, where the same operations are O(log n).
!!! warning "Quadratic cost of building large objects" !!! warning "Quadratic cost of building large objects"
Because every insertion scans all elements inserted so far, building an object of `n` distinct keys costs Because every insertion scans all elements inserted so far, building an object of `n` distinct keys costs
**O(n²)** in total. This applies to filling an [`ordered_json`](../ordered_json.md) object key by key as well as to **O(n²)** in total. This applies to filling an [`ordered_json`](ordered_json.md) object key by key as well as to
parsing one, since the parser inserts each key as it is read. parsing one, since the parser inserts each key as it is read.
The cost is negligible for the object sizes typically found in configuration files or API payloads, but it grows The cost is negligible for the object sizes typically found in configuration files or API payloads, but it grows
@@ -107,7 +106,7 @@ This differs from `#!cpp std::map`, where the same operations are O(log n).
If key order matters for objects of that size, consider a container with a lookup index, such as If key order matters for objects of that size, consider a container with a lookup index, such as
[`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map)
([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)), as the object type -- see ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)), as the object type -- see
[object order](../../features/object_order.md). [object order](../features/object_order.md).
## Examples ## Examples
@@ -127,10 +126,10 @@ This differs from `#!cpp std::map`, where the same operations are O(log n).
## See also ## See also
- [ordered_json](../ordered_json.md) - [ordered_json](ordered_json.md)
## Version history ## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md). - Added in version 3.9.0 to implement [`nlohmann::ordered_json`](ordered_json.md).
- Added **key_compare** member in version 3.11.0. - Added **key_compare** member in version 3.11.0.
- Changed in version 3.13.0: growing the storage moves the mapped values instead of copying them. - Changed in version 3.13.0: growing the storage moves the mapped values instead of copying them.
@@ -1,28 +0,0 @@
# <small>nlohmann::ordered_map::</small>Container
```cpp
using Container = std::vector<std::pair<const Key, T>, Allocator>;
```
The base container type that `ordered_map` publicly inherits from. Elements are stored in insertion
order as `#!cpp std::pair<const Key, T>` entries in a `std::vector`.
## Examples
??? example
The example shows the type `Container`.
```cpp
--8<-- "examples/ordered_map__Container.cpp"
```
Output:
```
--8<-- "examples/ordered_map__Container.output"
```
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
-61
View File
@@ -1,61 +0,0 @@
# <small>nlohmann::ordered_map::</small>at
```cpp
// (1)
T& at(const key_type& key);
const T& at(const key_type& key) const;
// (2)
template<class KeyType>
T& at(KeyType&& key);
template<class KeyType>
const T& at(KeyType&& key) const;
```
1. Returns a reference to the value mapped to `key`.
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
(heterogeneous lookup, e.g. looking up by a `#!cpp const char*` without constructing a temporary
`key_type`). Only participates in overload resolution if `KeyType` is usable as a key type.
## Template parameters
`KeyType`
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
## Parameters
`key` (in)
: key of the element to find
## Return value
reference to the mapped value of the element with key equal to `key`
## Exceptions
Throws `std::out_of_range` if no element with key `key` exists.
## Complexity
Linear in the number of elements.
## Examples
??? example
The example shows how `at` is used.
```cpp
--8<-- "examples/ordered_map__at.cpp"
```
Output:
```
--8<-- "examples/ordered_map__at.output"
```
## Version history
- Added in version 3.9.1 to implement [`nlohmann::ordered_json`](../ordered_json.md).
- Overload (2) added in version 3.11.0.
-53
View File
@@ -1,53 +0,0 @@
# <small>nlohmann::ordered_map::</small>count
```cpp
// (1)
size_type count(const key_type& key) const;
// (2)
template<class KeyType>
size_type count(KeyType&& key) const;
```
1. Returns the number of elements with key equal to `key` (0 or 1, since keys are unique).
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
## Template parameters
`KeyType`
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
## Parameters
`key` (in)
: key of the elements to count
## Return value
number of elements with key equal to `key` (0 or 1)
## Complexity
Linear in the number of elements.
## Examples
??? example
The example shows how `count` is used.
```cpp
--8<-- "examples/ordered_map__count.cpp"
```
Output:
```
--8<-- "examples/ordered_map__count.output"
```
## Version history
- Added in version 3.9.1 to implement [`nlohmann::ordered_json`](../ordered_json.md).
- Overload (2) added in version 3.11.0.
@@ -1,58 +0,0 @@
# <small>nlohmann::ordered_map::</small>emplace
```cpp
// (1)
std::pair<iterator, bool> emplace(const key_type& key, T&& t);
// (2)
template<class KeyType>
std::pair<iterator, bool> emplace(KeyType&& key, T&& t);
```
1. Inserts `#!cpp {key, t}` if no element with an equal key already exists (per [`key_compare`](key_compare.md)),
appending it at the end to preserve insertion order. If an equal key already exists, does nothing.
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
## Template parameters
`KeyType`
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
## Parameters
`key` (in)
: key of the element to insert
`t` (in)
: value of the element to insert
## Return value
pair of an iterator to the (possibly newly inserted) element, and a `bool` that is `true` if insertion
took place and `false` if an element with an equal key already existed
## Complexity
Linear in the number of elements.
## Examples
??? example
The example shows how `emplace` is used.
```cpp
--8<-- "examples/ordered_map__emplace.cpp"
```
Output:
```
--8<-- "examples/ordered_map__emplace.output"
```
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
- Overload (2) added in version 3.11.0.
-75
View File
@@ -1,75 +0,0 @@
# <small>nlohmann::ordered_map::</small>erase
```cpp
// (1)
size_type erase(const key_type& key);
// (2)
template<class KeyType>
size_type erase(KeyType&& key);
// (3)
iterator erase(iterator pos);
// (4)
iterator erase(iterator first, iterator last);
```
1. Removes the element with key equal to `key`, if any, preserving the relative order of the remaining
elements.
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
3. Removes the element at `pos`.
4. Removes the elements in range `[first, last)`.
## Template parameters
`KeyType`
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
## Parameters
`key` (in)
: key of the element to remove
`pos` (in)
: iterator to the element to remove
`first` (in)
: iterator to the first element to remove
`last` (in)
: iterator one past the last element to remove
## Return value
1. number of elements removed (0 or 1)
2. number of elements removed (0 or 1)
3. iterator following the removed element
4. iterator following the last removed element
## Complexity
Linear in the number of elements (elements after the removed one(s) are shifted to keep storage
contiguous).
## Examples
??? example
The example shows how `erase` is used.
```cpp
--8<-- "examples/ordered_map__erase.cpp"
```
Output:
```
--8<-- "examples/ordered_map__erase.output"
```
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
- Overload (2) added in version 3.11.0.
-56
View File
@@ -1,56 +0,0 @@
# <small>nlohmann::ordered_map::</small>find
```cpp
// (1)
iterator find(const key_type& key);
const_iterator find(const key_type& key) const;
// (2)
template<class KeyType>
iterator find(KeyType&& key);
template<class KeyType>
const_iterator find(KeyType&& key) const;
```
1. Returns an iterator to the element with key equal to `key`, or `end()` if no such element exists.
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
## Template parameters
`KeyType`
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
## Parameters
`key` (in)
: key of the element to find
## Return value
iterator to the element with key equal to `key`, or `end()` if not found
## Complexity
Linear in the number of elements.
## Examples
??? example
The example shows how `find` is used.
```cpp
--8<-- "examples/ordered_map__find.cpp"
```
Output:
```
--8<-- "examples/ordered_map__find.output"
```
## Version history
- Added in version 3.9.1 to implement [`nlohmann::ordered_json`](../ordered_json.md).
- Overload (2) added in version 3.11.0.
@@ -1,63 +0,0 @@
# <small>nlohmann::ordered_map::</small>insert
```cpp
// (1)
std::pair<iterator, bool> insert(value_type&& value);
std::pair<iterator, bool> insert(const value_type& value);
// (2)
template<typename InputIt>
void insert(InputIt first, InputIt last);
```
1. Inserts `value` if no element with an equal key already exists (per [`key_compare`](key_compare.md)),
appending it at the end to preserve insertion order. If an equal key already exists, does nothing.
2. Inserts the elements from range `[first, last)`, in iteration order, applying the same equal-key rule
as (1) to each element.
## Template parameters
`InputIt`
: an input iterator type
## Parameters
`value` (in)
: value to insert
`first` (in)
: iterator to the first element to insert
`last` (in)
: iterator one past the last element to insert
## Return value
1. pair of an iterator to the (possibly newly inserted) element, and a `bool` that is `true` if insertion
took place and `false` if an element with an equal key already existed
2. (none)
## Complexity
1. Linear in the number of elements.
2. Linear in the distance between `first` and `last`, times linear in the number of elements.
## Examples
??? example
The example shows how `insert` is used.
```cpp
--8<-- "examples/ordered_map__insert.cpp"
```
Output:
```
--8<-- "examples/ordered_map__insert.output"
```
## Version history
- Added in version 3.9.1 to implement [`nlohmann::ordered_json`](../ordered_json.md).
@@ -1,34 +0,0 @@
# <small>nlohmann::ordered_map::</small>key_compare
```cpp
using key_compare = std::equal_to<Key>; // until C++14
using key_compare = std::equal_to<>; // since C++14
```
The comparator used to determine key equality when looking up elements. Unlike `std::map`, `ordered_map`
uses linear search with `key_compare` rather than an ordering relation, since element order reflects
insertion order rather than key order.
Since C++14, the transparent `#!cpp std::equal_to<>` is used, which enables heterogeneous lookup (e.g.
looking up by a `#!cpp const char*` key without constructing a temporary `Key`).
## Examples
??? example
The example shows how `key_compare` is used.
```cpp
--8<-- "examples/ordered_map__key_compare.cpp"
```
Output:
```
--8<-- "examples/ordered_map__key_compare.output"
```
## Version history
- Added in version 3.11.0.
@@ -1,32 +0,0 @@
# <small>nlohmann::ordered_map::</small>operator=
```cpp
// (1)
ordered_map& operator=(const ordered_map& other);
// (2)
ordered_map& operator=(ordered_map&& other) noexcept(std::is_nothrow_move_assignable<Container>::value);
```
1. Copy assignment operator.
2. Move assignment operator.
## Parameters
`other` (in)
: value to assign from
## Return value
`*this`
## Complexity
1. Linear in the size of `other`.
2. Constant.
<!-- NOLINT Examples -->
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
@@ -1,62 +0,0 @@
# <small>nlohmann::ordered_map::</small>operator[]
```cpp
// (1)
T& operator[](const key_type& key);
const T& operator[](const key_type& key) const;
// (2)
template<class KeyType>
T& operator[](KeyType&& key);
template<class KeyType>
const T& operator[](KeyType&& key) const;
```
1. Returns a reference to the value mapped to `key`, inserting a default-constructed `T` (non-`const`
overload only) if no such element exists yet.
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
## Template parameters
`KeyType`
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
## Parameters
`key` (in)
: key of the element to find or insert
## Return value
reference to the mapped value of the element with key equal to `key`
## Exceptions
The `const` overloads throw `std::out_of_range` if no element with key `key` exists (they delegate to
[`at`](at.md)).
## Complexity
Linear in the number of elements.
## Examples
??? example
The example shows how `operator[]` is used.
```cpp
--8<-- "examples/ordered_map__operator_idx.cpp"
```
Output:
```
--8<-- "examples/ordered_map__operator_idx.output"
```
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
- Overload (2) added in version 3.11.0.
@@ -1,66 +0,0 @@
# <small>nlohmann::ordered_map::</small>ordered_map
```cpp
// (1)
ordered_map() noexcept(noexcept(Container()));
// (2)
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc)));
// (3)
template <class It>
ordered_map(It first, It last, const Allocator& alloc = Allocator());
// (4)
ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator());
// (5)
ordered_map(const ordered_map&) = default;
// (6)
ordered_map(ordered_map&&) noexcept(std::is_nothrow_move_constructible<Container>::value) = default;
```
1. Default constructor. Creates an empty `ordered_map`.
2. Creates an empty `ordered_map` using the given allocator.
3. Creates an `ordered_map` from the elements in range `[first, last)`, inserted in iteration order.
4. Creates an `ordered_map` from an initializer list of key/value pairs, inserted in list order.
5. Copy constructor.
6. Move constructor.
These constructors are declared explicitly (rather than inherited via `#!cpp using Container::Container`)
because older compilers (GCC <= 5.5, Xcode <= 9.4) do not handle the inherited constructors correctly.
## Template parameters
`It`
: an input iterator type
## Parameters
`alloc` (in)
: allocator to use for the underlying container
`first` (in)
: iterator to the first element to insert
`last` (in)
: iterator one past the last element to insert
`init` (in)
: initializer list of key/value pairs to insert
## Complexity
1. Constant.
2. Constant.
3. Linear in the distance between `first` and `last`.
4. Linear in the size of `init`.
5. Linear in the size of `other`.
6. Constant.
<!-- NOLINT Examples -->
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
@@ -1,17 +0,0 @@
# <small>nlohmann::ordered_map::</small>~ordered_map
```cpp
~ordered_map() = default;
```
Destroys the `ordered_map` and frees all allocated memory.
## Complexity
Linear in the number of elements.
<!-- NOLINT Examples -->
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
+13 -1
View File
@@ -15,7 +15,19 @@ class base_class_with_hidden_members
} }
}; };
using json = nlohmann::json::with_base_class_t<base_class_with_hidden_members>; using json = 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
>;
int main() int main()
{ {
@@ -1,21 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// an empty binary value is encoded differently by the two drafts:
// draft2 omits the optimized type marker for an empty byte array,
// while draft3 always writes it
json j = json::binary({});
// encode using BJData draft2 (the default)
auto v_draft2 = json::to_bjdata(j, true, true, json::bjdata_version_t::draft2);
// encode using BJData draft3
auto v_draft3 = json::to_bjdata(j, true, true, json::bjdata_version_t::draft3);
std::cout << "draft2 size: " << v_draft2.size() << '\n'
<< "draft3 size: " << v_draft3.size() << std::endl;
}
@@ -1,2 +0,0 @@
draft2 size: 4
draft3 size: 6
@@ -1,11 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using byte_container_with_subtype = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>;
int main()
{
std::cout << std::boolalpha
<< std::is_same<byte_container_with_subtype::container_type, std::vector<std::uint8_t>>::value
<< std::endl;
}
@@ -1,10 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using byte_container_with_subtype = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>;
int main()
{
std::cout << std::boolalpha
<< std::is_same<byte_container_with_subtype::subtype_type, std::uint64_t>::value << std::endl;
}
@@ -19,9 +19,25 @@ 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) << '\n' << j.contains("/baz"_json_pointer) << std::endl;
// an array index with a leading '0' is not found
<< j.contains("/array/01"_json_pointer) << '\n' try
// an array index that is not a number is not found {
<< j.contains("/array/one"_json_pointer) << std::endl; // try to use an array index with leading '0'
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,5 +5,3 @@ true
false false
false false
false false
false
false
@@ -1,10 +1,11 @@
#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::json::with_array_t<custom_array_type>; using custom_json = nlohmann::basic_json<std::map, custom_array_type>;
int main() int main()
{ {
@@ -1,10 +1,16 @@
#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::json::with_binary_t<custom_binary_type>; using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool,
std::int64_t, std::uint64_t, double, std::allocator,
nlohmann::adl_serializer, custom_binary_type>;
int main() int main()
{ {
@@ -1,11 +1,12 @@
#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::json::with_object_t<custom_object_type>; using custom_json = nlohmann::basic_json<custom_object_type, std::vector>;
int main() int main()
{ {
@@ -1,10 +1,12 @@
#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::json::with_string_t<custom_string_type>; using custom_json = nlohmann::basic_json<std::map, std::vector, custom_string_type>;
int main() int main()
{ {
@@ -1,13 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// an initializer_list_t is what a braced-init-list of JSON values is deduced as
json::initializer_list_t init = {"a", 1, 2.0, false};
json j(init);
std::cout << j.dump() << std::endl;
}
@@ -1 +0,0 @@
["a",1,2.0,false]
@@ -1,10 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
std::cout << std::boolalpha
<< std::is_same<json::json_sax_t::binary_t, json::binary_t>::value << std::endl;
}
@@ -1 +0,0 @@
true
@@ -1,10 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
std::cout << std::boolalpha
<< std::is_same<json::json_sax_t::number_float_t, json::number_float_t>::value << std::endl;
}
@@ -1 +0,0 @@
true
@@ -1,10 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
std::cout << std::boolalpha
<< std::is_same<json::json_sax_t::number_integer_t, json::number_integer_t>::value << std::endl;
}
@@ -1 +0,0 @@
true
@@ -1,10 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
std::cout << std::boolalpha
<< std::is_same<json::json_sax_t::number_unsigned_t, json::number_unsigned_t>::value << std::endl;
}
@@ -1 +0,0 @@
true
@@ -1,10 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
std::cout << std::boolalpha
<< std::is_same<json::json_sax_t::string_t, json::string_t>::value << std::endl;
}
@@ -1 +0,0 @@
true
-10
View File
@@ -1,10 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
std::cout << std::boolalpha
<< std::is_same<json::json_sax_t, nlohmann::json_sax<json>>::value << std::endl;
}
@@ -1 +0,0 @@
true
@@ -1,12 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
using Map = nlohmann::ordered_map<std::string, int>;
std::cout << std::boolalpha
<< "Container is std::vector<std::pair<const Key, T>>: "
<< std::is_same<Map::Container, std::vector<std::pair<const std::string, int>>>::value
<< std::endl;
}
@@ -1 +0,0 @@
Container is std::vector<std::pair<const Key, T>>: true
@@ -1,26 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
nlohmann::ordered_map<std::string, int> m;
m["one"] = 1;
m["two"] = 2;
// access an existing element
std::cout << "m.at(\"one\") = " << m.at("one") << std::endl;
// modify through the reference returned by at()
m.at("two") = 22;
std::cout << "m.at(\"two\") = " << m.at("two") << std::endl;
// accessing a missing key throws
try
{
m.at("three");
}
catch (const std::out_of_range& e)
{
std::cout << "exception: " << e.what() << std::endl;
}
}
@@ -1,3 +0,0 @@
m.at("one") = 1
m.at("two") = 22
exception: key not found
@@ -1,12 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
nlohmann::ordered_map<std::string, int> m;
m["one"] = 1;
std::cout << std::boolalpha
<< "m.count(\"one\") = " << m.count("one") << '\n'
<< "m.count(\"two\") = " << m.count("two") << std::endl;
}
@@ -1,2 +0,0 @@
m.count("one") = 1
m.count("two") = 0
@@ -1,15 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
nlohmann::ordered_map<std::string, std::string> m;
// emplace a new element
auto res1 = m.emplace("one", "eins");
std::cout << std::boolalpha << "inserted: " << res1.second << ", value: " << res1.first->second << std::endl;
// emplace with an already-existing key: no-op, returns the existing element
auto res2 = m.emplace("one", "uno");
std::cout << std::boolalpha << "inserted: " << res2.second << ", value: " << res2.first->second << std::endl;
}
@@ -1,2 +0,0 @@
inserted: true, value: eins
inserted: false, value: eins
@@ -1,24 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
nlohmann::ordered_map<std::string, int> m;
m["one"] = 1;
m["two"] = 2;
m["three"] = 3;
// erase by key
std::size_t removed = m.erase("two");
std::cout << "removed by key: " << removed << std::endl;
// erase by iterator
m.erase(m.begin());
std::cout << "remaining: ";
for (const auto& element : m)
{
std::cout << element.first << ' ';
}
std::cout << std::endl;
}
@@ -1,2 +0,0 @@
removed by key: 1
remaining: three
@@ -1,19 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
nlohmann::ordered_map<std::string, int> m;
m["one"] = 1;
auto it = m.find("one");
if (it != m.end())
{
std::cout << "found: " << it->first << " = " << it->second << std::endl;
}
if (m.find("two") == m.end())
{
std::cout << "\"two\" not found" << std::endl;
}
}
@@ -1,2 +0,0 @@
found: one = 1
"two" not found
@@ -1,21 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
nlohmann::ordered_map<std::string, int> m;
// insert a single value
auto res = m.insert({"one", 1});
std::cout << std::boolalpha << "inserted: " << res.second << std::endl;
// insert a range from another container
std::vector<std::pair<const std::string, int>> more = {{"two", 2}, {"three", 3}};
m.insert(more.begin(), more.end());
for (const auto& element : m)
{
std::cout << element.first << ':' << element.second << ' ';
}
std::cout << std::endl;
}
@@ -1,2 +0,0 @@
inserted: true
one:1 two:2 three:3
@@ -1,12 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
using Map = nlohmann::ordered_map<std::string, int>;
Map::key_compare compare{};
std::cout << std::boolalpha
<< "compare(\"a\", \"a\") = " << compare("a", "a") << '\n'
<< "compare(\"a\", \"b\") = " << compare("a", "b") << std::endl;
}
@@ -1,2 +0,0 @@
compare("a", "a") = true
compare("a", "b") = false
@@ -1,14 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
int main()
{
nlohmann::ordered_map<std::string, int> m;
// operator[] inserts a default-constructed value if the key doesn't exist yet
m["one"] = 1;
std::cout << "m[\"one\"] = " << m["one"] << std::endl;
// accessing again just returns the existing value
std::cout << "m[\"one\"] = " << m["one"] << std::endl;
}
@@ -1,2 +0,0 @@
m["one"] = 1
m["one"] = 1
+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 j = json::parse("[1,2,3,]"); json::parse("[1,2,3,]");
} }
catch (const json::parse_error& e) catch (const json::parse_error& e)
{ {
+3 -3
View File
@@ -51,16 +51,16 @@ If you do want to preserve the **insertion order**, you can use the type [`nlohm
--8<-- "examples/ordered_json.output" --8<-- "examples/ordered_json.output"
``` ```
Alternatively, [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) also preserves the insertion order and, unlike [`ordered_map`](../api/ordered_map/index.md), keeps a lookup index, so it does not have the quadratic cost described below. It is used through a small adapter ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). Alternatively, [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) also preserves the insertion order and, unlike [`ordered_map`](../api/ordered_map.md), keeps a lookup index, so it does not have the quadratic cost described below. It is used through a small adapter ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
If the order does not matter and you only want faster lookup, `boost::unordered_flat_map`, `absl::flat_hash_map`, `absl::node_hash_map`, and several other hash maps work through an adapter that restores the template argument order `basic_json` expects; see [Template Parameter Requirements](types/template_parameters.md#objecttype). Note these are *unordered*, not insertion-ordered. If the order does not matter and you only want faster lookup, `boost::unordered_flat_map`, `absl::flat_hash_map`, `absl::node_hash_map`, and several other hash maps work through an adapter that restores the template argument order `basic_json` expects; see [Template Parameter Requirements](types/template_parameters.md#objecttype). Note these are *unordered*, not insertion-ordered.
[`tsl::ordered_map`](https://github.com/Tessil/ordered-map) cannot be used: its iterators expose the mapped value as `const`, while `basic_json` needs to modify it in place. [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) cannot be used: its iterators expose the mapped value as `const`, while `basic_json` needs to modify it in place.
The [`ordered_map`](../api/ordered_map/index.md) behind `nlohmann::ordered_json` is deliberately minimal and has no lookup The [`ordered_map`](../api/ordered_map.md) behind `nlohmann::ordered_json` is deliberately minimal and has no lookup
index, so every key access is a linear scan and building an object of `n` keys costs O(n²). This is unnoticeable at index, so every key access is a linear scan and building an object of `n` keys costs O(n²). This is unnoticeable at
typical object sizes but becomes significant for objects with many thousands of keys; see typical object sizes but becomes significant for objects with many thousands of keys; see
[`ordered_map` complexity](../api/ordered_map/index.md#complexity). The alternatives above keep a lookup index and do not [`ordered_map` complexity](../api/ordered_map.md#complexity). The alternatives above keep a lookup index and do not
have this cost. have this cost.
### Notes on parsing ### Notes on parsing
+2 -2
View File
@@ -88,10 +88,10 @@ whether it is worth the loss of human readability at all -- depends on the actua
The default [`json`](../api/json.md) type stores object keys in a `#!cpp std::map`, giving logarithmic-time lookup, The default [`json`](../api/json.md) type stores object keys in a `#!cpp std::map`, giving logarithmic-time lookup,
insertion, and erasure, at the cost of sorting keys alphabetically rather than preserving insertion order (see insertion, and erasure, at the cost of sorting keys alphabetically rather than preserving insertion order (see
[Object Order](object_order.md)). [`ordered_json`](../api/ordered_json.md) uses [Object Order](object_order.md)). [`ordered_json`](../api/ordered_json.md) uses
[`nlohmann::ordered_map`](../api/ordered_map/index.md) instead, a `#!cpp std::vector`-backed container with no lookup index: [`nlohmann::ordered_map`](../api/ordered_map.md) instead, a `#!cpp std::vector`-backed container with no lookup index:
every key-based operation is a **linear scan**, so building an object of `n` distinct keys costs **O(n²)** in total -- every key-based operation is a **linear scan**, so building an object of `n` distinct keys costs **O(n²)** in total --
this applies equally to inserting keys one by one and to parsing an object, since the parser inserts each key as it is this applies equally to inserting keys one by one and to parsing an object, since the parser inserts each key as it is
read. The [measurements on the `ordered_map` page](../api/ordered_map/index.md#complexity) show this is read. The [measurements on the `ordered_map` page](../api/ordered_map.md#complexity) show this is
negligible at typical object sizes (2000 keys: 0.7 ms for `json` vs. 3.6 ms for `ordered_json`, a 5x factor) but grows negligible at typical object sizes (2000 keys: 0.7 ms for `json` vs. 3.6 ms for `ordered_json`, a 5x factor) but grows
steeply for large, machine-generated objects (16 000 keys: 3.3 ms vs. 181.6 ms, a 54x factor). steeply for large, machine-generated objects (16 000 keys: 3.3 ms vs. 181.6 ms, a 54x factor).
@@ -351,8 +351,9 @@ 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="1" ```cpp hl_lines="2"
using json_ld = nlohmann::json::with_float_t<long double>; using json_ld = nlohmann::basic_json<std::map, std::vector, std::string, bool,
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,10 +8,6 @@ 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:
@@ -42,7 +38,7 @@ Requirements are split into two groups:
| Template parameter | Default | Notable substitutes | | Template parameter | Default | Notable substitutes |
|-------------------------------------------------------------------|-----------------------------------|-----------------------------------------------------------------------| |-------------------------------------------------------------------|-----------------------------------|-----------------------------------------------------------------------|
| [`ObjectType`](#objecttype) | `std::map` | [`nlohmann::ordered_map`](../../api/ordered_map/index.md), Abseil hash maps | | [`ObjectType`](#objecttype) | `std::map` | [`nlohmann::ordered_map`](../../api/ordered_map.md), Abseil hash maps |
| [`ArrayType`](#arraytype) | `std::vector` | `#!cpp std::deque` | | [`ArrayType`](#arraytype) | `std::vector` | `#!cpp std::deque` |
| [`StringType`](#stringtype) | `std::string` | `std::string`-like types over `char` | | [`StringType`](#stringtype) | `std::string` | `std::string`-like types over `char` |
| [`BooleanType`](#booleantype) | `bool` | none worth using | | [`BooleanType`](#booleantype) | `bool` | none worth using |
@@ -147,7 +143,7 @@ struct unordered_map_object
using base_t::base_t; using base_t::base_t;
}; };
using unordered_json = nlohmann::json::with_object_t<unordered_map_object>; using unordered_json = nlohmann::basic_json<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
@@ -180,7 +176,7 @@ struct flat_hash_object
using base_t::base_t; using base_t::base_t;
}; };
using flat_hash_json = nlohmann::json::with_object_t<flat_hash_object>; using flat_hash_json = nlohmann::basic_json<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,
@@ -235,7 +231,7 @@ The library does not sort or de-duplicate keys itself; the behavior described in
| Container | Notes | | Container | Notes |
|----------------------------------------------------------------------------------|-------------------------------------------------------------------------------| |----------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
| `#!cpp std::map` (default) | | | `#!cpp std::map` (default) | |
| [`nlohmann::ordered_map`](../../api/ordered_map/index.md) | used by [`ordered_json`](../../api/ordered_json.md); keeps insertion order | | [`nlohmann::ordered_map`](../../api/ordered_map.md) | used by [`ordered_json`](../../api/ordered_json.md); keeps insertion order |
| [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) | keeps insertion order; adapter puts `fifo_map_compare` in the comparator slot | | [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) | keeps insertion order; adapter puts `fifo_map_compare` in the comparator slot |
| `boost::container::map`, `boost::container::flat_map` | no adapter needed | | `boost::container::map`, `boost::container::flat_map` | no adapter needed |
| `#!cpp std::unordered_map` | through the adapter above; not with libstdc++ 9, see the note | | `#!cpp std::unordered_map` | through the adapter above; not with libstdc++ 9, see the note |
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -50,7 +50,7 @@ The public headers are in [`include/nlohmann`](https://github.com/nlohmann/json/
- [`adl_serializer.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/adl_serializer.hpp), [`byte_container_with_subtype.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/byte_container_with_subtype.hpp), and [`ordered_map.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/ordered_map.hpp) define - [`adl_serializer.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/adl_serializer.hpp), [`byte_container_with_subtype.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/byte_container_with_subtype.hpp), and [`ordered_map.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/ordered_map.hpp) define
[`adl_serializer`](../api/adl_serializer/index.md), [`adl_serializer`](../api/adl_serializer/index.md),
[`byte_container_with_subtype`](../api/byte_container_with_subtype/index.md), and [`byte_container_with_subtype`](../api/byte_container_with_subtype/index.md), and
[`ordered_map`](../api/ordered_map/index.md). [`ordered_map`](../api/ordered_map.md).
Everything else lives in [`detail/`](https://github.com/nlohmann/json/tree/develop/include/nlohmann/detail) and namespace `nlohmann::detail`, which is not part of the public API. Paths Everything else lives in [`detail/`](https://github.com/nlohmann/json/tree/develop/include/nlohmann/detail) and namespace `nlohmann::detail`, which is not part of the public API. Paths
below are relative to `include/nlohmann`. below are relative to `include/nlohmann`.
@@ -97,7 +97,7 @@ is generated from these files with `make amalgamate` and must not be edited by h
The library provides two specializations: The library provides two specializations:
- [`json`](../api/json.md) uses all default template arguments. - [`json`](../api/json.md) uses all default template arguments.
- [`ordered_json`](../api/ordered_json.md) uses [`ordered_map`](../api/ordered_map/index.md) as `ObjectType` to keep the - [`ordered_json`](../api/ordered_json.md) uses [`ordered_map`](../api/ordered_map.md) as `ObjectType` to keep the
insertion order of object keys. insertion order of object keys.
The requirements on the template arguments are listed in The requirements on the template arguments are listed in
+1 -2
View File
@@ -2,8 +2,7 @@
This page summarizes the notable changes of every release and links to the relevant documentation. This page summarizes the notable changes of every release and links to the relevant documentation.
The **complete release notes** — including all changes, the download files, and their checksums — are The **complete release notes** — including all changes, the download files, and their checksums — are
published on the [GitHub releases page](https://github.com/nlohmann/json/releases). For a raw, published on the [GitHub releases page](https://github.com/nlohmann/json/releases).
signature-level diff of the public API between releases, see [API Changes](api_changes.md).
!!! info "Unreleased changes" !!! info "Unreleased changes"
@@ -116,7 +116,7 @@ function to use instead.
=== "Deprecated" === "Deprecated"
```cpp ```cpp
using my_json = nlohmann::json::with_string_t<my_string_type>; using my_json = nlohmann::basic_json<std::map, std::vector, my_string_type>;
nlohmann::json_pointer<my_json> ptr("/foo/bar/1"); nlohmann::json_pointer<my_json> ptr("/foo/bar/1");
``` ```
+1 -28
View File
@@ -52,7 +52,6 @@ nav:
- "FAQ": home/faq.md - "FAQ": home/faq.md
- home/exceptions.md - home/exceptions.md
- home/releases.md - home/releases.md
- home/api_changes.md
- home/design_goals.md - home/design_goals.md
- home/architecture.md - home/architecture.md
- home/customers.md - home/customers.md
@@ -124,7 +123,6 @@ nav:
- 'begin': api/basic_json/begin.md - 'begin': api/basic_json/begin.md
- 'binary': api/basic_json/binary.md - 'binary': api/basic_json/binary.md
- 'binary_t': api/basic_json/binary_t.md - 'binary_t': api/basic_json/binary_t.md
- 'bjdata_version_t': api/basic_json/bjdata_version_t.md
- 'boolean_t': api/basic_json/boolean_t.md - 'boolean_t': api/basic_json/boolean_t.md
- 'cbegin': api/basic_json/cbegin.md - 'cbegin': api/basic_json/cbegin.md
- 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md - 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md
@@ -163,7 +161,6 @@ nav:
- 'get_to': api/basic_json/get_to.md - 'get_to': api/basic_json/get_to.md
- 'std::formatter&lt;basic_json&gt;': api/basic_json/std_formatter.md - 'std::formatter&lt;basic_json&gt;': api/basic_json/std_formatter.md
- 'std::hash&lt;basic_json&gt;': api/basic_json/std_hash.md - 'std::hash&lt;basic_json&gt;': api/basic_json/std_hash.md
- 'initializer_list_t': api/basic_json/initializer_list_t.md
- 'input_format_t': api/basic_json/input_format_t.md - 'input_format_t': api/basic_json/input_format_t.md
- 'insert': api/basic_json/insert.md - 'insert': api/basic_json/insert.md
- 'invalid_iterator': api/basic_json/invalid_iterator.md - 'invalid_iterator': api/basic_json/invalid_iterator.md
@@ -182,7 +179,6 @@ nav:
- 'is_structured': api/basic_json/is_structured.md - 'is_structured': api/basic_json/is_structured.md
- 'items': api/basic_json/items.md - 'items': api/basic_json/items.md
- 'json_base_class_t': api/basic_json/json_base_class_t.md - 'json_base_class_t': api/basic_json/json_base_class_t.md
- 'json_sax_t': api/basic_json/json_sax_t.md
- 'json_serializer': api/basic_json/json_serializer.md - 'json_serializer': api/basic_json/json_serializer.md
- 'max_size': api/basic_json/max_size.md - 'max_size': api/basic_json/max_size.md
- 'meta': api/basic_json/meta.md - 'meta': api/basic_json/meta.md
@@ -241,13 +237,11 @@ nav:
- 'Overview': api/byte_container_with_subtype/index.md - 'Overview': api/byte_container_with_subtype/index.md
- '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md - '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md
- 'clear_subtype': api/byte_container_with_subtype/clear_subtype.md - 'clear_subtype': api/byte_container_with_subtype/clear_subtype.md
- 'container_type': api/byte_container_with_subtype/container_type.md
- 'has_subtype': api/byte_container_with_subtype/has_subtype.md - 'has_subtype': api/byte_container_with_subtype/has_subtype.md
- 'operator==': api/byte_container_with_subtype/operator_eq.md - 'operator==': api/byte_container_with_subtype/operator_eq.md
- 'operator!=': api/byte_container_with_subtype/operator_ne.md - 'operator!=': api/byte_container_with_subtype/operator_ne.md
- 'set_subtype': api/byte_container_with_subtype/set_subtype.md - 'set_subtype': api/byte_container_with_subtype/set_subtype.md
- 'subtype': api/byte_container_with_subtype/subtype.md - 'subtype': api/byte_container_with_subtype/subtype.md
- 'subtype_type': api/byte_container_with_subtype/subtype_type.md
- adl_serializer: - adl_serializer:
- 'Overview': api/adl_serializer/index.md - 'Overview': api/adl_serializer/index.md
- 'from_json': api/adl_serializer/from_json.md - 'from_json': api/adl_serializer/from_json.md
@@ -274,46 +268,25 @@ nav:
- 'to_string': api/json_pointer/to_string.md - 'to_string': api/json_pointer/to_string.md
- json_sax: - json_sax:
- 'Overview': api/json_sax/index.md - 'Overview': api/json_sax/index.md
- '(Constructor)': api/json_sax/json_sax.md
- '(Destructor)': api/json_sax/~json_sax.md
- 'operator=': api/json_sax/operator=.md
- 'binary': api/json_sax/binary.md - 'binary': api/json_sax/binary.md
- 'binary_t': api/json_sax/binary_t.md
- 'boolean': api/json_sax/boolean.md - 'boolean': api/json_sax/boolean.md
- 'end_array': api/json_sax/end_array.md - 'end_array': api/json_sax/end_array.md
- 'end_object': api/json_sax/end_object.md - 'end_object': api/json_sax/end_object.md
- 'key': api/json_sax/key.md - 'key': api/json_sax/key.md
- 'null': api/json_sax/null.md - 'null': api/json_sax/null.md
- 'number_float': api/json_sax/number_float.md - 'number_float': api/json_sax/number_float.md
- 'number_float_t': api/json_sax/number_float_t.md
- 'number_integer': api/json_sax/number_integer.md - 'number_integer': api/json_sax/number_integer.md
- 'number_integer_t': api/json_sax/number_integer_t.md
- 'number_unsigned': api/json_sax/number_unsigned.md - 'number_unsigned': api/json_sax/number_unsigned.md
- 'number_unsigned_t': api/json_sax/number_unsigned_t.md
- 'parse_error': api/json_sax/parse_error.md - 'parse_error': api/json_sax/parse_error.md
- 'start_array': api/json_sax/start_array.md - 'start_array': api/json_sax/start_array.md
- 'start_object': api/json_sax/start_object.md - 'start_object': api/json_sax/start_object.md
- 'string': api/json_sax/string.md - 'string': api/json_sax/string.md
- 'string_t': api/json_sax/string_t.md
- 'operator<<(basic_json), operator<<(json_pointer)': api/operator_ltlt.md - 'operator<<(basic_json), operator<<(json_pointer)': api/operator_ltlt.md
- 'operator>>(basic_json)': api/operator_gtgt.md - 'operator>>(basic_json)': api/operator_gtgt.md
- 'operator""_json': api/operator_literal_json.md - 'operator""_json': api/operator_literal_json.md
- 'operator""_json_pointer': api/operator_literal_json_pointer.md - 'operator""_json_pointer': api/operator_literal_json_pointer.md
- 'ordered_json': api/ordered_json.md - 'ordered_json': api/ordered_json.md
- ordered_map: - 'ordered_map': api/ordered_map.md
- 'Overview': api/ordered_map/index.md
- '(Constructor)': api/ordered_map/ordered_map.md
- '(Destructor)': api/ordered_map/~ordered_map.md
- 'operator=': api/ordered_map/operator=.md
- 'at': api/ordered_map/at.md
- 'Container': api/ordered_map/Container.md
- 'count': api/ordered_map/count.md
- 'emplace': api/ordered_map/emplace.md
- 'erase': api/ordered_map/erase.md
- 'find': api/ordered_map/find.md
- 'insert': api/ordered_map/insert.md
- 'key_compare': api/ordered_map/key_compare.md
- 'operator[]': api/ordered_map/operator[].md
- macros: - macros:
- 'Overview': api/macros/index.md - 'Overview': api/macros/index.md
- 'JSON_ASSERT': api/macros/json_assert.md - 'JSON_ASSERT': api/macros/json_assert.md
@@ -22,9 +22,7 @@ template<typename BinaryType>
class byte_container_with_subtype : public BinaryType class byte_container_with_subtype : public BinaryType
{ {
public: public:
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/container_type/
using container_type = BinaryType; using container_type = BinaryType;
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype_type/
using subtype_type = std::uint64_t; using subtype_type = std::uint64_t;
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
@@ -56,14 +54,12 @@ class byte_container_with_subtype : public BinaryType
, m_has_subtype(true) , m_has_subtype(true)
{} {}
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/operator_eq/
bool operator==(const byte_container_with_subtype& rhs) const bool operator==(const byte_container_with_subtype& rhs) const
{ {
return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) == return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype); std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
} }
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/operator_ne/
bool operator!=(const byte_container_with_subtype& rhs) const bool operator!=(const byte_container_with_subtype& rhs) const
{ {
return !(rhs == *this); return !(rhs == *this);
+2 -11
View File
@@ -9,15 +9,12 @@
#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 or platform-specific intrinsics where available and plain // compiler builtins where available and plain C++ otherwise, so they need no
// C++ otherwise, so they work regardless of byte order. // platform headers and work regardless of byte order.
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail
@@ -55,12 +52,6 @@ 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;
@@ -34,21 +34,15 @@ input.
template<typename BasicJsonType> template<typename BasicJsonType>
struct json_sax struct json_sax
{ {
/// @sa https://json.nlohmann.me/api/json_sax/number_integer_t/
using number_integer_t = typename BasicJsonType::number_integer_t; using number_integer_t = typename BasicJsonType::number_integer_t;
/// @sa https://json.nlohmann.me/api/json_sax/number_unsigned_t/
using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
/// @sa https://json.nlohmann.me/api/json_sax/number_float_t/
using number_float_t = typename BasicJsonType::number_float_t; using number_float_t = typename BasicJsonType::number_float_t;
/// @sa https://json.nlohmann.me/api/json_sax/string_t/
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
/// @sa https://json.nlohmann.me/api/json_sax/binary_t/
using binary_t = typename BasicJsonType::binary_t; using binary_t = typename BasicJsonType::binary_t;
/*! /*!
@brief a null value was read @brief a null value was read
@return whether parsing should proceed @return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/null/
*/ */
virtual bool null() = 0; virtual bool null() = 0;
@@ -56,7 +50,6 @@ struct json_sax
@brief a boolean value was read @brief a boolean value was read
@param[in] val boolean value @param[in] val boolean value
@return whether parsing should proceed @return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/boolean/
*/ */
virtual bool boolean(bool val) = 0; virtual bool boolean(bool val) = 0;
@@ -64,7 +57,6 @@ struct json_sax
@brief an integer number was read @brief an integer number was read
@param[in] val integer value @param[in] val integer value
@return whether parsing should proceed @return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/number_integer/
*/ */
virtual bool number_integer(number_integer_t val) = 0; virtual bool number_integer(number_integer_t val) = 0;
@@ -72,7 +64,6 @@ struct json_sax
@brief an unsigned integer number was read @brief an unsigned integer number was read
@param[in] val unsigned integer value @param[in] val unsigned integer value
@return whether parsing should proceed @return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/number_unsigned/
*/ */
virtual bool number_unsigned(number_unsigned_t val) = 0; virtual bool number_unsigned(number_unsigned_t val) = 0;
@@ -81,7 +72,6 @@ struct json_sax
@param[in] val floating-point value @param[in] val floating-point value
@param[in] s raw token value @param[in] s raw token value
@return whether parsing should proceed @return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/number_float/
*/ */
virtual bool number_float(number_float_t val, const string_t& s) = 0; virtual bool number_float(number_float_t val, const string_t& s) = 0;
@@ -90,7 +80,6 @@ struct json_sax
@param[in] val string value @param[in] val string value
@return whether parsing should proceed @return whether parsing should proceed
@note It is safe to move the passed string value. @note It is safe to move the passed string value.
@sa https://json.nlohmann.me/api/json_sax/string/
*/ */
virtual bool string(string_t& val) = 0; virtual bool string(string_t& val) = 0;
@@ -99,7 +88,6 @@ struct json_sax
@param[in] val binary value @param[in] val binary value
@return whether parsing should proceed @return whether parsing should proceed
@note It is safe to move the passed binary value. @note It is safe to move the passed binary value.
@sa https://json.nlohmann.me/api/json_sax/binary/
*/ */
virtual bool binary(binary_t& val) = 0; virtual bool binary(binary_t& val) = 0;
@@ -108,7 +96,6 @@ struct json_sax
@param[in] elements number of object elements or -1 if unknown @param[in] elements number of object elements or -1 if unknown
@return whether parsing should proceed @return whether parsing should proceed
@note binary formats may report the number of elements @note binary formats may report the number of elements
@sa https://json.nlohmann.me/api/json_sax/start_object/
*/ */
virtual bool start_object(std::size_t elements) = 0; virtual bool start_object(std::size_t elements) = 0;
@@ -117,14 +104,12 @@ struct json_sax
@param[in] val object key @param[in] val object key
@return whether parsing should proceed @return whether parsing should proceed
@note It is safe to move the passed string. @note It is safe to move the passed string.
@sa https://json.nlohmann.me/api/json_sax/key/
*/ */
virtual bool key(string_t& val) = 0; virtual bool key(string_t& val) = 0;
/*! /*!
@brief the end of an object was read @brief the end of an object was read
@return whether parsing should proceed @return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/end_object/
*/ */
virtual bool end_object() = 0; virtual bool end_object() = 0;
@@ -133,14 +118,12 @@ struct json_sax
@param[in] elements number of array elements or -1 if unknown @param[in] elements number of array elements or -1 if unknown
@return whether parsing should proceed @return whether parsing should proceed
@note binary formats may report the number of elements @note binary formats may report the number of elements
@sa https://json.nlohmann.me/api/json_sax/start_array/
*/ */
virtual bool start_array(std::size_t elements) = 0; virtual bool start_array(std::size_t elements) = 0;
/*! /*!
@brief the end of an array was read @brief the end of an array was read
@return whether parsing should proceed @return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/end_array/
*/ */
virtual bool end_array() = 0; virtual bool end_array() = 0;
@@ -150,23 +133,16 @@ struct json_sax
@param[in] last_token the last read token @param[in] last_token the last read token
@param[in] ex an exception object describing the error @param[in] ex an exception object describing the error
@return whether parsing should proceed (must return false) @return whether parsing should proceed (must return false)
@sa https://json.nlohmann.me/api/json_sax/parse_error/
*/ */
virtual bool parse_error(std::size_t position, virtual bool parse_error(std::size_t position,
const std::string& last_token, const std::string& last_token,
const detail::exception& ex) = 0; const detail::exception& ex) = 0;
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
json_sax() = default; json_sax() = default;
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
json_sax(const json_sax&) = default; json_sax(const json_sax&) = default;
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
json_sax(json_sax&&) noexcept = default; json_sax(json_sax&&) noexcept = default;
/// @sa https://json.nlohmann.me/api/json_sax/operator=/
json_sax& operator=(const json_sax&) = default; json_sax& operator=(const json_sax&) = default;
/// @sa https://json.nlohmann.me/api/json_sax/operator=/
json_sax& operator=(json_sax&&) noexcept = default; json_sax& operator=(json_sax&&) noexcept = default;
/// @sa https://json.nlohmann.me/api/json_sax/~json_sax/
virtual ~json_sax() = default; virtual ~json_sax() = default;
}; };
+39 -152
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
@@ -57,7 +57,6 @@ class json_pointer
public: public:
// for backwards compatibility accept BasicJsonType // for backwards compatibility accept BasicJsonType
/// @sa https://json.nlohmann.me/api/json_pointer/string_t/
using string_t = typename string_t_helper<RefStringType>::type; using string_t = typename string_t_helper<RefStringType>::type;
/// @brief create JSON pointer /// @brief create JSON pointer
@@ -360,82 +359,33 @@ class json_pointer
private: private:
/*! /*!
@brief the pointer prefixes of a flattened object, and which of them denote arrays @brief the reference token sequences that 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.
*/ */
struct prefix_tree using array_parents_t = std::set<std::vector<string_t>>;
{
// 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 (times the logarithm Complexity: Linear in the number of reference tokens.
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 prefix_tree& tree) const BasicJsonType& get_and_create(BasicJsonType& j, const array_parents_t& array_parents) const
{ {
auto* result = &j; auto* result = &j;
// the number of the prefix consumed so far; used to look up whether // the reference tokens that have been consumed so far; used to look up
// the value to be created below is an array or an object // whether the value to be created below is an array or an object
std::size_t id = 0; std::vector<string_t> prefix;
// 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
@@ -445,7 +395,7 @@ class json_pointer
{ {
case detail::value_t::null: case detail::value_t::null:
{ {
if (tree.is_array[id]) if (array_parents.find(prefix) != array_parents.end())
{ {
// 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
@@ -490,7 +440,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));
} }
id = tree.find_child(id, reference_token); prefix.push_back(reference_token);
} }
return *result; return *result;
@@ -928,74 +878,49 @@ 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)
{ {
using object_const_iterator = typename BasicJsonType::object_t::const_iterator; switch (value.type())
// 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 (v.m_data.m_value.array->empty()) if (value.m_data.m_value.array->empty())
{ {
// flatten empty array as null // flatten empty array as null
result[path] = nullptr; result[reference_string] = nullptr;
} }
else else
{ {
stack.emplace_back(&v, object_const_iterator(), path.size()); // iterate array and use index as a reference string
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 (v.m_data.m_value.object->empty()) if (value.m_data.m_value.object->empty())
{ {
// flatten empty object as null // flatten empty object as null
result[path] = nullptr; result[reference_string] = nullptr;
} }
else else
{ {
stack.emplace_back(&v, v.m_data.m_value.object->begin(), path.size()); // iterate object and use keys as reference string
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:
@@ -1009,50 +934,8 @@ class json_pointer
default: default:
{ {
// add a primitive value with its reference string // add a primitive value with its reference string
result[path] = v; result[reference_string] = value;
return; break;
}
}
};
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);
} }
} }
} }
@@ -1080,15 +963,19 @@ 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 prefix_tree) // objects (see array_parents_t)
prefix_tree tree; array_parents_t array_parents;
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::size_t id = 0; std::vector<string_t> prefix;
for (auto& reference_token : ptr.reference_tokens) for (auto& reference_token : ptr.reference_tokens)
{ {
id = tree.add_child(id, std::move(reference_token)); if (reference_token == "0")
{
array_parents.insert(prefix);
}
prefix.push_back(std::move(reference_token));
} }
} }
@@ -1104,7 +991,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, tree) = element.second; json_pointer(element.first).get_and_create(result, array_parents) = element.second;
} }
return result; return result;
+77 -126
View File
@@ -85,12 +85,6 @@ 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;
@@ -250,7 +244,16 @@ class binary_writer
case value_t::string: case value_t::string:
{ {
write_cbor_string(*j.m_data.m_value.string, j); string_t storage;
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;
} }
@@ -313,20 +316,23 @@ 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 written directly (not via a temporary // el.first is checked here, against the object as
// basic_json), with the object as diagnostics context // diagnostics context, because write_cbor(el.first)
write_cbor_string(el.first, j); // converts it to a temporary basic_json that would be
// 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;
@@ -485,7 +491,39 @@ class binary_writer
case value_t::string: case value_t::string:
{ {
write_msgpack_string(*j.m_data.m_value.string, j); string_t storage;
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;
} }
@@ -591,20 +629,19 @@ 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 written directly with the // as in write_cbor, el.first is checked here against the
// object as diagnostics context // object as diagnostics context; the recursive call below
write_msgpack_string(el.first, j); // handles keep/replace/ignore like any other string
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;
@@ -782,10 +819,8 @@ 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(key_string, j, storage); const string_t& key = sanitize_utf8_for_write(el.first, 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()),
@@ -990,9 +1025,13 @@ class binary_writer
continue; continue;
} }
// the key is written directly (not via a temporary basic_json), // el.first is checked here, against the object as diagnostics
// with the object as diagnostics context, as in write_cbor // context, like the matching check in write_cbor's object case
write_cbor_string(current.object_it->first, *current.value); if (error_handler == error_handler_t::strict)
{
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);
@@ -1067,9 +1106,11 @@ class binary_writer
continue; continue;
} }
// as in write_cbor_iterative, the key is written directly with if (error_handler == error_handler_t::strict)
// the object as diagnostics context {
write_msgpack_string(current.object_it->first, *current.value); check_utf8(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);
@@ -1325,10 +1366,8 @@ 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(key_string, j, storage); const string_t& key = sanitize_utf8_for_write(current.object_it->first, 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()),
@@ -1949,85 +1988,6 @@ 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 //
//////////// ////////////
@@ -2770,11 +2730,6 @@ 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
@@ -2804,10 +2759,6 @@ 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
JSON_INLINE_VARIABLE constexpr std::uint8_t UTF8_ACCEPT = 0; static constexpr std::uint8_t UTF8_ACCEPT = 0;
JSON_INLINE_VARIABLE constexpr std::uint8_t UTF8_REJECT = 1; static 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
+1 -41
View File
@@ -205,34 +205,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
using serializer = ::nlohmann::detail::serializer<basic_json>; using serializer = ::nlohmann::detail::serializer<basic_json>;
public: public:
/// @brief the type of the JSON value
/// @sa https://json.nlohmann.me/api/basic_json/value_t/
using value_t = detail::value_t; using value_t = detail::value_t;
/// JSON Pointer, see @ref nlohmann::json_pointer /// JSON Pointer, see @ref nlohmann::json_pointer
using json_pointer = ::nlohmann::json_pointer<StringType>; using json_pointer = ::nlohmann::json_pointer<StringType>;
template<typename T, typename SFINAE> template<typename T, typename SFINAE>
using json_serializer = JSONSerializer<T, SFINAE>; using json_serializer = JSONSerializer<T, SFINAE>;
/// how to treat decoding errors /// how to treat decoding errors
/// @sa https://json.nlohmann.me/api/basic_json/error_handler_t/
using error_handler_t = detail::error_handler_t; using error_handler_t = detail::error_handler_t;
/// how to treat CBOR tags /// how to treat CBOR tags
/// @sa https://json.nlohmann.me/api/basic_json/cbor_tag_handler_t/
using cbor_tag_handler_t = detail::cbor_tag_handler_t; using cbor_tag_handler_t = detail::cbor_tag_handler_t;
/// how to encode BJData /// how to encode BJData
/// @sa https://json.nlohmann.me/api/basic_json/bjdata_version_t/
using bjdata_version_t = detail::bjdata_version_t; using bjdata_version_t = detail::bjdata_version_t;
/// base class used to inject custom functionality into each instance of basic_json /// base class used to inject custom functionality into each instance of basic_json
/// @sa https://json.nlohmann.me/api/basic_json/json_base_class_t/ /// @sa https://json.nlohmann.me/api/basic_json/json_base_class_t/
using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>; using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;
/// helper type for initializer lists of basic_json values /// helper type for initializer lists of basic_json values
/// @sa https://json.nlohmann.me/api/basic_json/initializer_list_t/
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>; using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
/// @brief the type of the SAX interface used to parse and serialize the JSON value
/// @sa https://json.nlohmann.me/api/basic_json/input_format_t/
using input_format_t = detail::input_format_t; using input_format_t = detail::input_format_t;
/// SAX interface type, see @ref nlohmann::json_sax /// SAX interface type, see @ref nlohmann::json_sax
/// @sa https://json.nlohmann.me/api/basic_json/json_sax_t/
using json_sax_t = json_sax<basic_json>; using json_sax_t = json_sax<basic_json>;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -438,19 +429,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// the template arguments passed to class @ref basic_json. /// the template arguments passed to class @ref basic_json.
/// @{ /// @{
#if defined(JSON_HAS_CPP_14)
/// @brief default object key comparator type /// @brief default object key comparator type
/// The actual object key comparator type (@ref object_comparator_t) may be /// The actual object key comparator type (@ref object_comparator_t) may be
/// different. /// different.
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/ /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
#if defined(JSON_HAS_CPP_14)
// use of transparent comparator avoids unnecessary repeated construction of temporaries // use of transparent comparator avoids unnecessary repeated construction of temporaries
// in functions involving lookup by key with types other than object_t::key_type (aka. StringType) // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
using default_object_comparator_t = std::less<>; using default_object_comparator_t = std::less<>;
#else #else
/// @brief default object key comparator type
/// The actual object key comparator type (@ref object_comparator_t) may be
/// different.
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
using default_object_comparator_t = std::less<StringType>; using default_object_comparator_t = std::less<StringType>;
#endif #endif
@@ -2518,7 +2505,6 @@ public:
// other constructors and destructor // // other constructors and destructor //
/////////////////////////////////////// ///////////////////////////////////////
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
template<typename JsonRef, template<typename JsonRef,
detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>, detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 > std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
@@ -3104,8 +3090,6 @@ public:
@throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
@since version 2.1.0 @since version 2.1.0
@sa https://json.nlohmann.me/api/basic_json/get/
*/ */
template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>> template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
#if defined(JSON_HAS_CPP_14) #if defined(JSON_HAS_CPP_14)
@@ -3149,8 +3133,6 @@ public:
@sa see @ref get_ptr() for explicit pointer-member access @sa see @ref get_ptr() for explicit pointer-member access
@since version 1.0.0 @since version 1.0.0
@sa https://json.nlohmann.me/api/basic_json/get/
*/ */
template<typename PointerType, typename std::enable_if< template<typename PointerType, typename std::enable_if<
std::is_pointer<PointerType>::value, int>::type = 0> std::is_pointer<PointerType>::value, int>::type = 0>
@@ -3177,7 +3159,6 @@ public:
// specialization to allow calling get_to with a basic_json value // specialization to allow calling get_to with a basic_json value
// see https://github.com/nlohmann/json/issues/2175 // see https://github.com/nlohmann/json/issues/2175
/// @sa https://json.nlohmann.me/api/basic_json/get_to/
template<typename ValueType, template<typename ValueType,
detail::enable_if_t < detail::enable_if_t <
detail::is_basic_json<ValueType>::value, detail::is_basic_json<ValueType>::value,
@@ -3188,7 +3169,6 @@ public:
return v; return v;
} }
/// @sa https://json.nlohmann.me/api/basic_json/get_to/
template < template <
typename T, std::size_t N, typename T, std::size_t N,
typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
@@ -3253,7 +3233,6 @@ public:
@since version 1.0.0 @since version 1.0.0
*/ */
/// @sa https://json.nlohmann.me/api/basic_json/operator_ValueType/
template < typename ValueType, typename std::enable_if < template < typename ValueType, typename std::enable_if <
detail::conjunction < detail::conjunction <
detail::negation<std::is_pointer<ValueType>>, detail::negation<std::is_pointer<ValueType>>,
@@ -3562,14 +3541,12 @@ public:
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
// (they seemingly cannot be constrained to resolve the ambiguity) // (they seemingly cannot be constrained to resolve the ambiguity)
/// @sa https://json.nlohmann.me/api/basic_json/operator[]/
template<typename T> template<typename T>
reference operator[](T* key) reference operator[](T* key)
{ {
return operator[](typename object_t::key_type(key)); return operator[](typename object_t::key_type(key));
} }
/// @sa https://json.nlohmann.me/api/basic_json/operator[]/
template<typename T> template<typename T>
const_reference operator[](T* key) const const_reference operator[](T* key) const
{ {
@@ -3747,7 +3724,6 @@ public:
return found != nullptr ? found->template get<ReturnType>() : std::forward<ValueType>(default_value); return found != nullptr ? found->template get<ReturnType>() : std::forward<ValueType>(default_value);
} }
/// @sa https://json.nlohmann.me/api/basic_json/value/
template < class ValueType, class BasicJsonType, detail::enable_if_t < template < class ValueType, class BasicJsonType, detail::enable_if_t <
detail::is_basic_json<BasicJsonType>::value detail::is_basic_json<BasicJsonType>::value
&& detail::is_getable<basic_json_t, ValueType>::value && detail::is_getable<basic_json_t, ValueType>::value
@@ -3762,7 +3738,6 @@ public:
} }
#endif #endif
/// @sa https://json.nlohmann.me/api/basic_json/value/
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type, template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t < detail::enable_if_t <
detail::is_basic_json<BasicJsonType>::value detail::is_basic_json<BasicJsonType>::value
@@ -4130,7 +4105,6 @@ public:
return ptr.contains(this); return ptr.contains(this);
} }
/// @sa https://json.nlohmann.me/api/basic_json/contains/
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
@@ -5647,7 +5621,6 @@ public:
return result; return result;
} }
/// @sa https://json.nlohmann.me/api/basic_json/parse/
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
static basic_json parse(detail::span_input_adapter&& i, static basic_json parse(detail::span_input_adapter&& i,
@@ -5689,7 +5662,6 @@ public:
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true); return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
} }
/// @sa https://json.nlohmann.me/api/basic_json/accept/
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
static bool accept(detail::span_input_adapter&& i, static bool accept(detail::span_input_adapter&& i,
@@ -6136,7 +6108,6 @@ public:
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::cbor, strict, allow_exceptions, error_handler, tag_handler); return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::cbor, strict, allow_exceptions, error_handler, tag_handler);
} }
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
template<typename T> template<typename T>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
@@ -6152,7 +6123,6 @@ public:
} }
#endif #endif
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
static basic_json from_cbor(detail::span_input_adapter&& i, static basic_json from_cbor(detail::span_input_adapter&& i,
@@ -6192,7 +6162,6 @@ public:
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::msgpack, strict, allow_exceptions, error_handler); return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::msgpack, strict, allow_exceptions, error_handler);
} }
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
template<typename T> template<typename T>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
@@ -6207,7 +6176,6 @@ public:
} }
#endif #endif
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
static basic_json from_msgpack(detail::span_input_adapter&& i, static basic_json from_msgpack(detail::span_input_adapter&& i,
@@ -6246,7 +6214,6 @@ public:
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::ubjson, strict, allow_exceptions, error_handler); return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::ubjson, strict, allow_exceptions, error_handler);
} }
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
template<typename T> template<typename T>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
@@ -6261,7 +6228,6 @@ public:
} }
#endif #endif
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
static basic_json from_ubjson(detail::span_input_adapter&& i, static basic_json from_ubjson(detail::span_input_adapter&& i,
@@ -6376,7 +6342,6 @@ public:
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bson, strict, allow_exceptions, error_handler); return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bson, strict, allow_exceptions, error_handler);
} }
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
template<typename T> template<typename T>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
@@ -6391,7 +6356,6 @@ public:
} }
#endif #endif
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
static basic_json from_bson(detail::span_input_adapter&& i, static basic_json from_bson(detail::span_input_adapter&& i,
@@ -6420,7 +6384,6 @@ public:
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
@@ -6439,7 +6402,6 @@ public:
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
@@ -6458,7 +6420,6 @@ public:
return ptr.get_checked(this); return ptr.get_checked(this);
} }
/// @sa https://json.nlohmann.me/api/basic_json/at/
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
@@ -6477,7 +6438,6 @@ public:
return ptr.get_checked(this); return ptr.get_checked(this);
} }
/// @sa https://json.nlohmann.me/api/basic_json/at/
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
Loaded 100 of 162 files, more files were not shown because too many files have changed in this diff. Show more