1
0
mirror of https://github.com/nlohmann/json.git synced 2026-07-31 08:03:03 +04:00

Compare commits

..

4 Commits

Author SHA1 Message Date
Niels Lohmann a27065bd12 Regenerate api_surface.json after merging develop
develop gained iterator+sentinel support for accept()/parse()/sax_parse()/
from_cbor()/from_msgpack()/from_ubjson()/from_bjdata()/from_bson() (#5205)
since this branch was created, which check_api_docs.yml's drift check caught
immediately: GitHub's pull_request trigger checks out the PR-vs-base merge
commit, not the PR branch in isolation, so CI was comparing the committed
api_surface.json (generated before that upstream change existed) against a
fresh extraction of a json.hpp that already had it.

This superseded an earlier, incorrect diagnosis of the same symptom (a
JSON_HAS_RANGES cross-environment pin) -- that fix remains in place since it's
still a real, independent determinism improvement for three other
JSON_HAS_RANGES-gated locations in type_traits.hpp, but it wasn't the actual
cause of this particular mismatch: these new overloads turned out to be
unconditional (SFINAE-gated via can_compare_ne, not preprocessor-gated), so
no environment-detection difference was involved here at all.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 23:45:46 +02:00
Niels Lohmann 3940f4b730 Merge remote-tracking branch 'origin/develop' into claude/todo-191-plan-508110 2026-07-11 23:43:30 +02:00
Niels Lohmann 0663907b68 Fix cross-environment API-surface drift and lint findings from CI
extract_api.py's own extraction wasn't deterministic across machines, which
CI's drift check caught immediately: JSON_HAS_RANGES auto-detects via the
standard library's __cpp_lib_ranges feature-test macro, which isn't reliably
gated to C++20 mode by every stdlib -- undefined under -std=c++17 with macOS's
libc++, but defined under the identical flag with the Ubuntu stdlib CI uses,
so parse()/accept()/from_*() extracted different signatures purely depending
on which machine ran the extraction. Pinned to -DJSON_HAS_RANGES=0: the
deterministic and safe choice, since pinning to 1 was tried first and found to
fail to parse on a stdlib without full <ranges> support even when the macro
claims otherwise.

Also found and fixed a second, independent source of the same class of drift:
get_identity_name() used cursor.spelling verbatim for CONVERSION_FUNCTION
cursors, which libclang renders as its own internally-canonicalized form of
the return type rather than what's literally written. Confirmed for
json_pointer::operator string_t() spelling differently on two machines
pinned to the identical libclang==18.1.1 wheel, with the JSON_HAS_RANGES fix
above ruled out as the cause. Now derived from the cursor's own raw source
text instead, immune to libclang's dependent-type resolution differences and
incidentally more readable than the libclang-internal forms it replaces.

Bumped SURFACE_FORMAT_VERSION to 3 and regenerated all 27 history snapshots
and the committed api_surface.json; both fixes are documented in
tools/api_checker/history/README.md's format-history log.

Also fixes diff_api.py's format_version guard, which only compared the two
loaded surfaces against each other and never against SURFACE_FORMAT_VERSION
(what this build actually understands) -- two surfaces on the same,
newer-than-expected format_version would have silently passed the guard.

Remaining fixes are the concretely actionable findings from Codacy's review
of the new tools/api_checker/ files: unused imports/variables, a stray
f-string with no placeholders. Left the docstring-formatting nitpicks
(pydocstyle D2xx/D4xx) and generic subprocess-usage notices alone -- the
former has no established convention elsewhere in this codebase's Python
tooling to conform to, and the latter are inherent to a dev tool that shells
out to git/clang with developer-controlled arguments, not user input.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 18:59:19 +02:00
Niels Lohmann f23b3c63a2 Add AST-based public API checker and fix documentation gaps it found (#3691)
Adds tools/api_checker/: extract_api.py derives the public API surface directly
from the libclang AST (independent of documentation status), check_docs.py flags
public entries missing @sa links (and @sa on non-public ones), diff_api.py does
an overload-aware breaking/feature diff between two refs, check_macros.py cross-
checks documented macros against #define sites, and snapshot_release.py backfills
immutable per-release surface snapshots into tools/api_checker/history/ (v3.1.0
through v3.12.0) so diff_api.py can compare releases without live extraction.
POLICY.md documents what counts as public API and what stability is guaranteed.

Running this tooling against the current tree found and fixed a real documentation
backlog: ~25 new API doc pages (ordered_map's methods, json_sax's ctor/dtor/
operator=, byte_container_with_subtype's comparison operators, several orphaned
type aliases), each with a compiled and output-verified example, plus missing
@sa comments and stale/incorrect Version History entries on several existing
pages (found by diffing consecutive release pairs and checking whether the
resulting change was actually reflected in the target page's history section).

Also adds docs/home/api_changes.md, a per-release, per-function reference of
public API changes (v3.1.0 through v3.12.0) generated from the history/
snapshots, complementing (not replacing) the existing release notes.

Along the way, found and fixed several extractor bugs by testing against real
release tags rather than trusting the algorithm in isolation -- most notably an
identity-key scheme based on libclang's USR that encoded the enclosing class
template's own arity, and a since-renamed ABI inline-namespace pattern
(json_v3_11_0 vs. today's json_abi_v3_11_2) that neither of two earlier regex
attempts stripped correctly. Both are documented in extract_api.py's docstrings
and tools/api_checker/history/README.md so the failure mode doesn't recur
silently.

.github/workflows/check_api_docs.yml runs extract_api.py + check_docs.py in CI,
advisory-only for now (documented backlog may not be at zero for entities this
PR didn't touch), plus a blocking drift check on the committed
tools/api_checker/api_surface.json.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 18:59:00 +02:00
147 changed files with 72375 additions and 1851 deletions
+81
View File
@@ -0,0 +1,81 @@
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
+5
View File
@@ -3,6 +3,7 @@
*.gcno
*.gcda
.DS_Store
__pycache__/
/.idea
/cmake-build-*
@@ -43,5 +44,9 @@ venv
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
MODULE.bazel.lock
-1
View File
@@ -21,7 +21,6 @@ cc_library(
"include/nlohmann/adl_serializer.hpp",
"include/nlohmann/byte_container_with_subtype.hpp",
"include/nlohmann/detail/abi_macros.hpp",
"include/nlohmann/detail/conversions/from_chars.hpp",
"include/nlohmann/detail/conversions/from_json.hpp",
"include/nlohmann/detail/conversions/to_chars.hpp",
"include/nlohmann/detail/conversions/to_json.hpp",
+1 -1
View File
@@ -106,7 +106,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).
: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.
: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.
: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.
+1 -1
View File
@@ -49,7 +49,7 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
- `std::counted_iterator` with a different sentinel type
## Parameters
@@ -420,7 +420,9 @@ basic_json(basic_json&& other) noexcept;
1. Since version 1.0.0.
2. Since version 1.0.0.
3. Since version 2.1.0.
4. Since version 3.2.0.
4. Since version 3.2.0. Also initializes the position reported by
[`start_pos()`](start_pos.md)/[`end_pos()`](end_pos.md) from `val` when
[`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) is enabled, since version 3.12.0.
5. Since version 1.0.0.
6. Since version 1.0.0.
7. Since version 1.0.0.
@@ -0,0 +1,38 @@
# <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.
@@ -36,10 +36,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters
+2 -4
View File
@@ -36,10 +36,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters
+2 -4
View File
@@ -39,10 +39,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters
@@ -36,10 +36,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters
@@ -36,10 +36,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters
@@ -0,0 +1,32 @@
# <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.
@@ -0,0 +1,31 @@
# <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.
@@ -51,3 +51,5 @@ Linear.
## Version history
- 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.
@@ -85,3 +85,8 @@ Linear in the size of the JSON value.
- Since version 1.0.0.
- Macros `JSON_EXPLICIT`/[`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) added
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 -1
View File
@@ -48,7 +48,7 @@ static basic_json parse(IteratorType first, SentinelType last,
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
- `std::counted_iterator` with a different sentinel type
## Parameters
+1 -4
View File
@@ -48,10 +48,7 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
with a size of 1, 2, or 4 bytes (interpreted respectively as UTF-8, UTF-16, and UTF-32)
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for overload (2), for instance.
- a custom sentinel type for C++20 ranges
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for overload (2)
`SAX`
: a class fulfilling the SAX event listener interface; see [`json_sax`](../json_sax/index.md)
@@ -0,0 +1,32 @@
# <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.
@@ -0,0 +1,45 @@
# <small>nlohmann::byte_container_with_subtype::</small>operator==
```cpp
bool operator==(const byte_container_with_subtype& rhs) const;
```
Compares two `byte_container_with_subtype` values for equality by comparing the underlying binary
container, the subtype, and whether a subtype is set.
## Parameters
`rhs` (in)
: value to compare `*this` against
## Return value
whether `*this` and `rhs` are equal
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Linear in the size of the underlying binary container.
## Examples
??? example
The example demonstrates comparing `byte_container_with_subtype` values.
```cpp
--8<-- "examples/byte_container_with_subtype__operator_eq.cpp"
```
Output:
```
--8<-- "examples/byte_container_with_subtype__operator_eq.output"
```
## Version history
- Since version 3.8.0.
@@ -0,0 +1,45 @@
# <small>nlohmann::byte_container_with_subtype::</small>operator!=
```cpp
bool operator!=(const byte_container_with_subtype& rhs) const;
```
Compares two `byte_container_with_subtype` values for inequality. Implemented as the negation of
[`operator==`](operator_eq.md).
## Parameters
`rhs` (in)
: value to compare `*this` against
## Return value
whether `*this` and `rhs` are not equal
## Exception safety
No-throw guarantee: this function never throws exceptions.
## Complexity
Linear in the size of the underlying binary container.
## Examples
??? example
The example demonstrates comparing `byte_container_with_subtype` values.
```cpp
--8<-- "examples/byte_container_with_subtype__operator_ne.cpp"
```
Output:
```
--8<-- "examples/byte_container_with_subtype__operator_ne.output"
```
## Version history
- Since version 3.8.0.
@@ -0,0 +1,28 @@
# <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
@@ -0,0 +1,30 @@
# <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
@@ -0,0 +1,33 @@
# <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.
@@ -0,0 +1,30 @@
# <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.
@@ -0,0 +1,30 @@
# <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.
@@ -0,0 +1,30 @@
# <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.
@@ -0,0 +1,29 @@
# <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
@@ -0,0 +1,30 @@
# <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.
@@ -0,0 +1,22 @@
# <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.
@@ -38,8 +38,7 @@ When the macro is not defined, the library will define it to its default value.
Diagnostic messages can also be controlled with the CMake option
[`JSON_Diagnostics`](../../integration/cmake.md#json_diagnostics) (`OFF` by default)
which defines `JSON_DIAGNOSTICS` accordingly. Note this only applies when building the
library from source — see the pre-installed-package caveat on that page.
which defines `JSON_DIAGNOSTICS` accordingly.
## Examples
+2 -2
View File
@@ -8,7 +8,7 @@ This type preserves the insertion order of object keys.
## Iterator invalidation
The type is based on [`ordered_map`](ordered_map.md) which in turn uses a `std::vector` to store object elements.
The type is based on [`ordered_map`](ordered_map/index.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
[`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.
@@ -31,7 +31,7 @@ reference after the insertion point will point to the same index, which is now a
## See also
- [ordered_map](ordered_map.md)
- [ordered_map](ordered_map/index.md)
- [Object Order](../features/object_order.md)
## Version history
@@ -0,0 +1,28 @@
# <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
@@ -0,0 +1,61 @@
# <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
@@ -0,0 +1,53 @@
# <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.
@@ -0,0 +1,58 @@
# <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
@@ -0,0 +1,75 @@
# <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
@@ -0,0 +1,56 @@
# <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.
@@ -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>;
```
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>`).
## Template parameters
@@ -32,12 +32,12 @@ case all iterators (including the `end()` iterator) and all references to the el
- **key_type** - key type (`Key`)
- **mapped_type** - mapped type (`T`)
- **Container** - base container type (`#!cpp std::vector<std::pair<const Key, T>, Allocator>`)
- [**Container**](Container.md) - base container type (`#!cpp std::vector<std::pair<const Key, T>, Allocator>`)
- **iterator**
- **const_iterator**
- **size_type**
- **value_type**
- **key_compare** - key comparison function
- [**key_compare**](key_compare.md) - key comparison function
```cpp
std::equal_to<Key> // until C++14
@@ -46,15 +46,16 @@ std::equal_to<> // since C++14
## Member functions
- (constructor)
- (destructor)
- **emplace**
- **operator\[\]**
- **at**
- **erase**
- **count**
- **find**
- **insert**
- [(constructor)](ordered_map.md)
- [(destructor)](~ordered_map.md)
- [**operator=**](operator=.md)
- [**emplace**](emplace.md)
- [**operator\[\]**](operator[].md)
- [**at**](at.md)
- [**erase**](erase.md)
- [**count**](count.md)
- [**find**](find.md)
- [**insert**](insert.md)
## Examples
@@ -74,9 +75,9 @@ std::equal_to<> // since C++14
## See also
- [ordered_json](ordered_json.md)
- [ordered_json](../ordered_json.md)
## 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.
@@ -0,0 +1,63 @@
# <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).
@@ -0,0 +1,34 @@
# <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.
@@ -0,0 +1,32 @@
# <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).
@@ -0,0 +1,62 @@
# <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.
@@ -0,0 +1,66 @@
# <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).
@@ -0,0 +1,17 @@
# <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).
@@ -0,0 +1,21 @@
#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;
}
@@ -0,0 +1,2 @@
draft2 size: 4
draft3 size: 6
@@ -0,0 +1,11 @@
#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;
}
@@ -0,0 +1,15 @@
#include <iostream>
#include <nlohmann/json.hpp>
using byte_container_with_subtype = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>;
int main()
{
byte_container_with_subtype c1({0xca, 0xfe});
byte_container_with_subtype c2({0xca, 0xfe});
byte_container_with_subtype c3({0xca, 0xfe}, 42);
std::cout << std::boolalpha
<< "c1 == c2: " << (c1 == c2) << '\n'
<< "c1 == c3: " << (c1 == c3) << std::endl;
}
@@ -0,0 +1,2 @@
c1 == c2: true
c1 == c3: false
@@ -0,0 +1,15 @@
#include <iostream>
#include <nlohmann/json.hpp>
using byte_container_with_subtype = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>;
int main()
{
byte_container_with_subtype c1({0xca, 0xfe});
byte_container_with_subtype c2({0xca, 0xfe});
byte_container_with_subtype c3({0xca, 0xfe}, 42);
std::cout << std::boolalpha
<< "c1 != c2: " << (c1 != c2) << '\n'
<< "c1 != c3: " << (c1 != c3) << std::endl;
}
@@ -0,0 +1,2 @@
c1 != c2: false
c1 != c3: true
@@ -0,0 +1,10 @@
#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;
}
@@ -0,0 +1,13 @@
#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;
}
@@ -0,0 +1 @@
["a",1,2.0,false]
@@ -0,0 +1,10 @@
#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;
}
@@ -0,0 +1 @@
true
@@ -0,0 +1,10 @@
#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;
}
@@ -0,0 +1 @@
true
@@ -0,0 +1,10 @@
#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;
}
@@ -0,0 +1 @@
true
@@ -0,0 +1,10 @@
#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;
}
@@ -0,0 +1 @@
true
@@ -0,0 +1,10 @@
#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;
}
@@ -0,0 +1 @@
true
+10
View File
@@ -0,0 +1,10 @@
#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;
}
@@ -0,0 +1 @@
true
@@ -0,0 +1,12 @@
#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;
}
@@ -0,0 +1 @@
Container is std::vector<std::pair<const Key, T>>: true
@@ -0,0 +1,26 @@
#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;
}
}
@@ -0,0 +1,3 @@
m.at("one") = 1
m.at("two") = 22
exception: key not found
@@ -0,0 +1,12 @@
#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;
}
@@ -0,0 +1,2 @@
m.count("one") = 1
m.count("two") = 0
@@ -0,0 +1,15 @@
#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;
}
@@ -0,0 +1,2 @@
inserted: true, value: eins
inserted: false, value: eins
@@ -0,0 +1,24 @@
#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;
}
@@ -0,0 +1,2 @@
removed by key: 1
remaining: three
@@ -0,0 +1,19 @@
#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;
}
}
@@ -0,0 +1,2 @@
found: one = 1
"two" not found
@@ -0,0 +1,21 @@
#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;
}
@@ -0,0 +1,2 @@
inserted: true
one:1 two:2 three:3
@@ -0,0 +1,12 @@
#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;
}
@@ -0,0 +1,2 @@
compare("a", "a") = true
compare("a", "b") = false
@@ -0,0 +1,14 @@
#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;
}
@@ -0,0 +1,2 @@
m["one"] = 1
m["one"] = 1
-36
View File
@@ -47,28 +47,6 @@ json j = {{"one", 1}, {"two", 2}};
auto m = j.get<std::map<std::string, int>>(); // {{"one", 1}, {"two", 2}}
```
`#!cpp std::pair` and `#!cpp std::tuple` are also supported, converting positionally to and from a JSON array:
```cpp
json j = {1.0, "hello", 42};
auto t = j.get<std::tuple<double, std::string, int>>(); // {1.0, "hello", 42}
```
!!! info "Extracting references into a tuple"
A tuple type may also hold references (e.g. `#!cpp std::tuple<double&, std::string&>`) to avoid copying: `get`
then returns a tuple of references pointing directly at the elements stored inside the `basic_json` array,
rather than a tuple of copies:
```cpp
json j = {1.0, "hello"};
auto refs = j.get<std::tuple<double&, std::string&>>();
std::get<1>(refs) = "world"; // modifies j[1] in place
```
A referenced type must be one the library actually stores (or an arithmetic type it can convert to/from);
otherwise this is a compile error.
## Implicit conversions
By default, a JSON value implicitly converts to a compatible C++ type, so the explicit `get` call can often be omitted:
@@ -158,20 +136,6 @@ std::vector<int> numbers = {1, 2, 3};
json j = numbers; // [1,2,3]
```
!!! info "Constructing from a C++20 range view"
A `json` array can also be constructed directly from a C++20 range view (`std::ranges::view`), such as the result
of `std::views::filter` or `std::views::transform` -- no intermediate container is needed:
```cpp
std::vector<int> nums{1, 2, 37, 42, 21};
auto filtered = nums | std::views::filter([](int i) { return i > 10; });
json j(filtered); // [37,42,21]
```
This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due
to incomplete C++20 ranges support there.
## Your own types
The conversions above are built in for standard types. To make the same syntax work for **your own** types, provide
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -17,7 +17,7 @@ The main structure is class [nlohmann::basic_json](../api/basic_json/index.md).
- describe template parameters of `basic_json`
- [`json`](../api/json.md)
- [`ordered_json`](../api/ordered_json.md) via [`ordered_map`](../api/ordered_map.md)
- [`ordered_json`](../api/ordered_json.md) via [`ordered_map`](../api/ordered_map/index.md)
## Value storage
+2 -1
View File
@@ -2,7 +2,8 @@
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
published on the [GitHub releases page](https://github.com/nlohmann/json/releases).
published on the [GitHub releases page](https://github.com/nlohmann/json/releases). For a raw,
signature-level diff of the public API between releases, see [API Changes](api_changes.md).
## v3.12.0 (2025-04-11)
-25
View File
@@ -135,31 +135,6 @@ Enable CI build targets. The exact targets are used during the several CI steps
Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default.
!!! warning "Does not apply to a pre-installed package"
This option only takes effect when building nlohmann/json from source as part of your own
CMake project (e.g. via [`FetchContent`](#fetchcontent) or [`add_subdirectory`](#external)).
It has **no effect** on a package that was already built and installed elsewhere (Homebrew,
vcpkg, a system package, etc.) — the resulting compile definition is baked into the exported
`nlohmann_jsonTargets.cmake` at install time, and `set(JSON_Diagnostics ON)` before
`find_package()` does not change it (verified against the Homebrew-installed package: the
exported target still carries a fixed `$<$<BOOL:OFF>:JSON_DIAGNOSTICS=1>`, regardless of any
variable set in the consuming project).
To enable extended diagnostics for a pre-installed package, override the imported target's
property directly after `find_package()`:
```cmake
find_package(nlohmann_json REQUIRED)
set_target_properties(nlohmann_json::nlohmann_json PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "JSON_DIAGNOSTICS=1")
```
This only works cleanly when your project is the sole consumer of that imported target. If
nlohmann_json is pulled in from more than one place in your dependency graph with different
`JSON_DIAGNOSTICS` values, you may see a `"JSON_DIAGNOSTICS" redefined` compiler error, since
conflicting `-D` flags can end up on the same compile command line.
### `JSON_Diagnostic_Positions`
Enable position diagnostics by defining macro [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md). This option is `OFF` by default.
+30 -1
View File
@@ -52,6 +52,7 @@ nav:
- "FAQ": home/faq.md
- home/exceptions.md
- home/releases.md
- home/api_changes.md
- home/design_goals.md
- home/architecture.md
- home/customers.md
@@ -117,6 +118,7 @@ nav:
- 'begin': api/basic_json/begin.md
- 'binary': api/basic_json/binary.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
- 'cbegin': api/basic_json/cbegin.md
- 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md
@@ -154,6 +156,7 @@ nav:
- 'get_to': api/basic_json/get_to.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
- 'initializer_list_t': api/basic_json/initializer_list_t.md
- 'input_format_t': api/basic_json/input_format_t.md
- 'insert': api/basic_json/insert.md
- 'invalid_iterator': api/basic_json/invalid_iterator.md
@@ -172,6 +175,7 @@ nav:
- 'is_structured': api/basic_json/is_structured.md
- 'items': api/basic_json/items.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
- 'max_size': api/basic_json/max_size.md
- 'meta': api/basic_json/meta.md
@@ -228,9 +232,13 @@ nav:
- 'Overview': api/byte_container_with_subtype/index.md
- '(constructor)': api/byte_container_with_subtype/byte_container_with_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
- 'operator==': api/byte_container_with_subtype/operator_eq.md
- 'operator!=': api/byte_container_with_subtype/operator_ne.md
- 'set_subtype': api/byte_container_with_subtype/set_subtype.md
- 'subtype': api/byte_container_with_subtype/subtype.md
- 'subtype_type': api/byte_container_with_subtype/subtype_type.md
- adl_serializer:
- 'Overview': api/adl_serializer/index.md
- 'from_json': api/adl_serializer/from_json.md
@@ -256,25 +264,46 @@ nav:
- 'to_string': api/json_pointer/to_string.md
- json_sax:
- '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_t': api/json_sax/binary_t.md
- 'boolean': api/json_sax/boolean.md
- 'end_array': api/json_sax/end_array.md
- 'end_object': api/json_sax/end_object.md
- 'key': api/json_sax/key.md
- 'null': api/json_sax/null.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_t': api/json_sax/number_integer_t.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
- 'start_array': api/json_sax/start_array.md
- 'start_object': api/json_sax/start_object.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)': api/operator_gtgt.md
- 'operator""_json': api/operator_literal_json.md
- 'operator""_json_pointer': api/operator_literal_json_pointer.md
- 'ordered_json': api/ordered_json.md
- 'ordered_map': api/ordered_map.md
- ordered_map:
- '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:
- 'Overview': api/macros/index.md
- 'JSON_ASSERT': api/macros/json_assert.md
@@ -22,7 +22,9 @@ template<typename BinaryType>
class byte_container_with_subtype : public BinaryType
{
public:
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/container_type/
using container_type = BinaryType;
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype_type/
using subtype_type = std::uint64_t;
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
@@ -54,12 +56,14 @@ class byte_container_with_subtype : public BinaryType
, 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
{
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);
}
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/operator_ne/
bool operator!=(const byte_container_with_subtype& rhs) const
{
return !(rhs == *this);
@@ -1,636 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#pragma once
#include <nlohmann/detail/macro_scope.hpp>
#if JSON_HAS_FROM_CHARS
#include <algorithm> // find, find_if
#include <charconv> // from_chars, from_chars_result
#include <cmath> // isnan
#else
#include <cctype> // isspace
#include <cerrno> // ERANGE
#include <clocale> // localeconv, newlocale, freelocale
#include <cstdlib> // strto*
#include <memory> // unique_ptr
#include <type_traits> // enable_if, is_unsigned, remove_pointer
#include <utility> // declval
#ifdef __has_include
#if __has_include(<xlocale.h>)
#include <xlocale.h> // strto*_l, isspace_l
#endif
#endif
#endif
#include <limits> // numeric_limits<T>::[has_]infinity, quiet_NaN
#include <system_error> // errc
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{
constexpr char get_locale_independent_decimal_point() noexcept
{
return '.';
}
#if JSON_HAS_FROM_CHARS
//////////////////////////////////////////////
// Delegate to std::from_chars if supported //
//////////////////////////////////////////////
/*!
@brief Number parsing implementation details
A traits class template that allows users of nlohmann::detail::from_chars to
query details of the used implementation.
@tparam T numeric type to parse, matching the `value` argument of from_chars
*/
template <typename T>
struct from_chars_traits
{
/// whether the from_chars in unaffected by the current global C locale
static constexpr bool is_locale_independent = true;
/// getter for the character used as decimal point by from_chars
static constexpr char(*get_decimal_point)() = &get_locale_independent_decimal_point;
};
using std::from_chars_result;
/*!
@brief Parse integer/floating-point numbers
Parses the string [first, last) into the numeric type T.
This implementation merely delegates to `std::from_chars` with one noteworthy
difference: Different C++ standard library implementations do not agree on
whether `value` should be set in the out-of-range case for floating-point
numbers. Presently, libstdc++ leaves `value` unchanged whereas libc++ and MS STL
set `value` to +/-0 or +/-inf which allows its users to distinguish between the
various cases of over- and underflow. The C++ proposal [P4168][1] details this
discrepancy and advocates to standardize the latter behavior.
Since we need to be able to distinguish absolute underflow (+/-0) from absolute
overflow (+/-inf), this implementation "corrects" the out-of-range behavior
accordingly by estimating the effective exponent through manual string parsing.
[1]: https://isocpp.org/files/papers/P4168R0.html
@tparam T numeric type to parse
@param[in] first points to the beginning of the parsed string (inclusive)
@param[in] end points to the end of the parsed string (exclusive)
@param[out] value references the variable to set the parsed number
@return structure consisting of `ptr` and `ec` such that:
- If the string starting at `first` matches a number, `ptr` points to
the address immediately after the last character that matches.
* If the matched number can be represented by `T`, `value` is set and
`ec` is value-initialized.
* If the matched number cannot be represented by `T`, `ec` is set to
`std::errc::result_out_of_range` and depending on the type of `T`:
+ `value` is left unchanged for integral `T`,
+ `value` is set to +/-0 or +/-inf for floating-point `T`.
- If the string starting at `first` doesn't match a number, `ptr`
points to `first`, `ec` is `std::errc::invalid_argument`, and `value`
is left unchanged.
*/
template <typename T>
JSON_HEDLEY_NON_NULL(1, 2)
inline from_chars_result from_chars(const char* first, const char* last, T& value)
{
// No implementation of std::from_chars will set its value argument to NaN,
// so by using NaN as the initial value, we can tell if it changed.
T inner_value = std::numeric_limits<T>::quiet_NaN();
auto res = std::from_chars(first, last, inner_value);
if constexpr (std::numeric_limits<T>::has_infinity)
{
if (res.ec == std::errc::result_out_of_range)
{
if (std::isnan(inner_value)) // inner_value was not set
{
// [first, res.ptr) matches a valid floating-point number that's
// out-of-range and our std::from_chars did not set `value`, so we
// need to distinguish the type of under-/overflow ourselves.
const char* mantissa_begin = *first == '-' ? first + 1 : first;
const char* mantissa_end = std::find_if(mantissa_begin, res.ptr, [](char c)
{
return c == 'e' || c == 'E';
});
const char* decimal_point = std::find(mantissa_begin, mantissa_end, '.');
const char* significant_digit = std::find_if(mantissa_begin, mantissa_end, [](char d)
{
return d >= '1' && d <= '9';
});
// Position of the significant digit relative to the decimal gives
// the order of magnitude of the mantissa.
auto effective_exponent = static_cast<int>(decimal_point - significant_digit);
// If the number includes an explicit exponent, add that to the the
// total exponent.
if (mantissa_end != res.ptr)
{
const char* exponent_begin = *(mantissa_end + 1) == '+'
? mantissa_end + 2 // skip the exponent's + sign
: mantissa_end + 1;
int exponent = 0;
auto exp_res = std::from_chars(exponent_begin, res.ptr, exponent);
JSON_ASSERT(exp_res.ptr == res.ptr);
if (exp_res.ec == std::errc::result_out_of_range)
{
// NOTE: Parentheses around function names mitigate min/max macro collision on Windows
effective_exponent = *exponent_begin == '-'
? (std::numeric_limits<int>::min)()
: (std::numeric_limits<int>::max)();
}
else
{
JSON_ASSERT(exp_res.ec == std::errc{});
effective_exponent += exponent;
}
}
// Set `value` to the sign-correct non-finite value based on the
// effective exponent.
value = (*first == '-' ? -1 : 1) * (effective_exponent < 0
? T{}
: std::numeric_limits<T>::infinity());
}
else
{
value = inner_value;
}
}
}
if (res.ec == std::errc{})
{
value = inner_value;
}
return res;
}
#else
//////////////////////////////////////////////
// Fallback implementation using strto*[_l] //
//////////////////////////////////////////////
#if defined(_WIN32)
/*!
@brief Extended locale functions on Windows
A trait object which provides wrappers for isspace and the strto* family of
functions, based on the platform's support for extended locale APIs.
This is the Windows implementation. The primary class template definition
falls back to the standard locale-dependent functions, which is used on
MinGW, whose C runtime only provides an incomplete subset of the
`_<funcname>_l` family (e.g., missing `_strtof_l`/`_strtold_l` depending on
the toolchain version). A specialization for genuine MSVC (including
clang-cl, which mimics the MSVC ABI and CRT) is used instead, as the full
`_<funcname>_l` family has reliably been available there since at least
Visual Studio 2005.
*/
template <typename = const char*, typename = float>
struct extended_locale_traits
{
static constexpr bool is_locale_independent = false;
JSON_HEDLEY_PURE
static char get_decimal_point() noexcept
{
const auto* loc = localeconv();
JSON_ASSERT(loc != nullptr);
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
}
static int isspace(int c) noexcept
{
return std::isspace(c);
}
// NOLINTNEXTLINE(runtime/int)
static long long strtoll(const char* str, char** endptr) noexcept
{
return std::strtoll(str, endptr, 10);
}
// NOLINTNEXTLINE(runtime/int)
static unsigned long long strtoull(const char* str, char** endptr) noexcept
{
return std::strtoull(str, endptr, 10);
}
static constexpr float(&strtof)(const char*, char**) = std::strtof;
static constexpr double(&strtod)(const char*, char**) = std::strtod;
static constexpr long double(&strtold)(const char*, char**) = std::strtold;
};
#if defined(_MSC_VER)
/*!
@brief Get a pointer to a globally shared instance of the "C" locale on Windows
This function uses _create_locale/_free_locale to allocate a "C" locale instance
which can be passed to extended locale APIs. This instance is created on first
use and has static storage duration, such that it can be used for the duration
of the program.
*/
inline _locale_t get_c_locale_t() noexcept
{
struct LocaleTDeleter
{
void operator()(_locale_t loc) noexcept
{
::_free_locale(loc);
}
};
using LocaleUPtr = std::unique_ptr<std::remove_pointer<_locale_t>::type, LocaleTDeleter>;
static const LocaleUPtr c_locale = LocaleUPtr{::_create_locale(LC_ALL, "C"), LocaleTDeleter{}};
return c_locale.get();
}
template <typename T>
struct extended_locale_traits<T, float>
{
static constexpr bool is_locale_independent = true;
static constexpr char(&get_decimal_point)() = get_locale_independent_decimal_point;
static int isspace(int c) noexcept
{
return _isspace_l(c, get_c_locale_t());
}
// NOLINTNEXTLINE(runtime/int)
static long long strtoll(const char* str, char** endptr) noexcept
{
return _strtoll_l(str, endptr, 10, get_c_locale_t());
}
// NOLINTNEXTLINE(runtime/int)
static unsigned long long strtoull(const char* str, char** endptr) noexcept
{
return _strtoull_l(str, endptr, 10, get_c_locale_t());
}
static float strtof(T str, char** str_end)
{
return _strtof_l(str, str_end, get_c_locale_t());
}
static double strtod(T str, char** str_end)
{
return _strtod_l(str, str_end, get_c_locale_t());
}
static long double strtold(T str, char** str_end)
{
return _strtold_l(str, str_end, get_c_locale_t());
}
};
#endif
#else
/*!
@brief Get a pointer to a globally shared instance of the "C" locale on POSIX
This function uses newlocale/freelocale to allocate a "C" locale instance
which can be passed to extended locale APIs. This instance is created on first
use and has static storage duration, such that it can be used for the duration
of the program.
newlocale/freelocale themselves are in POSIX and are available independent of
the platform's support for extended locale APIs.
*/
inline locale_t get_c_locale_t() noexcept
{
struct LocaleTDeleter
{
void operator()(locale_t loc) noexcept
{
::freelocale(loc);
}
};
using LocaleUPtr = std::unique_ptr<std::remove_pointer<locale_t>::type, LocaleTDeleter>;
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wexit-time-destructors"
#endif
static const LocaleUPtr c_locale = LocaleUPtr {::newlocale(LC_ALL_MASK, "C", nullptr), LocaleTDeleter{}};
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
return c_locale.get();
}
/*!
@brief Extended locale functions on POSIX
A trait object which provides wrappers for isspace and the strto* family of
functions, based on the platform's support for extended locale APIs.
This is the POSIX implementation where extended locale support might not be
available. The primary class template definition falls back to the standard
locale-dependent functions. A partial specialization uses SFINAE to detect the
availability of `strtof_l` (as a proxy for the whole `<funcname>_l` family) and
provides access to locale-independent functions.
*/
template <typename = const char*, typename = float>
struct extended_locale_traits
{
static constexpr bool is_locale_independent = false;
/*!
@brief Query the decimal point used by the current C locale
Note that calling this function while switching the global C locale from
another thread is undefined behavior.
*/
JSON_HEDLEY_PURE
static char get_decimal_point() noexcept
{
const auto* loc = localeconv();
JSON_ASSERT(loc != nullptr);
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
}
static int isspace(int c) noexcept
{
return std::isspace(c);
}
// NOLINTNEXTLINE(runtime/int)
static long long strtoll(const char* str, char** endptr) noexcept
{
return std::strtoll(str, endptr, 10);
}
// NOLINTNEXTLINE(runtime/int)
static unsigned long long strtoull(const char* str, char** endptr) noexcept
{
return std::strtoull(str, endptr, 10);
}
static constexpr float(&strtof)(const char*, char**) = std::strtof;
static constexpr double(&strtod)(const char*, char**) = std::strtod;
static constexpr long double(&strtold)(const char*, char**) = std::strtold;
};
template <typename T>
struct extended_locale_traits<T, decltype(strtof_l(
std::declval<T>(),
std::declval<char**>(),
std::declval<locale_t>()))>
{
static constexpr bool is_locale_independent = true;
static constexpr char(&get_decimal_point)() = get_locale_independent_decimal_point;
static int isspace(int c) noexcept
{
return isspace_l(c, get_c_locale_t());
}
// NOLINTNEXTLINE(runtime/int)
static long long strtoll(const char* str, char** endptr) noexcept
{
return ::strtoll_l(str, endptr, 10, get_c_locale_t());
}
// NOLINTNEXTLINE(runtime/int)
static unsigned long long strtoull(const char* str, char** endptr) noexcept
{
return ::strtoull_l(str, endptr, 10, get_c_locale_t());
}
static float strtof(T str, char** str_end)
{
return ::strtof_l(str, str_end, get_c_locale_t());
}
static double strtod(T str, char** str_end)
{
return ::strtod_l(str, str_end, get_c_locale_t());
}
static long double strtold(T str, char** str_end)
{
return ::strtold_l(str, str_end, get_c_locale_t());
}
};
#endif
/*!
@brief Number parsing implementation details
A traits class template that allows users of nlohmann::detail::from_chars to
query details of the used implementation.
Each specialization provides the following static members:
- is_locale_independent: whether the from_chars in unaffected by the current
global C locale
- get_decimal_point: getter for the character used as decimal point by from_chars
- strto: dispatches to the C standard library strto* function for type T, or to
the corresponding extended locale function, if available.
@tparam T numeric type to parse, matching the `value` argument of from_chars
*/
template <typename T>
struct from_chars_traits;
template <>
struct from_chars_traits<long long> // NOLINT(runtime/int)
{
static constexpr bool is_locale_independent = extended_locale_traits<>::is_locale_independent;
static char get_decimal_point()
{
return extended_locale_traits<>::get_decimal_point();
}
// NOLINTNEXTLINE(runtime/int)
static constexpr long long(*strto)(const char*, char**) = &extended_locale_traits<>::strtoll;
};
template <>
struct from_chars_traits<unsigned long long> // NOLINT(runtime/int)
{
static constexpr bool is_locale_independent = extended_locale_traits<>::is_locale_independent;
static char get_decimal_point()
{
return extended_locale_traits<>::get_decimal_point();
}
// NOLINTNEXTLINE(runtime/int)
static constexpr unsigned long long(*strto)(const char*, char**) = &extended_locale_traits<>::strtoull;
};
template <>
struct from_chars_traits<float>
{
static constexpr bool is_locale_independent = extended_locale_traits<>::is_locale_independent;
static char get_decimal_point()
{
return extended_locale_traits<>::get_decimal_point();
}
static constexpr float(*strto)(const char*, char**) = &extended_locale_traits<>::strtof;
};
template <>
struct from_chars_traits<double>
{
static constexpr bool is_locale_independent = extended_locale_traits<>::is_locale_independent;
static char get_decimal_point()
{
return extended_locale_traits<>::get_decimal_point();
}
static constexpr double(*strto)(const char*, char**) = &extended_locale_traits<>::strtod;
};
template <>
struct from_chars_traits<long double>
{
static constexpr bool is_locale_independent = extended_locale_traits<>::is_locale_independent;
static char get_decimal_point()
{
return extended_locale_traits<>::get_decimal_point();
}
static constexpr long double(*strto)(const char*, char**) = &extended_locale_traits<>::strtold;
};
template <typename T>
constexpr typename std::enable_if<std::numeric_limits<T>::has_infinity, bool>::type is_out_of_range_value(T value) noexcept
{
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
return value == T {} || value == std::numeric_limits<T>::infinity() || value == -std::numeric_limits<T>::infinity();
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
template <typename T>
constexpr typename std::enable_if < !std::numeric_limits<T>::has_infinity, bool >::type is_out_of_range_value(T value) noexcept
{
// NOTE: Parentheses around function names mitigate min/max macro collision on Windows
return value == (std::numeric_limits<T>::max)() || value == (std::numeric_limits<T>::min)();
}
struct from_chars_result
{
const char* ptr;
std::errc ec;
};
/*!
@brief Parse integer/floating-point numbers
Parses the string [first, last) into the numeric type T.
This implementation uses the C standard library functions strto*, or their
extended locale counterparts strto*_l, to emulate the behavior of
`std::from_chars` on platforms where it is not (fully) supported.
Regarding the under-/overflow behavior, this implementation adopts the behavior
proposed by [P4168][1] and implemented by libc++ and MS STL of setting `value`
to the corresponding non-finite floating-point value in case of an out-of-range
result.
[1]: https://isocpp.org/files/papers/P4168R0.html
@pre Unlike std::from_chars, this implementation requires the string to be
null-terminated, such that `last` dereferences into a NUL byte.
@tparam T numeric type to parse
@param[in] first points to the beginning of the parsed string (inclusive)
@param[in] end points to the end of the parsed string (exclusive)
@param[out] value references the variable to set the parsed number
@return structure consisting of `ptr` and `ec` such that:
- If the string starting at `first` matches a number, `ptr` points to
the address immediately after the last character that matches.
* If the matched number can be represented by `T`, `value` is set and
`ec` is value-initialized.
* If the matched number cannot be represented by `T`, `ec` is set to
`std::errc::result_out_of_range` and depending on the type of `T`:
+ `value` is left unchanged for integral `T`,
+ `value` is set to +/-0 or +/-inf for floating-point `T`.
- If the string starting at `first` doesn't match a number, `ptr`
points to `first`, `ec` is `std::errc::invalid_argument`, and `value`
is left unchanged.
*/
template <typename T>
JSON_HEDLEY_NON_NULL(1, 2)
inline from_chars_result from_chars(const char* first, const char* last, T& value)
{
JSON_ASSERT(*last == '\0');
// Unlike strto*, from_chars does not accept leading whitespace or + signs
if (first == last || *first == '+'
|| (std::is_unsigned<T>::value && *first == '-')
|| extended_locale_traits<>::isspace(*first) != 0)
{
return {first, std::errc::invalid_argument};
}
errno = 0;
char* ptr = nullptr; // NOLINT(misc-const-correctness)
T result = from_chars_traits<T>::strto(first, &ptr);
if (ptr == first)
{
return {ptr, std::errc::invalid_argument};
}
// Upon under-/overflow, strto* returns a marginal value and sets errno.
// Note that it is NOT sufficient to just check errno: strto* only clears
// errno if the parsed string actually parses into 0/[U]LLONG_MIN/-_MAX
// and this result was returned without indicating an under-/overflow.
// Otherwise, errno may not be relied upon to indicate the *absence* of
// an out-of-range error.
if (is_out_of_range_value(result) && errno == ERANGE)
{
if (std::numeric_limits<T>::has_infinity)
{
// ONLY for floating-point types, set `value` to the same non-finite
// result returned by strto* to allow users to distinguish between
// different types of under-/overflow.
value = result;
}
return {ptr, std::errc::result_out_of_range};
}
value = result;
return {ptr, std::errc{}};
}
#endif
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
@@ -220,29 +220,20 @@ class iterator_input_adapter
// whether IteratorType refers to a contiguous range and therefore supports
// a std::memcpy fast path (pointers always do; in C++20 we can also detect
// library iterators such as those of std::vector and std::string).
// Computing the available element count needs either same-type iterators
// (plain std::distance) or, in C++20, a sized sentinel (std::ranges::distance),
// e.g. std::counted_iterator paired with std::default_sentinel_t.
// The fast path also requires SentinelType == IteratorType so std::distance works.
static constexpr bool iterator_is_contiguous =
std::is_same<IteratorType, SentinelType>::value && (
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
(std::is_same<IteratorType, SentinelType>::value || std::sized_sentinel_for<SentinelType, IteratorType>)
&& (std::contiguous_iterator<IteratorType> || std::is_pointer<IteratorType>::value);
#else
std::is_same<IteratorType, SentinelType>::value && std::is_pointer<IteratorType>::value;
std::contiguous_iterator<IteratorType> ||
#endif
std::is_pointer<IteratorType>::value);
// contiguous fast path: bulk copy the remaining range with std::memcpy
template<class T>
std::size_t get_elements_impl(T* dest, std::size_t count, std::true_type /*contiguous*/)
{
const std::size_t wanted = count * sizeof(T);
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
// std::ranges::distance also supports sized sentinels of a different
// type (e.g. std::counted_iterator + std::default_sentinel_t)
const std::size_t available = static_cast<std::size_t>(std::ranges::distance(current, end)) * sizeof(char_type);
#else
const std::size_t available = static_cast<std::size_t>(std::distance(current, end)) * sizeof(char_type);
#endif
const std::size_t copied = (std::min)(wanted, available);
if (JSON_HEDLEY_LIKELY(copied != 0))
{
@@ -31,15 +31,21 @@ input.
template<typename BasicJsonType>
struct json_sax
{
/// @sa https://json.nlohmann.me/api/json_sax/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;
/// @sa https://json.nlohmann.me/api/json_sax/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;
/// @sa https://json.nlohmann.me/api/json_sax/binary_t/
using binary_t = typename BasicJsonType::binary_t;
/*!
@brief a null value was read
@return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/null/
*/
virtual bool null() = 0;
@@ -47,6 +53,7 @@ struct json_sax
@brief a boolean value was read
@param[in] val boolean value
@return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/boolean/
*/
virtual bool boolean(bool val) = 0;
@@ -54,6 +61,7 @@ struct json_sax
@brief an integer number was read
@param[in] val integer value
@return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/number_integer/
*/
virtual bool number_integer(number_integer_t val) = 0;
@@ -61,6 +69,7 @@ struct json_sax
@brief an unsigned integer number was read
@param[in] val unsigned integer value
@return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/number_unsigned/
*/
virtual bool number_unsigned(number_unsigned_t val) = 0;
@@ -69,6 +78,7 @@ struct json_sax
@param[in] val floating-point value
@param[in] s raw token value
@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;
@@ -77,6 +87,7 @@ struct json_sax
@param[in] val string value
@return whether parsing should proceed
@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;
@@ -85,6 +96,7 @@ struct json_sax
@param[in] val binary value
@return whether parsing should proceed
@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;
@@ -93,6 +105,7 @@ struct json_sax
@param[in] elements number of object elements or -1 if unknown
@return whether parsing should proceed
@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;
@@ -101,12 +114,14 @@ struct json_sax
@param[in] val object key
@return whether parsing should proceed
@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;
/*!
@brief the end of an object was read
@return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/end_object/
*/
virtual bool end_object() = 0;
@@ -115,12 +130,14 @@ struct json_sax
@param[in] elements number of array elements or -1 if unknown
@return whether parsing should proceed
@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;
/*!
@brief the end of an array was read
@return whether parsing should proceed
@sa https://json.nlohmann.me/api/json_sax/end_array/
*/
virtual bool end_array() = 0;
@@ -130,16 +147,23 @@ struct json_sax
@param[in] last_token the last read token
@param[in] ex an exception object describing the error
@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,
const std::string& last_token,
const detail::exception& ex) = 0;
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
json_sax() = default;
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
json_sax(const json_sax&) = default;
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
json_sax(json_sax&&) noexcept = default;
/// @sa https://json.nlohmann.me/api/json_sax/operator=/
json_sax& operator=(const json_sax&) = default;
/// @sa https://json.nlohmann.me/api/json_sax/operator=/
json_sax& operator=(json_sax&&) noexcept = default;
/// @sa https://json.nlohmann.me/api/json_sax/~json_sax/
virtual ~json_sax() = default;
};
+45 -16
View File
@@ -9,15 +9,15 @@
#pragma once
#include <array> // array
#include <clocale> // localeconv
#include <cstddef> // size_t
#include <cstdio> // snprintf
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
#include <initializer_list> // initializer_list
#include <string> // char_traits, string
#include <system_error> // errc
#include <utility> // move
#include <vector> // vector
#include <nlohmann/detail/conversions/from_chars.hpp>
#include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/position_t.hpp>
#include <nlohmann/detail/macro_scope.hpp>
@@ -152,7 +152,7 @@ class lexer : public lexer_base<BasicJsonType>
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
: ia(std::move(adapter))
, ignore_comments(ignore_comments_)
, decimal_point_char(static_cast<char_int_type>(from_chars_traits<number_float_t>::get_decimal_point()))
, decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
{}
// deleted because of pointer members
@@ -163,6 +163,19 @@ class lexer : public lexer_base<BasicJsonType>
~lexer() = default;
private:
/////////////////////
// locales
/////////////////////
/// return the locale-dependent decimal point
JSON_HEDLEY_PURE
static char get_decimal_point() noexcept
{
const auto* loc = localeconv();
JSON_ASSERT(loc != nullptr);
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
}
/////////////////////
// scan functions
/////////////////////
@@ -928,6 +941,24 @@ class lexer : public lexer_base<BasicJsonType>
}
}
JSON_HEDLEY_NON_NULL(2)
static void strtof(float& f, const char* str, char** endptr) noexcept
{
f = std::strtof(str, endptr);
}
JSON_HEDLEY_NON_NULL(2)
static void strtof(double& f, const char* str, char** endptr) noexcept
{
f = std::strtod(str, endptr);
}
JSON_HEDLEY_NON_NULL(2)
static void strtof(long double& f, const char* str, char** endptr) noexcept
{
f = std::strtold(str, endptr);
}
/*!
@brief scan a number literal
@@ -1248,18 +1279,19 @@ scan_number_done:
// we are done scanning a number)
unget();
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
errno = 0;
// try to parse integers first and fall back to floats
if (number_type == token_type::value_unsigned)
{
unsigned long long x{}; // NOLINT(runtime/int)
const auto res = ::nlohmann::detail::from_chars(token_buffer.data(), token_buffer.data() + token_buffer.size(), x);
const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
// we checked the number format before
JSON_ASSERT(res.ptr == token_buffer.data() + token_buffer.size());
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
if (res.ec != std::errc::result_out_of_range)
if (errno != ERANGE)
{
JSON_ASSERT(res.ec == std::errc{});
value_unsigned = static_cast<number_unsigned_t>(x);
if (value_unsigned == x)
{
@@ -1269,15 +1301,13 @@ scan_number_done:
}
else if (number_type == token_type::value_integer)
{
long long x{}; // NOLINT(runtime/int)
const auto res = ::nlohmann::detail::from_chars(token_buffer.data(), token_buffer.data() + token_buffer.size(), x);
const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
// we checked the number format before
JSON_ASSERT(res.ptr == token_buffer.data() + token_buffer.size());
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
if (res.ec != std::errc::result_out_of_range)
if (errno != ERANGE)
{
JSON_ASSERT(res.ec == std::errc{});
value_integer = static_cast<number_integer_t>(x);
if (value_integer == x)
{
@@ -1288,11 +1318,10 @@ scan_number_done:
// this code is reached if we parse a floating-point number or if an
// integer conversion above failed
const auto res = ::nlohmann::detail::from_chars(token_buffer.data(), token_buffer.data() + token_buffer.size(), value_float);
strtof(value_float, token_buffer.data(), &endptr);
// we checked the number format before
JSON_ASSERT(res.ptr == token_buffer.data() + token_buffer.size());
JSON_ASSERT(res.ec != std::errc::invalid_argument);
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
return token_type::value_float;
}
+1
View File
@@ -55,6 +55,7 @@ class json_pointer
public:
// for backwards compatibility accept BasicJsonType
/// @sa https://json.nlohmann.me/api/json_pointer/string_t/
using string_t = typename string_t_helper<RefStringType>::type;
/// @brief create JSON pointer
-14
View File
@@ -124,20 +124,6 @@
#define JSON_HAS_FILESYSTEM 0
#endif
#ifndef JSON_HAS_FROM_CHARS
#if defined(JSON_HAS_CPP_17) && defined(__cpp_lib_to_chars)
// The std::from_chars<float> implementation in libstdc++ 11 gets some of the corner cases wrong;
// starting with libstdc++ 12, these are fixed by switching the implementation to fast_float.
#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE < 12
#define JSON_HAS_FROM_CHARS 0
#else
#define JSON_HAS_FROM_CHARS 1
#endif
#else
#define JSON_HAS_FROM_CHARS 0
#endif
#endif
#ifndef JSON_HAS_THREE_WAY_COMPARISON
#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \
&& defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L

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