mirror of
https://github.com/nlohmann/json.git
synced 2026-09-29 19:20:30 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6c115a9a6 | ||
|
|
33ef25099d |
@@ -1,81 +0,0 @@
|
|||||||
name: "Check API documentation"
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_api_docs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Checkout pull request
|
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
||||||
|
|
||||||
- name: Install clang
|
|
||||||
# Used only as a subprocess for `clang++ -E -v` system-include-path discovery in
|
|
||||||
# extract_api.py; it does not need to version-match the pinned libclang pip wheel
|
|
||||||
# below, which does the actual AST parsing. Do not "fix" this to be version-matched.
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y clang
|
|
||||||
|
|
||||||
- name: Install Python dependencies
|
|
||||||
run: pip install -r tools/api_checker/requirements.txt
|
|
||||||
|
|
||||||
- name: Extract API and regenerate the committed surface file
|
|
||||||
run: |
|
|
||||||
python3 tools/api_checker/extract_api.py \
|
|
||||||
--header include/nlohmann/json.hpp \
|
|
||||||
--include include \
|
|
||||||
--output /tmp/api_snapshot.json \
|
|
||||||
--surface-output tools/api_checker/api_surface.json
|
|
||||||
|
|
||||||
- name: "Check API documentation (Phase 1: advisory)"
|
|
||||||
# Surfaces missing/broken @sa links without failing the job while the backlog from the
|
|
||||||
# initial AST-based rollout is burned down. See tools/api_checker/POLICY.md and the PR
|
|
||||||
# that introduced this workflow for the two-phase rollout plan.
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
python3 tools/api_checker/check_docs.py \
|
|
||||||
--snapshot /tmp/api_snapshot.json
|
|
||||||
|
|
||||||
- name: Check macro documentation (advisory only)
|
|
||||||
# Cross-checks docs/mkdocs/docs/api/macros/ pages against #define sites. Only checks the
|
|
||||||
# documented-macro-still-exists direction; never blocks CI. See POLICY.md.
|
|
||||||
run: python3 tools/api_checker/check_macros.py
|
|
||||||
|
|
||||||
- name: Check for uncommitted API surface changes
|
|
||||||
id: diff
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ github.workspace }}/patch
|
|
||||||
git diff --patch --no-color -- tools/api_checker/api_surface.json > ${{ github.workspace }}/patch/api_surface.patch
|
|
||||||
if [ -s ${{ github.workspace }}/patch/api_surface.patch ]; then
|
|
||||||
echo "tools/api_checker/api_surface.json is out of date. Diff:"
|
|
||||||
cat ${{ github.workspace }}/patch/api_surface.patch
|
|
||||||
echo "has_diff=true" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "has_diff=false" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Uploaded so contributors can fix their PR with `git apply api_surface.patch`
|
|
||||||
# instead of installing libclang locally.
|
|
||||||
- name: Upload patch
|
|
||||||
if: steps.diff.outputs.has_diff == 'true'
|
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
||||||
with:
|
|
||||||
name: api-surface-patch
|
|
||||||
path: patch/api_surface.patch
|
|
||||||
|
|
||||||
- name: Fail if API surface file is not up to date
|
|
||||||
# Unlike the doc-backlog check above, this is purely mechanical regeneration with no
|
|
||||||
# backlog to phase in -- blocking from the start, matching check_amalgamation.yml's
|
|
||||||
# precedent. Contributors who add/remove/rename public API must regenerate and commit
|
|
||||||
# tools/api_checker/api_surface.json as part of their PR.
|
|
||||||
if: steps.diff.outputs.has_diff == 'true'
|
|
||||||
run: exit 1
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
*.gcno
|
*.gcno
|
||||||
*.gcda
|
*.gcda
|
||||||
.DS_Store
|
.DS_Store
|
||||||
__pycache__/
|
|
||||||
|
|
||||||
/.idea
|
/.idea
|
||||||
/cmake-build-*
|
/cmake-build-*
|
||||||
@@ -44,9 +43,5 @@ venv
|
|||||||
|
|
||||||
nlohmann_json.spdx
|
nlohmann_json.spdx
|
||||||
|
|
||||||
# api_checker: ephemeral, location/doc-status-sensitive working file (not the committed
|
|
||||||
# release-tracking artifact -- see tools/api_checker/api_surface.json for that)
|
|
||||||
/tools/api_checker/api_snapshot.json
|
|
||||||
|
|
||||||
# Bazel-related
|
# Bazel-related
|
||||||
MODULE.bazel.lock
|
MODULE.bazel.lock
|
||||||
|
|||||||
@@ -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).
|
:books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/docs/mkdocs/docs/examples), or browse through the [**help pages**](https://json.nlohmann.me).
|
||||||
|
|
||||||
:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or have a look at the [quick reference](#quick-reference) below. The public API surface is derived mechanically and checked for documentation coverage by the tooling in [`tools/api_checker/`](tools/api_checker/), whose [POLICY.md](tools/api_checker/POLICY.md) defines what counts as public API and what stability is guaranteed.
|
:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or have a look at the [quick reference](#quick-reference) below.
|
||||||
|
|
||||||
:bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as much information as possible to help us understand and reproduce your issue.
|
:bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as much information as possible to help us understand and reproduce your issue.
|
||||||
|
|
||||||
|
|||||||
@@ -420,9 +420,7 @@ basic_json(basic_json&& other) noexcept;
|
|||||||
1. Since version 1.0.0.
|
1. Since version 1.0.0.
|
||||||
2. Since version 1.0.0.
|
2. Since version 1.0.0.
|
||||||
3. Since version 2.1.0.
|
3. Since version 2.1.0.
|
||||||
4. Since version 3.2.0. Also initializes the position reported by
|
4. Since version 3.2.0.
|
||||||
[`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.
|
5. Since version 1.0.0.
|
||||||
6. Since version 1.0.0.
|
6. Since version 1.0.0.
|
||||||
7. Since version 1.0.0.
|
7. Since version 1.0.0.
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
# <small>nlohmann::basic_json::</small>bjdata_version_t
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
enum class bjdata_version_t
|
|
||||||
{
|
|
||||||
draft2,
|
|
||||||
draft3,
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
This enumeration is used in the [`to_bjdata`](to_bjdata.md) function to choose which draft version of
|
|
||||||
the BJData specification to encode ND-array extensions for:
|
|
||||||
|
|
||||||
draft2
|
|
||||||
: encode using the BJData Draft 2 ND-array format
|
|
||||||
|
|
||||||
draft3
|
|
||||||
: encode using the BJData Draft 3 ND-array format
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `bjdata_version_t` selects the BJData draft used by `to_bjdata`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/bjdata_version_t.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/bjdata_version_t.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.12.0.
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# <small>nlohmann::basic_json::</small>initializer_list_t
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
|
|
||||||
```
|
|
||||||
|
|
||||||
The type used for the initializer-list [constructor](basic_json.md) (overload 5) and for functions
|
|
||||||
such as [`operator=`](operator=.md) that accept a braced-init-list of JSON values. Each element wraps a
|
|
||||||
`basic_json` value or something convertible to one, deferring the decision of whether the list should be
|
|
||||||
parsed as a JSON array or a JSON object to the constructor itself.
|
|
||||||
|
|
||||||
See the [constructor](basic_json.md) documentation for how `initializer_list_t` values are interpreted.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how an `initializer_list_t` is used to construct a JSON value.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/initializer_list_t.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/initializer_list_t.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Since version 1.0.0.
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# <small>nlohmann::basic_json::</small>json_sax_t
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using json_sax_t = json_sax<basic_json>;
|
|
||||||
```
|
|
||||||
|
|
||||||
The [`json_sax`](../json_sax/index.md) interface bound to this `basic_json` specialization, i.e. with
|
|
||||||
`BasicJsonType` fixed to `basic_json`. Used as the SAX interface type by [`sax_parse`](sax_parse.md) and
|
|
||||||
other SAX-based parsing functions.
|
|
||||||
|
|
||||||
See [`nlohmann::json_sax`](../json_sax/index.md) for more information.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `json_sax_t`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/json_sax_t.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/json_sax_t.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
|
||||||
@@ -51,5 +51,3 @@ Linear.
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 1.0.0.
|
- Added in version 1.0.0.
|
||||||
- The `noexcept` specification was extended to also depend on
|
|
||||||
[`json_base_class_t`](json_base_class_t.md)'s move-assignment in version 3.11.3.
|
|
||||||
|
|||||||
@@ -85,8 +85,3 @@ Linear in the size of the JSON value.
|
|||||||
- Since version 1.0.0.
|
- Since version 1.0.0.
|
||||||
- Macros `JSON_EXPLICIT`/[`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) added
|
- Macros `JSON_EXPLICIT`/[`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) added
|
||||||
in version 3.9.0.
|
in version 3.9.0.
|
||||||
- The exclusion of `std::any` from this conversion became conditional on
|
|
||||||
[`JSON_HAS_STATIC_RTTI`](../macros/json_has_static_rtti.md) in version 3.11.3.
|
|
||||||
- `std::optional<T>` excluded from this conversion in version 3.13.0; use
|
|
||||||
[`get<std::optional<T>>()`](get.md)/[`get_to()`](get_to.md) instead (see
|
|
||||||
[Converting values](../../features/conversions.md)).
|
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
# <small>nlohmann::byte_container_with_subtype::</small>container_type
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using container_type = BinaryType;
|
|
||||||
```
|
|
||||||
|
|
||||||
The type of the underlying binary container, forwarded from the `BinaryType` template parameter that
|
|
||||||
`byte_container_with_subtype` is instantiated with. `byte_container_with_subtype` publicly inherits from
|
|
||||||
`container_type`.
|
|
||||||
|
|
||||||
See [`basic_json::binary_t`](../basic_json/binary_t.md) for the type typically used to instantiate
|
|
||||||
`BinaryType`.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `container_type`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/byte_container_with_subtype__container_type.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/byte_container_with_subtype__container_type.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Since version 3.8.0.
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# <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.
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# <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.
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# <small>nlohmann::byte_container_with_subtype::</small>subtype_type
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using subtype_type = std::uint64_t;
|
|
||||||
```
|
|
||||||
|
|
||||||
The type used to store the optional binary subtype tag. See [`subtype`](subtype.md) and
|
|
||||||
[`set_subtype`](set_subtype.md).
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `subtype_type`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/byte_container_with_subtype__subtype_type.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/byte_container_with_subtype__subtype_type.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Since version 3.8.0.
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# <small>nlohmann::json_sax::</small>binary_t
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using binary_t = typename BasicJsonType::binary_t;
|
|
||||||
```
|
|
||||||
|
|
||||||
The type used by the [`binary`](binary.md) callback for JSON binary values, forwarded from the
|
|
||||||
`BasicJsonType` template parameter.
|
|
||||||
|
|
||||||
See [`basic_json::binary_t`](../basic_json/binary_t.md) for more information.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `binary_t` and its relation to `basic_json::binary_t`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/json_sax__binary_t.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/json_sax__binary_t.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.8.0.
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# <small>nlohmann::json_sax::</small>json_sax
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
json_sax() = default;
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
json_sax(const json_sax&) = default;
|
|
||||||
|
|
||||||
// (3)
|
|
||||||
json_sax(json_sax&&) noexcept = default;
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Default constructor.
|
|
||||||
2. Copy constructor.
|
|
||||||
3. Move constructor.
|
|
||||||
|
|
||||||
`json_sax` is a pure abstract base class with no data members of its own, so all three constructors are
|
|
||||||
defaulted and only exist to make derived SAX consumers explicitly copyable/movable.
|
|
||||||
|
|
||||||
## Exception safety
|
|
||||||
|
|
||||||
No-throw guarantee: none of these constructors throw exceptions.
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Constant.
|
|
||||||
|
|
||||||
<!-- NOLINT Examples -->
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# <small>nlohmann::json_sax::</small>number_float_t
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using number_float_t = typename BasicJsonType::number_float_t;
|
|
||||||
```
|
|
||||||
|
|
||||||
The type used by the [`number_float`](number_float.md) callback for JSON floating-point numbers,
|
|
||||||
forwarded from the `BasicJsonType` template parameter.
|
|
||||||
|
|
||||||
See [`basic_json::number_float_t`](../basic_json/number_float_t.md) for more information.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `number_float_t` and its relation to `basic_json::number_float_t`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/json_sax__number_float_t.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/json_sax__number_float_t.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# <small>nlohmann::json_sax::</small>number_integer_t
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
|
||||||
```
|
|
||||||
|
|
||||||
The type used by the [`number_integer`](number_integer.md) callback for JSON integer numbers, forwarded
|
|
||||||
from the `BasicJsonType` template parameter.
|
|
||||||
|
|
||||||
See [`basic_json::number_integer_t`](../basic_json/number_integer_t.md) for more information.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `number_integer_t` and its relation to `basic_json::number_integer_t`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/json_sax__number_integer_t.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/json_sax__number_integer_t.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# <small>nlohmann::json_sax::</small>number_unsigned_t
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
|
||||||
```
|
|
||||||
|
|
||||||
The type used by the [`number_unsigned`](number_unsigned.md) callback for JSON unsigned integer numbers,
|
|
||||||
forwarded from the `BasicJsonType` template parameter.
|
|
||||||
|
|
||||||
See [`basic_json::number_unsigned_t`](../basic_json/number_unsigned_t.md) for more information.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `number_unsigned_t` and its relation to `basic_json::number_unsigned_t`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/json_sax__number_unsigned_t.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/json_sax__number_unsigned_t.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# <small>nlohmann::json_sax::</small>operator=
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
json_sax& operator=(const json_sax&) = default;
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
json_sax& operator=(json_sax&&) noexcept = default;
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Copy assignment operator.
|
|
||||||
2. Move assignment operator.
|
|
||||||
|
|
||||||
`json_sax` is a pure abstract base class with no data members of its own, so both assignment operators
|
|
||||||
are defaulted and only exist to make derived SAX consumers explicitly copy-/move-assignable.
|
|
||||||
|
|
||||||
## Exception safety
|
|
||||||
|
|
||||||
No-throw guarantee: neither operator throws exceptions.
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Constant.
|
|
||||||
|
|
||||||
<!-- NOLINT Examples -->
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# <small>nlohmann::json_sax::</small>string_t
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using string_t = typename BasicJsonType::string_t;
|
|
||||||
```
|
|
||||||
|
|
||||||
The type used by the [`string`](string.md) and [`key`](key.md) callbacks for JSON strings and object
|
|
||||||
keys, forwarded from the `BasicJsonType` template parameter.
|
|
||||||
|
|
||||||
See [`basic_json::string_t`](../basic_json/string_t.md) for more information.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `string_t` and its relation to `basic_json::string_t`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/json_sax__string_t.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/json_sax__string_t.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# <small>nlohmann::json_sax::</small>~json_sax
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
virtual ~json_sax() = default;
|
|
||||||
```
|
|
||||||
|
|
||||||
Destructor. Virtual to allow proper destruction of derived SAX consumer classes through a
|
|
||||||
pointer/reference to `json_sax`.
|
|
||||||
|
|
||||||
## Exception safety
|
|
||||||
|
|
||||||
No-throw guarantee: this destructor never throws exceptions.
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Constant.
|
|
||||||
|
|
||||||
<!-- NOLINT Examples -->
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
|
||||||
@@ -8,16 +8,16 @@ This type preserves the insertion order of object keys.
|
|||||||
|
|
||||||
## Iterator invalidation
|
## Iterator invalidation
|
||||||
|
|
||||||
The type is based on [`ordered_map`](ordered_map/index.md) which in turn uses a `std::vector` to store object elements.
|
The type is based on [`ordered_map`](ordered_map.md) which in turn uses a `std::vector` to store object elements.
|
||||||
Therefore, adding object elements can yield a reallocation in which case all iterators (including the
|
Therefore, adding object elements can yield a reallocation in which case all iterators (including the
|
||||||
[`end()`](basic_json/end.md) iterator) and all references to the elements are invalidated. Also, any iterator or
|
[`end()`](basic_json/end.md) iterator) and all references to the elements are invalidated. Also, any iterator or
|
||||||
reference after the insertion point will point to the same index, which is now a different value.
|
reference after the insertion point will point to the same index, which is now a different value.
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
[`ordered_map`](ordered_map/index.md) has no lookup index: every key-based object operation is a linear scan, so building or
|
[`ordered_map`](ordered_map.md) has no lookup index: every key-based object operation is a linear scan, so building or
|
||||||
parsing an object of `n` keys costs O(n²) rather than O(n log n). See
|
parsing an object of `n` keys costs O(n²) rather than O(n log n). See
|
||||||
[`ordered_map` complexity](ordered_map/index.md#complexity) for the per-operation table and for measured numbers.
|
[`ordered_map` complexity](ordered_map.md#complexity) for the per-operation table and for measured numbers.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ parsing an object of `n` keys costs O(n²) rather than O(n log n). See
|
|||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [ordered_map](ordered_map/index.md)
|
- [ordered_map](ordered_map.md)
|
||||||
- [Object Order](../features/object_order.md)
|
- [Object Order](../features/object_order.md)
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ template<class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>;
|
struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>;
|
||||||
```
|
```
|
||||||
|
|
||||||
A minimal map-like container that preserves insertion order for use within [`nlohmann::ordered_json`](../ordered_json.md)
|
A minimal map-like container that preserves insertion order for use within [`nlohmann::ordered_json`](ordered_json.md)
|
||||||
(`nlohmann::basic_json<ordered_map>`).
|
(`nlohmann::basic_json<ordered_map>`).
|
||||||
|
|
||||||
## Template parameters
|
## Template parameters
|
||||||
@@ -32,12 +32,12 @@ case all iterators (including the `end()` iterator) and all references to the el
|
|||||||
|
|
||||||
- **key_type** - key type (`Key`)
|
- **key_type** - key type (`Key`)
|
||||||
- **mapped_type** - mapped type (`T`)
|
- **mapped_type** - mapped type (`T`)
|
||||||
- [**Container**](Container.md) - base container type (`#!cpp std::vector<std::pair<const Key, T>, Allocator>`)
|
- **Container** - base container type (`#!cpp std::vector<std::pair<const Key, T>, Allocator>`)
|
||||||
- **iterator**
|
- **iterator**
|
||||||
- **const_iterator**
|
- **const_iterator**
|
||||||
- **size_type**
|
- **size_type**
|
||||||
- **value_type**
|
- **value_type**
|
||||||
- [**key_compare**](key_compare.md) - key comparison function
|
- **key_compare** - key comparison function
|
||||||
```cpp
|
```cpp
|
||||||
std::equal_to<Key> // until C++14
|
std::equal_to<Key> // until C++14
|
||||||
|
|
||||||
@@ -46,16 +46,15 @@ std::equal_to<> // since C++14
|
|||||||
|
|
||||||
## Member functions
|
## Member functions
|
||||||
|
|
||||||
- [(constructor)](ordered_map.md)
|
- (constructor)
|
||||||
- [(destructor)](~ordered_map.md)
|
- (destructor)
|
||||||
- [**operator=**](operator=.md)
|
- **emplace**
|
||||||
- [**emplace**](emplace.md)
|
- **operator\[\]**
|
||||||
- [**operator\[\]**](operator[].md)
|
- **at**
|
||||||
- [**at**](at.md)
|
- **erase**
|
||||||
- [**erase**](erase.md)
|
- **count**
|
||||||
- [**count**](count.md)
|
- **find**
|
||||||
- [**find**](find.md)
|
- **insert**
|
||||||
- [**insert**](insert.md)
|
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
@@ -117,9 +116,9 @@ This differs from `#!cpp std::map`, where the same operations are O(log n).
|
|||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [ordered_json](../ordered_json.md)
|
- [ordered_json](ordered_json.md)
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](ordered_json.md).
|
||||||
- Added **key_compare** member in version 3.11.0.
|
- Added **key_compare** member in version 3.11.0.
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>Container
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using Container = std::vector<std::pair<const Key, T>, Allocator>;
|
|
||||||
```
|
|
||||||
|
|
||||||
The base container type that `ordered_map` publicly inherits from. Elements are stored in insertion
|
|
||||||
order as `#!cpp std::pair<const Key, T>` entries in a `std::vector`.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows the type `Container`.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__Container.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__Container.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>at
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
T& at(const key_type& key);
|
|
||||||
const T& at(const key_type& key) const;
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
template<class KeyType>
|
|
||||||
T& at(KeyType&& key);
|
|
||||||
template<class KeyType>
|
|
||||||
const T& at(KeyType&& key) const;
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Returns a reference to the value mapped to `key`.
|
|
||||||
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
(heterogeneous lookup, e.g. looking up by a `#!cpp const char*` without constructing a temporary
|
|
||||||
`key_type`). Only participates in overload resolution if `KeyType` is usable as a key type.
|
|
||||||
|
|
||||||
## Template parameters
|
|
||||||
|
|
||||||
`KeyType`
|
|
||||||
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`key` (in)
|
|
||||||
: key of the element to find
|
|
||||||
|
|
||||||
## Return value
|
|
||||||
|
|
||||||
reference to the mapped value of the element with key equal to `key`
|
|
||||||
|
|
||||||
## Exceptions
|
|
||||||
|
|
||||||
Throws `std::out_of_range` if no element with key `key` exists.
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Linear in the number of elements.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `at` is used.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__at.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__at.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.1 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
- Overload (2) added in version 3.11.0.
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>count
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
size_type count(const key_type& key) const;
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
template<class KeyType>
|
|
||||||
size_type count(KeyType&& key) const;
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Returns the number of elements with key equal to `key` (0 or 1, since keys are unique).
|
|
||||||
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
|
|
||||||
|
|
||||||
## Template parameters
|
|
||||||
|
|
||||||
`KeyType`
|
|
||||||
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`key` (in)
|
|
||||||
: key of the elements to count
|
|
||||||
|
|
||||||
## Return value
|
|
||||||
|
|
||||||
number of elements with key equal to `key` (0 or 1)
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Linear in the number of elements.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `count` is used.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__count.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__count.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.1 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
- Overload (2) added in version 3.11.0.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>emplace
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
std::pair<iterator, bool> emplace(const key_type& key, T&& t);
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
template<class KeyType>
|
|
||||||
std::pair<iterator, bool> emplace(KeyType&& key, T&& t);
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Inserts `#!cpp {key, t}` if no element with an equal key already exists (per [`key_compare`](key_compare.md)),
|
|
||||||
appending it at the end to preserve insertion order. If an equal key already exists, does nothing.
|
|
||||||
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
|
|
||||||
|
|
||||||
## Template parameters
|
|
||||||
|
|
||||||
`KeyType`
|
|
||||||
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`key` (in)
|
|
||||||
: key of the element to insert
|
|
||||||
|
|
||||||
`t` (in)
|
|
||||||
: value of the element to insert
|
|
||||||
|
|
||||||
## Return value
|
|
||||||
|
|
||||||
pair of an iterator to the (possibly newly inserted) element, and a `bool` that is `true` if insertion
|
|
||||||
took place and `false` if an element with an equal key already existed
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Linear in the number of elements.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `emplace` is used.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__emplace.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__emplace.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
- Overload (2) added in version 3.11.0.
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>erase
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
size_type erase(const key_type& key);
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
template<class KeyType>
|
|
||||||
size_type erase(KeyType&& key);
|
|
||||||
|
|
||||||
// (3)
|
|
||||||
iterator erase(iterator pos);
|
|
||||||
|
|
||||||
// (4)
|
|
||||||
iterator erase(iterator first, iterator last);
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Removes the element with key equal to `key`, if any, preserving the relative order of the remaining
|
|
||||||
elements.
|
|
||||||
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
|
|
||||||
3. Removes the element at `pos`.
|
|
||||||
4. Removes the elements in range `[first, last)`.
|
|
||||||
|
|
||||||
## Template parameters
|
|
||||||
|
|
||||||
`KeyType`
|
|
||||||
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`key` (in)
|
|
||||||
: key of the element to remove
|
|
||||||
|
|
||||||
`pos` (in)
|
|
||||||
: iterator to the element to remove
|
|
||||||
|
|
||||||
`first` (in)
|
|
||||||
: iterator to the first element to remove
|
|
||||||
|
|
||||||
`last` (in)
|
|
||||||
: iterator one past the last element to remove
|
|
||||||
|
|
||||||
## Return value
|
|
||||||
|
|
||||||
1. number of elements removed (0 or 1)
|
|
||||||
2. number of elements removed (0 or 1)
|
|
||||||
3. iterator following the removed element
|
|
||||||
4. iterator following the last removed element
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Linear in the number of elements (elements after the removed one(s) are shifted to keep storage
|
|
||||||
contiguous).
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `erase` is used.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__erase.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__erase.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
- Overload (2) added in version 3.11.0.
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>find
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
iterator find(const key_type& key);
|
|
||||||
const_iterator find(const key_type& key) const;
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
template<class KeyType>
|
|
||||||
iterator find(KeyType&& key);
|
|
||||||
template<class KeyType>
|
|
||||||
const_iterator find(KeyType&& key) const;
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Returns an iterator to the element with key equal to `key`, or `end()` if no such element exists.
|
|
||||||
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
|
|
||||||
|
|
||||||
## Template parameters
|
|
||||||
|
|
||||||
`KeyType`
|
|
||||||
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`key` (in)
|
|
||||||
: key of the element to find
|
|
||||||
|
|
||||||
## Return value
|
|
||||||
|
|
||||||
iterator to the element with key equal to `key`, or `end()` if not found
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Linear in the number of elements.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `find` is used.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__find.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__find.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.1 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
- Overload (2) added in version 3.11.0.
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>insert
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
std::pair<iterator, bool> insert(value_type&& value);
|
|
||||||
std::pair<iterator, bool> insert(const value_type& value);
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
template<typename InputIt>
|
|
||||||
void insert(InputIt first, InputIt last);
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Inserts `value` if no element with an equal key already exists (per [`key_compare`](key_compare.md)),
|
|
||||||
appending it at the end to preserve insertion order. If an equal key already exists, does nothing.
|
|
||||||
2. Inserts the elements from range `[first, last)`, in iteration order, applying the same equal-key rule
|
|
||||||
as (1) to each element.
|
|
||||||
|
|
||||||
## Template parameters
|
|
||||||
|
|
||||||
`InputIt`
|
|
||||||
: an input iterator type
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`value` (in)
|
|
||||||
: value to insert
|
|
||||||
|
|
||||||
`first` (in)
|
|
||||||
: iterator to the first element to insert
|
|
||||||
|
|
||||||
`last` (in)
|
|
||||||
: iterator one past the last element to insert
|
|
||||||
|
|
||||||
## Return value
|
|
||||||
|
|
||||||
1. pair of an iterator to the (possibly newly inserted) element, and a `bool` that is `true` if insertion
|
|
||||||
took place and `false` if an element with an equal key already existed
|
|
||||||
2. (none)
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
1. Linear in the number of elements.
|
|
||||||
2. Linear in the distance between `first` and `last`, times linear in the number of elements.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `insert` is used.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__insert.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__insert.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.1 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>key_compare
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
using key_compare = std::equal_to<Key>; // until C++14
|
|
||||||
|
|
||||||
using key_compare = std::equal_to<>; // since C++14
|
|
||||||
```
|
|
||||||
|
|
||||||
The comparator used to determine key equality when looking up elements. Unlike `std::map`, `ordered_map`
|
|
||||||
uses linear search with `key_compare` rather than an ordering relation, since element order reflects
|
|
||||||
insertion order rather than key order.
|
|
||||||
|
|
||||||
Since C++14, the transparent `#!cpp std::equal_to<>` is used, which enables heterogeneous lookup (e.g.
|
|
||||||
looking up by a `#!cpp const char*` key without constructing a temporary `Key`).
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `key_compare` is used.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__key_compare.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__key_compare.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.11.0.
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>operator=
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
ordered_map& operator=(const ordered_map& other);
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
ordered_map& operator=(ordered_map&& other) noexcept(std::is_nothrow_move_assignable<Container>::value);
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Copy assignment operator.
|
|
||||||
2. Move assignment operator.
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`other` (in)
|
|
||||||
: value to assign from
|
|
||||||
|
|
||||||
## Return value
|
|
||||||
|
|
||||||
`*this`
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
1. Linear in the size of `other`.
|
|
||||||
2. Constant.
|
|
||||||
|
|
||||||
<!-- NOLINT Examples -->
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>operator[]
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
T& operator[](const key_type& key);
|
|
||||||
const T& operator[](const key_type& key) const;
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
template<class KeyType>
|
|
||||||
T& operator[](KeyType&& key);
|
|
||||||
template<class KeyType>
|
|
||||||
const T& operator[](KeyType&& key) const;
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Returns a reference to the value mapped to `key`, inserting a default-constructed `T` (non-`const`
|
|
||||||
overload only) if no such element exists yet.
|
|
||||||
2. Same as (1), but for any `KeyType` comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
(heterogeneous lookup). Only participates in overload resolution if `KeyType` is usable as a key type.
|
|
||||||
|
|
||||||
## Template parameters
|
|
||||||
|
|
||||||
`KeyType`
|
|
||||||
: a type comparable to `key_type` via [`key_compare`](key_compare.md)
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`key` (in)
|
|
||||||
: key of the element to find or insert
|
|
||||||
|
|
||||||
## Return value
|
|
||||||
|
|
||||||
reference to the mapped value of the element with key equal to `key`
|
|
||||||
|
|
||||||
## Exceptions
|
|
||||||
|
|
||||||
The `const` overloads throw `std::out_of_range` if no element with key `key` exists (they delegate to
|
|
||||||
[`at`](at.md)).
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Linear in the number of elements.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example
|
|
||||||
|
|
||||||
The example shows how `operator[]` is used.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
--8<-- "examples/ordered_map__operator_idx.cpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--8<-- "examples/ordered_map__operator_idx.output"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
- Overload (2) added in version 3.11.0.
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>ordered_map
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// (1)
|
|
||||||
ordered_map() noexcept(noexcept(Container()));
|
|
||||||
|
|
||||||
// (2)
|
|
||||||
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc)));
|
|
||||||
|
|
||||||
// (3)
|
|
||||||
template <class It>
|
|
||||||
ordered_map(It first, It last, const Allocator& alloc = Allocator());
|
|
||||||
|
|
||||||
// (4)
|
|
||||||
ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator());
|
|
||||||
|
|
||||||
// (5)
|
|
||||||
ordered_map(const ordered_map&) = default;
|
|
||||||
|
|
||||||
// (6)
|
|
||||||
ordered_map(ordered_map&&) noexcept(std::is_nothrow_move_constructible<Container>::value) = default;
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Default constructor. Creates an empty `ordered_map`.
|
|
||||||
2. Creates an empty `ordered_map` using the given allocator.
|
|
||||||
3. Creates an `ordered_map` from the elements in range `[first, last)`, inserted in iteration order.
|
|
||||||
4. Creates an `ordered_map` from an initializer list of key/value pairs, inserted in list order.
|
|
||||||
5. Copy constructor.
|
|
||||||
6. Move constructor.
|
|
||||||
|
|
||||||
These constructors are declared explicitly (rather than inherited via `#!cpp using Container::Container`)
|
|
||||||
because older compilers (GCC <= 5.5, Xcode <= 9.4) do not handle the inherited constructors correctly.
|
|
||||||
|
|
||||||
## Template parameters
|
|
||||||
|
|
||||||
`It`
|
|
||||||
: an input iterator type
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
`alloc` (in)
|
|
||||||
: allocator to use for the underlying container
|
|
||||||
|
|
||||||
`first` (in)
|
|
||||||
: iterator to the first element to insert
|
|
||||||
|
|
||||||
`last` (in)
|
|
||||||
: iterator one past the last element to insert
|
|
||||||
|
|
||||||
`init` (in)
|
|
||||||
: initializer list of key/value pairs to insert
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
1. Constant.
|
|
||||||
2. Constant.
|
|
||||||
3. Linear in the distance between `first` and `last`.
|
|
||||||
4. Linear in the size of `init`.
|
|
||||||
5. Linear in the size of `other`.
|
|
||||||
6. Constant.
|
|
||||||
|
|
||||||
<!-- NOLINT Examples -->
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# <small>nlohmann::ordered_map::</small>~ordered_map
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
~ordered_map() = default;
|
|
||||||
```
|
|
||||||
|
|
||||||
Destroys the `ordered_map` and frees all allocated memory.
|
|
||||||
|
|
||||||
## Complexity
|
|
||||||
|
|
||||||
Linear in the number of elements.
|
|
||||||
|
|
||||||
<!-- NOLINT Examples -->
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](../ordered_json.md).
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// an empty binary value is encoded differently by the two drafts:
|
|
||||||
// draft2 omits the optimized type marker for an empty byte array,
|
|
||||||
// while draft3 always writes it
|
|
||||||
json j = json::binary({});
|
|
||||||
|
|
||||||
// encode using BJData draft2 (the default)
|
|
||||||
auto v_draft2 = json::to_bjdata(j, true, true, json::bjdata_version_t::draft2);
|
|
||||||
|
|
||||||
// encode using BJData draft3
|
|
||||||
auto v_draft3 = json::to_bjdata(j, true, true, json::bjdata_version_t::draft3);
|
|
||||||
|
|
||||||
std::cout << "draft2 size: " << v_draft2.size() << '\n'
|
|
||||||
<< "draft3 size: " << v_draft3.size() << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
draft2 size: 4
|
|
||||||
draft3 size: 6
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using byte_container_with_subtype = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< std::is_same<byte_container_with_subtype::container_type, std::vector<std::uint8_t>>::value
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using byte_container_with_subtype = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
c1 == c2: true
|
|
||||||
c1 == c3: false
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using byte_container_with_subtype = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
c1 != c2: false
|
|
||||||
c1 != c3: true
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using byte_container_with_subtype = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< std::is_same<byte_container_with_subtype::subtype_type, std::uint64_t>::value << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// an initializer_list_t is what a braced-init-list of JSON values is deduced as
|
|
||||||
json::initializer_list_t init = {"a", 1, 2.0, false};
|
|
||||||
|
|
||||||
json j(init);
|
|
||||||
std::cout << j.dump() << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["a",1,2.0,false]
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< std::is_same<json::json_sax_t::binary_t, json::binary_t>::value << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< std::is_same<json::json_sax_t::number_float_t, json::number_float_t>::value << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< std::is_same<json::json_sax_t::number_integer_t, json::number_integer_t>::value << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< std::is_same<json::json_sax_t::number_unsigned_t, json::number_unsigned_t>::value << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< std::is_same<json::json_sax_t::string_t, json::string_t>::value << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< std::is_same<json::json_sax_t, nlohmann::json_sax<json>>::value << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
using Map = nlohmann::ordered_map<std::string, int>;
|
|
||||||
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< "Container is std::vector<std::pair<const Key, T>>: "
|
|
||||||
<< std::is_same<Map::Container, std::vector<std::pair<const std::string, int>>>::value
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Container is std::vector<std::pair<const Key, T>>: true
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
nlohmann::ordered_map<std::string, int> m;
|
|
||||||
m["one"] = 1;
|
|
||||||
m["two"] = 2;
|
|
||||||
|
|
||||||
// access an existing element
|
|
||||||
std::cout << "m.at(\"one\") = " << m.at("one") << std::endl;
|
|
||||||
|
|
||||||
// modify through the reference returned by at()
|
|
||||||
m.at("two") = 22;
|
|
||||||
std::cout << "m.at(\"two\") = " << m.at("two") << std::endl;
|
|
||||||
|
|
||||||
// accessing a missing key throws
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m.at("three");
|
|
||||||
}
|
|
||||||
catch (const std::out_of_range& e)
|
|
||||||
{
|
|
||||||
std::cout << "exception: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
m.at("one") = 1
|
|
||||||
m.at("two") = 22
|
|
||||||
exception: key not found
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
nlohmann::ordered_map<std::string, int> m;
|
|
||||||
m["one"] = 1;
|
|
||||||
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< "m.count(\"one\") = " << m.count("one") << '\n'
|
|
||||||
<< "m.count(\"two\") = " << m.count("two") << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
m.count("one") = 1
|
|
||||||
m.count("two") = 0
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
nlohmann::ordered_map<std::string, std::string> m;
|
|
||||||
|
|
||||||
// emplace a new element
|
|
||||||
auto res1 = m.emplace("one", "eins");
|
|
||||||
std::cout << std::boolalpha << "inserted: " << res1.second << ", value: " << res1.first->second << std::endl;
|
|
||||||
|
|
||||||
// emplace with an already-existing key: no-op, returns the existing element
|
|
||||||
auto res2 = m.emplace("one", "uno");
|
|
||||||
std::cout << std::boolalpha << "inserted: " << res2.second << ", value: " << res2.first->second << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
inserted: true, value: eins
|
|
||||||
inserted: false, value: eins
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
nlohmann::ordered_map<std::string, int> m;
|
|
||||||
m["one"] = 1;
|
|
||||||
m["two"] = 2;
|
|
||||||
m["three"] = 3;
|
|
||||||
|
|
||||||
// erase by key
|
|
||||||
std::size_t removed = m.erase("two");
|
|
||||||
std::cout << "removed by key: " << removed << std::endl;
|
|
||||||
|
|
||||||
// erase by iterator
|
|
||||||
m.erase(m.begin());
|
|
||||||
|
|
||||||
std::cout << "remaining: ";
|
|
||||||
for (const auto& element : m)
|
|
||||||
{
|
|
||||||
std::cout << element.first << ' ';
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
removed by key: 1
|
|
||||||
remaining: three
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
nlohmann::ordered_map<std::string, int> m;
|
|
||||||
m["one"] = 1;
|
|
||||||
|
|
||||||
auto it = m.find("one");
|
|
||||||
if (it != m.end())
|
|
||||||
{
|
|
||||||
std::cout << "found: " << it->first << " = " << it->second << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.find("two") == m.end())
|
|
||||||
{
|
|
||||||
std::cout << "\"two\" not found" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
found: one = 1
|
|
||||||
"two" not found
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
nlohmann::ordered_map<std::string, int> m;
|
|
||||||
|
|
||||||
// insert a single value
|
|
||||||
auto res = m.insert({"one", 1});
|
|
||||||
std::cout << std::boolalpha << "inserted: " << res.second << std::endl;
|
|
||||||
|
|
||||||
// insert a range from another container
|
|
||||||
std::vector<std::pair<const std::string, int>> more = {{"two", 2}, {"three", 3}};
|
|
||||||
m.insert(more.begin(), more.end());
|
|
||||||
|
|
||||||
for (const auto& element : m)
|
|
||||||
{
|
|
||||||
std::cout << element.first << ':' << element.second << ' ';
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
inserted: true
|
|
||||||
one:1 two:2 three:3
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
using Map = nlohmann::ordered_map<std::string, int>;
|
|
||||||
Map::key_compare compare{};
|
|
||||||
|
|
||||||
std::cout << std::boolalpha
|
|
||||||
<< "compare(\"a\", \"a\") = " << compare("a", "a") << '\n'
|
|
||||||
<< "compare(\"a\", \"b\") = " << compare("a", "b") << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
compare("a", "a") = true
|
|
||||||
compare("a", "b") = false
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
nlohmann::ordered_map<std::string, int> m;
|
|
||||||
|
|
||||||
// operator[] inserts a default-constructed value if the key doesn't exist yet
|
|
||||||
m["one"] = 1;
|
|
||||||
std::cout << "m[\"one\"] = " << m["one"] << std::endl;
|
|
||||||
|
|
||||||
// accessing again just returns the existing value
|
|
||||||
std::cout << "m[\"one\"] = " << m["one"] << std::endl;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
m["one"] = 1
|
|
||||||
m["one"] = 1
|
|
||||||
@@ -51,16 +51,16 @@ If you do want to preserve the **insertion order**, you can use the type [`nlohm
|
|||||||
--8<-- "examples/ordered_json.output"
|
--8<-- "examples/ordered_json.output"
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) also preserves the insertion order and, unlike [`ordered_map`](../api/ordered_map/index.md), keeps a lookup index, so it does not have the quadratic cost described below. It is used through a small adapter ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
|
Alternatively, [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) also preserves the insertion order and, unlike [`ordered_map`](../api/ordered_map.md), keeps a lookup index, so it does not have the quadratic cost described below. It is used through a small adapter ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
|
||||||
|
|
||||||
If the order does not matter and you only want faster lookup, `boost::unordered_flat_map`, `absl::flat_hash_map`, `absl::node_hash_map`, and several other hash maps work through an adapter that restores the template argument order `basic_json` expects; see [Template Parameter Requirements](types/template_parameters.md#objecttype). Note these are *unordered*, not insertion-ordered.
|
If the order does not matter and you only want faster lookup, `boost::unordered_flat_map`, `absl::flat_hash_map`, `absl::node_hash_map`, and several other hash maps work through an adapter that restores the template argument order `basic_json` expects; see [Template Parameter Requirements](types/template_parameters.md#objecttype). Note these are *unordered*, not insertion-ordered.
|
||||||
|
|
||||||
[`tsl::ordered_map`](https://github.com/Tessil/ordered-map) cannot be used: its iterators expose the mapped value as `const`, while `basic_json` needs to modify it in place.
|
[`tsl::ordered_map`](https://github.com/Tessil/ordered-map) cannot be used: its iterators expose the mapped value as `const`, while `basic_json` needs to modify it in place.
|
||||||
|
|
||||||
The [`ordered_map`](../api/ordered_map/index.md) behind `nlohmann::ordered_json` is deliberately minimal and has no lookup
|
The [`ordered_map`](../api/ordered_map.md) behind `nlohmann::ordered_json` is deliberately minimal and has no lookup
|
||||||
index, so every key access is a linear scan and building an object of `n` keys costs O(n²). This is unnoticeable at
|
index, so every key access is a linear scan and building an object of `n` keys costs O(n²). This is unnoticeable at
|
||||||
typical object sizes but becomes significant for objects with many thousands of keys; see
|
typical object sizes but becomes significant for objects with many thousands of keys; see
|
||||||
[`ordered_map` complexity](../api/ordered_map/index.md#complexity). The alternatives above keep a lookup index and do not
|
[`ordered_map` complexity](../api/ordered_map.md#complexity). The alternatives above keep a lookup index and do not
|
||||||
have this cost.
|
have this cost.
|
||||||
|
|
||||||
### Notes on parsing
|
### Notes on parsing
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Requirements are split into two groups:
|
|||||||
|
|
||||||
| Template parameter | Default | Notable substitutes |
|
| Template parameter | Default | Notable substitutes |
|
||||||
|-------------------------------------------------------------------|-----------------------------------|-----------------------------------------------------------------------|
|
|-------------------------------------------------------------------|-----------------------------------|-----------------------------------------------------------------------|
|
||||||
| [`ObjectType`](#objecttype) | `std::map` | [`nlohmann::ordered_map`](../../api/ordered_map/index.md), Abseil hash maps |
|
| [`ObjectType`](#objecttype) | `std::map` | [`nlohmann::ordered_map`](../../api/ordered_map.md), Abseil hash maps |
|
||||||
| [`ArrayType`](#arraytype) | `std::vector` | `#!cpp std::deque` |
|
| [`ArrayType`](#arraytype) | `std::vector` | `#!cpp std::deque` |
|
||||||
| [`StringType`](#stringtype) | `std::string` | `std::string`-like types over `char` |
|
| [`StringType`](#stringtype) | `std::string` | `std::string`-like types over `char` |
|
||||||
| [`BooleanType`](#booleantype) | `bool` | none worth using |
|
| [`BooleanType`](#booleantype) | `bool` | none worth using |
|
||||||
@@ -230,7 +230,7 @@ The library does not sort or de-duplicate keys itself; the behavior described in
|
|||||||
| Container | Notes |
|
| Container | Notes |
|
||||||
|----------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
|
|----------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
|
||||||
| `#!cpp std::map` (default) | |
|
| `#!cpp std::map` (default) | |
|
||||||
| [`nlohmann::ordered_map`](../../api/ordered_map/index.md) | used by [`ordered_json`](../../api/ordered_json.md); keeps insertion order |
|
| [`nlohmann::ordered_map`](../../api/ordered_map.md) | used by [`ordered_json`](../../api/ordered_json.md); keeps insertion order |
|
||||||
| [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) | keeps insertion order; adapter puts `fifo_map_compare` in the comparator slot |
|
| [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) | keeps insertion order; adapter puts `fifo_map_compare` in the comparator slot |
|
||||||
| `boost::container::map`, `boost::container::flat_map` | no adapter needed |
|
| `boost::container::map`, `boost::container::flat_map` | no adapter needed |
|
||||||
| `#!cpp std::unordered_map` | through the adapter above; not with libstdc++ 9, see the note |
|
| `#!cpp std::unordered_map` | through the adapter above; not with libstdc++ 9, see the note |
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ The public headers are in [`include/nlohmann`](https://github.com/nlohmann/json/
|
|||||||
- [`adl_serializer.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/adl_serializer.hpp), [`byte_container_with_subtype.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/byte_container_with_subtype.hpp), and [`ordered_map.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/ordered_map.hpp) define
|
- [`adl_serializer.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/adl_serializer.hpp), [`byte_container_with_subtype.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/byte_container_with_subtype.hpp), and [`ordered_map.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/ordered_map.hpp) define
|
||||||
[`adl_serializer`](../api/adl_serializer/index.md),
|
[`adl_serializer`](../api/adl_serializer/index.md),
|
||||||
[`byte_container_with_subtype`](../api/byte_container_with_subtype/index.md), and
|
[`byte_container_with_subtype`](../api/byte_container_with_subtype/index.md), and
|
||||||
[`ordered_map`](../api/ordered_map/index.md).
|
[`ordered_map`](../api/ordered_map.md).
|
||||||
|
|
||||||
Everything else lives in [`detail/`](https://github.com/nlohmann/json/tree/develop/include/nlohmann/detail) and namespace `nlohmann::detail`, which is not part of the public API. Paths
|
Everything else lives in [`detail/`](https://github.com/nlohmann/json/tree/develop/include/nlohmann/detail) and namespace `nlohmann::detail`, which is not part of the public API. Paths
|
||||||
below are relative to `include/nlohmann`.
|
below are relative to `include/nlohmann`.
|
||||||
@@ -97,7 +97,7 @@ is generated from these files with `make amalgamate` and must not be edited by h
|
|||||||
The library provides two specializations:
|
The library provides two specializations:
|
||||||
|
|
||||||
- [`json`](../api/json.md) uses all default template arguments.
|
- [`json`](../api/json.md) uses all default template arguments.
|
||||||
- [`ordered_json`](../api/ordered_json.md) uses [`ordered_map`](../api/ordered_map/index.md) as `ObjectType` to keep the
|
- [`ordered_json`](../api/ordered_json.md) uses [`ordered_map`](../api/ordered_map.md) as `ObjectType` to keep the
|
||||||
insertion order of object keys.
|
insertion order of object keys.
|
||||||
|
|
||||||
The requirements on the template arguments are listed in
|
The requirements on the template arguments are listed in
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
This page summarizes the notable changes of every release and links to the relevant documentation.
|
This page summarizes the notable changes of every release and links to the relevant documentation.
|
||||||
The **complete release notes** — including all changes, the download files, and their checksums — are
|
The **complete release notes** — including all changes, the download files, and their checksums — are
|
||||||
published on the [GitHub releases page](https://github.com/nlohmann/json/releases). For a raw,
|
published on the [GitHub releases page](https://github.com/nlohmann/json/releases).
|
||||||
signature-level diff of the public API between releases, see [API Changes](api_changes.md).
|
|
||||||
|
|
||||||
## v3.12.0 (2025-04-11)
|
## v3.12.0 (2025-04-11)
|
||||||
|
|
||||||
|
|||||||
+1
-30
@@ -52,7 +52,6 @@ nav:
|
|||||||
- "FAQ": home/faq.md
|
- "FAQ": home/faq.md
|
||||||
- home/exceptions.md
|
- home/exceptions.md
|
||||||
- home/releases.md
|
- home/releases.md
|
||||||
- home/api_changes.md
|
|
||||||
- home/design_goals.md
|
- home/design_goals.md
|
||||||
- home/architecture.md
|
- home/architecture.md
|
||||||
- home/customers.md
|
- home/customers.md
|
||||||
@@ -120,7 +119,6 @@ nav:
|
|||||||
- 'begin': api/basic_json/begin.md
|
- 'begin': api/basic_json/begin.md
|
||||||
- 'binary': api/basic_json/binary.md
|
- 'binary': api/basic_json/binary.md
|
||||||
- 'binary_t': api/basic_json/binary_t.md
|
- 'binary_t': api/basic_json/binary_t.md
|
||||||
- 'bjdata_version_t': api/basic_json/bjdata_version_t.md
|
|
||||||
- 'boolean_t': api/basic_json/boolean_t.md
|
- 'boolean_t': api/basic_json/boolean_t.md
|
||||||
- 'cbegin': api/basic_json/cbegin.md
|
- 'cbegin': api/basic_json/cbegin.md
|
||||||
- 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md
|
- 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md
|
||||||
@@ -159,7 +157,6 @@ nav:
|
|||||||
- 'get_to': api/basic_json/get_to.md
|
- 'get_to': api/basic_json/get_to.md
|
||||||
- 'std::formatter<basic_json>': api/basic_json/std_formatter.md
|
- 'std::formatter<basic_json>': api/basic_json/std_formatter.md
|
||||||
- 'std::hash<basic_json>': api/basic_json/std_hash.md
|
- 'std::hash<basic_json>': api/basic_json/std_hash.md
|
||||||
- 'initializer_list_t': api/basic_json/initializer_list_t.md
|
|
||||||
- 'input_format_t': api/basic_json/input_format_t.md
|
- 'input_format_t': api/basic_json/input_format_t.md
|
||||||
- 'insert': api/basic_json/insert.md
|
- 'insert': api/basic_json/insert.md
|
||||||
- 'invalid_iterator': api/basic_json/invalid_iterator.md
|
- 'invalid_iterator': api/basic_json/invalid_iterator.md
|
||||||
@@ -178,7 +175,6 @@ nav:
|
|||||||
- 'is_structured': api/basic_json/is_structured.md
|
- 'is_structured': api/basic_json/is_structured.md
|
||||||
- 'items': api/basic_json/items.md
|
- 'items': api/basic_json/items.md
|
||||||
- 'json_base_class_t': api/basic_json/json_base_class_t.md
|
- 'json_base_class_t': api/basic_json/json_base_class_t.md
|
||||||
- 'json_sax_t': api/basic_json/json_sax_t.md
|
|
||||||
- 'json_serializer': api/basic_json/json_serializer.md
|
- 'json_serializer': api/basic_json/json_serializer.md
|
||||||
- 'max_size': api/basic_json/max_size.md
|
- 'max_size': api/basic_json/max_size.md
|
||||||
- 'meta': api/basic_json/meta.md
|
- 'meta': api/basic_json/meta.md
|
||||||
@@ -236,13 +232,9 @@ nav:
|
|||||||
- 'Overview': api/byte_container_with_subtype/index.md
|
- 'Overview': api/byte_container_with_subtype/index.md
|
||||||
- '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md
|
- '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md
|
||||||
- 'clear_subtype': api/byte_container_with_subtype/clear_subtype.md
|
- 'clear_subtype': api/byte_container_with_subtype/clear_subtype.md
|
||||||
- 'container_type': api/byte_container_with_subtype/container_type.md
|
|
||||||
- 'has_subtype': api/byte_container_with_subtype/has_subtype.md
|
- 'has_subtype': api/byte_container_with_subtype/has_subtype.md
|
||||||
- 'operator==': api/byte_container_with_subtype/operator_eq.md
|
|
||||||
- 'operator!=': api/byte_container_with_subtype/operator_ne.md
|
|
||||||
- 'set_subtype': api/byte_container_with_subtype/set_subtype.md
|
- 'set_subtype': api/byte_container_with_subtype/set_subtype.md
|
||||||
- 'subtype': api/byte_container_with_subtype/subtype.md
|
- 'subtype': api/byte_container_with_subtype/subtype.md
|
||||||
- 'subtype_type': api/byte_container_with_subtype/subtype_type.md
|
|
||||||
- adl_serializer:
|
- adl_serializer:
|
||||||
- 'Overview': api/adl_serializer/index.md
|
- 'Overview': api/adl_serializer/index.md
|
||||||
- 'from_json': api/adl_serializer/from_json.md
|
- 'from_json': api/adl_serializer/from_json.md
|
||||||
@@ -268,46 +260,25 @@ nav:
|
|||||||
- 'to_string': api/json_pointer/to_string.md
|
- 'to_string': api/json_pointer/to_string.md
|
||||||
- json_sax:
|
- json_sax:
|
||||||
- 'Overview': api/json_sax/index.md
|
- 'Overview': api/json_sax/index.md
|
||||||
- '(Constructor)': api/json_sax/json_sax.md
|
|
||||||
- '(Destructor)': api/json_sax/~json_sax.md
|
|
||||||
- 'operator=': api/json_sax/operator=.md
|
|
||||||
- 'binary': api/json_sax/binary.md
|
- 'binary': api/json_sax/binary.md
|
||||||
- 'binary_t': api/json_sax/binary_t.md
|
|
||||||
- 'boolean': api/json_sax/boolean.md
|
- 'boolean': api/json_sax/boolean.md
|
||||||
- 'end_array': api/json_sax/end_array.md
|
- 'end_array': api/json_sax/end_array.md
|
||||||
- 'end_object': api/json_sax/end_object.md
|
- 'end_object': api/json_sax/end_object.md
|
||||||
- 'key': api/json_sax/key.md
|
- 'key': api/json_sax/key.md
|
||||||
- 'null': api/json_sax/null.md
|
- 'null': api/json_sax/null.md
|
||||||
- 'number_float': api/json_sax/number_float.md
|
- 'number_float': api/json_sax/number_float.md
|
||||||
- 'number_float_t': api/json_sax/number_float_t.md
|
|
||||||
- 'number_integer': api/json_sax/number_integer.md
|
- 'number_integer': api/json_sax/number_integer.md
|
||||||
- 'number_integer_t': api/json_sax/number_integer_t.md
|
|
||||||
- 'number_unsigned': api/json_sax/number_unsigned.md
|
- 'number_unsigned': api/json_sax/number_unsigned.md
|
||||||
- 'number_unsigned_t': api/json_sax/number_unsigned_t.md
|
|
||||||
- 'parse_error': api/json_sax/parse_error.md
|
- 'parse_error': api/json_sax/parse_error.md
|
||||||
- 'start_array': api/json_sax/start_array.md
|
- 'start_array': api/json_sax/start_array.md
|
||||||
- 'start_object': api/json_sax/start_object.md
|
- 'start_object': api/json_sax/start_object.md
|
||||||
- 'string': api/json_sax/string.md
|
- 'string': api/json_sax/string.md
|
||||||
- 'string_t': api/json_sax/string_t.md
|
|
||||||
- 'operator<<(basic_json), operator<<(json_pointer)': api/operator_ltlt.md
|
- 'operator<<(basic_json), operator<<(json_pointer)': api/operator_ltlt.md
|
||||||
- 'operator>>(basic_json)': api/operator_gtgt.md
|
- 'operator>>(basic_json)': api/operator_gtgt.md
|
||||||
- 'operator""_json': api/operator_literal_json.md
|
- 'operator""_json': api/operator_literal_json.md
|
||||||
- 'operator""_json_pointer': api/operator_literal_json_pointer.md
|
- 'operator""_json_pointer': api/operator_literal_json_pointer.md
|
||||||
- 'ordered_json': api/ordered_json.md
|
- 'ordered_json': api/ordered_json.md
|
||||||
- ordered_map:
|
- 'ordered_map': api/ordered_map.md
|
||||||
- 'Overview': api/ordered_map/index.md
|
|
||||||
- '(Constructor)': api/ordered_map/ordered_map.md
|
|
||||||
- '(Destructor)': api/ordered_map/~ordered_map.md
|
|
||||||
- 'operator=': api/ordered_map/operator=.md
|
|
||||||
- 'at': api/ordered_map/at.md
|
|
||||||
- 'Container': api/ordered_map/Container.md
|
|
||||||
- 'count': api/ordered_map/count.md
|
|
||||||
- 'emplace': api/ordered_map/emplace.md
|
|
||||||
- 'erase': api/ordered_map/erase.md
|
|
||||||
- 'find': api/ordered_map/find.md
|
|
||||||
- 'insert': api/ordered_map/insert.md
|
|
||||||
- 'key_compare': api/ordered_map/key_compare.md
|
|
||||||
- 'operator[]': api/ordered_map/operator[].md
|
|
||||||
- macros:
|
- macros:
|
||||||
- 'Overview': api/macros/index.md
|
- 'Overview': api/macros/index.md
|
||||||
- 'JSON_ASSERT': api/macros/json_assert.md
|
- 'JSON_ASSERT': api/macros/json_assert.md
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ template<typename BinaryType>
|
|||||||
class byte_container_with_subtype : public BinaryType
|
class byte_container_with_subtype : public BinaryType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/container_type/
|
|
||||||
using container_type = BinaryType;
|
using container_type = BinaryType;
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype_type/
|
|
||||||
using subtype_type = std::uint64_t;
|
using subtype_type = std::uint64_t;
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
||||||
@@ -56,14 +54,12 @@ class byte_container_with_subtype : public BinaryType
|
|||||||
, m_has_subtype(true)
|
, m_has_subtype(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/operator_eq/
|
|
||||||
bool operator==(const byte_container_with_subtype& rhs) const
|
bool operator==(const byte_container_with_subtype& rhs) const
|
||||||
{
|
{
|
||||||
return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
|
return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
|
||||||
std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
|
std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/operator_ne/
|
|
||||||
bool operator!=(const byte_container_with_subtype& rhs) const
|
bool operator!=(const byte_container_with_subtype& rhs) const
|
||||||
{
|
{
|
||||||
return !(rhs == *this);
|
return !(rhs == *this);
|
||||||
|
|||||||
@@ -33,21 +33,15 @@ input.
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
struct json_sax
|
struct json_sax
|
||||||
{
|
{
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/number_integer_t/
|
|
||||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/number_unsigned_t/
|
|
||||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/number_float_t/
|
|
||||||
using number_float_t = typename BasicJsonType::number_float_t;
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/string_t/
|
|
||||||
using string_t = typename BasicJsonType::string_t;
|
using string_t = typename BasicJsonType::string_t;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/binary_t/
|
|
||||||
using binary_t = typename BasicJsonType::binary_t;
|
using binary_t = typename BasicJsonType::binary_t;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief a null value was read
|
@brief a null value was read
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/null/
|
|
||||||
*/
|
*/
|
||||||
virtual bool null() = 0;
|
virtual bool null() = 0;
|
||||||
|
|
||||||
@@ -55,7 +49,6 @@ struct json_sax
|
|||||||
@brief a boolean value was read
|
@brief a boolean value was read
|
||||||
@param[in] val boolean value
|
@param[in] val boolean value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/boolean/
|
|
||||||
*/
|
*/
|
||||||
virtual bool boolean(bool val) = 0;
|
virtual bool boolean(bool val) = 0;
|
||||||
|
|
||||||
@@ -63,7 +56,6 @@ struct json_sax
|
|||||||
@brief an integer number was read
|
@brief an integer number was read
|
||||||
@param[in] val integer value
|
@param[in] val integer value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/number_integer/
|
|
||||||
*/
|
*/
|
||||||
virtual bool number_integer(number_integer_t val) = 0;
|
virtual bool number_integer(number_integer_t val) = 0;
|
||||||
|
|
||||||
@@ -71,7 +63,6 @@ struct json_sax
|
|||||||
@brief an unsigned integer number was read
|
@brief an unsigned integer number was read
|
||||||
@param[in] val unsigned integer value
|
@param[in] val unsigned integer value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/number_unsigned/
|
|
||||||
*/
|
*/
|
||||||
virtual bool number_unsigned(number_unsigned_t val) = 0;
|
virtual bool number_unsigned(number_unsigned_t val) = 0;
|
||||||
|
|
||||||
@@ -80,7 +71,6 @@ struct json_sax
|
|||||||
@param[in] val floating-point value
|
@param[in] val floating-point value
|
||||||
@param[in] s raw token value
|
@param[in] s raw token value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/number_float/
|
|
||||||
*/
|
*/
|
||||||
virtual bool number_float(number_float_t val, const string_t& s) = 0;
|
virtual bool number_float(number_float_t val, const string_t& s) = 0;
|
||||||
|
|
||||||
@@ -89,7 +79,6 @@ struct json_sax
|
|||||||
@param[in] val string value
|
@param[in] val string value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note It is safe to move the passed string value.
|
@note It is safe to move the passed string value.
|
||||||
@sa https://json.nlohmann.me/api/json_sax/string/
|
|
||||||
*/
|
*/
|
||||||
virtual bool string(string_t& val) = 0;
|
virtual bool string(string_t& val) = 0;
|
||||||
|
|
||||||
@@ -98,7 +87,6 @@ struct json_sax
|
|||||||
@param[in] val binary value
|
@param[in] val binary value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note It is safe to move the passed binary value.
|
@note It is safe to move the passed binary value.
|
||||||
@sa https://json.nlohmann.me/api/json_sax/binary/
|
|
||||||
*/
|
*/
|
||||||
virtual bool binary(binary_t& val) = 0;
|
virtual bool binary(binary_t& val) = 0;
|
||||||
|
|
||||||
@@ -107,7 +95,6 @@ struct json_sax
|
|||||||
@param[in] elements number of object elements or -1 if unknown
|
@param[in] elements number of object elements or -1 if unknown
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note binary formats may report the number of elements
|
@note binary formats may report the number of elements
|
||||||
@sa https://json.nlohmann.me/api/json_sax/start_object/
|
|
||||||
*/
|
*/
|
||||||
virtual bool start_object(std::size_t elements) = 0;
|
virtual bool start_object(std::size_t elements) = 0;
|
||||||
|
|
||||||
@@ -116,14 +103,12 @@ struct json_sax
|
|||||||
@param[in] val object key
|
@param[in] val object key
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note It is safe to move the passed string.
|
@note It is safe to move the passed string.
|
||||||
@sa https://json.nlohmann.me/api/json_sax/key/
|
|
||||||
*/
|
*/
|
||||||
virtual bool key(string_t& val) = 0;
|
virtual bool key(string_t& val) = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief the end of an object was read
|
@brief the end of an object was read
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/end_object/
|
|
||||||
*/
|
*/
|
||||||
virtual bool end_object() = 0;
|
virtual bool end_object() = 0;
|
||||||
|
|
||||||
@@ -132,14 +117,12 @@ struct json_sax
|
|||||||
@param[in] elements number of array elements or -1 if unknown
|
@param[in] elements number of array elements or -1 if unknown
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note binary formats may report the number of elements
|
@note binary formats may report the number of elements
|
||||||
@sa https://json.nlohmann.me/api/json_sax/start_array/
|
|
||||||
*/
|
*/
|
||||||
virtual bool start_array(std::size_t elements) = 0;
|
virtual bool start_array(std::size_t elements) = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief the end of an array was read
|
@brief the end of an array was read
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/end_array/
|
|
||||||
*/
|
*/
|
||||||
virtual bool end_array() = 0;
|
virtual bool end_array() = 0;
|
||||||
|
|
||||||
@@ -149,23 +132,16 @@ struct json_sax
|
|||||||
@param[in] last_token the last read token
|
@param[in] last_token the last read token
|
||||||
@param[in] ex an exception object describing the error
|
@param[in] ex an exception object describing the error
|
||||||
@return whether parsing should proceed (must return false)
|
@return whether parsing should proceed (must return false)
|
||||||
@sa https://json.nlohmann.me/api/json_sax/parse_error/
|
|
||||||
*/
|
*/
|
||||||
virtual bool parse_error(std::size_t position,
|
virtual bool parse_error(std::size_t position,
|
||||||
const std::string& last_token,
|
const std::string& last_token,
|
||||||
const detail::exception& ex) = 0;
|
const detail::exception& ex) = 0;
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
|
|
||||||
json_sax() = default;
|
json_sax() = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
|
|
||||||
json_sax(const json_sax&) = default;
|
json_sax(const json_sax&) = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
|
|
||||||
json_sax(json_sax&&) noexcept = default;
|
json_sax(json_sax&&) noexcept = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/operator=/
|
|
||||||
json_sax& operator=(const json_sax&) = default;
|
json_sax& operator=(const json_sax&) = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/operator=/
|
|
||||||
json_sax& operator=(json_sax&&) noexcept = default;
|
json_sax& operator=(json_sax&&) noexcept = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/~json_sax/
|
|
||||||
virtual ~json_sax() = default;
|
virtual ~json_sax() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <clocale> // localeconv
|
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdio> // snprintf
|
#include <cstdio> // snprintf
|
||||||
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
|
|
||||||
#include <initializer_list> // initializer_list
|
#include <initializer_list> // initializer_list
|
||||||
#include <string> // char_traits, string
|
#include <string> // char_traits, string
|
||||||
#include <utility> // move
|
#include <utility> // move
|
||||||
@@ -217,18 +215,6 @@ class lexer : public lexer_base<BasicJsonType>
|
|||||||
~lexer() = default;
|
~lexer() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/////////////////////
|
|
||||||
// locales
|
|
||||||
/////////////////////
|
|
||||||
|
|
||||||
/// return the decimal point of the current locale
|
|
||||||
static char get_decimal_point() noexcept
|
|
||||||
{
|
|
||||||
const auto* loc = localeconv();
|
|
||||||
JSON_ASSERT(loc != nullptr);
|
|
||||||
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// scan functions
|
// scan functions
|
||||||
/////////////////////
|
/////////////////////
|
||||||
@@ -1036,24 +1022,6 @@ 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
|
@brief scan a number literal
|
||||||
|
|
||||||
@@ -1093,7 +1061,7 @@ class lexer : public lexer_base<BasicJsonType>
|
|||||||
@note The scanner is independent of the current locale: token_buffer
|
@note The scanner is independent of the current locale: token_buffer
|
||||||
always holds `.`. Only the std::strtod fallback of convert_number()
|
always holds `.`. Only the std::strtod fallback of convert_number()
|
||||||
depends on the locale, and it looks up the decimal point right
|
depends on the locale, and it looks up the decimal point right
|
||||||
before converting (see convert_float_locale_aware()).
|
before converting (see detail::convert_float_locale_aware()).
|
||||||
*/
|
*/
|
||||||
token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated.
|
token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated.
|
||||||
{
|
{
|
||||||
@@ -1424,59 +1392,6 @@ scan_number_done:
|
|||||||
return token_type::uninitialized;
|
return token_type::uninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief check whether Clinger's fast path can still succeed for this token
|
|
||||||
|
|
||||||
parse_float_fast() needs a significand below 2^53. A mantissa with 17 or
|
|
||||||
more significant digits is at least 10^16 and therefore always exceeds it,
|
|
||||||
so calling the fast path would walk the token one extra time only to
|
|
||||||
decline before strtod has to run anyway.
|
|
||||||
|
|
||||||
Significant digits are the mantissa's digits from the first nonzero one on;
|
|
||||||
the sign, the decimal point, leading zeros, and the exponent do not count.
|
|
||||||
The answer is derived from indices - the digits are not scanned again - so
|
|
||||||
this stays off the hot path of the number scanners.
|
|
||||||
|
|
||||||
@param[in] mantissa_end offset just past the last mantissa byte in
|
|
||||||
token_buffer
|
|
||||||
@return false if parse_float_fast() is guaranteed to decline
|
|
||||||
*/
|
|
||||||
bool mantissa_fits_clinger(std::size_t mantissa_end) const
|
|
||||||
{
|
|
||||||
// 10^16 already exceeds 2^53, so 17 digits can never fit
|
|
||||||
constexpr std::size_t limit = 17;
|
|
||||||
|
|
||||||
const std::size_t neg = (!token_buffer.empty() && token_buffer[0] == '-') ? 1u : 0u;
|
|
||||||
const std::size_t has_dot = (decimal_point_position != std::string::npos) ? 1u : 0u;
|
|
||||||
// the JSON grammar restricts the integer part to "0" or [1-9][0-9]*, so
|
|
||||||
// a leading zero can only be a lone "0", which is not significant
|
|
||||||
const std::size_t lead_zero = (token_buffer[neg] == '0') ? 1u : 0u;
|
|
||||||
JSON_ASSERT(mantissa_end >= neg + has_dot + lead_zero);
|
|
||||||
std::size_t digits = mantissa_end - neg - has_dot - lead_zero;
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_LIKELY(digits < limit))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only a number below 1 can carry further insignificant zeros, and only
|
|
||||||
// while the count stays at the limit does removing them change the
|
|
||||||
// answer - so this loop is skipped for all but a few tokens. The
|
|
||||||
// fraction is located through decimal_point_position rather than by
|
|
||||||
// searching '.'.
|
|
||||||
if (lead_zero != 0)
|
|
||||||
{
|
|
||||||
JSON_ASSERT(has_dot != 0); // an integer "0" cannot reach the limit
|
|
||||||
for (std::size_t i = decimal_point_position + 1;
|
|
||||||
digits >= limit && i < mantissa_end && token_buffer[i] == '0'; ++i)
|
|
||||||
{
|
|
||||||
--digits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return digits < limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief convert the number text in token_buffer to its value and token type
|
@brief convert the number text in token_buffer to its value and token type
|
||||||
|
|
||||||
@@ -1490,7 +1405,7 @@ scan_number_done:
|
|||||||
token_buffer (the index of 'e'/'E', or
|
token_buffer (the index of 'e'/'E', or
|
||||||
token_buffer.size() when there is no exponent);
|
token_buffer.size() when there is no exponent);
|
||||||
used to skip Clinger's fast path when it cannot
|
used to skip Clinger's fast path when it cannot
|
||||||
possibly succeed - see mantissa_fits_clinger()
|
possibly succeed - see detail::mantissa_fits_clinger()
|
||||||
*/
|
*/
|
||||||
token_type convert_number(token_type number_type, std::size_t mantissa_end)
|
token_type convert_number(token_type number_type, std::size_t mantissa_end)
|
||||||
{
|
{
|
||||||
@@ -1563,77 +1478,15 @@ scan_number_done:
|
|||||||
// (Eisel-Lemire, locale-independent, correctly rounded) when available;
|
// (Eisel-Lemire, locale-independent, correctly rounded) when available;
|
||||||
// otherwise the exact Clinger fast path (double only); otherwise the
|
// otherwise the exact Clinger fast path (double only); otherwise the
|
||||||
// locale-aware strtof/strtod/strtold.
|
// locale-aware strtof/strtod/strtold.
|
||||||
if (parse_float_from_chars(num_begin, num_end, value_float))
|
if (convert_float_fast(num_begin, num_end, decimal_point_position, mantissa_end, value_float))
|
||||||
{
|
|
||||||
return token_type::value_float;
|
|
||||||
}
|
|
||||||
// Skipping a fast path that cannot succeed is lossless and saves a full
|
|
||||||
// extra pass over the token's bytes, which otherwise shows up on
|
|
||||||
// high-precision inputs such as canada.json
|
|
||||||
if (mantissa_fits_clinger(mantissa_end)
|
|
||||||
&& parse_float_fast(num_begin, num_end, value_float))
|
|
||||||
{
|
{
|
||||||
return token_type::value_float;
|
return token_type::value_float;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_float_locale_aware();
|
convert_float_locale_aware(token_buffer, decimal_point_position, value_float);
|
||||||
return token_type::value_float;
|
return token_type::value_float;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief convert the float in token_buffer with strtof/strtod/strtold
|
|
||||||
|
|
||||||
These functions expect the decimal point of the *current* locale, so it is
|
|
||||||
looked up right before the conversion instead of once when the lexer is
|
|
||||||
constructed: a locale change in between (by a parser callback, a SAX
|
|
||||||
handler, or another thread) must not truncate the value (#5198). The
|
|
||||||
token has been validated before, so if the conversion stops early and the
|
|
||||||
decimal point changed in the meantime, the locale changed between the
|
|
||||||
lookup and the call, and the conversion is repeated with the new decimal
|
|
||||||
point. If the decimal point did not change, a retry cannot succeed: the
|
|
||||||
locale's decimal point is not a single character (e.g., the two-byte
|
|
||||||
U+066B of ar_EG.UTF-8 or fa_IR.UTF-8) and cannot be substituted in place.
|
|
||||||
The value strtod parsed up to that point is kept, as before this change.
|
|
||||||
|
|
||||||
Note that changing the locale in another thread *while* strtod runs is
|
|
||||||
undefined behavior of the C library, which this function cannot prevent.
|
|
||||||
*/
|
|
||||||
void convert_float_locale_aware()
|
|
||||||
{
|
|
||||||
const bool has_dot = decimal_point_position != std::string::npos;
|
|
||||||
char decimal_point = get_decimal_point();
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
const bool substitute = has_dot && decimal_point != '.';
|
|
||||||
if (substitute)
|
|
||||||
{
|
|
||||||
token_buffer[decimal_point_position] = static_cast<typename string_t::value_type>(decimal_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
|
||||||
strtof(value_float, token_buffer.data(), &endptr);
|
|
||||||
|
|
||||||
if (substitute)
|
|
||||||
{
|
|
||||||
// get_string() hands the token to the SAX interface with '.'
|
|
||||||
token_buffer[decimal_point_position] = '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_LIKELY(endptr == token_buffer.data() + token_buffer.size()))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// retry only if the locale changed; otherwise, this would loop forever
|
|
||||||
const char current_decimal_point = get_decimal_point();
|
|
||||||
if (current_decimal_point == decimal_point)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
decimal_point = current_decimal_point;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief contiguous fast path for scanning a number
|
@brief contiguous fast path for scanning a number
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,12 @@
|
|||||||
|
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <cfloat> // FLT_EVAL_METHOD
|
#include <cfloat> // FLT_EVAL_METHOD
|
||||||
|
#include <clocale> // localeconv
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdint> // int64_t, uint64_t
|
#include <cstdint> // int64_t, uint64_t
|
||||||
|
#include <cstdlib> // strtof, strtod, strtold
|
||||||
#include <limits> // numeric_limits
|
#include <limits> // numeric_limits
|
||||||
|
#include <string> // string
|
||||||
|
|
||||||
#include <nlohmann/detail/macro_scope.hpp>
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
@@ -29,8 +32,9 @@
|
|||||||
|
|
||||||
// This file contains the value-conversion helpers used by the lexer to turn an
|
// This file contains the value-conversion helpers used by the lexer to turn an
|
||||||
// already-validated number token into a value, without the locale/errno
|
// already-validated number token into a value, without the locale/errno
|
||||||
// overhead of std::strtoull/std::strtod. They are free functions so the lexer
|
// overhead of std::strtoull/std::strtod where possible. They are free functions
|
||||||
// stays focused on scanning; see lexer::convert_number().
|
// so the lexer stays focused on scanning (see lexer::convert_number()) and so
|
||||||
|
// that other parsers of JSON text can convert tokens exactly like it does.
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
namespace detail
|
namespace detail
|
||||||
@@ -293,5 +297,183 @@ bool parse_float_from_chars(const char* first, const char* last, FloatType& out)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief check whether Clinger's fast path can still succeed for a float token
|
||||||
|
|
||||||
|
parse_float_fast() needs a significand below 2^53. A mantissa with 17 or
|
||||||
|
more significant digits is at least 10^16 and therefore always exceeds it,
|
||||||
|
so calling the fast path would walk the token one extra time only to
|
||||||
|
decline before strtod has to run anyway.
|
||||||
|
|
||||||
|
Significant digits are the mantissa's digits from the first nonzero one on;
|
||||||
|
the sign, the decimal point, leading zeros, and the exponent do not count.
|
||||||
|
The answer is derived from indices - the digits are not scanned again - so
|
||||||
|
this stays off the hot path of the number scanners.
|
||||||
|
|
||||||
|
@param[in] token the validated number token ('.' as decimal point)
|
||||||
|
@param[in] decimal_point_position index of the '.' in @a token, or
|
||||||
|
std::string::npos if there is none
|
||||||
|
@param[in] mantissa_end offset just past the last mantissa byte
|
||||||
|
@return false if parse_float_fast() is guaranteed to decline
|
||||||
|
*/
|
||||||
|
inline bool mantissa_fits_clinger(const char* token, std::size_t decimal_point_position, std::size_t mantissa_end) noexcept
|
||||||
|
{
|
||||||
|
// 10^16 already exceeds 2^53, so 17 digits can never fit
|
||||||
|
constexpr std::size_t limit = 17;
|
||||||
|
|
||||||
|
const std::size_t neg = (token[0] == '-') ? 1u : 0u;
|
||||||
|
const std::size_t has_dot = (decimal_point_position != std::string::npos) ? 1u : 0u;
|
||||||
|
// the JSON grammar restricts the integer part to "0" or [1-9][0-9]*, so
|
||||||
|
// a leading zero can only be a lone "0", which is not significant
|
||||||
|
const std::size_t lead_zero = (token[neg] == '0') ? 1u : 0u;
|
||||||
|
JSON_ASSERT(mantissa_end >= neg + has_dot + lead_zero);
|
||||||
|
std::size_t digits = mantissa_end - neg - has_dot - lead_zero;
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_LIKELY(digits < limit))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only a number below 1 can carry further insignificant zeros, and only
|
||||||
|
// while the count stays at the limit does removing them change the
|
||||||
|
// answer - so this loop is skipped for all but a few tokens. The
|
||||||
|
// fraction is located through decimal_point_position rather than by
|
||||||
|
// searching '.'.
|
||||||
|
if (lead_zero != 0)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(has_dot != 0); // an integer "0" cannot reach the limit
|
||||||
|
for (std::size_t i = decimal_point_position + 1;
|
||||||
|
digits >= limit && i < mantissa_end && token[i] == '0'; ++i)
|
||||||
|
{
|
||||||
|
--digits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return digits < limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief convert a validated float token without the C library, if possible
|
||||||
|
|
||||||
|
Tries std::from_chars (when available) and then Clinger's exact fast path
|
||||||
|
(double only), skipping the latter when it cannot succeed.
|
||||||
|
|
||||||
|
@param[in] first pointer to the first character of the token
|
||||||
|
@param[in] last pointer past the last character
|
||||||
|
@param[in] decimal_point_position index of the '.' in the token, or
|
||||||
|
std::string::npos if there is none
|
||||||
|
@param[in] mantissa_end offset just past the last mantissa byte (the
|
||||||
|
index of 'e'/'E', or the token length)
|
||||||
|
@param[out] value the converted value on success
|
||||||
|
@return true if the value was converted; false if convert_float_locale_aware()
|
||||||
|
must convert it
|
||||||
|
*/
|
||||||
|
template<typename FloatType>
|
||||||
|
bool convert_float_fast(const char* first, const char* last, std::size_t decimal_point_position,
|
||||||
|
std::size_t mantissa_end, FloatType& value) noexcept
|
||||||
|
{
|
||||||
|
if (parse_float_from_chars(first, last, value))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Skipping a fast path that cannot succeed is lossless and saves a full
|
||||||
|
// extra pass over the token's bytes, which otherwise shows up on
|
||||||
|
// high-precision inputs such as canada.json
|
||||||
|
return mantissa_fits_clinger(first, decimal_point_position, mantissa_end)
|
||||||
|
&& parse_float_fast(first, last, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
inline void strtof_by_type(float& f, const char* str, char** endptr) noexcept
|
||||||
|
{
|
||||||
|
f = std::strtof(str, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
inline void strtof_by_type(double& f, const char* str, char** endptr) noexcept
|
||||||
|
{
|
||||||
|
f = std::strtod(str, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
inline void strtof_by_type(long double& f, const char* str, char** endptr) noexcept
|
||||||
|
{
|
||||||
|
f = std::strtold(str, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the decimal point of the current locale
|
||||||
|
inline char get_decimal_point() noexcept
|
||||||
|
{
|
||||||
|
const auto* loc = localeconv();
|
||||||
|
JSON_ASSERT(loc != nullptr);
|
||||||
|
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief convert a validated float token with strtof/strtod/strtold
|
||||||
|
|
||||||
|
These functions expect the decimal point of the *current* locale, so it is
|
||||||
|
looked up right before the conversion instead of once when the lexer is
|
||||||
|
constructed: a locale change in between (by a parser callback, a SAX
|
||||||
|
handler, or another thread) must not truncate the value (#5198). The
|
||||||
|
token has been validated before, so if the conversion stops early and the
|
||||||
|
decimal point changed in the meantime, the locale changed between the
|
||||||
|
lookup and the call, and the conversion is repeated with the new decimal
|
||||||
|
point. If the decimal point did not change, a retry cannot succeed: the
|
||||||
|
locale's decimal point is not a single character (e.g., the two-byte
|
||||||
|
U+066B of ar_EG.UTF-8 or fa_IR.UTF-8) and cannot be substituted in place.
|
||||||
|
The value strtod parsed up to that point is kept, as before this change.
|
||||||
|
|
||||||
|
Note that changing the locale in another thread *while* strtod runs is
|
||||||
|
undefined behavior of the C library, which this function cannot prevent.
|
||||||
|
|
||||||
|
@param[in,out] token the token with '.' as decimal point; its
|
||||||
|
decimal point is replaced during the
|
||||||
|
conversion and restored afterwards
|
||||||
|
(data() must be NUL-terminated)
|
||||||
|
@param[in] decimal_point_position index of the '.' in @a token, or
|
||||||
|
std::string::npos if there is none
|
||||||
|
@param[out] value the converted value
|
||||||
|
*/
|
||||||
|
template<typename StringType, typename FloatType>
|
||||||
|
void convert_float_locale_aware(StringType& token, std::size_t decimal_point_position, FloatType& value)
|
||||||
|
{
|
||||||
|
const bool has_dot = decimal_point_position != std::string::npos;
|
||||||
|
char decimal_point = get_decimal_point();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const bool substitute = has_dot && decimal_point != '.';
|
||||||
|
if (substitute)
|
||||||
|
{
|
||||||
|
token[decimal_point_position] = static_cast<typename StringType::value_type>(decimal_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
strtof_by_type(value, token.data(), &endptr);
|
||||||
|
|
||||||
|
if (substitute)
|
||||||
|
{
|
||||||
|
// the caller hands the token on (e.g. to the SAX interface) with '.'
|
||||||
|
token[decimal_point_position] = '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_LIKELY(endptr == token.data() + token.size()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// retry only if the locale changed; otherwise, this would loop forever
|
||||||
|
const char current_decimal_point = get_decimal_point();
|
||||||
|
if (current_decimal_point == decimal_point)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
decimal_point = current_decimal_point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ class json_pointer
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// for backwards compatibility accept BasicJsonType
|
// for backwards compatibility accept BasicJsonType
|
||||||
/// @sa https://json.nlohmann.me/api/json_pointer/string_t/
|
|
||||||
using string_t = typename string_t_helper<RefStringType>::type;
|
using string_t = typename string_t_helper<RefStringType>::type;
|
||||||
|
|
||||||
/// @brief create JSON pointer
|
/// @brief create JSON pointer
|
||||||
|
|||||||
@@ -202,31 +202,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
using serializer = ::nlohmann::detail::serializer<basic_json>;
|
using serializer = ::nlohmann::detail::serializer<basic_json>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief the type of the JSON value
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/value_t/
|
|
||||||
using value_t = detail::value_t;
|
using value_t = detail::value_t;
|
||||||
/// JSON Pointer, see @ref nlohmann::json_pointer
|
/// JSON Pointer, see @ref nlohmann::json_pointer
|
||||||
using json_pointer = ::nlohmann::json_pointer<StringType>;
|
using json_pointer = ::nlohmann::json_pointer<StringType>;
|
||||||
template<typename T, typename SFINAE>
|
template<typename T, typename SFINAE>
|
||||||
using json_serializer = JSONSerializer<T, SFINAE>;
|
using json_serializer = JSONSerializer<T, SFINAE>;
|
||||||
/// how to treat decoding errors
|
/// how to treat decoding errors
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/error_handler_t/
|
|
||||||
using error_handler_t = detail::error_handler_t;
|
using error_handler_t = detail::error_handler_t;
|
||||||
/// how to treat CBOR tags
|
/// how to treat CBOR tags
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/cbor_tag_handler_t/
|
|
||||||
using cbor_tag_handler_t = detail::cbor_tag_handler_t;
|
using cbor_tag_handler_t = detail::cbor_tag_handler_t;
|
||||||
/// how to encode BJData
|
/// how to encode BJData
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/bjdata_version_t/
|
|
||||||
using bjdata_version_t = detail::bjdata_version_t;
|
using bjdata_version_t = detail::bjdata_version_t;
|
||||||
/// helper type for initializer lists of basic_json values
|
/// helper type for initializer lists of basic_json values
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/initializer_list_t/
|
|
||||||
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
|
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
|
||||||
|
|
||||||
/// @brief the type of the SAX interface used to parse and serialize the JSON value
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/input_format_t/
|
|
||||||
using input_format_t = detail::input_format_t;
|
using input_format_t = detail::input_format_t;
|
||||||
/// SAX interface type, see @ref nlohmann::json_sax
|
/// SAX interface type, see @ref nlohmann::json_sax
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/json_sax_t/
|
|
||||||
using json_sax_t = json_sax<basic_json>;
|
using json_sax_t = json_sax<basic_json>;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
@@ -368,19 +359,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// the template arguments passed to class @ref basic_json.
|
/// the template arguments passed to class @ref basic_json.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
#if defined(JSON_HAS_CPP_14)
|
|
||||||
/// @brief default object key comparator type
|
/// @brief default object key comparator type
|
||||||
/// The actual object key comparator type (@ref object_comparator_t) may be
|
/// The actual object key comparator type (@ref object_comparator_t) may be
|
||||||
/// different.
|
/// different.
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
|
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
|
||||||
|
#if defined(JSON_HAS_CPP_14)
|
||||||
// use of transparent comparator avoids unnecessary repeated construction of temporaries
|
// use of transparent comparator avoids unnecessary repeated construction of temporaries
|
||||||
// in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
|
// in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
|
||||||
using default_object_comparator_t = std::less<>;
|
using default_object_comparator_t = std::less<>;
|
||||||
#else
|
#else
|
||||||
/// @brief default object key comparator type
|
|
||||||
/// The actual object key comparator type (@ref object_comparator_t) may be
|
|
||||||
/// different.
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
|
|
||||||
using default_object_comparator_t = std::less<StringType>;
|
using default_object_comparator_t = std::less<StringType>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1926,7 +1913,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// other constructors and destructor //
|
// other constructors and destructor //
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
|
||||||
template<typename JsonRef,
|
template<typename JsonRef,
|
||||||
detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
|
detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
|
||||||
std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
|
std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
|
||||||
@@ -2510,8 +2496,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
@throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
|
@throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
|
||||||
|
|
||||||
@since version 2.1.0
|
@since version 2.1.0
|
||||||
|
|
||||||
@sa https://json.nlohmann.me/api/basic_json/get/
|
|
||||||
*/
|
*/
|
||||||
template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
|
template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
|
||||||
#if defined(JSON_HAS_CPP_14)
|
#if defined(JSON_HAS_CPP_14)
|
||||||
@@ -2555,8 +2539,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
@sa see @ref get_ptr() for explicit pointer-member access
|
@sa see @ref get_ptr() for explicit pointer-member access
|
||||||
|
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
|
|
||||||
@sa https://json.nlohmann.me/api/basic_json/get/
|
|
||||||
*/
|
*/
|
||||||
template<typename PointerType, typename std::enable_if<
|
template<typename PointerType, typename std::enable_if<
|
||||||
std::is_pointer<PointerType>::value, int>::type = 0>
|
std::is_pointer<PointerType>::value, int>::type = 0>
|
||||||
@@ -2583,7 +2565,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
// specialization to allow calling get_to with a basic_json value
|
// specialization to allow calling get_to with a basic_json value
|
||||||
// see https://github.com/nlohmann/json/issues/2175
|
// see https://github.com/nlohmann/json/issues/2175
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/get_to/
|
|
||||||
template<typename ValueType,
|
template<typename ValueType,
|
||||||
detail::enable_if_t <
|
detail::enable_if_t <
|
||||||
detail::is_basic_json<ValueType>::value,
|
detail::is_basic_json<ValueType>::value,
|
||||||
@@ -2594,7 +2575,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/get_to/
|
|
||||||
template <
|
template <
|
||||||
typename T, std::size_t N,
|
typename T, std::size_t N,
|
||||||
typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||||
@@ -2659,7 +2639,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ValueType/
|
|
||||||
template < typename ValueType, typename std::enable_if <
|
template < typename ValueType, typename std::enable_if <
|
||||||
detail::conjunction <
|
detail::conjunction <
|
||||||
detail::negation<std::is_pointer<ValueType>>,
|
detail::negation<std::is_pointer<ValueType>>,
|
||||||
@@ -2932,14 +2911,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
||||||
// (they seemingly cannot be constrained to resolve the ambiguity)
|
// (they seemingly cannot be constrained to resolve the ambiguity)
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator[]/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
reference operator[](T* key)
|
reference operator[](T* key)
|
||||||
{
|
{
|
||||||
return operator[](typename object_t::key_type(key));
|
return operator[](typename object_t::key_type(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator[]/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const_reference operator[](T* key) const
|
const_reference operator[](T* key) const
|
||||||
{
|
{
|
||||||
@@ -3149,7 +3126,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/value/
|
|
||||||
template < class ValueType, class BasicJsonType, detail::enable_if_t <
|
template < class ValueType, class BasicJsonType, detail::enable_if_t <
|
||||||
detail::is_basic_json<BasicJsonType>::value
|
detail::is_basic_json<BasicJsonType>::value
|
||||||
&& detail::is_getable<basic_json_t, ValueType>::value
|
&& detail::is_getable<basic_json_t, ValueType>::value
|
||||||
@@ -3160,7 +3136,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return value(ptr.convert(), default_value);
|
return value(ptr.convert(), default_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/value/
|
|
||||||
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
|
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
|
||||||
detail::enable_if_t <
|
detail::enable_if_t <
|
||||||
detail::is_basic_json<BasicJsonType>::value
|
detail::is_basic_json<BasicJsonType>::value
|
||||||
@@ -3540,7 +3515,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.contains(this);
|
return ptr.contains(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/contains/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
@@ -4960,7 +4934,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/parse/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
|
||||||
static basic_json parse(detail::span_input_adapter&& i,
|
static basic_json parse(detail::span_input_adapter&& i,
|
||||||
@@ -4997,7 +4970,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||||
static bool accept(detail::span_input_adapter&& i,
|
static bool accept(detail::span_input_adapter&& i,
|
||||||
@@ -5381,7 +5353,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||||
@@ -5393,7 +5364,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
|
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||||
static basic_json from_cbor(detail::span_input_adapter&& i,
|
static basic_json from_cbor(detail::span_input_adapter&& i,
|
||||||
@@ -5449,7 +5419,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||||
@@ -5460,7 +5429,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
|
return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||||
static basic_json from_msgpack(detail::span_input_adapter&& i,
|
static basic_json from_msgpack(detail::span_input_adapter&& i,
|
||||||
@@ -5515,7 +5483,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||||
@@ -5526,7 +5493,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
|
return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||||
static basic_json from_ubjson(detail::span_input_adapter&& i,
|
static basic_json from_ubjson(detail::span_input_adapter&& i,
|
||||||
@@ -5655,7 +5621,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||||
@@ -5666,7 +5631,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return from_bson(ptr, ptr + len, strict, allow_exceptions);
|
return from_bson(ptr, ptr + len, strict, allow_exceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||||
static basic_json from_bson(detail::span_input_adapter&& i,
|
static basic_json from_bson(detail::span_input_adapter&& i,
|
||||||
@@ -5699,7 +5663,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.get_unchecked(this);
|
return ptr.get_unchecked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
||||||
@@ -5714,7 +5677,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.get_unchecked(this);
|
return ptr.get_unchecked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||||
@@ -5729,7 +5691,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.get_checked(this);
|
return ptr.get_checked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/at/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
||||||
@@ -5744,7 +5705,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.get_checked(this);
|
return ptr.get_checked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/at/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||||
|
|||||||
@@ -30,41 +30,30 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
{
|
{
|
||||||
using key_type = Key;
|
using key_type = Key;
|
||||||
using mapped_type = T;
|
using mapped_type = T;
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/Container/
|
|
||||||
using Container = std::vector<std::pair<const Key, T>, Allocator>;
|
using Container = std::vector<std::pair<const Key, T>, Allocator>;
|
||||||
using iterator = typename Container::iterator;
|
using iterator = typename Container::iterator;
|
||||||
using const_iterator = typename Container::const_iterator;
|
using const_iterator = typename Container::const_iterator;
|
||||||
using size_type = typename Container::size_type;
|
using size_type = typename Container::size_type;
|
||||||
using value_type = typename Container::value_type;
|
using value_type = typename Container::value_type;
|
||||||
#ifdef JSON_HAS_CPP_14
|
#ifdef JSON_HAS_CPP_14
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/key_compare/
|
|
||||||
using key_compare = std::equal_to<>;
|
using key_compare = std::equal_to<>;
|
||||||
#else
|
#else
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/key_compare/
|
|
||||||
using key_compare = std::equal_to<Key>;
|
using key_compare = std::equal_to<Key>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Explicit constructors instead of `using Container::Container`
|
// Explicit constructors instead of `using Container::Container`
|
||||||
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
|
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
ordered_map() noexcept(noexcept(Container())) : Container{} {}
|
ordered_map() noexcept(noexcept(Container())) : Container{} {}
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
|
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
template <class It>
|
template <class It>
|
||||||
ordered_map(It first, It last, const Allocator& alloc = Allocator())
|
ordered_map(It first, It last, const Allocator& alloc = Allocator())
|
||||||
: Container{first, last, alloc} {}
|
: Container{first, last, alloc} {}
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
|
ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
|
||||||
: Container{init, alloc} {}
|
: Container{init, alloc} {}
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
ordered_map(const ordered_map&) = default;
|
ordered_map(const ordered_map&) = default;
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
ordered_map(ordered_map&&) noexcept(std::is_nothrow_move_constructible<Container>::value) = default;
|
ordered_map(ordered_map&&) noexcept(std::is_nothrow_move_constructible<Container>::value) = default;
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/~ordered_map/
|
|
||||||
~ordered_map() = default;
|
~ordered_map() = default;
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator=/
|
|
||||||
ordered_map& operator=(const ordered_map& other)
|
ordered_map& operator=(const ordered_map& other)
|
||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other)
|
||||||
@@ -75,14 +64,12 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator=/
|
|
||||||
ordered_map& operator=(ordered_map&& other) noexcept(std::is_nothrow_move_assignable<Container>::value)
|
ordered_map& operator=(ordered_map&& other) noexcept(std::is_nothrow_move_assignable<Container>::value)
|
||||||
{
|
{
|
||||||
Container::operator=(std::move(static_cast<Container&>(other)));
|
Container::operator=(std::move(static_cast<Container&>(other)));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/emplace/
|
|
||||||
std::pair<iterator, bool> emplace(const key_type& key, T&& t)
|
std::pair<iterator, bool> emplace(const key_type& key, T&& t)
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -96,7 +83,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return {std::prev(this->end()), true};
|
return {std::prev(this->end()), true};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/emplace/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
std::pair<iterator, bool> emplace(KeyType && key, T && t)
|
std::pair<iterator, bool> emplace(KeyType && key, T && t)
|
||||||
@@ -112,13 +98,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return {std::prev(this->end()), true};
|
return {std::prev(this->end()), true};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator[]/
|
|
||||||
T& operator[](const key_type& key)
|
T& operator[](const key_type& key)
|
||||||
{
|
{
|
||||||
return emplace(key, T{}).first->second;
|
return emplace(key, T{}).first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator[]/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
T & operator[](KeyType && key)
|
T & operator[](KeyType && key)
|
||||||
@@ -126,13 +110,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return emplace(std::forward<KeyType>(key), T{}).first->second;
|
return emplace(std::forward<KeyType>(key), T{}).first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator[]/
|
|
||||||
const T& operator[](const key_type& key) const
|
const T& operator[](const key_type& key) const
|
||||||
{
|
{
|
||||||
return at(key);
|
return at(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator[]/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
const T & operator[](KeyType && key) const
|
const T & operator[](KeyType && key) const
|
||||||
@@ -140,7 +122,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return at(std::forward<KeyType>(key));
|
return at(std::forward<KeyType>(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/at/
|
|
||||||
T& at(const key_type& key)
|
T& at(const key_type& key)
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -154,7 +135,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
JSON_THROW(std::out_of_range("key not found"));
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/at/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -170,7 +150,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
JSON_THROW(std::out_of_range("key not found"));
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/at/
|
|
||||||
const T& at(const key_type& key) const
|
const T& at(const key_type& key) const
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -184,7 +163,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
JSON_THROW(std::out_of_range("key not found"));
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/at/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -200,7 +178,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
JSON_THROW(std::out_of_range("key not found"));
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/erase/
|
|
||||||
size_type erase(const key_type& key)
|
size_type erase(const key_type& key)
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -220,7 +197,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/erase/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -242,13 +218,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/erase/
|
|
||||||
iterator erase(iterator pos)
|
iterator erase(iterator pos)
|
||||||
{
|
{
|
||||||
return erase(pos, std::next(pos));
|
return erase(pos, std::next(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/erase/
|
|
||||||
iterator erase(iterator first, iterator last)
|
iterator erase(iterator first, iterator last)
|
||||||
{
|
{
|
||||||
if (first == last)
|
if (first == last)
|
||||||
@@ -302,7 +276,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::begin() + offset;
|
return Container::begin() + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/count/
|
|
||||||
size_type count(const key_type& key) const
|
size_type count(const key_type& key) const
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -315,7 +288,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/count/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -330,7 +302,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/find/
|
|
||||||
iterator find(const key_type& key)
|
iterator find(const key_type& key)
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -343,7 +314,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::end();
|
return Container::end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/find/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -358,7 +328,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::end();
|
return Container::end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/find/
|
|
||||||
const_iterator find(const key_type& key) const
|
const_iterator find(const key_type& key) const
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -371,7 +340,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::end();
|
return Container::end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/find/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
const_iterator find(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
const_iterator find(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -386,13 +354,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::end();
|
return Container::end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/insert/
|
|
||||||
std::pair<iterator, bool> insert( value_type&& value )
|
std::pair<iterator, bool> insert( value_type&& value )
|
||||||
{
|
{
|
||||||
return emplace(value.first, std::move(value.second));
|
return emplace(value.first, std::move(value.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/insert/
|
|
||||||
std::pair<iterator, bool> insert( const value_type& value )
|
std::pair<iterator, bool> insert( const value_type& value )
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -410,7 +376,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
|
using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
|
||||||
std::input_iterator_tag>::value>::type;
|
std::input_iterator_tag>::value>::type;
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/insert/
|
|
||||||
template<typename InputIt, typename = require_input_iter<InputIt>>
|
template<typename InputIt, typename = require_input_iter<InputIt>>
|
||||||
void insert(InputIt first, InputIt last)
|
void insert(InputIt first, InputIt last)
|
||||||
{
|
{
|
||||||
|
|||||||
+189
-258
@@ -7154,9 +7154,7 @@ template<typename BinaryType>
|
|||||||
class byte_container_with_subtype : public BinaryType
|
class byte_container_with_subtype : public BinaryType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/container_type/
|
|
||||||
using container_type = BinaryType;
|
using container_type = BinaryType;
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype_type/
|
|
||||||
using subtype_type = std::uint64_t;
|
using subtype_type = std::uint64_t;
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
||||||
@@ -7188,14 +7186,12 @@ class byte_container_with_subtype : public BinaryType
|
|||||||
, m_has_subtype(true)
|
, m_has_subtype(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/operator_eq/
|
|
||||||
bool operator==(const byte_container_with_subtype& rhs) const
|
bool operator==(const byte_container_with_subtype& rhs) const
|
||||||
{
|
{
|
||||||
return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
|
return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
|
||||||
std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
|
std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/operator_ne/
|
|
||||||
bool operator!=(const byte_container_with_subtype& rhs) const
|
bool operator!=(const byte_container_with_subtype& rhs) const
|
||||||
{
|
{
|
||||||
return !(rhs == *this);
|
return !(rhs == *this);
|
||||||
@@ -8476,10 +8472,8 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
|
|
||||||
|
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <clocale> // localeconv
|
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdio> // snprintf
|
#include <cstdio> // snprintf
|
||||||
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
|
|
||||||
#include <initializer_list> // initializer_list
|
#include <initializer_list> // initializer_list
|
||||||
#include <string> // char_traits, string
|
#include <string> // char_traits, string
|
||||||
#include <utility> // move
|
#include <utility> // move
|
||||||
@@ -8500,9 +8494,12 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
|
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <cfloat> // FLT_EVAL_METHOD
|
#include <cfloat> // FLT_EVAL_METHOD
|
||||||
|
#include <clocale> // localeconv
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdint> // int64_t, uint64_t
|
#include <cstdint> // int64_t, uint64_t
|
||||||
|
#include <cstdlib> // strtof, strtod, strtold
|
||||||
#include <limits> // numeric_limits
|
#include <limits> // numeric_limits
|
||||||
|
#include <string> // string
|
||||||
|
|
||||||
// #include <nlohmann/detail/macro_scope.hpp>
|
// #include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
@@ -8520,8 +8517,9 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
|
|
||||||
// This file contains the value-conversion helpers used by the lexer to turn an
|
// This file contains the value-conversion helpers used by the lexer to turn an
|
||||||
// already-validated number token into a value, without the locale/errno
|
// already-validated number token into a value, without the locale/errno
|
||||||
// overhead of std::strtoull/std::strtod. They are free functions so the lexer
|
// overhead of std::strtoull/std::strtod where possible. They are free functions
|
||||||
// stays focused on scanning; see lexer::convert_number().
|
// so the lexer stays focused on scanning (see lexer::convert_number()) and so
|
||||||
|
// that other parsers of JSON text can convert tokens exactly like it does.
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
namespace detail
|
namespace detail
|
||||||
@@ -8784,6 +8782,184 @@ bool parse_float_from_chars(const char* first, const char* last, FloatType& out)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief check whether Clinger's fast path can still succeed for a float token
|
||||||
|
|
||||||
|
parse_float_fast() needs a significand below 2^53. A mantissa with 17 or
|
||||||
|
more significant digits is at least 10^16 and therefore always exceeds it,
|
||||||
|
so calling the fast path would walk the token one extra time only to
|
||||||
|
decline before strtod has to run anyway.
|
||||||
|
|
||||||
|
Significant digits are the mantissa's digits from the first nonzero one on;
|
||||||
|
the sign, the decimal point, leading zeros, and the exponent do not count.
|
||||||
|
The answer is derived from indices - the digits are not scanned again - so
|
||||||
|
this stays off the hot path of the number scanners.
|
||||||
|
|
||||||
|
@param[in] token the validated number token ('.' as decimal point)
|
||||||
|
@param[in] decimal_point_position index of the '.' in @a token, or
|
||||||
|
std::string::npos if there is none
|
||||||
|
@param[in] mantissa_end offset just past the last mantissa byte
|
||||||
|
@return false if parse_float_fast() is guaranteed to decline
|
||||||
|
*/
|
||||||
|
inline bool mantissa_fits_clinger(const char* token, std::size_t decimal_point_position, std::size_t mantissa_end) noexcept
|
||||||
|
{
|
||||||
|
// 10^16 already exceeds 2^53, so 17 digits can never fit
|
||||||
|
constexpr std::size_t limit = 17;
|
||||||
|
|
||||||
|
const std::size_t neg = (token[0] == '-') ? 1u : 0u;
|
||||||
|
const std::size_t has_dot = (decimal_point_position != std::string::npos) ? 1u : 0u;
|
||||||
|
// the JSON grammar restricts the integer part to "0" or [1-9][0-9]*, so
|
||||||
|
// a leading zero can only be a lone "0", which is not significant
|
||||||
|
const std::size_t lead_zero = (token[neg] == '0') ? 1u : 0u;
|
||||||
|
JSON_ASSERT(mantissa_end >= neg + has_dot + lead_zero);
|
||||||
|
std::size_t digits = mantissa_end - neg - has_dot - lead_zero;
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_LIKELY(digits < limit))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only a number below 1 can carry further insignificant zeros, and only
|
||||||
|
// while the count stays at the limit does removing them change the
|
||||||
|
// answer - so this loop is skipped for all but a few tokens. The
|
||||||
|
// fraction is located through decimal_point_position rather than by
|
||||||
|
// searching '.'.
|
||||||
|
if (lead_zero != 0)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(has_dot != 0); // an integer "0" cannot reach the limit
|
||||||
|
for (std::size_t i = decimal_point_position + 1;
|
||||||
|
digits >= limit && i < mantissa_end && token[i] == '0'; ++i)
|
||||||
|
{
|
||||||
|
--digits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return digits < limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief convert a validated float token without the C library, if possible
|
||||||
|
|
||||||
|
Tries std::from_chars (when available) and then Clinger's exact fast path
|
||||||
|
(double only), skipping the latter when it cannot succeed.
|
||||||
|
|
||||||
|
@param[in] first pointer to the first character of the token
|
||||||
|
@param[in] last pointer past the last character
|
||||||
|
@param[in] decimal_point_position index of the '.' in the token, or
|
||||||
|
std::string::npos if there is none
|
||||||
|
@param[in] mantissa_end offset just past the last mantissa byte (the
|
||||||
|
index of 'e'/'E', or the token length)
|
||||||
|
@param[out] value the converted value on success
|
||||||
|
@return true if the value was converted; false if convert_float_locale_aware()
|
||||||
|
must convert it
|
||||||
|
*/
|
||||||
|
template<typename FloatType>
|
||||||
|
bool convert_float_fast(const char* first, const char* last, std::size_t decimal_point_position,
|
||||||
|
std::size_t mantissa_end, FloatType& value) noexcept
|
||||||
|
{
|
||||||
|
if (parse_float_from_chars(first, last, value))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Skipping a fast path that cannot succeed is lossless and saves a full
|
||||||
|
// extra pass over the token's bytes, which otherwise shows up on
|
||||||
|
// high-precision inputs such as canada.json
|
||||||
|
return mantissa_fits_clinger(first, decimal_point_position, mantissa_end)
|
||||||
|
&& parse_float_fast(first, last, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
inline void strtof_by_type(float& f, const char* str, char** endptr) noexcept
|
||||||
|
{
|
||||||
|
f = std::strtof(str, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
inline void strtof_by_type(double& f, const char* str, char** endptr) noexcept
|
||||||
|
{
|
||||||
|
f = std::strtod(str, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
inline void strtof_by_type(long double& f, const char* str, char** endptr) noexcept
|
||||||
|
{
|
||||||
|
f = std::strtold(str, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the decimal point of the current locale
|
||||||
|
inline char get_decimal_point() noexcept
|
||||||
|
{
|
||||||
|
const auto* loc = localeconv();
|
||||||
|
JSON_ASSERT(loc != nullptr);
|
||||||
|
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief convert a validated float token with strtof/strtod/strtold
|
||||||
|
|
||||||
|
These functions expect the decimal point of the *current* locale, so it is
|
||||||
|
looked up right before the conversion instead of once when the lexer is
|
||||||
|
constructed: a locale change in between (by a parser callback, a SAX
|
||||||
|
handler, or another thread) must not truncate the value (#5198). The
|
||||||
|
token has been validated before, so if the conversion stops early and the
|
||||||
|
decimal point changed in the meantime, the locale changed between the
|
||||||
|
lookup and the call, and the conversion is repeated with the new decimal
|
||||||
|
point. If the decimal point did not change, a retry cannot succeed: the
|
||||||
|
locale's decimal point is not a single character (e.g., the two-byte
|
||||||
|
U+066B of ar_EG.UTF-8 or fa_IR.UTF-8) and cannot be substituted in place.
|
||||||
|
The value strtod parsed up to that point is kept, as before this change.
|
||||||
|
|
||||||
|
Note that changing the locale in another thread *while* strtod runs is
|
||||||
|
undefined behavior of the C library, which this function cannot prevent.
|
||||||
|
|
||||||
|
@param[in,out] token the token with '.' as decimal point; its
|
||||||
|
decimal point is replaced during the
|
||||||
|
conversion and restored afterwards
|
||||||
|
(data() must be NUL-terminated)
|
||||||
|
@param[in] decimal_point_position index of the '.' in @a token, or
|
||||||
|
std::string::npos if there is none
|
||||||
|
@param[out] value the converted value
|
||||||
|
*/
|
||||||
|
template<typename StringType, typename FloatType>
|
||||||
|
void convert_float_locale_aware(StringType& token, std::size_t decimal_point_position, FloatType& value)
|
||||||
|
{
|
||||||
|
const bool has_dot = decimal_point_position != std::string::npos;
|
||||||
|
char decimal_point = get_decimal_point();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const bool substitute = has_dot && decimal_point != '.';
|
||||||
|
if (substitute)
|
||||||
|
{
|
||||||
|
token[decimal_point_position] = static_cast<typename StringType::value_type>(decimal_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
strtof_by_type(value, token.data(), &endptr);
|
||||||
|
|
||||||
|
if (substitute)
|
||||||
|
{
|
||||||
|
// the caller hands the token on (e.g. to the SAX interface) with '.'
|
||||||
|
token[decimal_point_position] = '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_LIKELY(endptr == token.data() + token.size()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// retry only if the locale changed; otherwise, this would loop forever
|
||||||
|
const char current_decimal_point = get_decimal_point();
|
||||||
|
if (current_decimal_point == decimal_point)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
decimal_point = current_decimal_point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
||||||
@@ -9313,18 +9489,6 @@ class lexer : public lexer_base<BasicJsonType>
|
|||||||
~lexer() = default;
|
~lexer() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/////////////////////
|
|
||||||
// locales
|
|
||||||
/////////////////////
|
|
||||||
|
|
||||||
/// return the decimal point of the current locale
|
|
||||||
static char get_decimal_point() noexcept
|
|
||||||
{
|
|
||||||
const auto* loc = localeconv();
|
|
||||||
JSON_ASSERT(loc != nullptr);
|
|
||||||
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// scan functions
|
// scan functions
|
||||||
/////////////////////
|
/////////////////////
|
||||||
@@ -10132,24 +10296,6 @@ 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
|
@brief scan a number literal
|
||||||
|
|
||||||
@@ -10189,7 +10335,7 @@ class lexer : public lexer_base<BasicJsonType>
|
|||||||
@note The scanner is independent of the current locale: token_buffer
|
@note The scanner is independent of the current locale: token_buffer
|
||||||
always holds `.`. Only the std::strtod fallback of convert_number()
|
always holds `.`. Only the std::strtod fallback of convert_number()
|
||||||
depends on the locale, and it looks up the decimal point right
|
depends on the locale, and it looks up the decimal point right
|
||||||
before converting (see convert_float_locale_aware()).
|
before converting (see detail::convert_float_locale_aware()).
|
||||||
*/
|
*/
|
||||||
token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated.
|
token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated.
|
||||||
{
|
{
|
||||||
@@ -10520,59 +10666,6 @@ scan_number_done:
|
|||||||
return token_type::uninitialized;
|
return token_type::uninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief check whether Clinger's fast path can still succeed for this token
|
|
||||||
|
|
||||||
parse_float_fast() needs a significand below 2^53. A mantissa with 17 or
|
|
||||||
more significant digits is at least 10^16 and therefore always exceeds it,
|
|
||||||
so calling the fast path would walk the token one extra time only to
|
|
||||||
decline before strtod has to run anyway.
|
|
||||||
|
|
||||||
Significant digits are the mantissa's digits from the first nonzero one on;
|
|
||||||
the sign, the decimal point, leading zeros, and the exponent do not count.
|
|
||||||
The answer is derived from indices - the digits are not scanned again - so
|
|
||||||
this stays off the hot path of the number scanners.
|
|
||||||
|
|
||||||
@param[in] mantissa_end offset just past the last mantissa byte in
|
|
||||||
token_buffer
|
|
||||||
@return false if parse_float_fast() is guaranteed to decline
|
|
||||||
*/
|
|
||||||
bool mantissa_fits_clinger(std::size_t mantissa_end) const
|
|
||||||
{
|
|
||||||
// 10^16 already exceeds 2^53, so 17 digits can never fit
|
|
||||||
constexpr std::size_t limit = 17;
|
|
||||||
|
|
||||||
const std::size_t neg = (!token_buffer.empty() && token_buffer[0] == '-') ? 1u : 0u;
|
|
||||||
const std::size_t has_dot = (decimal_point_position != std::string::npos) ? 1u : 0u;
|
|
||||||
// the JSON grammar restricts the integer part to "0" or [1-9][0-9]*, so
|
|
||||||
// a leading zero can only be a lone "0", which is not significant
|
|
||||||
const std::size_t lead_zero = (token_buffer[neg] == '0') ? 1u : 0u;
|
|
||||||
JSON_ASSERT(mantissa_end >= neg + has_dot + lead_zero);
|
|
||||||
std::size_t digits = mantissa_end - neg - has_dot - lead_zero;
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_LIKELY(digits < limit))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only a number below 1 can carry further insignificant zeros, and only
|
|
||||||
// while the count stays at the limit does removing them change the
|
|
||||||
// answer - so this loop is skipped for all but a few tokens. The
|
|
||||||
// fraction is located through decimal_point_position rather than by
|
|
||||||
// searching '.'.
|
|
||||||
if (lead_zero != 0)
|
|
||||||
{
|
|
||||||
JSON_ASSERT(has_dot != 0); // an integer "0" cannot reach the limit
|
|
||||||
for (std::size_t i = decimal_point_position + 1;
|
|
||||||
digits >= limit && i < mantissa_end && token_buffer[i] == '0'; ++i)
|
|
||||||
{
|
|
||||||
--digits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return digits < limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief convert the number text in token_buffer to its value and token type
|
@brief convert the number text in token_buffer to its value and token type
|
||||||
|
|
||||||
@@ -10586,7 +10679,7 @@ scan_number_done:
|
|||||||
token_buffer (the index of 'e'/'E', or
|
token_buffer (the index of 'e'/'E', or
|
||||||
token_buffer.size() when there is no exponent);
|
token_buffer.size() when there is no exponent);
|
||||||
used to skip Clinger's fast path when it cannot
|
used to skip Clinger's fast path when it cannot
|
||||||
possibly succeed - see mantissa_fits_clinger()
|
possibly succeed - see detail::mantissa_fits_clinger()
|
||||||
*/
|
*/
|
||||||
token_type convert_number(token_type number_type, std::size_t mantissa_end)
|
token_type convert_number(token_type number_type, std::size_t mantissa_end)
|
||||||
{
|
{
|
||||||
@@ -10659,77 +10752,15 @@ scan_number_done:
|
|||||||
// (Eisel-Lemire, locale-independent, correctly rounded) when available;
|
// (Eisel-Lemire, locale-independent, correctly rounded) when available;
|
||||||
// otherwise the exact Clinger fast path (double only); otherwise the
|
// otherwise the exact Clinger fast path (double only); otherwise the
|
||||||
// locale-aware strtof/strtod/strtold.
|
// locale-aware strtof/strtod/strtold.
|
||||||
if (parse_float_from_chars(num_begin, num_end, value_float))
|
if (convert_float_fast(num_begin, num_end, decimal_point_position, mantissa_end, value_float))
|
||||||
{
|
|
||||||
return token_type::value_float;
|
|
||||||
}
|
|
||||||
// Skipping a fast path that cannot succeed is lossless and saves a full
|
|
||||||
// extra pass over the token's bytes, which otherwise shows up on
|
|
||||||
// high-precision inputs such as canada.json
|
|
||||||
if (mantissa_fits_clinger(mantissa_end)
|
|
||||||
&& parse_float_fast(num_begin, num_end, value_float))
|
|
||||||
{
|
{
|
||||||
return token_type::value_float;
|
return token_type::value_float;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_float_locale_aware();
|
convert_float_locale_aware(token_buffer, decimal_point_position, value_float);
|
||||||
return token_type::value_float;
|
return token_type::value_float;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief convert the float in token_buffer with strtof/strtod/strtold
|
|
||||||
|
|
||||||
These functions expect the decimal point of the *current* locale, so it is
|
|
||||||
looked up right before the conversion instead of once when the lexer is
|
|
||||||
constructed: a locale change in between (by a parser callback, a SAX
|
|
||||||
handler, or another thread) must not truncate the value (#5198). The
|
|
||||||
token has been validated before, so if the conversion stops early and the
|
|
||||||
decimal point changed in the meantime, the locale changed between the
|
|
||||||
lookup and the call, and the conversion is repeated with the new decimal
|
|
||||||
point. If the decimal point did not change, a retry cannot succeed: the
|
|
||||||
locale's decimal point is not a single character (e.g., the two-byte
|
|
||||||
U+066B of ar_EG.UTF-8 or fa_IR.UTF-8) and cannot be substituted in place.
|
|
||||||
The value strtod parsed up to that point is kept, as before this change.
|
|
||||||
|
|
||||||
Note that changing the locale in another thread *while* strtod runs is
|
|
||||||
undefined behavior of the C library, which this function cannot prevent.
|
|
||||||
*/
|
|
||||||
void convert_float_locale_aware()
|
|
||||||
{
|
|
||||||
const bool has_dot = decimal_point_position != std::string::npos;
|
|
||||||
char decimal_point = get_decimal_point();
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
const bool substitute = has_dot && decimal_point != '.';
|
|
||||||
if (substitute)
|
|
||||||
{
|
|
||||||
token_buffer[decimal_point_position] = static_cast<typename string_t::value_type>(decimal_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
|
||||||
strtof(value_float, token_buffer.data(), &endptr);
|
|
||||||
|
|
||||||
if (substitute)
|
|
||||||
{
|
|
||||||
// get_string() hands the token to the SAX interface with '.'
|
|
||||||
token_buffer[decimal_point_position] = '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_LIKELY(endptr == token_buffer.data() + token_buffer.size()))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// retry only if the locale changed; otherwise, this would loop forever
|
|
||||||
const char current_decimal_point = get_decimal_point();
|
|
||||||
if (current_decimal_point == decimal_point)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
decimal_point = current_decimal_point;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief contiguous fast path for scanning a number
|
@brief contiguous fast path for scanning a number
|
||||||
|
|
||||||
@@ -11451,21 +11482,15 @@ input.
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
struct json_sax
|
struct json_sax
|
||||||
{
|
{
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/number_integer_t/
|
|
||||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/number_unsigned_t/
|
|
||||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/number_float_t/
|
|
||||||
using number_float_t = typename BasicJsonType::number_float_t;
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/string_t/
|
|
||||||
using string_t = typename BasicJsonType::string_t;
|
using string_t = typename BasicJsonType::string_t;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/binary_t/
|
|
||||||
using binary_t = typename BasicJsonType::binary_t;
|
using binary_t = typename BasicJsonType::binary_t;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief a null value was read
|
@brief a null value was read
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/null/
|
|
||||||
*/
|
*/
|
||||||
virtual bool null() = 0;
|
virtual bool null() = 0;
|
||||||
|
|
||||||
@@ -11473,7 +11498,6 @@ struct json_sax
|
|||||||
@brief a boolean value was read
|
@brief a boolean value was read
|
||||||
@param[in] val boolean value
|
@param[in] val boolean value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/boolean/
|
|
||||||
*/
|
*/
|
||||||
virtual bool boolean(bool val) = 0;
|
virtual bool boolean(bool val) = 0;
|
||||||
|
|
||||||
@@ -11481,7 +11505,6 @@ struct json_sax
|
|||||||
@brief an integer number was read
|
@brief an integer number was read
|
||||||
@param[in] val integer value
|
@param[in] val integer value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/number_integer/
|
|
||||||
*/
|
*/
|
||||||
virtual bool number_integer(number_integer_t val) = 0;
|
virtual bool number_integer(number_integer_t val) = 0;
|
||||||
|
|
||||||
@@ -11489,7 +11512,6 @@ struct json_sax
|
|||||||
@brief an unsigned integer number was read
|
@brief an unsigned integer number was read
|
||||||
@param[in] val unsigned integer value
|
@param[in] val unsigned integer value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/number_unsigned/
|
|
||||||
*/
|
*/
|
||||||
virtual bool number_unsigned(number_unsigned_t val) = 0;
|
virtual bool number_unsigned(number_unsigned_t val) = 0;
|
||||||
|
|
||||||
@@ -11498,7 +11520,6 @@ struct json_sax
|
|||||||
@param[in] val floating-point value
|
@param[in] val floating-point value
|
||||||
@param[in] s raw token value
|
@param[in] s raw token value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/number_float/
|
|
||||||
*/
|
*/
|
||||||
virtual bool number_float(number_float_t val, const string_t& s) = 0;
|
virtual bool number_float(number_float_t val, const string_t& s) = 0;
|
||||||
|
|
||||||
@@ -11507,7 +11528,6 @@ struct json_sax
|
|||||||
@param[in] val string value
|
@param[in] val string value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note It is safe to move the passed string value.
|
@note It is safe to move the passed string value.
|
||||||
@sa https://json.nlohmann.me/api/json_sax/string/
|
|
||||||
*/
|
*/
|
||||||
virtual bool string(string_t& val) = 0;
|
virtual bool string(string_t& val) = 0;
|
||||||
|
|
||||||
@@ -11516,7 +11536,6 @@ struct json_sax
|
|||||||
@param[in] val binary value
|
@param[in] val binary value
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note It is safe to move the passed binary value.
|
@note It is safe to move the passed binary value.
|
||||||
@sa https://json.nlohmann.me/api/json_sax/binary/
|
|
||||||
*/
|
*/
|
||||||
virtual bool binary(binary_t& val) = 0;
|
virtual bool binary(binary_t& val) = 0;
|
||||||
|
|
||||||
@@ -11525,7 +11544,6 @@ struct json_sax
|
|||||||
@param[in] elements number of object elements or -1 if unknown
|
@param[in] elements number of object elements or -1 if unknown
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note binary formats may report the number of elements
|
@note binary formats may report the number of elements
|
||||||
@sa https://json.nlohmann.me/api/json_sax/start_object/
|
|
||||||
*/
|
*/
|
||||||
virtual bool start_object(std::size_t elements) = 0;
|
virtual bool start_object(std::size_t elements) = 0;
|
||||||
|
|
||||||
@@ -11534,14 +11552,12 @@ struct json_sax
|
|||||||
@param[in] val object key
|
@param[in] val object key
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note It is safe to move the passed string.
|
@note It is safe to move the passed string.
|
||||||
@sa https://json.nlohmann.me/api/json_sax/key/
|
|
||||||
*/
|
*/
|
||||||
virtual bool key(string_t& val) = 0;
|
virtual bool key(string_t& val) = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief the end of an object was read
|
@brief the end of an object was read
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/end_object/
|
|
||||||
*/
|
*/
|
||||||
virtual bool end_object() = 0;
|
virtual bool end_object() = 0;
|
||||||
|
|
||||||
@@ -11550,14 +11566,12 @@ struct json_sax
|
|||||||
@param[in] elements number of array elements or -1 if unknown
|
@param[in] elements number of array elements or -1 if unknown
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@note binary formats may report the number of elements
|
@note binary formats may report the number of elements
|
||||||
@sa https://json.nlohmann.me/api/json_sax/start_array/
|
|
||||||
*/
|
*/
|
||||||
virtual bool start_array(std::size_t elements) = 0;
|
virtual bool start_array(std::size_t elements) = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief the end of an array was read
|
@brief the end of an array was read
|
||||||
@return whether parsing should proceed
|
@return whether parsing should proceed
|
||||||
@sa https://json.nlohmann.me/api/json_sax/end_array/
|
|
||||||
*/
|
*/
|
||||||
virtual bool end_array() = 0;
|
virtual bool end_array() = 0;
|
||||||
|
|
||||||
@@ -11567,23 +11581,16 @@ struct json_sax
|
|||||||
@param[in] last_token the last read token
|
@param[in] last_token the last read token
|
||||||
@param[in] ex an exception object describing the error
|
@param[in] ex an exception object describing the error
|
||||||
@return whether parsing should proceed (must return false)
|
@return whether parsing should proceed (must return false)
|
||||||
@sa https://json.nlohmann.me/api/json_sax/parse_error/
|
|
||||||
*/
|
*/
|
||||||
virtual bool parse_error(std::size_t position,
|
virtual bool parse_error(std::size_t position,
|
||||||
const std::string& last_token,
|
const std::string& last_token,
|
||||||
const detail::exception& ex) = 0;
|
const detail::exception& ex) = 0;
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
|
|
||||||
json_sax() = default;
|
json_sax() = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
|
|
||||||
json_sax(const json_sax&) = default;
|
json_sax(const json_sax&) = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/json_sax/
|
|
||||||
json_sax(json_sax&&) noexcept = default;
|
json_sax(json_sax&&) noexcept = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/operator=/
|
|
||||||
json_sax& operator=(const json_sax&) = default;
|
json_sax& operator=(const json_sax&) = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/operator=/
|
|
||||||
json_sax& operator=(json_sax&&) noexcept = default;
|
json_sax& operator=(json_sax&&) noexcept = default;
|
||||||
/// @sa https://json.nlohmann.me/api/json_sax/~json_sax/
|
|
||||||
virtual ~json_sax() = default;
|
virtual ~json_sax() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -18926,7 +18933,6 @@ class json_pointer
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// for backwards compatibility accept BasicJsonType
|
// for backwards compatibility accept BasicJsonType
|
||||||
/// @sa https://json.nlohmann.me/api/json_pointer/string_t/
|
|
||||||
using string_t = typename string_t_helper<RefStringType>::type;
|
using string_t = typename string_t_helper<RefStringType>::type;
|
||||||
|
|
||||||
/// @brief create JSON pointer
|
/// @brief create JSON pointer
|
||||||
@@ -25821,41 +25827,30 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
{
|
{
|
||||||
using key_type = Key;
|
using key_type = Key;
|
||||||
using mapped_type = T;
|
using mapped_type = T;
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/Container/
|
|
||||||
using Container = std::vector<std::pair<const Key, T>, Allocator>;
|
using Container = std::vector<std::pair<const Key, T>, Allocator>;
|
||||||
using iterator = typename Container::iterator;
|
using iterator = typename Container::iterator;
|
||||||
using const_iterator = typename Container::const_iterator;
|
using const_iterator = typename Container::const_iterator;
|
||||||
using size_type = typename Container::size_type;
|
using size_type = typename Container::size_type;
|
||||||
using value_type = typename Container::value_type;
|
using value_type = typename Container::value_type;
|
||||||
#ifdef JSON_HAS_CPP_14
|
#ifdef JSON_HAS_CPP_14
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/key_compare/
|
|
||||||
using key_compare = std::equal_to<>;
|
using key_compare = std::equal_to<>;
|
||||||
#else
|
#else
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/key_compare/
|
|
||||||
using key_compare = std::equal_to<Key>;
|
using key_compare = std::equal_to<Key>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Explicit constructors instead of `using Container::Container`
|
// Explicit constructors instead of `using Container::Container`
|
||||||
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
|
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
ordered_map() noexcept(noexcept(Container())) : Container{} {}
|
ordered_map() noexcept(noexcept(Container())) : Container{} {}
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
|
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
template <class It>
|
template <class It>
|
||||||
ordered_map(It first, It last, const Allocator& alloc = Allocator())
|
ordered_map(It first, It last, const Allocator& alloc = Allocator())
|
||||||
: Container{first, last, alloc} {}
|
: Container{first, last, alloc} {}
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
|
ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
|
||||||
: Container{init, alloc} {}
|
: Container{init, alloc} {}
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
ordered_map(const ordered_map&) = default;
|
ordered_map(const ordered_map&) = default;
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/ordered_map/
|
|
||||||
ordered_map(ordered_map&&) noexcept(std::is_nothrow_move_constructible<Container>::value) = default;
|
ordered_map(ordered_map&&) noexcept(std::is_nothrow_move_constructible<Container>::value) = default;
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/~ordered_map/
|
|
||||||
~ordered_map() = default;
|
~ordered_map() = default;
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator=/
|
|
||||||
ordered_map& operator=(const ordered_map& other)
|
ordered_map& operator=(const ordered_map& other)
|
||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other)
|
||||||
@@ -25866,14 +25861,12 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator=/
|
|
||||||
ordered_map& operator=(ordered_map&& other) noexcept(std::is_nothrow_move_assignable<Container>::value)
|
ordered_map& operator=(ordered_map&& other) noexcept(std::is_nothrow_move_assignable<Container>::value)
|
||||||
{
|
{
|
||||||
Container::operator=(std::move(static_cast<Container&>(other)));
|
Container::operator=(std::move(static_cast<Container&>(other)));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/emplace/
|
|
||||||
std::pair<iterator, bool> emplace(const key_type& key, T&& t)
|
std::pair<iterator, bool> emplace(const key_type& key, T&& t)
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -25887,7 +25880,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return {std::prev(this->end()), true};
|
return {std::prev(this->end()), true};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/emplace/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
std::pair<iterator, bool> emplace(KeyType && key, T && t)
|
std::pair<iterator, bool> emplace(KeyType && key, T && t)
|
||||||
@@ -25903,13 +25895,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return {std::prev(this->end()), true};
|
return {std::prev(this->end()), true};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator[]/
|
|
||||||
T& operator[](const key_type& key)
|
T& operator[](const key_type& key)
|
||||||
{
|
{
|
||||||
return emplace(key, T{}).first->second;
|
return emplace(key, T{}).first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator[]/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
T & operator[](KeyType && key)
|
T & operator[](KeyType && key)
|
||||||
@@ -25917,13 +25907,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return emplace(std::forward<KeyType>(key), T{}).first->second;
|
return emplace(std::forward<KeyType>(key), T{}).first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator[]/
|
|
||||||
const T& operator[](const key_type& key) const
|
const T& operator[](const key_type& key) const
|
||||||
{
|
{
|
||||||
return at(key);
|
return at(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/operator[]/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
const T & operator[](KeyType && key) const
|
const T & operator[](KeyType && key) const
|
||||||
@@ -25931,7 +25919,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return at(std::forward<KeyType>(key));
|
return at(std::forward<KeyType>(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/at/
|
|
||||||
T& at(const key_type& key)
|
T& at(const key_type& key)
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -25945,7 +25932,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
JSON_THROW(std::out_of_range("key not found"));
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/at/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -25961,7 +25947,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
JSON_THROW(std::out_of_range("key not found"));
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/at/
|
|
||||||
const T& at(const key_type& key) const
|
const T& at(const key_type& key) const
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -25975,7 +25960,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
JSON_THROW(std::out_of_range("key not found"));
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/at/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -25991,7 +25975,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
JSON_THROW(std::out_of_range("key not found"));
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/erase/
|
|
||||||
size_type erase(const key_type& key)
|
size_type erase(const key_type& key)
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -26011,7 +25994,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/erase/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -26033,13 +26015,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/erase/
|
|
||||||
iterator erase(iterator pos)
|
iterator erase(iterator pos)
|
||||||
{
|
{
|
||||||
return erase(pos, std::next(pos));
|
return erase(pos, std::next(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/erase/
|
|
||||||
iterator erase(iterator first, iterator last)
|
iterator erase(iterator first, iterator last)
|
||||||
{
|
{
|
||||||
if (first == last)
|
if (first == last)
|
||||||
@@ -26093,7 +26073,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::begin() + offset;
|
return Container::begin() + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/count/
|
|
||||||
size_type count(const key_type& key) const
|
size_type count(const key_type& key) const
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -26106,7 +26085,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/count/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -26121,7 +26099,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/find/
|
|
||||||
iterator find(const key_type& key)
|
iterator find(const key_type& key)
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -26134,7 +26111,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::end();
|
return Container::end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/find/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -26149,7 +26125,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::end();
|
return Container::end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/find/
|
|
||||||
const_iterator find(const key_type& key) const
|
const_iterator find(const key_type& key) const
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -26162,7 +26137,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::end();
|
return Container::end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/find/
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
const_iterator find(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
const_iterator find(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
@@ -26177,13 +26151,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
return Container::end();
|
return Container::end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/insert/
|
|
||||||
std::pair<iterator, bool> insert( value_type&& value )
|
std::pair<iterator, bool> insert( value_type&& value )
|
||||||
{
|
{
|
||||||
return emplace(value.first, std::move(value.second));
|
return emplace(value.first, std::move(value.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/insert/
|
|
||||||
std::pair<iterator, bool> insert( const value_type& value )
|
std::pair<iterator, bool> insert( const value_type& value )
|
||||||
{
|
{
|
||||||
for (auto it = this->begin(); it != this->end(); ++it)
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
@@ -26201,7 +26173,6 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
|
|||||||
using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
|
using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
|
||||||
std::input_iterator_tag>::value>::type;
|
std::input_iterator_tag>::value>::type;
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/ordered_map/insert/
|
|
||||||
template<typename InputIt, typename = require_input_iter<InputIt>>
|
template<typename InputIt, typename = require_input_iter<InputIt>>
|
||||||
void insert(InputIt first, InputIt last)
|
void insert(InputIt first, InputIt last)
|
||||||
{
|
{
|
||||||
@@ -26347,31 +26318,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
using serializer = ::nlohmann::detail::serializer<basic_json>;
|
using serializer = ::nlohmann::detail::serializer<basic_json>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief the type of the JSON value
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/value_t/
|
|
||||||
using value_t = detail::value_t;
|
using value_t = detail::value_t;
|
||||||
/// JSON Pointer, see @ref nlohmann::json_pointer
|
/// JSON Pointer, see @ref nlohmann::json_pointer
|
||||||
using json_pointer = ::nlohmann::json_pointer<StringType>;
|
using json_pointer = ::nlohmann::json_pointer<StringType>;
|
||||||
template<typename T, typename SFINAE>
|
template<typename T, typename SFINAE>
|
||||||
using json_serializer = JSONSerializer<T, SFINAE>;
|
using json_serializer = JSONSerializer<T, SFINAE>;
|
||||||
/// how to treat decoding errors
|
/// how to treat decoding errors
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/error_handler_t/
|
|
||||||
using error_handler_t = detail::error_handler_t;
|
using error_handler_t = detail::error_handler_t;
|
||||||
/// how to treat CBOR tags
|
/// how to treat CBOR tags
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/cbor_tag_handler_t/
|
|
||||||
using cbor_tag_handler_t = detail::cbor_tag_handler_t;
|
using cbor_tag_handler_t = detail::cbor_tag_handler_t;
|
||||||
/// how to encode BJData
|
/// how to encode BJData
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/bjdata_version_t/
|
|
||||||
using bjdata_version_t = detail::bjdata_version_t;
|
using bjdata_version_t = detail::bjdata_version_t;
|
||||||
/// helper type for initializer lists of basic_json values
|
/// helper type for initializer lists of basic_json values
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/initializer_list_t/
|
|
||||||
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
|
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
|
||||||
|
|
||||||
/// @brief the type of the SAX interface used to parse and serialize the JSON value
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/input_format_t/
|
|
||||||
using input_format_t = detail::input_format_t;
|
using input_format_t = detail::input_format_t;
|
||||||
/// SAX interface type, see @ref nlohmann::json_sax
|
/// SAX interface type, see @ref nlohmann::json_sax
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/json_sax_t/
|
|
||||||
using json_sax_t = json_sax<basic_json>;
|
using json_sax_t = json_sax<basic_json>;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
@@ -26513,19 +26475,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// the template arguments passed to class @ref basic_json.
|
/// the template arguments passed to class @ref basic_json.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
#if defined(JSON_HAS_CPP_14)
|
|
||||||
/// @brief default object key comparator type
|
/// @brief default object key comparator type
|
||||||
/// The actual object key comparator type (@ref object_comparator_t) may be
|
/// The actual object key comparator type (@ref object_comparator_t) may be
|
||||||
/// different.
|
/// different.
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
|
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
|
||||||
|
#if defined(JSON_HAS_CPP_14)
|
||||||
// use of transparent comparator avoids unnecessary repeated construction of temporaries
|
// use of transparent comparator avoids unnecessary repeated construction of temporaries
|
||||||
// in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
|
// in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
|
||||||
using default_object_comparator_t = std::less<>;
|
using default_object_comparator_t = std::less<>;
|
||||||
#else
|
#else
|
||||||
/// @brief default object key comparator type
|
|
||||||
/// The actual object key comparator type (@ref object_comparator_t) may be
|
|
||||||
/// different.
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
|
|
||||||
using default_object_comparator_t = std::less<StringType>;
|
using default_object_comparator_t = std::less<StringType>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -28071,7 +28029,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// other constructors and destructor //
|
// other constructors and destructor //
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
|
||||||
template<typename JsonRef,
|
template<typename JsonRef,
|
||||||
detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
|
detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
|
||||||
std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
|
std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
|
||||||
@@ -28655,8 +28612,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
@throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
|
@throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
|
||||||
|
|
||||||
@since version 2.1.0
|
@since version 2.1.0
|
||||||
|
|
||||||
@sa https://json.nlohmann.me/api/basic_json/get/
|
|
||||||
*/
|
*/
|
||||||
template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
|
template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
|
||||||
#if defined(JSON_HAS_CPP_14)
|
#if defined(JSON_HAS_CPP_14)
|
||||||
@@ -28700,8 +28655,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
@sa see @ref get_ptr() for explicit pointer-member access
|
@sa see @ref get_ptr() for explicit pointer-member access
|
||||||
|
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
|
|
||||||
@sa https://json.nlohmann.me/api/basic_json/get/
|
|
||||||
*/
|
*/
|
||||||
template<typename PointerType, typename std::enable_if<
|
template<typename PointerType, typename std::enable_if<
|
||||||
std::is_pointer<PointerType>::value, int>::type = 0>
|
std::is_pointer<PointerType>::value, int>::type = 0>
|
||||||
@@ -28728,7 +28681,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
// specialization to allow calling get_to with a basic_json value
|
// specialization to allow calling get_to with a basic_json value
|
||||||
// see https://github.com/nlohmann/json/issues/2175
|
// see https://github.com/nlohmann/json/issues/2175
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/get_to/
|
|
||||||
template<typename ValueType,
|
template<typename ValueType,
|
||||||
detail::enable_if_t <
|
detail::enable_if_t <
|
||||||
detail::is_basic_json<ValueType>::value,
|
detail::is_basic_json<ValueType>::value,
|
||||||
@@ -28739,7 +28691,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/get_to/
|
|
||||||
template <
|
template <
|
||||||
typename T, std::size_t N,
|
typename T, std::size_t N,
|
||||||
typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||||
@@ -28804,7 +28755,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ValueType/
|
|
||||||
template < typename ValueType, typename std::enable_if <
|
template < typename ValueType, typename std::enable_if <
|
||||||
detail::conjunction <
|
detail::conjunction <
|
||||||
detail::negation<std::is_pointer<ValueType>>,
|
detail::negation<std::is_pointer<ValueType>>,
|
||||||
@@ -29077,14 +29027,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
||||||
// (they seemingly cannot be constrained to resolve the ambiguity)
|
// (they seemingly cannot be constrained to resolve the ambiguity)
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator[]/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
reference operator[](T* key)
|
reference operator[](T* key)
|
||||||
{
|
{
|
||||||
return operator[](typename object_t::key_type(key));
|
return operator[](typename object_t::key_type(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator[]/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const_reference operator[](T* key) const
|
const_reference operator[](T* key) const
|
||||||
{
|
{
|
||||||
@@ -29294,7 +29242,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/value/
|
|
||||||
template < class ValueType, class BasicJsonType, detail::enable_if_t <
|
template < class ValueType, class BasicJsonType, detail::enable_if_t <
|
||||||
detail::is_basic_json<BasicJsonType>::value
|
detail::is_basic_json<BasicJsonType>::value
|
||||||
&& detail::is_getable<basic_json_t, ValueType>::value
|
&& detail::is_getable<basic_json_t, ValueType>::value
|
||||||
@@ -29305,7 +29252,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return value(ptr.convert(), default_value);
|
return value(ptr.convert(), default_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/value/
|
|
||||||
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
|
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
|
||||||
detail::enable_if_t <
|
detail::enable_if_t <
|
||||||
detail::is_basic_json<BasicJsonType>::value
|
detail::is_basic_json<BasicJsonType>::value
|
||||||
@@ -29685,7 +29631,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.contains(this);
|
return ptr.contains(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/contains/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
@@ -31105,7 +31050,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/parse/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
|
||||||
static basic_json parse(detail::span_input_adapter&& i,
|
static basic_json parse(detail::span_input_adapter&& i,
|
||||||
@@ -31142,7 +31086,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||||
static bool accept(detail::span_input_adapter&& i,
|
static bool accept(detail::span_input_adapter&& i,
|
||||||
@@ -31526,7 +31469,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||||
@@ -31538,7 +31480,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
|
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||||
static basic_json from_cbor(detail::span_input_adapter&& i,
|
static basic_json from_cbor(detail::span_input_adapter&& i,
|
||||||
@@ -31594,7 +31535,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||||
@@ -31605,7 +31545,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
|
return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||||
static basic_json from_msgpack(detail::span_input_adapter&& i,
|
static basic_json from_msgpack(detail::span_input_adapter&& i,
|
||||||
@@ -31660,7 +31599,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||||
@@ -31671,7 +31609,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
|
return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||||
static basic_json from_ubjson(detail::span_input_adapter&& i,
|
static basic_json from_ubjson(detail::span_input_adapter&& i,
|
||||||
@@ -31800,7 +31737,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||||
@@ -31811,7 +31747,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return from_bson(ptr, ptr + len, strict, allow_exceptions);
|
return from_bson(ptr, ptr + len, strict, allow_exceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||||
static basic_json from_bson(detail::span_input_adapter&& i,
|
static basic_json from_bson(detail::span_input_adapter&& i,
|
||||||
@@ -31844,7 +31779,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.get_unchecked(this);
|
return ptr.get_unchecked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
||||||
@@ -31859,7 +31793,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.get_unchecked(this);
|
return ptr.get_unchecked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||||
@@ -31874,7 +31807,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.get_checked(this);
|
return ptr.get_checked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/at/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
||||||
@@ -31889,7 +31821,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return ptr.get_checked(this);
|
return ptr.get_checked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/at/
|
|
||||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||||
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||||
|
|||||||
@@ -8,3 +8,6 @@ The following changes have been made to the code with respect to <https://github
|
|||||||
- membership check
|
- membership check
|
||||||
- made function from `_is_within`
|
- made function from `_is_within`
|
||||||
- removed unused variable `actual_path`
|
- removed unused variable `actual_path`
|
||||||
|
- Added the optional config key `external`: include paths listed there are kept as
|
||||||
|
`#include` directives instead of being inlined (the first directive per path; the
|
||||||
|
repeated ones are commented out).
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ Python v.2.7.0 or higher is required.
|
|||||||
amalgamation. Have a look at `test/source.c.json` and `test/include.h.json`
|
amalgamation. Have a look at `test/source.c.json` and `test/include.h.json`
|
||||||
to see two examples.
|
to see two examples.
|
||||||
|
|
||||||
|
The optional `external` list names include paths that are kept as `#include`
|
||||||
|
directives instead of being inlined, e.g. `["nlohmann/json.hpp"]` for a header
|
||||||
|
that includes another amalgamated header. Only the first directive for each
|
||||||
|
of these paths is kept; the repeated ones are commented out.
|
||||||
|
|
||||||
* The `-s, --source` option should specify the path to the source directory.
|
* The `-s, --source` option should specify the path to the source directory.
|
||||||
This is useful for supporting separate source and build directories.
|
This is useful for supporting separate source and build directories.
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ class Amalgamation(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
|
# include paths that are kept as #include directives instead of
|
||||||
|
# being inlined (e.g. a header amalgamated on its own)
|
||||||
|
self.external = []
|
||||||
|
self.included_external = []
|
||||||
with open(args.config, 'r') as f:
|
with open(args.config, 'r') as f:
|
||||||
config = json.loads(f.read())
|
config = json.loads(f.read())
|
||||||
for key in config:
|
for key in config:
|
||||||
@@ -220,11 +224,14 @@ class TranslationUnit(object):
|
|||||||
while include_match:
|
while include_match:
|
||||||
if not _is_within(include_match, skippable_contexts):
|
if not _is_within(include_match, skippable_contexts):
|
||||||
include_path = include_match.group("path")
|
include_path = include_match.group("path")
|
||||||
search_same_dir = include_match.group(1) == '"'
|
if include_path in self.amalgamation.external:
|
||||||
found_included_path = self.amalgamation.find_included_file(
|
includes.append((include_match, None))
|
||||||
include_path, self.file_dir if search_same_dir else None)
|
else:
|
||||||
if found_included_path:
|
search_same_dir = include_match.group(1) == '"'
|
||||||
includes.append((include_match, found_included_path))
|
found_included_path = self.amalgamation.find_included_file(
|
||||||
|
include_path, self.file_dir if search_same_dir else None)
|
||||||
|
if found_included_path:
|
||||||
|
includes.append((include_match, found_included_path))
|
||||||
|
|
||||||
include_match = self.include_pattern.search(self.content,
|
include_match = self.include_pattern.search(self.content,
|
||||||
include_match.end())
|
include_match.end())
|
||||||
@@ -235,6 +242,17 @@ class TranslationUnit(object):
|
|||||||
for include in includes:
|
for include in includes:
|
||||||
include_match, found_included_path = include
|
include_match, found_included_path = include
|
||||||
tmp_content += self.content[prev_end:include_match.start()]
|
tmp_content += self.content[prev_end:include_match.start()]
|
||||||
|
if found_included_path is None:
|
||||||
|
# an external header: keep the first directive and comment
|
||||||
|
# out the repeated ones
|
||||||
|
include_path = include_match.group("path")
|
||||||
|
if include_path in self.amalgamation.included_external:
|
||||||
|
tmp_content += "// {0}".format(include_match.group(0))
|
||||||
|
else:
|
||||||
|
self.amalgamation.included_external.append(include_path)
|
||||||
|
tmp_content += include_match.group(0)
|
||||||
|
prev_end = include_match.end()
|
||||||
|
continue
|
||||||
tmp_content += "// {0}\n".format(include_match.group(0))
|
tmp_content += "// {0}\n".format(include_match.group(0))
|
||||||
if found_included_path not in self.amalgamation.included_files:
|
if found_included_path not in self.amalgamation.included_files:
|
||||||
t = TranslationUnit(found_included_path, self.amalgamation, False)
|
t = TranslationUnit(found_included_path, self.amalgamation, False)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"project": "JSON for Modern C++",
|
||||||
|
"target": "single_include/nlohmann/json_view.hpp",
|
||||||
|
"sources": [
|
||||||
|
"include/nlohmann/json_view.hpp"
|
||||||
|
],
|
||||||
|
"include_paths": ["include"],
|
||||||
|
"external": ["nlohmann/json.hpp"]
|
||||||
|
}
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
# Public API Policy
|
|
||||||
|
|
||||||
This document defines what counts as the **public API** of nlohmann/json for the purposes of the
|
|
||||||
`tools/api_checker/` tooling, what stability is (and is not) guaranteed, and how API changes are
|
|
||||||
classified as breaking or feature additions. It exists so that "public API" is a checkable, mechanical
|
|
||||||
property of the source, not a matter of convention or memory — see
|
|
||||||
[Discussion #3691](https://github.com/nlohmann/json/discussions/3691) for the original motivation.
|
|
||||||
|
|
||||||
## What counts as public API
|
|
||||||
|
|
||||||
The public API surface is derived from C++ semantics (class templates, access specifiers, namespace
|
|
||||||
scoping) by `extract_api.py`, not from the presence of documentation. It consists of:
|
|
||||||
|
|
||||||
1. **Public members of six class templates**: `basic_json`, `adl_serializer`,
|
|
||||||
`byte_container_with_subtype`, `json_pointer`, `json_sax`, `ordered_map`. Specifically, the *primary
|
|
||||||
template definition* (`CLASS_TEMPLATE` cursor with `is_definition() == True`) — never an implicit
|
|
||||||
instantiation, which silently drops SFINAE-guarded overloads. Two tiers apply:
|
|
||||||
- **Callable tier** (methods, constructors, destructors, conversion operators, function templates):
|
|
||||||
every public callable requires its own `@sa` documentation link, without exception.
|
|
||||||
- **Type tier** (public type aliases): requires `@sa`, except for a fixed exemption list of
|
|
||||||
STL-container named-requirement aliases that mirror standard-library conventions rather than being
|
|
||||||
independently documented: `value_type`, `reference`, `const_reference`, `pointer`, `const_pointer`,
|
|
||||||
`iterator`, `const_iterator`, `reverse_iterator`, `const_reverse_iterator`, `difference_type`,
|
|
||||||
`size_type`, `allocator_type`, `key_type`, `mapped_type`. This list is defined once, in
|
|
||||||
`extract_api.py`'s `stl_exempt` set, and referenced here rather than duplicated.
|
|
||||||
2. **Free functions and operators in `nlohmann::`**, including `nlohmann::literals::json_literals`
|
|
||||||
(the `operator""_json` / `operator""_json_pointer` user-defined literals). Comparison and stream
|
|
||||||
operators on `basic_json` and `json_pointer`, `operator/`, `swap`.
|
|
||||||
3. **The six alias-exposed exception types**: `basic_json::exception`, `parse_error`,
|
|
||||||
`invalid_iterator`, `type_error`, `out_of_range`, `other_error`. These are public `TYPE_ALIAS_DECL`s
|
|
||||||
in `basic_json` (e.g. `using exception = detail::exception;`) whose underlying class is physically
|
|
||||||
defined in `nlohmann::detail::exceptions.hpp`. `extract_api.py` follows the alias to find the `@sa` on
|
|
||||||
the underlying `detail::` class definition, since that's where the existing documentation convention
|
|
||||||
places it. Each exception class is documented as *one page* — its individual members (`what()`, `id`)
|
|
||||||
are not separately tracked, matching the existing one-page-per-class convention.
|
|
||||||
4. **Macros**, governed separately by `docs/mkdocs/docs/api/macros/` (the curated list of ~30 pages is
|
|
||||||
authoritative) and cross-checked, advisory-only, by `check_macros.py`. See "Known limitations" below
|
|
||||||
for why macros can't be checked the same way as everything else.
|
|
||||||
|
|
||||||
## What's excluded
|
|
||||||
|
|
||||||
- **Everything in `nlohmann::detail::`**, with the one narrow exception above (exception-type aliases).
|
|
||||||
**No stability is guaranteed for any symbol in the `detail::` namespace — clients must not rely on it**,
|
|
||||||
regardless of whether a given `detail::` symbol happens to be reachable from user code today. This is
|
|
||||||
an explicit, deliberate policy, not an oversight.
|
|
||||||
- **Private and protected members**, even of the six tracked classes. `extract_api.py` walks non-public
|
|
||||||
members only to check they don't carry a stray `@sa` (a documentation leak) — never to add them to the
|
|
||||||
public surface.
|
|
||||||
- **The ABI inline-namespace segment** (`json_abi_v3_12_0`, `json_abi_diag_v3_12_0`, etc. — see
|
|
||||||
[docs/mkdocs/docs/features/namespace.md](../../docs/mkdocs/docs/features/namespace.md)). This is a
|
|
||||||
version-tag identity concern for `diff_api.py` (it must not make every release look like the entire API
|
|
||||||
was removed and re-added), not a scoping or visibility concern — the symbols inside it are public or
|
|
||||||
not independent of the tag.
|
|
||||||
|
|
||||||
## Breaking vs. feature classification
|
|
||||||
|
|
||||||
`diff_api.py` compares the `public_api` surface of two snapshots using an overload-disambiguating
|
|
||||||
identity — `(scope, identity_name, kind, signature)`, where `signature` is the declaration's own
|
|
||||||
source text (return type, name, parameter list, trailing qualifiers; comments and constructors'
|
|
||||||
member-initializer-lists stripped). This is the third identity scheme this tooling has used; the
|
|
||||||
first two were each found broken by testing against real release tags, not by inspection — see
|
|
||||||
`extract_api.py`'s `identity_key()` docstring for the full history (a naive params-only key silently
|
|
||||||
collided on overloads differing only by constness/SFINAE; libclang's USR fixed that but encoded the
|
|
||||||
*enclosing class template's own arity*, so a single backward-compatible template-parameter addition
|
|
||||||
made ~228 of 330 `basic_json` entries look "changed" between two real releases with zero actual
|
|
||||||
breaking changes among them).
|
|
||||||
|
|
||||||
- An identity present only in the **new** snapshot → **feature** (addition).
|
|
||||||
- An identity present only in the **old** snapshot → **breaking** (removal).
|
|
||||||
- The same `(scope, name)` with one identity removed and a different one added → reported as a
|
|
||||||
**changed overload**, classified breaking by default. No automatic overload-compatibility reasoning
|
|
||||||
is attempted — whether a signature change is source-compatible is a judgment call for a human
|
|
||||||
reviewer, not a sound problem for a CI tool to solve unsupervised.
|
|
||||||
|
|
||||||
## Stable per-release API history
|
|
||||||
|
|
||||||
`tools/api_checker/history/<tag>.json` holds one immutable, committed API-surface record per
|
|
||||||
released `v3.*` tag (captured via `snapshot_release.py`; see `tools/api_checker/README.md` and
|
|
||||||
`tools/api_checker/history/README.md`). `diff_api.py` reads from here automatically when a ref
|
|
||||||
matches a stored file, instead of live-extracting via `git archive` every time.
|
|
||||||
|
|
||||||
Every surface file (the live `api_surface.json` and every `history/*.json` record) carries a
|
|
||||||
`format_version` integer. **Bump it whenever a change to the schema, or to the identity-computing
|
|
||||||
algorithm (`get_signature_text()`/`get_identity_name()`/`identity_key()` in `extract_api.py`), could
|
|
||||||
alter the `signature` or `identity_name` text for otherwise-unchanged source.** `diff_api.py` refuses
|
|
||||||
by default to compare two surfaces with different `format_version` values — this is a direct,
|
|
||||||
mechanical safeguard against the exact class of bug that motivated the current identity scheme (see
|
|
||||||
above): a silent algorithm change corrupting every historical comparison with no way to detect it.
|
|
||||||
An explicit `--allow-format-mismatch` flag exists for a deliberate, informed comparison anyway.
|
|
||||||
|
|
||||||
Practical implication for anyone changing `extract_api.py`'s identity logic: bump
|
|
||||||
`SURFACE_FORMAT_VERSION`, and treat every already-committed `history/*.json` file as needing a
|
|
||||||
`--force` regeneration (reviewed, not blind) before it can be meaningfully compared against surfaces
|
|
||||||
produced by the new algorithm version.
|
|
||||||
|
|
||||||
## Stability guarantees
|
|
||||||
|
|
||||||
This tooling makes the project's existing commitments *mechanically checkable* — it does not introduce a
|
|
||||||
new promise:
|
|
||||||
|
|
||||||
- `ChangeLog.md` states the project "adheres to [Semantic Versioning](http://semver.org/)."
|
|
||||||
- [docs/mkdocs/docs/home/releases.md](../../docs/mkdocs/docs/home/releases.md) marks every 3.x release "All
|
|
||||||
changes are backward-compatible" (except 3.0.0 itself, a major bump with a migration guide).
|
|
||||||
- `tests/abi/` provides a complementary, narrower guarantee: ABI/link compatibility *within one ABI tag*.
|
|
||||||
That is a binary-compatibility concern; this tooling's concern is source/API-level — a symbol can be
|
|
||||||
ABI-stable and still be a source-breaking change (e.g. a removed overload), or vice versa.
|
|
||||||
|
|
||||||
## Known limitations
|
|
||||||
|
|
||||||
- **Macros have no C++ access-specifier concept**, so the public/private test that works for classes
|
|
||||||
doesn't transfer. Only a minority of documented macro `#define`s have an attached `@sa`-style comment
|
|
||||||
(the `#ifndef X / #define X value #endif` idiom has no natural comment-attachment point), and internal
|
|
||||||
helper macros live in the same files as public configuration macros, so no path-based exclusion works
|
|
||||||
either. `check_macros.py` therefore only checks one direction: that every documented macro still has a
|
|
||||||
matching `#define` somewhere under `include/nlohmann/` (catches stale/renamed doc pages). It does
|
|
||||||
**not** attempt to detect undocumented macros — no reliable signal exists for that direction with the
|
|
||||||
current codebase conventions, and this tool doesn't pretend otherwise.
|
|
||||||
- **`diff_api.py` does not track exception specifications or template-parameter-only changes.** A
|
|
||||||
function whose `noexcept` status changes, or whose template parameter list changes without altering
|
|
||||||
its externally-visible identity, will not be flagged.
|
|
||||||
- **Known API-hygiene gap, surfaced by this tooling rather than fixed**:
|
|
||||||
`basic_json::insert_iterator` (a `public` member per C++ access rules) is a helper used internally by
|
|
||||||
`insert()`; its own source comment calls it "Helper for insertion of an iterator." It has no
|
|
||||||
documentation page and is deliberately left undocumented rather than either speculatively documented or
|
|
||||||
silently exempted — this is exactly the class of undocumented-and-probably-shouldn't-be-public symbol
|
|
||||||
this tooling exists to surface, per the motivating discussion. A future PR may reclassify it as private
|
|
||||||
as a (breaking, ABI-relevant) cleanup; that is out of scope here.
|
|
||||||
@@ -1,393 +0,0 @@
|
|||||||
# API Checker Tools
|
|
||||||
|
|
||||||
Tooling to extract, validate, and track changes to the public API surface of nlohmann/json.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
These tools use libclang AST parsing to programmatically derive "the public API" from C++ semantics
|
|
||||||
(class templates, access specifiers, namespace scoping) — independently of documentation status. The
|
|
||||||
extracted surface is the source of truth for what is considered "public API." On top of this, the tools
|
|
||||||
verify that every public entity carries a documentation link and detect API changes between releases.
|
|
||||||
A per-release historical record lives in [`history/`](history/README.md), one file per tagged `v3.*`
|
|
||||||
release, so past API changes can be derived without re-running libclang against old git refs.
|
|
||||||
|
|
||||||
See [POLICY.md](POLICY.md) for the full definition of what counts as public API, what's excluded, how
|
|
||||||
breaking vs. feature changes are classified, and known limitations.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Install dependencies:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install -r tools/api_checker/requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
- Python 3.7+
|
|
||||||
- libclang 18.1.1 (installed via pip)
|
|
||||||
- clang++ or clang (system package, for include-path discovery only — does not need to
|
|
||||||
version-match the pinned libclang wheel)
|
|
||||||
|
|
||||||
## Tools
|
|
||||||
|
|
||||||
### extract_api.py
|
|
||||||
|
|
||||||
Extract the public API surface by parsing C++ AST using libclang. Produces two different outputs for
|
|
||||||
two different consumers — see "Two outputs, one extraction pass" below for why.
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```bash
|
|
||||||
python3 tools/api_checker/extract_api.py \
|
|
||||||
--header include/nlohmann/json.hpp \
|
|
||||||
--include include \
|
|
||||||
--output api_snapshot.json \
|
|
||||||
--surface-output api_surface.json
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options:**
|
|
||||||
- `--header PATH` — Header file to analyze (default: `include/nlohmann/json.hpp`)
|
|
||||||
- `--include PATH` — Include directory for parsing (default: `include`)
|
|
||||||
- `--output PATH` — Full snapshot output (location + doc status; default: `api_snapshot.json`)
|
|
||||||
- `--surface-output PATH` — Minimal surface output (identity only; omit to skip)
|
|
||||||
- `--extra-isystem PATH` — Extra `-isystem` include path (repeatable), in case system-include
|
|
||||||
discovery via `clang++ -E -v` ever fails on a given runner image
|
|
||||||
- `--self-test` — Run self-tests and exit (validates ABI-tag stripping)
|
|
||||||
|
|
||||||
**How it works:**
|
|
||||||
Parses the header file using libclang with `PARSE_DETAILED_PROCESSING_RECORD`, discovers system
|
|
||||||
includes via `clang++ -E -x c++ -v /dev/null`, and walks the AST:
|
|
||||||
|
|
||||||
1. For each of the 6 public class templates (`basic_json`, `adl_serializer`, `byte_container_with_subtype`,
|
|
||||||
`json_pointer`, `json_sax`, `ordered_map`): locate the `CLASS_TEMPLATE` cursor with `is_definition() == True`
|
|
||||||
— never a `CLASS_DECL` implicit instantiation, which silently drops SFINAE-guarded overloads
|
|
||||||
2. Extract public members: `CXX_METHOD`, `CONSTRUCTOR`, `DESTRUCTOR`, `CONVERSION_FUNCTION`, `FUNCTION_TEMPLATE`
|
|
||||||
(callable tier — strict `@sa` requirement), and `TYPE_ALIAS_DECL` (type tier — with STL-container exemptions)
|
|
||||||
3. Extract free functions in `nlohmann::` namespace (excluding `detail::` and `std::`)
|
|
||||||
4. Normalize away ABI inline-namespace (regex `::json_abi[a-z_]*_v\d+_\d+_\d+` → `::`)
|
|
||||||
5. Use overload-disambiguating identity keys built from raw source-text signature capture,
|
|
||||||
ABI-tag-stripped — see "Identity keys" below
|
|
||||||
|
|
||||||
**Two outputs, one extraction pass:**
|
|
||||||
- `--output` (full snapshot): each entry carries `location` (file:line) and documentation status
|
|
||||||
(`doc_url`, `has_sa`). Consumed by `check_docs.py`. **Not meant to be committed** — `location` shifts
|
|
||||||
on any unrelated code edit and `doc_url` changes when doc pages move, so a diff of this file mixes real
|
|
||||||
API changes with pure noise.
|
|
||||||
- `--surface-output` (minimal surface): each entry has only `scope`, `kind`, `name`, `identity_name`,
|
|
||||||
`tier`, `signature`, and `pretty_signature` — nothing that can change without the API itself changing.
|
|
||||||
**This is the file that gets committed** (`tools/api_checker/api_surface.json` for the current
|
|
||||||
working tree, `tools/api_checker/history/<tag>.json` per released tag) and diffed by `diff_api.py`.
|
|
||||||
|
|
||||||
**Identity keys — three approaches were tried and rejected before arriving at the current one:**
|
|
||||||
1. `{scope, name, kind, params}` from `cursor.get_arguments()`: silently collided for any overload set
|
|
||||||
differentiated only by constness, ref-qualifiers, or SFINAE constraints rather than parameter types —
|
|
||||||
confirmed empirically: `basic_json`'s two zero-argument `get()` overloads (one `const`, one not) both
|
|
||||||
produced `params=[]` and silently overwrote each other. A full scan found **59 such silent overwrites
|
|
||||||
across 27 colliding names**.
|
|
||||||
2. libclang's USR: correctly disambiguates every overload (it encodes the full mangled signature) — but
|
|
||||||
*also* encodes the enclosing class template's own arity into every member's USR. Confirmed
|
|
||||||
empirically against real release tags: `basic_json` gaining one new defaulted template parameter
|
|
||||||
between v3.11.2 and v3.11.3 (a backward-compatible change) changed literally every member's USR,
|
|
||||||
which made `diff_api.py` report **228 of 330 entries as "changed"** for a release with zero real
|
|
||||||
breaking changes among them.
|
|
||||||
3. **Current approach**: raw source-text signature capture — `identity = (scope, identity_name, kind,
|
|
||||||
signature)`, where `signature` is the declaration's own text (return type, name, parameter list,
|
|
||||||
trailing cv/ref/noexcept qualifiers; comments and constructors' member-initializer-lists stripped;
|
|
||||||
stops before the function body) read directly via the cursor's byte-offset extent. This is what's
|
|
||||||
actually written in source — declared names like `ValueType`, never a resolved
|
|
||||||
`basic_json<T0,...,T10>` — so it's immune to the class-arity problem above. Verified by manually
|
|
||||||
cross-referencing every "added"/"removed"/"changed" entry in three real release-to-release diffs
|
|
||||||
(v3.11.2→v3.11.3, v3.11.3→v3.12.0, v3.12.0→HEAD) against the actual `git diff` of the source — every
|
|
||||||
one confirmed genuine. Full details, including several further edge-case fixes found the same way
|
|
||||||
(a libclang tokenizer gap, comment-stripping, constructor-name arity-poisoning), are in
|
|
||||||
`extract_api.py`'s `identity_key()`/`get_signature_text()` docstrings.
|
|
||||||
|
|
||||||
**Output (full snapshot, from `--output`):**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"extracted_from": "include/nlohmann/json.hpp"
|
|
||||||
},
|
|
||||||
"public_api": {
|
|
||||||
"<opaque internal key, not meant to be read>": {
|
|
||||||
"scope": "nlohmann::basic_json",
|
|
||||||
"name": "parse",
|
|
||||||
"identity_name": "parse",
|
|
||||||
"kind": "CXX_METHOD",
|
|
||||||
"tier": "callable",
|
|
||||||
"signature": "static basic_json parse ( InputType && i , ... )",
|
|
||||||
"location": "include/nlohmann/json.hpp:4104",
|
|
||||||
"doc_url": "https://json.nlohmann.me/api/basic_json/parse/",
|
|
||||||
"has_sa": true,
|
|
||||||
"pretty_signature": "nlohmann::basic_json::parse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"documented_non_public": []
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`documented_non_public` lists entities **not** part of the public surface (private/protected members of
|
|
||||||
the six tracked classes) that surprisingly carry an `@sa` URL into the documentation site
|
|
||||||
(`https://json.nlohmann.me/`) — a genuine documentation leak. `@sa` links to anything else, such as GitHub
|
|
||||||
issues, are ignored. It does not list public entries that merely lack `@sa`; that's `check_docs.py`'s job.
|
|
||||||
|
|
||||||
**Output (surface, from `--surface-output`):**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"format_version": 1,
|
|
||||||
"meta": {
|
|
||||||
"extracted_from": "include/nlohmann/json.hpp"
|
|
||||||
},
|
|
||||||
"public_api": [
|
|
||||||
{
|
|
||||||
"scope": "nlohmann::basic_json",
|
|
||||||
"kind": "CXX_METHOD",
|
|
||||||
"name": "parse",
|
|
||||||
"identity_name": "parse",
|
|
||||||
"tier": "callable",
|
|
||||||
"signature": "static basic_json parse ( InputType && i , parser_callback_t cb = nullptr , const bool allow_exceptions = true , const bool ignore_comments = false )",
|
|
||||||
"pretty_signature": "nlohmann::basic_json::parse"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A flat, sorted list of self-describing records — `signature`/`identity_name` are the same values
|
|
||||||
`identity_key()` joins into one opaque internal string, exposed here as explicit fields so the file is
|
|
||||||
readable and diffable by inspection, not just by tooling. `identity_name` differs from `name` only for
|
|
||||||
constructors/destructors (a canonical `"(constructor)"`/`"(destructor)"` placeholder — see
|
|
||||||
`get_identity_name()`'s docstring for why `cursor.spelling` isn't used directly there).
|
|
||||||
|
|
||||||
`format_version` guards against a future change to this schema or to the identity-computing algorithm
|
|
||||||
silently corrupting a comparison against an older stored surface — bump it whenever such a change could
|
|
||||||
alter `signature`/`identity_name` text for otherwise-unchanged source (see `diff_api.py`).
|
|
||||||
|
|
||||||
### check_docs.py
|
|
||||||
|
|
||||||
Verify that all public API entries have valid documentation links and that no non-public entities
|
|
||||||
carry `@sa` comments.
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```bash
|
|
||||||
python3 tools/api_checker/check_docs.py --snapshot api_snapshot.json
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options:**
|
|
||||||
- `--snapshot PATH` — Full API snapshot JSON file from `extract_api.py --output` (default: `api_snapshot.json`)
|
|
||||||
|
|
||||||
**How it works:**
|
|
||||||
Two-pass validation over the extracted snapshot:
|
|
||||||
|
|
||||||
1. For every `public_api` entry (callable tier, and type tier minus STL exemptions): flag if missing `@sa`,
|
|
||||||
flag if `@sa` URL doesn't resolve to an existing documentation file (following `docs/mkdocs/mkdocs.yml`'s
|
|
||||||
`redirect_maps` when a page has moved, and trying the class-overview conventions used by different
|
|
||||||
classes — flat `<class>.md`, nested `<class>/<class>.md`, nested `<class>/index.md`)
|
|
||||||
2. For every `documented_non_public` entry: flag as unexpected `@sa` on a non-public entity
|
|
||||||
|
|
||||||
**Output:**
|
|
||||||
Prints warnings for each issue, categorized by rule:
|
|
||||||
- `docs/missing_sa_comment` — public API without `@sa` documentation link
|
|
||||||
- `docs/missing_doc_file` — `@sa` URL points to non-existent `.md` file
|
|
||||||
- `docs/invalid_sa_url` — malformed `@sa` URL
|
|
||||||
- `docs/sa_on_non_public` — unexpected `@sa` on a non-public entity
|
|
||||||
|
|
||||||
Exits with status 0 if all checks pass, 1 if issues found.
|
|
||||||
|
|
||||||
### diff_api.py
|
|
||||||
|
|
||||||
Compare the public API surface between two refs and classify changes as feature (added) or
|
|
||||||
breaking (removed / changed overload).
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```bash
|
|
||||||
python3 tools/api_checker/diff_api.py --old v3.12.0 --new HEAD
|
|
||||||
python3 tools/api_checker/diff_api.py --old v3.11.2 --new v3.11.3 # both resolved from history/
|
|
||||||
python3 tools/api_checker/diff_api.py --old v3.12.0 --new HEAD --fail-on-breaking
|
|
||||||
python3 tools/api_checker/diff_api.py --old-file a.json --new-file b.json # compare two files directly
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options:**
|
|
||||||
- `--old REF` / `--new REF` — Refs to compare (tags, branches, commits). `--new` defaults to `HEAD`.
|
|
||||||
Each is resolved by checking `tools/api_checker/history/<ref>.json` first (fast — no libclang or
|
|
||||||
git-archive needed), falling back to live extraction if no matching file exists there.
|
|
||||||
- `--old-file PATH` / `--new-file PATH` — Load an arbitrary surface JSON file directly, bypassing
|
|
||||||
both git and `tools/api_checker/history/`. Mutually exclusive with `--old`/`--new` respectively.
|
|
||||||
- `--no-history` — Force live extraction even when a matching `tools/api_checker/history/<ref>.json`
|
|
||||||
exists. Useful to check that a stored record is still faithful to a fresh run of the current tool.
|
|
||||||
- `--allow-format-mismatch` — Proceed even if the two surfaces have different `format_version`
|
|
||||||
(otherwise `diff_api.py` refuses — see below).
|
|
||||||
- `--header PATH` / `--include PATH` — For live extraction only (default:
|
|
||||||
`include/nlohmann/json.hpp` / `include`)
|
|
||||||
- `--fail-on-breaking` — Exit with status 1 if breaking changes are detected
|
|
||||||
|
|
||||||
**How it works:**
|
|
||||||
For a ref not found in `tools/api_checker/history/`, checks out the **full `include/` tree** at
|
|
||||||
that ref into a temp directory via `git archive` (a single-file checkout of `json.hpp` is not
|
|
||||||
enough — it `#include`s dozens of other headers that must exist at the same ref), then runs the
|
|
||||||
*current* `extract_api.py --surface-output` against it. Diffs the two surfaces by identity
|
|
||||||
(`scope`, `identity_name`, `kind`, `signature`):
|
|
||||||
- Identity only in the new surface → **feature**.
|
|
||||||
- Identity only in the old surface → **breaking** (removed).
|
|
||||||
- Same `(scope, name)` with a removed identity and an added identity → grouped as a **changed
|
|
||||||
overload**, breaking by default. No automatic overload-compatibility reasoning is attempted — a
|
|
||||||
human judges whether the change is actually source-compatible.
|
|
||||||
|
|
||||||
Before diffing, the two surfaces' `format_version` fields are compared; a mismatch aborts with an
|
|
||||||
error (override with `--allow-format-mismatch`) rather than silently producing an unsound diff — see
|
|
||||||
`extract_api.py`'s `SURFACE_FORMAT_VERSION` docstring for the incident that motivated this guard.
|
|
||||||
|
|
||||||
ABI-tag stripping is inherited automatically since both extractions go through the same
|
|
||||||
`extract_api.py`.
|
|
||||||
|
|
||||||
**Use case:** Run before cutting a release to verify the changelog correctly categorizes changes as
|
|
||||||
breaking vs. features.
|
|
||||||
|
|
||||||
### snapshot_release.py
|
|
||||||
|
|
||||||
Capture an immutable, per-release API surface record into `tools/api_checker/history/<tag>.json`.
|
|
||||||
This is what makes `diff_api.py` fast for released tags — see "How it works" above.
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```bash
|
|
||||||
python3 tools/api_checker/snapshot_release.py --ref v3.12.0
|
|
||||||
python3 tools/api_checker/snapshot_release.py --ref v3.11.0 --ref v3.12.0 # repeatable
|
|
||||||
python3 tools/api_checker/snapshot_release.py --all-tags # every v3.* tag
|
|
||||||
python3 tools/api_checker/snapshot_release.py --ref v3.12.0 --force # overwrite an existing record
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options:**
|
|
||||||
- `--ref REF` — Git tag to snapshot; repeatable
|
|
||||||
- `--all-tags` — Snapshot every `v3.*` tag (existing files are skipped unless `--force`)
|
|
||||||
- `--output-dir PATH` — Where to write (default: `tools/api_checker/history/`)
|
|
||||||
- `--force` — Overwrite an existing history file. History files are immutable by convention —
|
|
||||||
only pass this for a deliberate, reviewed regeneration; review the resulting diff before
|
|
||||||
committing
|
|
||||||
- `--header PATH` / `--include PATH` — Same as `diff_api.py`'s live-extraction options
|
|
||||||
|
|
||||||
**How it works:** Reuses `diff_api.py`'s `extract_surface_for_ref()` for the git-archive-and-extract
|
|
||||||
work, then adds `generated_at`/`generator` provenance and writes the result to
|
|
||||||
`tools/api_checker/history/<ref>.json`. Given multiple refs (or `--all-tags`), does **not** abort
|
|
||||||
the batch on one failing ref — collects failures and prints a summary at the end, so one
|
|
||||||
unparseable old tag doesn't block backfilling the releases that do work. See
|
|
||||||
`tools/api_checker/history/README.md` for the currently-known gaps (pre-restructuring tags that
|
|
||||||
predate the `include/nlohmann/` layout entirely).
|
|
||||||
|
|
||||||
**Not CI-automated** — this is a manual step in the release checklist (see below), by design.
|
|
||||||
|
|
||||||
### check_macros.py
|
|
||||||
|
|
||||||
Advisory-only cross-check between documented macros and their `#define`/reference sites. **Never blocks
|
|
||||||
CI**, regardless of findings.
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```bash
|
|
||||||
python3 tools/api_checker/check_macros.py
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options:**
|
|
||||||
- `--macros-dir PATH` — Directory of macro doc pages (default: `docs/mkdocs/docs/api/macros`)
|
|
||||||
- `--include-dir PATH` — Directory to search for `#define`/reference sites (default: `include/nlohmann`)
|
|
||||||
|
|
||||||
**How it works:**
|
|
||||||
For each `.md` page under `docs/mkdocs/docs/api/macros/` (excluding `index.md`), extracts the macro
|
|
||||||
name(s) from the H1 heading — handling both plain single-macro headings and multi-line HTML headings
|
|
||||||
that list a family of related macros (e.g. the `NLOHMANN_DEFINE_DERIVED_TYPE_*` family) — then checks
|
|
||||||
whether each name is defined **or referenced** (`#define`, `#ifdef`, `#ifndef`, `defined(...)`) anywhere
|
|
||||||
under `include/nlohmann/`. Referenced-but-not-defined is deliberately accepted: macros like
|
|
||||||
`JSON_NOEXCEPTION` or `JSON_THROW_USER` are user-supplied overrides that the library only checks for,
|
|
||||||
never defines itself.
|
|
||||||
|
|
||||||
Only checks the documented-macro-still-exists direction (catches stale/renamed doc pages). Does **not**
|
|
||||||
check the converse (undocumented macros) — see [POLICY.md](POLICY.md)'s "Known limitations" for why.
|
|
||||||
|
|
||||||
## Continuous Integration
|
|
||||||
|
|
||||||
A GitHub Actions workflow (`.github/workflows/check_api_docs.yml`) runs on every pull request:
|
|
||||||
|
|
||||||
1. Installs `clang` (system package, for include discovery) and Python dependencies
|
|
||||||
2. Runs `extract_api.py`, regenerating both the ephemeral full snapshot and the tracked
|
|
||||||
`tools/api_checker/api_surface.json`
|
|
||||||
3. Runs `check_docs.py` — **Phase 1: advisory** (`continue-on-error: true`), surfacing the doc backlog
|
|
||||||
without failing the job while it's burned down. Will flip to blocking once the backlog is cleared.
|
|
||||||
4. Runs `check_macros.py` — always advisory
|
|
||||||
5. Diffs `tools/api_checker/api_surface.json` against the regenerated copy — **blocking from the start**
|
|
||||||
(unlike the doc-backlog check, this is purely mechanical regeneration with no backlog to phase in,
|
|
||||||
matching the precedent set by `check_amalgamation.yml`). Uploads a patch artifact if it differs, so
|
|
||||||
contributors can `git apply` it instead of installing libclang locally.
|
|
||||||
|
|
||||||
## Workflow: Adding New Public API
|
|
||||||
|
|
||||||
1. Add the new public method/function to the header
|
|
||||||
2. Add a `/// @sa https://json.nlohmann.me/api/<class>/<member>/` comment above it
|
|
||||||
3. Create the corresponding documentation page at `docs/mkdocs/docs/api/<class>/<member>.md` and a
|
|
||||||
`mkdocs.yml` nav entry
|
|
||||||
4. Regenerate and commit the tracked surface file:
|
|
||||||
```bash
|
|
||||||
python3 tools/api_checker/extract_api.py --surface-output tools/api_checker/api_surface.json
|
|
||||||
git add tools/api_checker/api_surface.json
|
|
||||||
```
|
|
||||||
5. Push your PR — CI verifies both the doc link and that the surface file is up to date
|
|
||||||
|
|
||||||
## Workflow: Release Checklist
|
|
||||||
|
|
||||||
Before cutting a release:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Diff current API against the previous release
|
|
||||||
python3 tools/api_checker/diff_api.py --old v3.12.0 --new HEAD
|
|
||||||
|
|
||||||
# Review the output to verify the changelog correctly categorizes breaking vs. feature changes
|
|
||||||
```
|
|
||||||
|
|
||||||
After tagging the release:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Capture and commit the new tag's API surface, so future diffs against it hit the fast,
|
|
||||||
# stored-file path instead of live-extracting every time. A manual step, not CI-automated.
|
|
||||||
python3 tools/api_checker/snapshot_release.py --ref v3.13.0
|
|
||||||
git add tools/api_checker/history/v3.13.0.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
**libclang not found:**
|
|
||||||
```
|
|
||||||
Error: Could not locate libclang library
|
|
||||||
```
|
|
||||||
→ Ensure libclang is installed: `python3 -m pip install libclang==18.1.1`
|
|
||||||
|
|
||||||
**Parse errors in header:**
|
|
||||||
```
|
|
||||||
Parse errors encountered:
|
|
||||||
... list of diagnostics ...
|
|
||||||
```
|
|
||||||
→ Check that system includes can be discovered. Run `clang++ -E -x c++ -v /dev/null` and verify
|
|
||||||
the output includes a section titled `#include <...> search starts here:` with system paths.
|
|
||||||
If include discovery fails, use `--extra-isystem PATH` to provide additional paths.
|
|
||||||
|
|
||||||
**No API entries extracted (or very few):**
|
|
||||||
- Check that the header file exists and is valid C++: `ls -la include/nlohmann/json.hpp`
|
|
||||||
- Verify that no parse errors occur above
|
|
||||||
- Confirm that you're targeting a `CLASS_TEMPLATE` definition, not an implicit instantiation
|
|
||||||
(the tool logs `Found N public API entries` — a zero or very small count suggests the wrong cursor kind)
|
|
||||||
|
|
||||||
**Doc link returns 404:**
|
|
||||||
- Verify the file exists at the expected path: `docs/mkdocs/docs/api/<class>/<member>.md`
|
|
||||||
- Check for URL encoding issues (e.g., `operator[]` → `operator%5B%5D`)
|
|
||||||
- Verify the URL structure in the `@sa` comment: should be `https://json.nlohmann.me/api/<path>/`
|
|
||||||
- Check `docs/mkdocs/mkdocs.yml`'s `redirect_maps` if the page has moved
|
|
||||||
|
|
||||||
**`tools/api_checker/api_surface.json` is out of date in CI:**
|
|
||||||
→ Regenerate and commit it: `python3 tools/api_checker/extract_api.py --surface-output tools/api_checker/api_surface.json`
|
|
||||||
|
|
||||||
**`diff_api.py` refuses with "format_version mismatch":**
|
|
||||||
→ One side is a stored surface (live `api_surface.json` or a `tools/api_checker/history/*.json`
|
|
||||||
file) captured with an older/newer version of `extract_api.py`'s identity-computing algorithm than
|
|
||||||
the other side. Comparing them directly could produce an unsound diff (this is exactly the failure
|
|
||||||
mode that motivated adding the check — see `extract_api.py`'s `SURFACE_FORMAT_VERSION` docstring).
|
|
||||||
Either regenerate the older side with the current tool, or pass `--allow-format-mismatch` if you
|
|
||||||
understand the risk and want to proceed anyway.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Report bugs or suggest improvements to [Discussion #3691](https://github.com/nlohmann/json/discussions/3691).
|
|
||||||
Read [POLICY.md](POLICY.md) first for the definition of public API this tooling enforces.
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,183 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Verify that public API entries have documentation links."""
|
|
||||||
|
|
||||||
# Consumes an API snapshot from extract_api.py and checks:
|
|
||||||
# 1. Every public callable/type-tier entry has an @sa comment (with exceptions)
|
|
||||||
# 2. Every @sa URL resolves to an existing documentation file
|
|
||||||
# 3. No @sa comments appear on non-public entities
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
# subprocess is only called with fixed argument lists, never through a shell.
|
|
||||||
import subprocess # nosec B404
|
|
||||||
import sys
|
|
||||||
from urllib.parse import unquote
|
|
||||||
|
|
||||||
warnings = 0
|
|
||||||
|
|
||||||
# STL-container-named-requirement aliases that are exempt from @sa requirement
|
|
||||||
STL_EXEMPT = {'value_type', 'reference', 'const_reference', 'pointer', 'const_pointer',
|
|
||||||
'iterator', 'const_iterator', 'reverse_iterator', 'const_reverse_iterator',
|
|
||||||
'difference_type', 'size_type', 'allocator_type', 'key_type', 'mapped_type'}
|
|
||||||
|
|
||||||
|
|
||||||
def get_repo_root():
|
|
||||||
"""Find the repository root via git, so this script works regardless of invoking CWD."""
|
|
||||||
try:
|
|
||||||
result = subprocess.run( # nosec B603 B607
|
|
||||||
['git', 'rev-parse', '--show-toplevel'],
|
|
||||||
capture_output=True, text=True, check=True, timeout=10
|
|
||||||
)
|
|
||||||
return result.stdout.strip()
|
|
||||||
except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired):
|
|
||||||
return os.getcwd()
|
|
||||||
|
|
||||||
|
|
||||||
REPO_ROOT = get_repo_root()
|
|
||||||
MKDOCS_YML = os.path.join(REPO_ROOT, 'docs', 'mkdocs', 'mkdocs.yml')
|
|
||||||
|
|
||||||
|
|
||||||
def load_redirect_map() -> dict:
|
|
||||||
"""
|
|
||||||
Parse the redirect_maps block of docs/mkdocs/mkdocs.yml: {old_relative_path: new_relative_path}.
|
|
||||||
|
|
||||||
mkdocs' redirect plugin lets a doc page move without breaking existing @sa URLs -- e.g.
|
|
||||||
'api/basic_json/operator_ltlt.md' redirects to the real file at 'api/operator_ltlt.md'.
|
|
||||||
Without consulting this map, url_to_docfile() would flag every redirected URL as a broken link.
|
|
||||||
"""
|
|
||||||
if not os.path.exists(MKDOCS_YML):
|
|
||||||
return {}
|
|
||||||
with open(MKDOCS_YML) as f:
|
|
||||||
content = f.read()
|
|
||||||
redirect_map = {}
|
|
||||||
for m in re.finditer(r"^\s*'([^']+\.md)':\s*(\S+\.md)\s*$", content, re.MULTILINE):
|
|
||||||
redirect_map[m.group(1)] = m.group(2)
|
|
||||||
return redirect_map
|
|
||||||
|
|
||||||
|
|
||||||
REDIRECT_MAP = load_redirect_map()
|
|
||||||
|
|
||||||
|
|
||||||
def report(rule: str, location: str, description: str):
|
|
||||||
"""Report a documentation issue."""
|
|
||||||
global warnings
|
|
||||||
warnings += 1
|
|
||||||
print(f'{warnings:3}. {location}: {description} [{rule}]')
|
|
||||||
|
|
||||||
|
|
||||||
def url_to_docfile(url: str) -> str | None:
|
|
||||||
"""Convert @sa URL to the documentation file it resolves to, following mkdocs redirects."""
|
|
||||||
if not url:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Extract path after /api/
|
|
||||||
match = re.search(r'/api/(.+?)/?$', url)
|
|
||||||
if not match:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# URL-decode each path component
|
|
||||||
path_parts = [unquote(part) for part in match.group(1).split('/')]
|
|
||||||
relative_path = 'api/' + '/'.join(path_parts) + '.md'
|
|
||||||
|
|
||||||
docs_root = os.path.join(REPO_ROOT, 'docs', 'mkdocs', 'docs')
|
|
||||||
direct_path = os.path.join(docs_root, relative_path)
|
|
||||||
|
|
||||||
# Class-overview URLs (a single path segment after /api/, e.g. ".../api/json_pointer/")
|
|
||||||
# use inconsistent on-disk conventions across classes: ordered_map.md is a flat file,
|
|
||||||
# byte_container_with_subtype/byte_container_with_subtype.md nests under a same-named
|
|
||||||
# file, json_pointer/index.md nests under index.md. Try all observed conventions.
|
|
||||||
candidates = [direct_path]
|
|
||||||
if len(path_parts) == 1:
|
|
||||||
stem = path_parts[0]
|
|
||||||
candidates.append(os.path.join(docs_root, 'api', stem, 'index.md'))
|
|
||||||
candidates.append(os.path.join(docs_root, 'api', stem, stem + '.md'))
|
|
||||||
|
|
||||||
redirected = REDIRECT_MAP.get(relative_path)
|
|
||||||
if redirected:
|
|
||||||
candidates.append(os.path.join(docs_root, redirected))
|
|
||||||
|
|
||||||
for candidate in candidates:
|
|
||||||
if os.path.exists(candidate):
|
|
||||||
return candidate
|
|
||||||
|
|
||||||
# Nothing resolved -- return the direct path so the caller reports a meaningful "missing" location.
|
|
||||||
return direct_path
|
|
||||||
|
|
||||||
|
|
||||||
def check_docs(snapshot_path: str):
|
|
||||||
"""Check documentation for all API entries."""
|
|
||||||
if not os.path.exists(snapshot_path):
|
|
||||||
print(f"Error: Snapshot file not found: {snapshot_path}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
with open(snapshot_path, 'r') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
api = data.get('public_api', {})
|
|
||||||
documented_non_public = data.get('documented_non_public', [])
|
|
||||||
|
|
||||||
print(f"Checking documentation for {len(api)} API entries...")
|
|
||||||
print(120 * "-")
|
|
||||||
|
|
||||||
# Check public API entries
|
|
||||||
for _identity_key, entry in sorted(api.items()):
|
|
||||||
location = entry.get('location', 'unknown')
|
|
||||||
name = entry.get('name', '?')
|
|
||||||
tier = entry.get('tier', '?')
|
|
||||||
doc_url = entry.get('doc_url')
|
|
||||||
has_sa = entry.get('has_sa', False)
|
|
||||||
|
|
||||||
# Skip type_exempt tier entries
|
|
||||||
if tier == 'type_exempt':
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Check for missing @sa
|
|
||||||
if not has_sa:
|
|
||||||
report('docs/missing_sa_comment', location,
|
|
||||||
f'public API "{name}" (tier: {tier}) has no @sa documentation link')
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Verify URL resolves to an existing file
|
|
||||||
doc_file = url_to_docfile(doc_url)
|
|
||||||
if not doc_file:
|
|
||||||
report('docs/invalid_sa_url', location,
|
|
||||||
f'public API "{name}" has invalid @sa URL: {doc_url}')
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not os.path.exists(doc_file):
|
|
||||||
display_path = os.path.relpath(doc_file, REPO_ROOT)
|
|
||||||
report('docs/missing_doc_file', location,
|
|
||||||
f'public API "{name}" @sa URL points to non-existent file: {display_path}')
|
|
||||||
|
|
||||||
# Check documented_non_public entries
|
|
||||||
for entry in documented_non_public:
|
|
||||||
location = entry.get('location', 'unknown')
|
|
||||||
reason = entry.get('reason', '?')
|
|
||||||
report('docs/sa_on_non_public', location,
|
|
||||||
f'@sa comment found on non-public entity: {reason}')
|
|
||||||
|
|
||||||
print(120 * "-")
|
|
||||||
|
|
||||||
if warnings > 0:
|
|
||||||
print(f"\nFound {warnings} documentation issues")
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
print("\nAll public API entries are properly documented ✓")
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description='Check documentation for public API')
|
|
||||||
parser.add_argument('--snapshot', default='api_snapshot.json',
|
|
||||||
help='Path to API snapshot JSON file')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if not check_docs(args.snapshot):
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Advisory-only cross-check between documented macros and their #define sites."""
|
|
||||||
|
|
||||||
# Macros have no C++ access-specifier concept, so the AST-based public/private test that
|
|
||||||
# extract_api.py uses for classes doesn't transfer -- see tools/api_checker/POLICY.md's "Known
|
|
||||||
# limitations" section. This script only checks one direction: that every macro documented under
|
|
||||||
# docs/mkdocs/docs/api/macros/ still has a matching #define somewhere under include/nlohmann/,
|
|
||||||
# catching stale or renamed doc pages. It does NOT check the converse (undocumented macros) --
|
|
||||||
# no reliable signal exists for that direction given this codebase's conventions.
|
|
||||||
#
|
|
||||||
# Never blocks CI -- always exits 0, even when it reports findings.
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
MACRO_TOKEN_RE = re.compile(r'\b([A-Z][A-Z0-9_]*)\b')
|
|
||||||
|
|
||||||
warnings = 0
|
|
||||||
|
|
||||||
|
|
||||||
def report(location: str, description: str):
|
|
||||||
global warnings
|
|
||||||
warnings += 1
|
|
||||||
print(f'{warnings:3}. {location}: {description}')
|
|
||||||
|
|
||||||
|
|
||||||
def extract_macro_names(md_path: str) -> list:
|
|
||||||
"""
|
|
||||||
Extract macro name(s) from a doc page's H1 heading.
|
|
||||||
|
|
||||||
Most pages use a single-line markdown heading ('# JSON_ASSERT'). A few document a family of
|
|
||||||
related macros under one page using a multi-line HTML heading listing comma-separated names
|
|
||||||
(e.g. NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, ..._WITH_DEFAULT, ..._ONLY_SERIALIZE). Handle
|
|
||||||
both: collect the heading text (markdown '# ...' line, or everything between <h1> and </h1>,
|
|
||||||
which may span multiple lines), then split on commas.
|
|
||||||
"""
|
|
||||||
with open(md_path) as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
heading_text = None
|
|
||||||
html_match = re.search(r'<h1>(.*?)</h1>', content, re.DOTALL)
|
|
||||||
if html_match:
|
|
||||||
heading_text = html_match.group(1)
|
|
||||||
else:
|
|
||||||
for line in content.splitlines():
|
|
||||||
if line.startswith('# '):
|
|
||||||
heading_text = line[2:]
|
|
||||||
break
|
|
||||||
|
|
||||||
if not heading_text:
|
|
||||||
return []
|
|
||||||
|
|
||||||
names = []
|
|
||||||
for part in heading_text.split(','):
|
|
||||||
match = MACRO_TOKEN_RE.search(part)
|
|
||||||
if match:
|
|
||||||
names.append(match.group(1))
|
|
||||||
return names
|
|
||||||
|
|
||||||
|
|
||||||
def macro_is_referenced(macro_name: str, include_dir: str) -> bool:
|
|
||||||
"""
|
|
||||||
Check whether macro_name is defined or referenced anywhere under include_dir.
|
|
||||||
|
|
||||||
A reference is any #ifdef, #ifndef, or defined() check.
|
|
||||||
|
|
||||||
Some documented macros (e.g. JSON_NOEXCEPTION, JSON_THROW_USER) are user-supplied overrides:
|
|
||||||
the library only checks whether they're defined, it never #defines them itself. Requiring a
|
|
||||||
literal #define would make this advisory check permanently noisy for that whole category, so
|
|
||||||
presence of any reference is treated as "this macro still exists in the codebase."
|
|
||||||
"""
|
|
||||||
pattern = re.compile(
|
|
||||||
r'#\s*define\s+' + re.escape(macro_name) + r'\b'
|
|
||||||
r'|#\s*ifn?def\s+' + re.escape(macro_name) + r'\b'
|
|
||||||
r'|defined\s*\(\s*' + re.escape(macro_name) + r'\s*\)'
|
|
||||||
r'|defined\s+' + re.escape(macro_name) + r'\b'
|
|
||||||
)
|
|
||||||
for root, _dirs, files in os.walk(include_dir):
|
|
||||||
for fname in files:
|
|
||||||
if not fname.endswith('.hpp'):
|
|
||||||
continue
|
|
||||||
path = os.path.join(root, fname)
|
|
||||||
with open(path, encoding='utf-8', errors='ignore') as f:
|
|
||||||
if pattern.search(f.read()):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def check_macros(macros_dir: str, include_dir: str) -> bool:
|
|
||||||
md_files = sorted(glob.glob(os.path.join(macros_dir, '*.md')))
|
|
||||||
md_files = [f for f in md_files if os.path.basename(f) != 'index.md']
|
|
||||||
|
|
||||||
print(f"Checking {len(md_files)} documented macros against #define sites in {include_dir}...")
|
|
||||||
print(120 * "-")
|
|
||||||
|
|
||||||
for md_path in md_files:
|
|
||||||
macro_names = extract_macro_names(md_path)
|
|
||||||
if not macro_names:
|
|
||||||
report(md_path, "could not extract macro name(s) from H1 heading")
|
|
||||||
continue
|
|
||||||
|
|
||||||
for macro_name in macro_names:
|
|
||||||
if not macro_is_referenced(macro_name, include_dir):
|
|
||||||
report(md_path, f'documented macro "{macro_name}" is not defined or referenced under {include_dir}')
|
|
||||||
|
|
||||||
print(120 * "-")
|
|
||||||
|
|
||||||
if warnings > 0:
|
|
||||||
print(f"\nFound {warnings} stale/renamed macro doc pages (advisory only, not blocking)")
|
|
||||||
else:
|
|
||||||
print("\nAll documented macros have a matching #define ✓")
|
|
||||||
|
|
||||||
return warnings == 0
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description='Advisory cross-check of documented macros vs. #define sites')
|
|
||||||
parser.add_argument('--macros-dir', default='docs/mkdocs/docs/api/macros',
|
|
||||||
help='Directory containing macro documentation pages')
|
|
||||||
parser.add_argument('--include-dir', default='include/nlohmann',
|
|
||||||
help='Directory to search for #define sites')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
check_macros(args.macros_dir, args.include_dir)
|
|
||||||
# Advisory only -- never fail CI regardless of findings.
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user