Compare commits

...
Author SHA1 Message Date
Niels Lohmann 64a5d233d0 json_view: from_json() of the macros reads views directly
get<T>() and get_to() of a view call T's from_json() with the view itself
when that from_json() accepts views but not an unrelated probe type, and
fall back to materialize() otherwise. The from_json() functions of the
NLOHMANN_DEFINE_TYPE_*, NLOHMANN_DEFINE_DERIVED_TYPE_* and
NLOHMANN_JSON_SERIALIZE_ENUM(_STRICT) macros accept basic_json values and
views; a derived type whose base reads only json reads the base part
through materialize(). The library's own from_json() overloads are not
called with views: from_json() of a view (and of the probe) only looks up
functions by ADL.

New public trait nlohmann::is_json_view<T>, and the member type
basic_json_type of basic_json_view. With duplicate keys, the members of
such a T are those the view's lookups find (the first ones).

bench_decode.cpp measures decoding into structs (4-6x faster than
materialize().get<T>() on twitter, citm_catalog, and synthetic records).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-25 13:33:39 +01:00
Niels Lohmann 315bd04c55 json_view: one SIMD macro set with the library
The view's vector code follows JSON_NO_SIMD, like the lexer and the float
writer, and skips the CPU check of SSSE3 when the code is compiled for
SSSE3 anyway (__SSSE3__), like the lexer. JSON_VIEW_NO_SIMD and
JSON_VIEW_USE_SSSE3 and their ABI tags _vns and _vssse3 are removed; they
were never released. JSON_NO_SIMD keeps its tag _ns.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-25 12:17:42 +01:00
Niels Lohmann ea3dca202b json_view: no save() and load() on big-endian targets
The image format is little-endian only. Instead of throwing
type_error.320 at runtime, save_image(), load_image() and the members
save() and load() do not exist on a big-endian target, so a call fails to
compile, like set() on a read-only document. type_error.320 remains for
saving a discarded document.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-25 12:12:21 +01:00
Niels Lohmann bcc19dca3f json_view: view_mode enum instead of bool Editable, node_kind for node::kind
basic_json_document and basic_json_view take a view_mode (read_only, the
default, or editable) instead of a bool: basic_json_document<json, true>
did not say what true means. The shortcut aliases are unchanged.

The kind of a node is a node_kind (the value_t values plus link, 10 as
before), which removes the static_cast<std::uint8_t>(value_t::...) of
every comparison. The node and image layouts are unchanged.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-25 12:07:13 +01:00
75 changed files with 1898 additions and 4284 deletions

No files matched your search

+3 -3
View File
@@ -163,9 +163,9 @@ jobs:
python3 $GENERATOR --list-tags
TAG_COUNT=$(python3 $GENERATOR --list-tags | wc -l)
python3 $GENERATOR --abi-tags diag,_dp,_vns --abi-tags _diag --output $RUNNER_TEMP/abi_tags.natvis
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_vns -->' $RUNNER_TEMP/abi_tags.natvis
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_vns_v[0-9_]* -->' $RUNNER_TEMP/abi_tags.natvis
python3 $GENERATOR --abi-tags diag,_dp,_ns --abi-tags _diag --output $RUNNER_TEMP/abi_tags.natvis
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_ns -->' $RUNNER_TEMP/abi_tags.natvis
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_ns_v[0-9_]* -->' $RUNNER_TEMP/abi_tags.natvis
test $(grep -c '<!-- Namespace ' $RUNNER_TEMP/abi_tags.natvis) -eq $(( $(grep -c '<!-- Namespace ' nlohmann_json.natvis) + 2 ))
python3 $GENERATOR --all --output $RUNNER_TEMP/all.natvis
+1
View File
@@ -90,6 +90,7 @@ cc_library(
"include/nlohmann/detail/view/simd.hpp",
"include/nlohmann/detail/view/string_ref.hpp",
"include/nlohmann/detail/view/value.hpp",
"include/nlohmann/detail/view/view_mode.hpp",
"include/nlohmann/json.hpp",
"include/nlohmann/json_fwd.hpp",
"include/nlohmann/json_literals.hpp",
+1 -1
View File
@@ -309,7 +309,7 @@ The "Check amalgamation" workflow fails if the file is out of date.
The file covers the namespace variants with up to two ABI tags. A Natvis file for other configurations can be
generated with the `--abi-tags` or `--all` options, for example
`make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my_nlohmann_json.natvis"`; see
`make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my_nlohmann_json.natvis"`; see
[`tools/generate_natvis`](tools/generate_natvis/README.md). With MSVC, CMake adds the file to the `nlohmann_json`
target and installs it.
+1 -1
View File
@@ -120,7 +120,7 @@ $(AMALGAMATED_VIEW_FILE): $(SRCS)
tools/amalgamate/amalgamate.py -c tools/amalgamate/config_json_view.json -s . --verbose=yes
NATVIS_VENV=tools/generate_natvis/venv
# extra options for generate_natvis.py, e.g. NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my.natvis"
# extra options for generate_natvis.py, e.g. NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my.natvis"
NATVIS_ARGS=
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
@@ -12,7 +12,7 @@ void erase(view_type array, I idx);
std::size_t erase(const json_pointer& ptr);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
has `erase`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
1. Removes every member of `object` whose key is `key` (see [Notes](#notes) on duplicate keys) and returns how many
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
template<typename BasicJsonType, bool Editable = false>
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
class basic_json_document;
```
@@ -20,9 +20,9 @@ is move-only: a copy would duplicate the whole index, the decoded-string buffer,
enough in every use we know of. The index, the decoded strings, and the owned text live in one heap block that the
document holds through a `#!cpp std::unique_ptr`; this is also why views survive a move of the document.
With `#!cpp Editable == true`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
With `#!cpp Mode == view_mode::editable`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
[`insert`](insert.md), and [`erase`](erase.md) to change values in place, see [Edits](#edits) below. The source text
itself is never written; a read-only document (`#!cpp Editable == false`, the default) does not carry any of the
itself is never written; a read-only document (`#!cpp view_mode::read_only`, the default) does not carry any of the
bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp static_assert`).
## Template parameters
@@ -32,9 +32,10 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
[`ordered_json`](../ordered_json.md). Only 64-bit `number_integer_t`/`number_unsigned_t` types are supported; this
is checked with a `static_assert`.
`Editable`
: whether the document supports [`set`](set.md), [`push_back`](push_back.md), [`insert`](insert.md), and
[`erase`](erase.md) (optional, `#!cpp false` by default). See [Edits](#edits) below.
`Mode`
: a [`view_mode`](../view_mode.md): `#!cpp view_mode::editable` if the document supports [`set`](set.md),
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md) (optional, `#!cpp view_mode::read_only`
by default). See [Edits](#edits) below.
## Specializations
@@ -47,7 +48,7 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
## Member types
- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view<BasicJsonType, Editable>`)
- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view<BasicJsonType, Mode>`)
- **value_t** - the JSON type enumeration, see [`basic_json::value_t`](../basic_json/value_t.md)
- **image_check** - how [`load()`](load.md) validates an image (`full`, `bounds`, `none`), see [`image_check`](load.md#image_check)
@@ -80,15 +81,15 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
### Edits
- [**set**](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers
to (`#!cpp Editable` documents only)
- [**push_back**](push_back.md) - append to an array (`#!cpp Editable` documents only)
- [**insert**](insert.md) - insert an element into an array before a given position (`#!cpp Editable` documents only)
to (editable documents only)
- [**push_back**](push_back.md) - append to an array (editable documents only)
- [**insert**](insert.md) - insert an element into an array before a given position (editable documents only)
- [**erase**](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
(`#!cpp Editable` documents only)
(editable documents only)
## Edits
An editable document (`#!cpp Editable == true`) can be changed after parsing, with [`set`](set.md),
An editable document (`#!cpp view_mode::editable`) can be changed after parsing, with [`set`](set.md),
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md);
[`json_editable_document`](../json_editable_document.md) and
[`ordered_json_editable_document`](../ordered_json_editable_document.md) are the corresponding specializations. A few
@@ -5,7 +5,7 @@ template<typename I, typename V>
view_type insert(view_type array, I idx, V&& value);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
has `insert`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
Inserts `value` into `array` as a new element before position `idx`, which must not be past the end
@@ -55,10 +55,7 @@ validate with overload 2 first, if the original vector must survive a failed loa
## Exceptions
On a big-endian target, throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) -- the same
exception [`save()`](save.md#exceptions) throws there, since the image format is little-endian only.
Otherwise throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
Throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
`save()` could have written, or fails the requested `check`:
| message | when |
@@ -95,6 +92,9 @@ are checked once, however many nodes refer to it.
## Notes
**Little-endian targets only.** On a big-endian target, `load()` does not exist, just like
[`save()`](save.md#notes): the image format is little-endian, so a call fails to compile.
### `image_check` { #image_check }
```cpp
@@ -13,7 +13,7 @@ editable, and it does not have to be `array`'s own document -- which is copied s
source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
has `push_back`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
## Template parameters
@@ -12,7 +12,7 @@ An edited document is written in its *current* state, with its values in documen
parser would have produced them for that JSON text: a member [`set`](set.md) added goes at the end, an
[`erase`](erase.md)d member leaves no trace, and a float that is not finite (NaN or positive/negative infinity)
becomes null, the same substitution [`dump()`](../basic_json_view/dump.md) makes. The same document always saves to
the same bytes -- also across `BasicJsonType` and `#!cpp Editable`, since the image reflects document order and
the same bytes -- also across `BasicJsonType` and the [`view_mode`](../view_mode.md), since the image reflects document order and
values only, not which specialization produced them.
## Return value
@@ -31,9 +31,6 @@ Throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) i
[discarded](is_discarded.md) -- a default-constructed document, or one a failed [`parse()`](parse.md)/
[`read()`](read.md) with `allow_exceptions == false` left discarded.
On a big-endian target, throws `type_error.320` with a different message instead: the image format is little-endian
only (see [Notes](#notes)).
Throws [`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the node count, the text, or
the decoded strings of the image would individually reach 4 GiB -- the same 32-bit offsets
[`parse()`](parse.md#exceptions) and, for edits, [`set`](set.md)/[`push_back`](push_back.md) are already limited to.
@@ -44,9 +41,6 @@ the decoded strings of the image would individually reach 4 GiB -- the same 32-b
[json.exception.type_error.320] cannot save a discarded json_document
```
```
[json.exception.type_error.320] json_document images need a little-endian target
```
```
[json.exception.out_of_range.416] images of 4 GiB or more are not supported by json_document
```
@@ -70,9 +64,9 @@ else -- see [`load`'s Exceptions](load.md#exceptions).
the *same* build on the *same* (little-endian) machine -- not as a long-term storage format. Keep the original
JSON text if you need to read a saved document back with a future library version.
**Little-endian only.** The image is written as raw little-endian bytes, with no byte-swapping. `save()` (and
[`load`](load.md)) throw `type_error.320` on a big-endian target rather than silently produce bytes a big-endian
reader could not interpret correctly.
**Little-endian targets only.** The image is written as raw little-endian bytes, with no byte-swapping. On a
big-endian target, `save()` and [`load`](load.md) do not exist: a call fails to compile rather than produce bytes a
big-endian reader could not interpret correctly.
## Examples
@@ -18,7 +18,7 @@ template<typename V>
view_type set(const json_pointer& ptr, V&& value);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
has `set`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
1. Replaces the value `target` refers to with `value`.
+25 -3
View File
@@ -27,8 +27,25 @@ For the types below, the conversion works directly on the flat index -- no `Basi
[`materialize()`](materialize.md)) does; `#!cpp std::map<std::string, basic_json_view>` keeps views of the members
instead of values
Every other `T` -- `#!cpp std::list`, `#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a
`from_json()`, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
A default-constructible `T` whose `from_json()` accepts views reads the view directly as well, member by member, without
building a `BasicJsonType` value. This covers the types of the
[`NLOHMANN_DEFINE_TYPE_*`](../macros/nlohmann_define_type_intrusive.md) and
[`NLOHMANN_DEFINE_DERIVED_TYPE_*`](../macros/nlohmann_define_derived_type.md) macros and the enumerations of
[`NLOHMANN_JSON_SERIALIZE_ENUM`](../macros/nlohmann_json_serialize_enum.md), and any `from_json()` constrained to
accept views, e.g. with [`is_json_view`](../is_json_view.md). A `from_json()` that also accepts types that are no JSON
values at all, such as the unconstrained `#!cpp template<typename BasicJsonType> void from_json(const BasicJsonType&,
T&)` of [arbitrary type conversions](../../features/arbitrary_types.md), is not called with a view: it may use
`BasicJsonType` functions a view does not have. See [json_view](../../features/json_view.md).
!!! warning "Duplicate keys"
Such a `from_json()` looks members up in the view, where a repeated key finds the **first** member, while
`#!cpp materialize().get<T>()` sees the **last** one, as [`BasicJsonType::parse()`](../basic_json/parse.md)
keeps it: for `#!cpp {"x":1,"x":2}`, `#!cpp get<point>()` reads `#!cpp x == 1`. See
[Duplicate keys](../../features/json_view.md#duplicate-keys).
Every other `T` -- `#!cpp std::list`, `#!cpp std::pair`, `#!cpp std::array`, user types whose `from_json()` is
written for `BasicJsonType` only, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
value first (as [`BasicJsonType::parse()`](../basic_json/parse.md) would), and converted from there exactly as
[`BasicJsonType::get<T>()`](../basic_json/get.md) would convert it.
@@ -55,10 +72,13 @@ Strong guarantee: there are no changes to the view or the document it refers to.
an element to `U` throws.
- For `#!cpp std::map`/`#!cpp std::unordered_map`: throws `type_error.302` if the value is not an object; otherwise,
whatever converting a member to the mapped type throws.
- For a `T` whose `from_json()` reads the view: whatever that `from_json()` throws; for the macros, the same
exceptions with the same messages as [`BasicJsonType::get<T>()`](../basic_json/get.md) of the same value.
- For every other `T`: whatever [`materialize().get<T>()`](../basic_json/get.md) throws -- typically `type_error.302`,
or whatever a user-provided `from_json()` throws.
None of the exceptions thrown directly by this function (the first three bullets above) carry a
None of the exceptions thrown directly by this function or by a `from_json()` that reads the view (the first four
bullets above) carry a
[`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no `BasicJsonType` value to point at. An
exception thrown while converting through `materialize()` (the last bullet) is different: it is thrown by a real
`BasicJsonType` value, so it **does** carry a `JSON_DIAGNOSTICS` path if `BasicJsonType` was built with it enabled.
@@ -76,6 +96,8 @@ document.
- `#!cpp std::map`/`#!cpp std::unordered_map`: linear in the number of members for walking them, plus the container's
own insertion cost per member (logarithmic for `#!cpp std::map`, amortized constant for `#!cpp
std::unordered_map`), times the complexity of converting one member to the mapped type.
- a `T` whose `from_json()` reads the view: the cost of that `from_json()`; for the macros, linear in the number of
members times the cost of a lookup, plus the cost of converting the members.
- every other `T`: the cost of [`materialize()`](materialize.md) and of destroying the `BasicJsonType` value
afterwards, plus that of [`BasicJsonType::get<T>()`](../basic_json/get.md).
@@ -5,12 +5,14 @@ template<typename T>
T& get_to(T& v) const;
```
Converts the value to `T` and stores it in `v`, in one of two ways:
Converts the value to `T` and stores it in `v`, in one of three ways:
- For the types that [`get<T>()`](get.md) converts directly -- arithmetic types, `#!cpp bool`,
`#!cpp std::nullptr_t`, [`string_view_t`](index.md#member-types), `#!cpp std::basic_string`, `BasicJsonType`,
`basic_json_view`, `#!cpp std::vector`, and `#!cpp std::map`/`#!cpp std::unordered_map` with string keys -- `v` is
assigned: `#!cpp v = get<T>()`.
- For a type whose `from_json()` accepts views (see [`get<T>()`](get.md)), that `from_json()` is called with the
view and the existing `v`, without building a `BasicJsonType` value.
- For every other type, the subtree is built into a `BasicJsonType` value and `#!cpp materialize().get_to(v)` is
called, i.e. `from_json()` is invoked with the existing `v`, exactly as
[`BasicJsonType::get_to()`](../basic_json/get_to.md) does.
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
template<typename BasicJsonType, bool Editable = false>
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
class basic_json_view;
```
@@ -37,7 +37,7 @@ Moving the document itself does not invalidate its views: the index is heap-allo
`#!cpp operator ValueType()`), and no `#!cpp get_ptr()` or `#!cpp get_ref()`; see [`get`](get.md).
`basic_json_view` itself is always read-only -- it never has a `set` or `push_back` of its own. A view of an
**editable** document (`#!cpp Editable == true`) sees every edit made through
**editable** document (`#!cpp view_mode::editable`) sees every edit made through
[`basic_json_document::set`](../basic_json_document/set.md) and
[`basic_json_document::push_back`](../basic_json_document/push_back.md): once a value is changed, every view that
still refers to it -- including ones taken before the change -- reads the new value. See
@@ -49,9 +49,10 @@ still refers to it -- including ones taken before the change -- reads the new va
: a specialization of [`basic_json`](../basic_json/index.md), matching the
[`basic_json_document`](../basic_json_document/index.md) the view was taken from.
`Editable`
: whether the view is of an editable document, matching the [`basic_json_document`](../basic_json_document/index.md)
it was taken from (optional, `#!cpp false` by default). See [Edits](../basic_json_document/index.md#edits).
`Mode`
: a [`view_mode`](../view_mode.md): whether the view is of an editable document, matching the
[`basic_json_document`](../basic_json_document/index.md) it was taken from (optional, `#!cpp view_mode::read_only` by
default). See [Edits](../basic_json_document/index.md#edits).
## Specializations
@@ -63,6 +64,7 @@ still refers to it -- including ones taken before the change -- reads the new va
## Member types
- **basic_json_type** - `BasicJsonType` (it also marks the class for [`is_json_view`](../is_json_view.md))
- **value_t** - the JSON type enumeration, see [`basic_json::value_t`](../basic_json/value_t.md)
- **string_t**, **number_integer_t**, **number_unsigned_t**, **number_float_t**, **json_pointer** - the corresponding
member types of `BasicJsonType`
+55
View File
@@ -0,0 +1,55 @@
# <small>nlohmann::</small>is_json_view
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
template<typename T>
struct is_json_view;
```
A type trait: `#!cpp is_json_view<T>::value` is `#!cpp true` if `T` is a [`basic_json_view`](basic_json_view/index.md)
of any `BasicJsonType` and any [`view_mode`](view_mode.md) -- [`json_view`](json_view.md),
[`json_editable_view`](json_editable_view.md), [`ordered_json_view`](ordered_json_view.md), ... -- and
`#!cpp false` otherwise, for [`basic_json`](basic_json/index.md) as well.
It is meant for constraining templates that accept views, in particular a `from_json()` that should read views
directly: [`get<T>()`](basic_json_view/get.md) on a view calls a `from_json()` with the view only if that `from_json()`
accepts views but not arbitrary types.
## Template parameters
`T`
: the type to check (without cv-qualifiers or references)
## Notes
A view is recognized by its member type `basic_json_type` (a [`basic_json`](basic_json/index.md) specialization) and
its [`materialize()`](basic_json_view/materialize.md) returning that type, so the trait needs no declaration of the
view class.
## Examples
??? example
The example below shows the trait, and a `from_json()` constrained to `json` values and views: `get<T>()` on a view
reads the view directly.
```cpp
--8<-- "examples/is_json_view.cpp"
```
Output:
```
--8<-- "examples/is_json_view.output"
```
## See also
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
- [get](basic_json_view/get.md) - which conversions read the view directly
- [view_mode](view_mode.md) - read-only or editable
## Version history
Added in version 3.13.0.
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
using json_editable_document = basic_json_document<json, true>;
using json_editable_document = basic_json_document<json, view_mode::editable>;
```
This type is an **editable** [`basic_json_document`](basic_json_document/index.md) of the default
+1 -1
View File
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
using json_editable_view = basic_json_view<json, true>;
using json_editable_view = basic_json_view<json, view_mode::editable>;
```
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of a
-2
View File
@@ -43,8 +43,6 @@ header. See also the [macro overview page](../../features/macros.md).
- [**JSON_SKIP_UNSUPPORTED_COMPILER_CHECK**](json_skip_unsupported_compiler_check.md) - do not warn about unsupported compilers
- [**JSON_USE_GLOBAL_UDLS**](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace
- [**JSON_USE_SIMDUTF**](json_use_simdutf.md) - use the simdutf library to accelerate UTF-8 validation
- [**JSON_VIEW_NO_SIMD**](json_view_no_simd.md) - use only portable code in the parser of `json_view.hpp`
- [**JSON_VIEW_USE_SSSE3**](json_view_use_ssse3.md) - validate non-ASCII strings with SSSE3 in the parser of `json_view.hpp`
## Library version
+3 -1
View File
@@ -5,7 +5,8 @@
```
When defined, the library uses only portable C++ code where it would otherwise use vector instructions: when scanning
strings during parsing, and when writing floating-point numbers during serialization.
strings during parsing, and when writing floating-point numbers during serialization. This includes the parser of
[`basic_json_document`](../basic_json_document/index.md) (`<nlohmann/json_view.hpp>`).
The macro is an escape hatch, for example for toolchains that cannot compile the vector code, for sanitizers or
analyzers that do not understand it, or to compare the speed of both variants. It does not change any result: values,
@@ -77,6 +78,7 @@ By default, `#!cpp JSON_NO_SIMD` is not defined, and vector instructions are use
- [**JSON_USE_SIMDUTF**](json_use_simdutf.md) - use the simdutf library to accelerate UTF-8 validation
- [**JSON_DISABLE_STREAM_BULK_SCAN**](json_disable_stream_bulk_scan.md) - read a `std::istream` one character at a time
- [Parsing: input sources and performance](../../features/parsing/index.md#input-sources-and-performance)
- [json_view](../../features/json_view.md) - the zero-copy view, whose parser the macro also affects
## Version history
@@ -1,52 +0,0 @@
# JSON_VIEW_NO_SIMD
```cpp
#define JSON_VIEW_NO_SIMD
```
When defined, the parser of [`basic_json_document`](../basic_json_document/index.md) (`<nlohmann/json_view.hpp>`)
uses only portable C++ to scan strings. By default, it scans long runs of string bytes 16 at a time with NEON on
AArch64 (with GCC and Clang) and SSE2 on x86-64, which are part of the baseline instruction sets of these
architectures, and validates non-ASCII text with NEON (or SSSE3, see
[`JSON_VIEW_USE_SSSE3`](json_view_use_ssse3.md)).
The same input is accepted or rejected either way, with the same values, and errors are reported the same way; only
the speed differs. The macro exists for platforms whose compilers lack the intrinsics headers, and to test the portable
code.
!!! note "ABI compatibility"
The macro selects between two definitions of the same inline functions. Whether it is defined is encoded in the
[namespace](../../features/namespace.md) (tag `_vns`), resulting in distinct symbol names. Translation units
compiled with and without it can therefore be linked into the same program without One Definition Rule (ODR)
violations, but they cannot exchange instances of library types.
## Default definition
By default, `#!cpp JSON_VIEW_NO_SIMD` is not defined, and the vector code is used where available.
```cpp
#undef JSON_VIEW_NO_SIMD
```
## Examples
??? example
The code below uses the portable string scanning of the view.
```cpp
#define JSON_VIEW_NO_SIMD
#include <nlohmann/json_view.hpp>
...
```
## See also
- [JSON_VIEW_USE_SSSE3](json_view_use_ssse3.md) - validate non-ASCII strings with SSSE3 on x86-64
- [json_view](../../features/json_view.md) - the zero-copy view
## Version history
- Added in version 3.13.0.
@@ -1,53 +0,0 @@
# JSON_VIEW_USE_SSSE3
```cpp
#define JSON_VIEW_USE_SSSE3
```
When defined on x86-64, the parser of [`basic_json_document`](../basic_json_document/index.md)
(`<nlohmann/json_view.hpp>`) validates non-ASCII text in strings with SSSE3 without asking the CPU first.
By default, the parser checks once at run time whether the CPU has SSSE3 (all x86-64 CPUs since about 2011 have it)
and then validates non-ASCII text 16 bytes at a time, using the "lookup4" algorithm of
[simdjson](https://github.com/simdjson/simdjson); on CPUs without SSSE3, it validates one UTF-8 sequence at a time.
The vector check is compiled for SSSE3 with a function attribute (GCC 4.9 and later, Clang), so this needs no compiler
option. With MSVC, the check uses `__cpuid`. On AArch64, the vector check uses NEON and is always on.
Define the macro only together with a compiler option that enables SSSE3 (e.g. `-mssse3`, or `-march=` with a CPU that
has it), and only for programs that run on such CPUs. It saves the check of the CPU, which costs little. The same
input is accepted or rejected either way; only the speed of non-ASCII text differs.
!!! note "ABI compatibility"
The macro selects between two definitions of the same inline functions. Whether it is defined is encoded in the
[namespace](../../features/namespace.md) (tag `_vssse3`, on every architecture), resulting in distinct symbol
names. Translation units compiled with and without it can therefore be linked into the same program without One
Definition Rule (ODR) violations, but they cannot exchange instances of library types.
## Default definition
By default, `#!cpp JSON_VIEW_USE_SSSE3` is not defined.
```cpp
#undef JSON_VIEW_USE_SSSE3
```
## Examples
??? example
With CMake, for a program that only runs on CPUs with SSSE3:
```cmake
target_compile_definitions(your_target PRIVATE JSON_VIEW_USE_SSSE3)
target_compile_options(your_target PRIVATE -mssse3)
```
## See also
- [JSON_VIEW_NO_SIMD](json_view_no_simd.md) - use only portable code in the view's parser
- [JSON_USE_SIMDUTF](json_use_simdutf.md) - validate UTF-8 with simdutf in `basic_json`'s parser
## Version history
- Added in version 3.13.0.
@@ -147,6 +147,13 @@ void to_json(BasicJsonType& j, const B& b) {
See Implementation limits for [NLOHMANN_DEFINE_TYPE_INTRUSIVE](nlohmann_define_type_intrusive.md) and
[NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE](nlohmann_define_type_non_intrusive.md), respectively.
!!! info "Views"
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
(`<nlohmann/json_view.hpp>`): [`get<T>()`](../basic_json_view/get.md) on a view looks the members up in the
view, without building a `json` value first. The base part is read from the view as well if the base's
`from_json()` accepts views, and from [`materialize()`](../basic_json_view/materialize.md) otherwise.
## Examples
??? example "Example: (1) NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE"
@@ -192,3 +199,5 @@ void to_json(BasicJsonType& j, const B& b) {
6. Added in version 3.12.0.
All six macros were changed to allow an empty member list in version 3.13.0.
The generated `from_json()` reads the views of `json_document`s since version 3.13.0.
@@ -81,6 +81,12 @@ See the examples below for the concrete generated code.
that serializes a struct's members positionally into a JSON array; for that, write `to_json`/`from_json` by
hand, building/reading a `json::array()` of the members in order.
!!! info "Views"
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
(`<nlohmann/json_view.hpp>`): [`get<T>()`](../basic_json_view/get.md) on a view looks the members up in the
view, without building a `json` value first.
## Examples
??? example "Example: (1) NLOHMANN_DEFINE_TYPE_INTRUSIVE"
@@ -189,3 +195,5 @@ See the examples below for the concrete generated code.
All three macros were changed to work with any `basic_json` specialization (not only `nlohmann::json`) in version 3.12.0,
and to allow an empty member list in version 3.13.0.
The generated `from_json()` reads the views of `json_document`s since version 3.13.0.
@@ -80,6 +80,12 @@ See the examples below for the concrete generated code.
that serializes a struct's members positionally into a JSON array; for that, write `to_json`/`from_json` by
hand, building/reading a `json::array()` of the members in order.
!!! info "Views"
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
(`<nlohmann/json_view.hpp>`): [`get<T>()`](../basic_json_view/get.md) on a view looks the members up in the
view, without building a `json` value first.
## Examples
??? example "Example: (1) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE"
@@ -188,3 +194,5 @@ See the examples below for the concrete generated code.
All three macros were changed to work with any `basic_json` specialization (not only `nlohmann::json`) in version 3.12.0,
and to allow an empty member list in version 3.13.0.
The generated `from_json()` reads the views of `json_document`s since version 3.13.0.
@@ -39,6 +39,6 @@ the library.
## Version history
- Added in version 3.11.0. Changed inline namespace name in version 3.11.2. Added the ABI tag `_dp` in
version 3.12.0, and the ABI tags `_bics`, `_psp`, `_snul`, `_sbu8`, `_ekmo`, `_dsbs`, `_dufio`, `_ns`, `_vns`,
and `_vssse3` in version 3.13.0; see
version 3.12.0, and the ABI tags `_bics`, `_psp`, `_snul`, `_sbu8`, `_ekmo`, `_dsbs`, `_dufio`, and `_ns` in
version 3.13.0; see
[`nlohmann` Namespace](../../features/namespace.md#structure).
@@ -45,6 +45,12 @@ inline void from_json(const BasicJsonType& j, type& e);
Define [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) to store them as objects
with the converted keys. Such maps can be read from both forms.
!!! info "Views"
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
(`<nlohmann/json_view.hpp>`), comparing the view with the entries of the mapping, without building a `json` value
first.
## Examples
??? example "Example: Basic usage"
@@ -88,3 +94,5 @@ inline void from_json(const BasicJsonType& j, type& e);
## Version history
Added in version 3.4.0.
The generated `from_json()` reads the views of `json_document`s since version 3.13.0.
@@ -48,6 +48,12 @@ inline void from_json(const BasicJsonType& j, type& e);
Define [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) to store them as objects
with the converted keys. Such maps can be read from both forms.
!!! info "Views"
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
(`<nlohmann/json_view.hpp>`), comparing the view with the entries of the mapping, without building a `json` value
first.
## Examples
??? example "Example: Basic usage"
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
using ordered_json_editable_document = basic_json_document<ordered_json, true>;
using ordered_json_editable_document = basic_json_document<ordered_json, view_mode::editable>;
```
This type is an **editable** [`basic_json_document`](basic_json_document/index.md) of the
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
using ordered_json_editable_view = basic_json_view<ordered_json, true>;
using ordered_json_editable_view = basic_json_view<ordered_json, view_mode::editable>;
```
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an
+80
View File
@@ -0,0 +1,80 @@
# <small>nlohmann::</small>view_mode
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
enum class view_mode : std::uint8_t
{
read_only,
editable
};
```
The second template parameter of [`basic_json_document`](basic_json_document/index.md) and
[`basic_json_view`](basic_json_view/index.md): whether a document can be changed after parsing, and whether a view is
of such a document.
`read_only`
: the default: the document is parsed once and then only read. It carries none of the bookkeeping edits need, and
calling [`set`](basic_json_document/set.md), [`push_back`](basic_json_document/push_back.md),
[`insert`](basic_json_document/insert.md), or [`erase`](basic_json_document/erase.md) on it fails to compile.
`editable`
: the document also offers [`set`](basic_json_document/set.md), [`push_back`](basic_json_document/push_back.md),
[`insert`](basic_json_document/insert.md), and [`erase`](basic_json_document/erase.md); its views see every edit,
see [Edits](basic_json_document/index.md#edits).
The shortcuts name both modes: [`json_document`](json_document.md) and [`json_view`](json_view.md) are read-only,
[`json_editable_document`](json_editable_document.md) and [`json_editable_view`](json_editable_view.md) are editable
(and likewise for `ordered_json`).
## Notes
The mode is part of the view's type, and there is no conversion between the two modes: a read-only view reads a
container in place, while a view of an editable document follows the links that edits leave behind. A function that
accepts views therefore names the modes it accepts in its signature:
```cpp
// views of editable documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::editable> v);
// views of read-only documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
// either
template<typename BasicJsonType, view_mode Mode>
void f(basic_json_view<BasicJsonType, Mode> v);
```
A function that takes a [`json_view`](json_view.md) accepts neither an [`ordered_json_view`](ordered_json_view.md)
nor a [`json_editable_view`](json_editable_view.md). Views of the two modes still compare with
[`operator==`](basic_json_view/operator_eq.md).
## Examples
??? example
The example below shows a function template that accepts the views of both modes, and one that accepts only
views of editable documents.
```cpp
--8<-- "examples/view_mode.cpp"
```
Output:
```
--8<-- "examples/view_mode.output"
```
## See also
- [basic_json_document](basic_json_document/index.md) - a parsed JSON text
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
- [json_editable_document](json_editable_document.md) - an editable document of `json`
## Version history
Added in version 3.13.0.
@@ -0,0 +1,34 @@
#include <iostream>
#include <type_traits>
#include <nlohmann/json_view.hpp>
using nlohmann::json;
namespace ns
{
struct person
{
std::string name;
int age = 0;
};
// reads json values and views (of any document type), but nothing else
template < typename J, typename std::enable_if < nlohmann::is_json_view<J>::value || std::is_same<J, json>::value, int >::type = 0 >
void from_json(const J& j, person& p)
{
p.name = j.at("name").template get<std::string>();
p.age = j.at("age").template get<int>();
}
} // namespace ns
int main()
{
std::cout << std::boolalpha
<< nlohmann::is_json_view<nlohmann::json_view>::value << ' '
<< nlohmann::is_json_view<nlohmann::ordered_json_editable_view>::value << ' '
<< nlohmann::is_json_view<json>::value << '\n';
const nlohmann::json_document doc = nlohmann::json_document::parse(R"({"name": "Ada", "age": 36})");
const auto p = doc.root().get<ns::person>(); // reads the view, no json value is built
std::cout << p.name << ' ' << p.age << '\n';
}
@@ -0,0 +1,2 @@
true true false
Ada 36
@@ -5,7 +5,7 @@ using ordered_json_editable_document = nlohmann::ordered_json_editable_document;
int main()
{
// ordered_json_editable_document is basic_json_document<nlohmann::ordered_json, true>
// ordered_json_editable_document is basic_json_document<nlohmann::ordered_json, nlohmann::view_mode::editable>
ordered_json_editable_document doc = ordered_json_editable_document::parse(R"({"z": 1, "a": 2, "m": 3})");
doc.set(doc.root(), "b", 4); // set() always appends a new member at the end
+29
View File
@@ -0,0 +1,29 @@
#include <iostream>
#include <nlohmann/json_view.hpp>
using nlohmann::basic_json_view;
using nlohmann::view_mode;
// accepts the views of read-only and of editable documents, of json and of ordered_json
template<typename BasicJsonType, view_mode Mode>
std::size_t count_members(basic_json_view<BasicJsonType, Mode> v)
{
return v.is_object() ? v.size() : 0;
}
// accepts only the views of editable documents
template<typename BasicJsonType>
bool is_edited(basic_json_view<BasicJsonType, view_mode::editable> v)
{
return v.is_string() && v.get_string() == "edited";
}
int main()
{
const nlohmann::json_document doc = nlohmann::json_document::parse(R"({"a": 1, "b": 2})");
nlohmann::json_editable_document edoc = nlohmann::json_editable_document::parse(R"({"a": 1})");
edoc.set(edoc.root()["a"], "edited");
std::cout << count_members(doc.root()) << ' ' << count_members(edoc.root()) << '\n';
std::cout << std::boolalpha << is_edited(edoc.root()["a"]) << '\n';
}
@@ -0,0 +1,2 @@
2 1
true
+10 -5
View File
@@ -185,6 +185,10 @@ key as well. Other zero-copy parsers that index the source text, such as yyjson
member. RFC 8259 only says that names within an object SHOULD be unique and that the behavior of a receiver that sees
duplicates is unpredictable, so neither choice is wrong.
The same holds for [`get<T>()`](../api/basic_json_view/get.md) of a type whose `from_json()` reads the view, such as
the types of the `NLOHMANN_DEFINE_TYPE_*` macros: their members are looked up, so `#!cpp get<point>()` of
`#!cpp {"x":1,"x":2}` reads `#!cpp x == 1`, while `#!cpp materialize().get<point>()` reads `#!cpp 2`.
**What stays the same as `parse()`?** [`materialize()`](../api/basic_json_view/materialize.md) and
[`get<std::map<...>>()`](../api/basic_json_view/get.md) replay every member in order, so they keep the *last* value
exactly like `#!cpp basic_json::parse()` (at the position of the first occurrence of the key, for an
@@ -252,14 +256,14 @@ the stream's `width`/`fill` for indentation.
## Editing a document
Everything above is read-only: a `json_document`/`json_view` lets you look at a parsed text without copying it, but
not change it. [`basic_json_document<BasicJsonType, true>`](../api/basic_json_document/index.md) -- more conveniently
not change it. [`basic_json_document<BasicJsonType, view_mode::editable>`](../api/basic_json_document/index.md) -- more conveniently
spelled [`json_editable_document`](../api/json_editable_document.md) or
[`ordered_json_editable_document`](../api/ordered_json_editable_document.md) -- also lets you
[`set`](../api/basic_json_document/set.md) a value, [`push_back`](../api/basic_json_document/push_back.md) onto or
[`insert`](../api/basic_json_document/insert.md) into an array, and [`erase`](../api/basic_json_document/erase.md)
an object member or an array element, still without ever building a `basic_json` tree for parts you do not touch.
`#!cpp Editable` defaults to `#!cpp false`, so `json_document`/`ordered_json_document` are unaffected -- they carry
The [mode](../api/view_mode.md) defaults to `#!cpp view_mode::read_only`, so `json_document`/`ordered_json_document` are unaffected -- they carry
none of the bookkeeping edits need, and calling `set`/`push_back`/`insert`/`erase` on one is a compile error, not a
runtime one.
@@ -354,9 +358,10 @@ validation entirely, for an image trusted as much as the process's own memory. S
!!! warning "Experimental"
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
stable. It is little-endian only, and tied to the library build that wrote it -- use it to cache a document or to
hand one to another process running the *same* build, not as a long-term storage format; keep the original JSON
text if a saved document needs to be readable by a future library version.
stable. It is little-endian only (on big-endian targets, `save()` and `load()` do not exist), and tied to the
library build that wrote it -- use it to cache a document or to hand one to another process running the *same*
build, not as a long-term storage format; keep the original JSON text if a saved document needs to be readable by
a future library version.
The idea of a document you can read without parsing comes from zero-copy formats such as
[FlatBuffers](https://github.com/google/flatbuffers) and [YaFF](https://github.com/yandex/yaff); the check
-17
View File
@@ -287,23 +287,6 @@ external dependency and is not defined by default.
See [full documentation of `JSON_USE_SIMDUTF`](../api/macros/json_use_simdutf.md).
## `JSON_VIEW_NO_SIMD`
When defined, the parser of [`basic_json_document`](../api/basic_json_document/index.md)
(`<nlohmann/json_view.hpp>`) uses only portable C++ to scan strings, instead of vector instructions (SSE2 on x86-64,
NEON on AArch64). The same input is accepted or rejected either way; only the speed differs. It is not defined by
default.
See [full documentation of `JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md).
## `JSON_VIEW_USE_SSSE3`
When defined on x86-64, the parser of [`basic_json_document`](../api/basic_json_document/index.md)
(`<nlohmann/json_view.hpp>`) validates non-ASCII text in strings with SSSE3 without asking the CPU first. It is not
defined by default.
See [full documentation of `JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md).
## `NLOHMANN_DEFINE_TYPE_*(...)`, `NLOHMANN_DEFINE_DERIVED_TYPE_*(...)`
The library defines 12 macros to simplify the serialization/deserialization of types. See the page on
+2 -6
View File
@@ -28,8 +28,6 @@ The complete default namespace name is derived as follows:
- [`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md) defined non-zero appends
`_dufio`.
- [`JSON_NO_SIMD`](../api/macros/json_no_simd.md) defined appends `_ns`.
- [`JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md) defined appends `_vns`.
- [`JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md) defined appends `_vssse3`.
- The inline namespace ends with the suffix `_v` followed by the 3 components of the version number separated by
underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component)
below.
@@ -115,7 +113,5 @@ follows:
([`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md)), `_ekmo`
([`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md)), `_dsbs`
([`JSON_DISABLE_STREAM_BULK_SCAN`](../api/macros/json_disable_stream_bulk_scan.md)), `_dufio`
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md)), `_ns`
([`JSON_NO_SIMD`](../api/macros/json_no_simd.md)), `_vns`
([`JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md)), and `_vssse3`
([`JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md)) in version 3.13.0.
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md)), and `_ns`
([`JSON_NO_SIMD`](../api/macros/json_no_simd.md)) in version 3.13.0.
+2 -2
View File
@@ -21,10 +21,10 @@ ABI tags are not covered and may show raw internal fields instead. To generate a
```
3. Generate a Natvis file with the tags of your configuration, for example for `JSON_DIAGNOSTICS`,
`JSON_DIAGNOSTIC_POSITIONS`, and `JSON_VIEW_NO_SIMD`:
`JSON_DIAGNOSTIC_POSITIONS`, and `JSON_NO_SIMD`:
```shell
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my_nlohmann_json.natvis"
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my_nlohmann_json.natvis"
```
4. Use the generated file instead of `nlohmann_json.natvis`.
-5
View File
@@ -853,17 +853,12 @@ from JSON text.
[`basic_json_document::save()`](../api/basic_json_document/save.md) cannot write an
[image](../features/json_view.md#images) of a [discarded](../api/basic_json_document/is_discarded.md) document.
[`save()`](../api/basic_json_document/save.md) and [`load()`](../api/basic_json_document/load.md) also throw this
exception on a big-endian target, since the image format is little-endian only.
!!! failure "Example messages"
```
[json.exception.type_error.320] cannot save a discarded json_document
```
```
[json.exception.type_error.320] json_document images need a little-endian target
```
!!! note
+2 -2
View File
@@ -358,6 +358,7 @@ nav:
- 'Overview': api/adl_serializer/index.md
- 'from_json': api/adl_serializer/from_json.md
- 'to_json': api/adl_serializer/to_json.md
- 'is_json_view': api/is_json_view.md
- 'json': api/json.md
- 'json_document': api/json_document.md
- 'json_editable_document': api/json_editable_document.md
@@ -407,6 +408,7 @@ nav:
- 'ordered_json_editable_view': api/ordered_json_editable_view.md
- 'ordered_json_view': api/ordered_json_view.md
- 'ordered_map': api/ordered_map.md
- 'view_mode': api/view_mode.md
- macros:
- 'Overview': api/macros/index.md
- 'JSON_ASSERT': api/macros/json_assert.md
@@ -441,8 +443,6 @@ nav:
- 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md
- 'JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS': api/macros/json_use_objects_for_enum_keyed_maps.md
- 'JSON_USE_SIMDUTF': api/macros/json_use_simdutf.md
- 'JSON_VIEW_NO_SIMD': api/macros/json_view_no_simd.md
- 'JSON_VIEW_USE_SSSE3': api/macros/json_view_use_ssse3.md
- 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_derived_type.md
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_intrusive.md
- 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_non_intrusive.md
+4 -18
View File
@@ -128,26 +128,14 @@
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
#endif
#ifdef JSON_VIEW_NO_SIMD
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD _vns
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD
#endif
#ifdef JSON_VIEW_USE_SSSE3
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3 _vssse3
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k, l, m) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -161,9 +149,7 @@
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
NLOHMANN_JSON_ABI_TAG_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3)
NLOHMANN_JSON_ABI_TAG_NO_SIMD)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
@@ -10,6 +10,7 @@
#include <algorithm> // min, transform
#include <array> // array
#include <cstddef> // nullptr_t
#include <forward_list> // forward_list
#include <iterator> // inserter, front_inserter, end
#include <map> // map
@@ -27,6 +28,7 @@
#include <nlohmann/detail/meta/identity_tag.hpp>
#include <nlohmann/detail/meta/std_fs.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/output/error_handler.hpp>
#include <nlohmann/detail/string_concat.hpp>
#include <nlohmann/detail/value_t.hpp>
@@ -665,16 +667,114 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
}
#endif
struct from_json_fn
namespace from_json_adl
{
template<typename BasicJsonType, typename T>
auto operator()(const BasicJsonType& j, T&& val) const
// hides the library's from_json() overloads above (and the from_json object):
// a call from this namespace finds only the from_json() functions of the
// arguments' own namespaces and classes (ADL); the declaration is never viable
// and never defined (not "= delete", which GCC before 6 reports as a use)
struct hidden;
void from_json(const hidden&);
// a type no from_json() written for JSON values accepts: a from_json() that
// accepts it is not constrained to them (see has_view_from_json; it lives
// here, so that ADL finds no other from_json() for it)
struct probe
{};
struct fn
{
template<typename SourceType, typename T>
auto operator()(const SourceType& j, T&& val) const
noexcept(noexcept(from_json(j, std::forward<T>(val))))
-> decltype(from_json(j, std::forward<T>(val)))
{
return from_json(j, std::forward<T>(val));
}
};
} // namespace from_json_adl
// the sources whose from_json() is only looked up by ADL: views (the library's
// overloads are written for basic_json) and the probe
template<typename T>
struct is_adl_only_from_json_source : disjunction<is_json_view<T>, std::is_same<T, from_json_adl::probe>> {};
struct from_json_fn
{
template < typename BasicJsonType, typename T,
enable_if_t < !is_adl_only_from_json_source<BasicJsonType>::value, int > = 0 >
auto operator()(const BasicJsonType& j, T && val) const
noexcept(noexcept(from_json(j, std::forward<T>(val))))
-> decltype(from_json(j, std::forward<T>(val)))
{
return from_json(j, std::forward<T>(val));
}
template < typename SourceType, typename T,
enable_if_t < is_adl_only_from_json_source<SourceType>::value, int > = 0 >
auto operator()(const SourceType& j, T && val) const
noexcept(noexcept(from_json_adl::fn {}(j, std::forward<T>(val))))
-> decltype(from_json_adl::fn {}(j, std::forward<T>(val)))
{
return from_json_adl::fn {}(j, std::forward<T>(val));
}
};
// Whether JSONSerializer::from_json(view, T&) reads T from a view (of
// <nlohmann/json_view.hpp>) directly: it must accept the view but not the
// probe. An unconstrained from_json() template (written for basic_json, but
// accepting anything) is thus not called with a view, nor are the library's
// own conversions; the view converts such types through materialize().
template<typename Serializer, typename SourceType, typename T>
using serializer_from_json_t = decltype(Serializer::from_json(std::declval<const SourceType&>(), std::declval<T&>()));
template<typename Serializer, typename View, typename T>
struct has_view_from_json
: conjunction < is_detected<serializer_from_json_t, Serializer, View, T>,
negation<is_detected<serializer_from_json_t, Serializer, from_json_adl::probe, T>>> {};
// the base part of a type of the NLOHMANN_DEFINE_DERIVED_TYPE_* macros: from a
// view through its get_to(), which reads the base from the view where the
// base's from_json() accepts views, and from materialize() otherwise
template<typename BasicJsonType, typename T, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
void from_json_base(const BasicJsonType& j, T& base)
{
from_json_fn {}(j, base);
}
template<typename View, typename T, enable_if_t<is_json_view<View>::value, int> = 0>
void from_json_base(const View& v, T& base)
{
v.get_to(base);
}
// the context of an exception thrown by a from_json() of the macros: the value
// itself for basic_json (for JSON_DIAGNOSTICS), none for a view
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
const BasicJsonType * from_json_context(const BasicJsonType& j) noexcept
{
return &j;
}
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
std::nullptr_t from_json_context(const View& /*unused*/) noexcept
{
return nullptr;
}
// a value as an exception message shows it (invalid UTF-8 replaced; the
// strings of a view are always valid UTF-8)
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
typename BasicJsonType::string_t from_json_dump(const BasicJsonType& j)
{
return j.dump(-1, ' ', false, error_handler_t::replace);
}
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
typename View::string_t from_json_dump(const View& v)
{
return v.dump();
}
} // namespace detail
+1 -1
View File
@@ -102,7 +102,7 @@ enum class exception_id : int
type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format
enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string
document_binary_value = 319, ///< a binary value is stored in a json_document
document_image_unsupported = 320, ///< a json_document image cannot be saved or loaded (discarded document, big-endian target)
document_image_unsupported = 320, ///< a discarded json_document cannot be saved as an image
discarded_value_used = 321, ///< a discarded value is used
// out_of_range
array_index_out_of_range = 401, ///< an array index is out of range
+33 -27
View File
@@ -291,15 +291,17 @@
}); \
j = ((it != std::end(m)) ? it : std::begin(m))->second; \
} \
template<typename BasicJsonType> \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> \
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
{ \
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
/* (for a view, the table holds basic_json values, which compare with the view) */ \
using nlohmann_json_value_t = nlohmann::detail::json_type_of_t<BasicJsonType>; \
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
static const std::pair<ENUM_TYPE, nlohmann_json_value_t> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
[&j](const std::pair<ENUM_TYPE, nlohmann_json_value_t>& ej_pair) -> bool \
{ \
return ej_pair.second == j; \
}); \
@@ -330,20 +332,22 @@
if (it != std::end(m)) j = it->second; \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range,"enum value out of range for " #ENUM_TYPE, nullptr)); \
} \
template<typename BasicJsonType> \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> \
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
{ \
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
/* (for a view, the table holds basic_json values, which compare with the view) */ \
using nlohmann_json_value_t = nlohmann::detail::json_type_of_t<BasicJsonType>; \
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
static const std::pair<ENUM_TYPE, nlohmann_json_value_t> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
[&j](const std::pair<ENUM_TYPE, nlohmann_json_value_t>& ej_pair) -> bool \
{ \
return ej_pair.second == j; \
}); \
if (it != std::end(m)) e = it->first; \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::from_json_context(j))); \
}
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
@@ -603,6 +607,8 @@
#define NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME(v1, v2) nlohmann_json_t.v2 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(v1, nlohmann_json_default_obj.v2) : nlohmann_json_default_obj.v2;
#define NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(...) template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> __VA_ARGS__
// from_json() also reads from the views of <nlohmann/json_view.hpp>
#define NLOHMANN_JSON_FROM_TYPE_TEMPLATE(...) template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> __VA_ARGS__
// Helpers used to dispatch the NLOHMANN_DEFINE_TYPE_*/NLOHMANN_DEFINE_DERIVED_TYPE_*
// macros below between a zero-member and a one-or-more-member implementation
@@ -655,18 +661,18 @@
*/
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_MEMBERS(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY(Type) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type&) { nlohmann_json_j = BasicJsonType::object(); }) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type is used as a declarator type, not in an expression */ \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType&, Type&) noexcept { })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType&, Type&) noexcept { })
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_TYPE_BODY(NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -676,7 +682,7 @@
*/
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
// identical to NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY: with no members there is nothing to default
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_EMPTY(Type) NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY(Type)
@@ -685,7 +691,7 @@
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -712,18 +718,18 @@
*/
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_MEMBERS(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY(Type) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type&) { nlohmann_json_j = BasicJsonType::object(); }) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type is used as a declarator type, not in an expression */ \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType&, Type&) noexcept { })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType&, Type&) noexcept { })
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_TYPE_BODY(NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -733,7 +739,7 @@
*/
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
// identical to NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY: with no members there is nothing to default
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_EMPTY(Type) NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY(Type)
@@ -742,7 +748,7 @@
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -769,18 +775,18 @@
*/
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_MEMBERS(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY(Type, BaseType) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); }) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type/BaseType are used as declarator types, not in expressions */ \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DERIVED_TYPE_BODY(NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -790,7 +796,7 @@
*/
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
// identical to NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY: with no members there is nothing to default
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_EMPTY(Type, BaseType) NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY(Type, BaseType)
@@ -799,7 +805,7 @@
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -827,18 +833,18 @@
*/
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_MEMBERS(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY(Type, BaseType) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); }) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type/BaseType are used as declarator types, not in expressions */ \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DERIVED_TYPE_BODY(NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -848,7 +854,7 @@
*/
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
// identical to NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY: with no members there is nothing to default
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_EMPTY(Type, BaseType) NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY(Type, BaseType)
@@ -857,7 +863,7 @@
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -340,6 +340,47 @@ template<class B> struct negation : std::integral_constant < bool, !B::value > {
#endif
///////////////////////
// json_view helpers //
///////////////////////
template<typename T>
using basic_json_type_t = typename T::basic_json_type;
template<typename T>
using materialize_function_t = decltype(std::declval<const T&>().materialize());
// a basic_json_view of <nlohmann/json_view.hpp> (detected by its member type
// basic_json_type, a basic_json, and materialize() returning that type, so that
// json.hpp needs no declaration of the view)
template<typename T, typename = void>
struct is_json_view : std::false_type {};
template<typename T>
struct is_json_view<T, enable_if_t<is_basic_json<detected_t<basic_json_type_t, T>>::value>>
: std::is_same<detected_t<materialize_function_t, T>, basic_json_type_t<T>> {};
// the types from_json() functions of the NLOHMANN_DEFINE_TYPE_* and
// NLOHMANN_JSON_SERIALIZE_ENUM macros read from
template<typename T>
struct is_basic_json_or_view : disjunction<is_basic_json<T>, is_json_view<T>> {};
// the basic_json type of a basic_json value or of a view
template<typename T, typename = void>
struct json_type_of
{
using type = T;
};
template<typename T>
struct json_type_of<T, enable_if_t<is_json_view<T>::value>>
{
using type = typename T::basic_json_type;
};
template<typename T>
using json_type_of_t = typename json_type_of<T>::type;
// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
// This causes compile errors in e.g., Clang 3.5 or GCC 4.9.
+1 -1
View File
@@ -978,7 +978,7 @@ indent_done:
std::memcpy(reinterpret_cast<unsigned char*>(n), &first, 8);
std::memcpy(reinterpret_cast<unsigned char*>(n) + 8, &second, 8);
#else
n->kind = static_cast<std::uint8_t>(k);
n->kind = static_cast<node_kind>(k);
n->flags = flags;
n->extra = extra;
n->off = static_cast<std::uint32_t>(off);
@@ -232,7 +232,7 @@ struct document_data
/// following loads.
static NLOHMANN_VIEW_ALWAYS_INLINE const node* deref(const node* n) noexcept
{
return NLOHMANN_VIEW_LIKELY(n->kind != kind_link) ? n : follow_link(n);
return NLOHMANN_VIEW_LIKELY(n->kind != node_kind::link) ? n : follow_link(n);
}
static NLOHMANN_VIEW_NOINLINE const node* follow_link(const node* n) noexcept
+19 -21
View File
@@ -26,12 +26,10 @@
#include <nlohmann/detail/view/lookup.hpp>
#include <nlohmann/detail/view/macro_scope.hpp>
#include <nlohmann/detail/view/node.hpp>
#include <nlohmann/detail/view/view_mode.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
template<typename BasicJsonType, bool Editable>
class basic_json_view;
namespace detail
{
namespace view
@@ -120,13 +118,13 @@ class editor
View set(const View& object, string_view_t key, V&& value)
{
node* const o = own(object);
if (o->kind != static_cast<std::uint8_t>(value_t::object) && o->kind != static_cast<std::uint8_t>(value_t::null))
if (o->kind != node_kind::object && o->kind != node_kind::null)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a string argument with ", object.type_name());
}
check_utf8(key.data(), key.size());
const encoded e = encode(std::forward<V>(value));
if (o->kind == static_cast<std::uint8_t>(value_t::null))
if (o->kind == node_kind::null)
{
become_empty(o, value_t::object);
}
@@ -171,7 +169,7 @@ class editor
View set(const View& array, std::size_t idx, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a numeric argument with ", array.type_name());
}
@@ -188,12 +186,12 @@ class editor
View push_back(const View& array, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array) && a->kind != static_cast<std::uint8_t>(value_t::null))
if (a->kind != node_kind::array && a->kind != node_kind::null)
{
throw_type_error(exception_id::push_back_wrong_type, "cannot use push_back() with ", array.type_name());
}
const encoded e = encode(std::forward<V>(value));
if (a->kind == static_cast<std::uint8_t>(value_t::null))
if (a->kind == node_kind::null)
{
become_empty(a, value_t::array);
}
@@ -212,7 +210,7 @@ class editor
View insert(const View& array, std::size_t idx, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::insert_wrong_type, "cannot use insert() with ", array.type_name());
}
@@ -232,7 +230,7 @@ class editor
std::size_t erase(const View& object, string_view_t key)
{
node* const o = own(object);
if (o->kind != static_cast<std::uint8_t>(value_t::object))
if (o->kind != node_kind::object)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", object.type_name());
}
@@ -250,7 +248,7 @@ class editor
void erase(const View& array, std::size_t idx)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", array.type_name());
}
@@ -328,7 +326,7 @@ class editor
{
const std::uint8_t linked = n->flags & node_flags::linked;
*n = node{};
n->kind = static_cast<std::uint8_t>(k);
n->kind = static_cast<node_kind>(k);
n->flags = static_cast<std::uint8_t>(node_flags::is_new | linked);
n->next = 1;
}
@@ -405,8 +403,8 @@ class editor
template<typename T>
struct is_view : std::false_type {};
template<typename J, bool E>
struct is_view<basic_json_view<J, E>> : std::true_type {};
template<typename J, view_mode M>
struct is_view<basic_json_view<J, M>> : std::true_type {};
template<typename V>
encoded encode(V&& v)
@@ -421,8 +419,8 @@ class editor
}
/// a view of any document (copied; nothing is shared with it)
template<typename J, bool E>
encoded encode_impl(const basic_json_view<J, E>& v, encode_tag<0> /*view*/)
template<typename J, view_mode M>
encoded encode_impl(const basic_json_view<J, M>& v, encode_tag<0> /*view*/)
{
if (NLOHMANN_VIEW_UNLIKELY(v.m_node == nullptr))
{
@@ -434,8 +432,8 @@ class editor
r.scalar = copy_scalar(*v.m_doc, *v.m_node);
return r;
}
r.region = alloc_nodes(m_doc, count_nodes<E>(*v.m_doc, v.m_node));
fill_nodes<E>(*v.m_doc, v.m_node, r.region);
r.region = alloc_nodes(m_doc, count_nodes<M == view_mode::editable>(*v.m_doc, v.m_node));
fill_nodes<M == view_mode::editable>(*v.m_doc, v.m_node, r.region);
edit_state_of(m_doc).regions.emplace(r.region, nullptr);
return r;
}
@@ -496,7 +494,7 @@ class editor
static node plain_node(value_t k) noexcept
{
node n{};
n.kind = static_cast<std::uint8_t>(k);
n.kind = static_cast<node_kind>(k);
n.flags = node_flags::is_new;
return n;
}
@@ -681,7 +679,7 @@ class editor
++r;
if (is_container(*n))
{
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object)});
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object});
}
// the next value: close finished containers, then step over the key
for (;;)
@@ -730,7 +728,7 @@ class editor
node* const self = out++;
*self = plain_node(static_cast<value_t>(n->kind));
self->len = n->len;
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object), self});
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object, self});
}
else
{
@@ -27,7 +27,7 @@
// live in chunks that never move; strings and number tokens written by edits
// live in the edit arena. An array/object whose elements change gets
// node_flags::moved: its elements then live in a separate sequence (a header
// node, then the entries), whose entries link to the values (kind_link).
// node, then the entries), whose entries link to the values (node_kind::link).
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
@@ -185,7 +185,7 @@ inline node* block_of(document_data& d, node* n, std::size_t extra)
return nh;
}
reserve_moved(d); // (so that set_moved() below cannot throw: the links are marked before)
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
const std::size_t used = 1 + (static_cast<std::size_t>(n->len) * (object ? 2 : 1));
const std::size_t cap = used + extra;
node* const h = alloc_nodes(d, cap);
@@ -251,7 +251,7 @@ inline node* find_parent(const document_data& d, const node* target)
{
return nullptr; // LCOV_EXCL_LINE (the value is inside c)
}
const bool object = c->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = c->kind == node_kind::object;
const node* down = nullptr;
for (const node* p = d.first_child_edited(c), *e = d.child_end_edited(c); p != e;)
{
+14 -16
View File
@@ -117,7 +117,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
r.off = (v->flags & (node_flags::moved | node_flags::is_new)) != 0 ? 0 : v->off;
r.len = 0; // counted below
r.next = 0; // set when the container is complete
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == static_cast<std::uint8_t>(value_t::object)});
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == node_kind::object});
break;
case value_t::string:
r = string_node(*v);
@@ -138,7 +138,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
if (t[0] == 'n' || t[0] == 'i' || (v->len > 1 && t[1] == 'i'))
{
r = node{}; // nan and infinity: null, as dump() writes them
r.kind = static_cast<std::uint8_t>(value_t::null);
r.kind = node_kind::null;
break;
}
r.off = static_cast<std::uint32_t>(d.size + text_tail.size());
@@ -182,12 +182,10 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
}
}
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no save() elsewhere)
/// the document as an image
inline std::vector<std::uint8_t> save_image(const document_data& d)
{
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
#endif
const std::size_t arena_size = d.arena_size;
std::vector<node> compacted;
std::string text_tail;
@@ -221,7 +219,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
// extra of an object, and the same document saves to the same bytes
for (std::size_t i = 0; i < count; ++i)
{
if (nodes[i].kind == static_cast<std::uint8_t>(value_t::object) && nodes[i].extra != 0)
if (nodes[i].kind == node_kind::object && nodes[i].extra != 0)
{
std::memset(o + (i * sizeof(node)) + offsetof(node, extra), 0, sizeof(nodes[i].extra));
}
@@ -243,6 +241,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
*o = 0;
return image;
}
#endif
/// the parts of a number token that the checks need
struct number_token
@@ -337,7 +336,7 @@ inline bool float_token_finite(const unsigned char* s, std::size_t len, const nu
if (static_cast<std::int64_t>(t.int_digits) + t.exponent > 300)
{
node n{};
n.kind = static_cast<std::uint8_t>(value_t::number_float);
n.kind = node_kind::number_float;
n.len = static_cast<std::uint32_t>(len);
const auto v = float_value<double>(reinterpret_cast<const char*>(s), n); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
return v <= (std::numeric_limits<double>::max)() && v >= -(std::numeric_limits<double>::max)();
@@ -358,7 +357,7 @@ inline bool check_integer(const node& n, const unsigned char* text)
}
// the token's value is the stored one; number_integer nodes of edits can
// be non-negative (as basic_json keeps the type of a value)
const bool integer = n.kind == static_cast<std::uint8_t>(value_t::number_integer);
const bool integer = n.kind == node_kind::number_integer;
if (t.is_float || t.int_digits > 20 || (t.negative && !integer))
{
return false;
@@ -540,7 +539,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
return false;
}
if (n.kind != static_cast<std::uint8_t>(value_t::number_float))
if (n.kind != node_kind::number_float)
{
return (n.extra >> 8u) == 0;
}
@@ -581,7 +580,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
const node& n = nodes[i];
if (!stack.empty() && stack.back().object && stack.back().expect_key)
{
if (n.kind != static_cast<std::uint8_t>(value_t::string) || !check_string(n))
if (n.kind != node_kind::string || !check_string(n))
{
return false;
}
@@ -622,7 +621,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
// (the contents of float tokens are checked later; the token of an
// integer has at most 256 characters)
if (n.kind == static_cast<std::uint8_t>(value_t::number_float))
if (n.kind == node_kind::number_float)
{
floats.push_back(float_range{n.off, n.len, n.extra});
}
@@ -640,7 +639,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
return false;
}
stack.push_back(frame{i + n.next, n.len, 0, n.kind == static_cast<std::uint8_t>(value_t::object), true});
stack.push_back(frame{i + n.next, n.len, 0, n.kind == node_kind::object, true});
complete = false;
break;
}
@@ -663,13 +662,11 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
throw_parse_error(exception_id::invalid_document_image, concat("invalid json_document image: ", what));
}
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no load() elsewhere)
/// Read an image into d. The text and the decoded strings stay in the image;
/// the nodes are copied (so that they are aligned, and edits can change them).
inline void load_image(document_data& d, const std::uint8_t* image, std::size_t size, image_check check)
{
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
#endif
if (image == nullptr || size < sizeof(image_header))
{
throw_invalid_image("too short");
@@ -729,7 +726,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
for (std::size_t i = 0; i < count; ++i)
{
const node& n = d.nodes[i];
if (n.kind == static_cast<std::uint8_t>(value_t::object) && n.len >= document_data::index_min_members)
if (n.kind == node_kind::object && n.len >= document_data::index_min_members)
{
d.large_objects.push_back(static_cast<std::uint32_t>(i));
}
@@ -738,6 +735,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
std::vector<std::uint32_t>().swap(d.large_objects); // (only needed while building)
d.discarded = false;
}
#endif
} // namespace view
} // namespace detail
+1 -1
View File
@@ -182,7 +182,7 @@ const node* element_at(const document_data& d, const node* array, std::size_t id
template<bool Editable>
const node* last_child(const document_data& d, const node* container) noexcept
{
const std::size_t value_offset = container->kind == static_cast<std::uint8_t>(value_t::object) ? 1 : 0;
const std::size_t value_offset = container->kind == node_kind::object ? 1 : 0;
const node* const end = navigation<Editable>::end(d, container);
const node* last = navigation<Editable>::first(d, container);
if (value_offset == 0 && container->next == container->len + 1u && (!navigation<Editable>::editable() || (container->flags & node_flags::moved) == 0))
+1 -1
View File
@@ -101,7 +101,7 @@ BasicJsonType materialize(const document_data& d, const node* n)
case value_t::object:
case value_t::array:
{
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
if (object)
{
sax.start_object(n->len);
+22 -9
View File
@@ -41,9 +41,21 @@ struct node_flags
static constexpr std::uint8_t linked = 32; ///< an entry of a moved sequence links to this value (editable documents): its extent in the parsed layout no longer matters
};
/// kind of an entry of an edited sequence that stands for a value stored
/// elsewhere (the address of the value's node is kept in the len/next bytes)
constexpr std::uint8_t kind_link = 10;
/// the kind of a node: the value_t of its value, or link
enum class node_kind : std::uint8_t
{
null = static_cast<std::uint8_t>(value_t::null),
object = static_cast<std::uint8_t>(value_t::object),
array = static_cast<std::uint8_t>(value_t::array),
string = static_cast<std::uint8_t>(value_t::string),
boolean = static_cast<std::uint8_t>(value_t::boolean),
number_integer = static_cast<std::uint8_t>(value_t::number_integer),
number_unsigned = static_cast<std::uint8_t>(value_t::number_unsigned),
number_float = static_cast<std::uint8_t>(value_t::number_float),
/// an entry of an edited sequence that stands for a value stored elsewhere
/// (the address of the value's node is kept in the len/next bytes)
link = static_cast<std::uint8_t>(value_t::discarded) + 1,
};
/// One entry of the flat index, in document order. An object's members are
/// stored as key node followed by the value's subtree. Integers keep their
@@ -51,7 +63,7 @@ constexpr std::uint8_t kind_link = 10;
/// always the next one, and the token length follows from `extra`).
struct node
{
std::uint8_t kind; ///< value_t, or kind_link
node_kind kind; ///< value_t, or link
std::uint8_t flags; ///< node_flags
std::uint16_t extra; ///< numbers: integer digits (low byte) and fraction digits (high byte), 255 = "many"; objects: number of the object's key hash index (1-based, 0 = none); otherwise 0
std::uint32_t off; ///< source offset (string content, number token, literal, bracket); arena offset if escaped/edited; number of the element sequence if moved
@@ -60,8 +72,9 @@ struct node
};
static_assert(sizeof(node) == 16, "node must stay 16 bytes");
// the node kinds are value_t values; the test below (object and array are 1
// and 2) and those of the number kinds depend on this numbering
// the node kinds are value_t values, and images store them as bytes; the test
// below (object and array are 1 and 2) and those of the number kinds depend
// on this numbering
static_assert(static_cast<std::uint8_t>(value_t::null) == 0 && static_cast<std::uint8_t>(value_t::object) == 1
&& static_cast<std::uint8_t>(value_t::array) == 2 && static_cast<std::uint8_t>(value_t::string) == 3
&& static_cast<std::uint8_t>(value_t::boolean) == 4 && static_cast<std::uint8_t>(value_t::number_integer) == 5
@@ -86,7 +99,7 @@ inline void make_link(node& n, node* target) noexcept
{
target->flags = static_cast<std::uint8_t>(target->flags | node_flags::linked);
n = node{};
n.kind = kind_link;
n.kind = node_kind::link;
std::memcpy(reinterpret_cast<unsigned char*>(&n) + 8, static_cast<const void*>(&target), sizeof(const node*)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
}
@@ -116,8 +129,8 @@ NLOHMANN_VIEW_ALWAYS_INLINE void set_integer_bits(node& n, std::uint64_t v) noex
/// token length of a number node
NLOHMANN_VIEW_ALWAYS_INLINE std::uint32_t number_length(const node& n) noexcept
{
return n.kind == static_cast<std::uint8_t>(value_t::number_float) ? n.len
: (n.extra & 0xFFu) + (n.kind == static_cast<std::uint8_t>(value_t::number_integer) ? 1u : 0u);
return n.kind == node_kind::number_float ? n.len
: (n.extra & 0xFFu) + (n.kind == node_kind::number_integer ? 1u : 0u);
}
/// estimated number of nodes for an input of `size` bytes (one node per ~12
+1 -1
View File
@@ -874,7 +874,7 @@ class view_serializer
case value_t::object:
case value_t::array:
{
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
room(8);
if (n->len == 0)
{
+5 -5
View File
@@ -24,25 +24,25 @@
// with different flags would have different definitions of the same inline
// functions): the check is compiled for SSSE3 with a function attribute and
// used where the CPU has SSSE3 (all x86-64 CPUs since about 2011), else the
// portable check. JSON_VIEW_USE_SSSE3 skips the CPU check (for code compiled
// for SSSE3 anyway); JSON_VIEW_NO_SIMD selects the portable code.
// portable check. Code compiled for SSSE3 anyway (-mssse3 or more) skips the
// CPU check. JSON_NO_SIMD selects the portable code, as in the lexer.
// NLOHMANN_VIEW_NO_TARGET_ATTRIBUTE (set by the GCC module interface, where GCC
// ignores the target attribute and then rejects the SSSE3 intrinsics) keeps the
// check portable without disabling the SSE2 code.
#if !defined(JSON_VIEW_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
#if !defined(JSON_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
#include <arm_neon.h>
#define NLOHMANN_VIEW_NEON 1
#else
#define NLOHMANN_VIEW_NEON 0
#endif
// (x86 only: other targets can define __SSE2__ as well, e.g., WebAssembly with -msse2, but have no <cpuid.h>)
#if !defined(JSON_VIEW_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#if !defined(JSON_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#include <emmintrin.h>
#define NLOHMANN_VIEW_SSE2 1
#else
#define NLOHMANN_VIEW_SSE2 0
#endif
#if NLOHMANN_VIEW_SSE2 && defined(JSON_VIEW_USE_SSSE3)
#if NLOHMANN_VIEW_SSE2 && defined(__SSSE3__)
#include <tmmintrin.h>
#define NLOHMANN_VIEW_SSSE3 1 // NOLINT(cppcoreguidelines-macro-to-enum,modernize-macro-to-enum)
#else
@@ -0,0 +1,27 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#pragma once
#include <cstdint> // uint8_t
#include <nlohmann/json.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
/// whether a basic_json_document and its views can be edited
enum class view_mode : std::uint8_t
{
read_only, ///< parsed once, then only read (the default)
editable, ///< also has set(), push_back(), insert(), and erase()
};
template<typename BasicJsonType, view_mode Mode>
class basic_json_view;
NLOHMANN_JSON_NAMESPACE_END
+83 -31
View File
@@ -84,6 +84,7 @@
#include <nlohmann/detail/view/serializer.hpp>
#include <nlohmann/detail/view/string_ref.hpp>
#include <nlohmann/detail/view/value.hpp>
#include <nlohmann/detail/view/view_mode.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
@@ -93,15 +94,20 @@ NLOHMANN_JSON_NAMESPACE_BEGIN
Trivially copyable (two pointers). Valid as long as the document is alive and
has not been re-parsed, and as long as a borrowed source text is alive.
*/
template<typename BasicJsonType, bool Editable = false>
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
class basic_json_view
{
/// whether this is a view of an editable document
static constexpr bool is_editable = Mode == view_mode::editable;
using node = detail::view::node;
using document_data = detail::view::document_data;
/// how the index is walked (with edits only for editable documents)
using navigation = detail::view::navigation<Editable>;
using navigation = detail::view::navigation<is_editable>;
public:
/// the basic_json type of the document (it also marks views for is_json_view)
using basic_json_type = BasicJsonType;
using value_t = detail::value_t;
using string_t = typename BasicJsonType::string_t;
using number_integer_t = typename BasicJsonType::number_integer_t;
@@ -446,7 +452,7 @@ class basic_json_view
if (is_structured() && m_node->len != 0)
{
return unedited() ? basic_json_view(m_doc, detail::view::last_child<false>(*m_doc, m_node) + (is_object() ? 1 : 0))
: basic_json_view(m_doc, navigation::value(detail::view::last_child<Editable>(*m_doc, m_node) + (is_object() ? 1 : 0)));
: basic_json_view(m_doc, navigation::value(detail::view::last_child<is_editable>(*m_doc, m_node) + (is_object() ? 1 : 0)));
}
return front();
}
@@ -504,7 +510,7 @@ class basic_json_view
/// more than once); 0 if this is not an object
size_type count(string_view_t key) const
{
return is_object() ? detail::view::count_members<Editable>(*m_doc, m_node, key.data(), key.size()) : 0;
return is_object() ? detail::view::count_members<is_editable>(*m_doc, m_node, key.data(), key.size()) : 0;
}
size_type count(const char* key) const
@@ -563,8 +569,10 @@ class basic_json_view
/// the value converted to T, as BasicJsonType::get<T>(): arithmetic types,
/// strings (string_view_t without a copy), std::nullptr_t, std::vector,
/// maps with string keys, and views are converted directly; other types
/// through materialize().get<T>()
/// maps with string keys, and views are converted directly; types whose
/// from_json() accepts views (those of the NLOHMANN_DEFINE_TYPE_* and
/// NLOHMANN_JSON_SERIALIZE_ENUM macros, say) read the view; other types
/// go through materialize().get<T>()
template<typename T>
NLOHMANN_VIEW_ALWAYS_INLINE T get() const
{
@@ -572,11 +580,12 @@ class basic_json_view
}
/// as BasicJsonType::get_to(): the types get<T>() converts directly are
/// assigned, all others are passed to from_json with v as it is
/// assigned, all others are passed to from_json with v as it is (with
/// the view if from_json() accepts views, else with materialize())
template<typename T>
T& get_to(T& v) const
{
get_to_impl(v, detail::view::is_direct_value<T, BasicJsonType, basic_json_view> {});
get_to_impl(v, get_to_kind<T> {});
return v;
}
@@ -646,7 +655,7 @@ class basic_json_view
}
else
{
detail::view::view_serializer<BasicJsonType, Editable>(*m_doc, out, estimate, style).dump(m_node);
detail::view::view_serializer<BasicJsonType, is_editable>(*m_doc, out, estimate, style).dump(m_node);
}
return out;
}
@@ -682,14 +691,14 @@ class basic_json_view
}
/// a view of an editable document compares with one of a read-only document
template < bool E, typename std::enable_if < E != Editable, int >::type = 0 >
friend bool operator==(const basic_json_view& a, const basic_json_view<BasicJsonType, E>& b)
template < view_mode M, typename std::enable_if < M != Mode, int >::type = 0 >
friend bool operator==(const basic_json_view& a, const basic_json_view<BasicJsonType, M>& b)
{
return detail::view::equal<BasicJsonType>(side(a), detail::view::view_side<BasicJsonType, basic_json_view<BasicJsonType, E>>(b));
return detail::view::equal<BasicJsonType>(side(a), detail::view::view_side<BasicJsonType, basic_json_view<BasicJsonType, M>>(b));
}
template < bool E, typename std::enable_if < E != Editable, int >::type = 0 >
friend bool operator!=(const basic_json_view& a, const basic_json_view<BasicJsonType, E>& b)
template < view_mode M, typename std::enable_if < M != Mode, int >::type = 0 >
friend bool operator!=(const basic_json_view& a, const basic_json_view<BasicJsonType, M>& b)
{
return !(a == b);
}
@@ -727,7 +736,7 @@ class basic_json_view
{
return BasicJsonType(value_t::discarded);
}
return unedited() ? detail::view::materialize<BasicJsonType, false>(*m_doc, m_node) : detail::view::materialize<BasicJsonType, Editable>(*m_doc, m_node);
return unedited() ? detail::view::materialize<BasicJsonType, false>(*m_doc, m_node) : detail::view::materialize<BasicJsonType, is_editable>(*m_doc, m_node);
}
/// byte offset of this value in the source text (for strings: of the
@@ -740,8 +749,8 @@ class basic_json_view
}
private:
template<typename, bool> friend class basic_json_document;
template<typename, bool> friend class basic_json_view;
template<typename, view_mode> friend class basic_json_document;
template<typename, view_mode> friend class basic_json_view;
template<typename, typename> friend class detail::view::editor;
friend iterator;
@@ -757,11 +766,11 @@ class basic_json_view
}
/// the template argument as a runtime condition: testing it directly in
/// `Editable && ...` makes the condition constant, which MSVC reports as
/// `is_editable && ...` makes the condition constant, which MSVC reports as
/// C4127
static bool editable() noexcept
{
return Editable;
return is_editable;
}
/// the number of source bytes of this value (estimated for values with
@@ -810,7 +819,7 @@ class basic_json_view
const node* const k = detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size());
return k != nullptr ? basic_json_view(m_doc, k + 1) : basic_json_view();
}
const node* const k = detail::view::find_member<Editable>(*m_doc, m_node, key.data(), key.size());
const node* const k = detail::view::find_member<is_editable>(*m_doc, m_node, key.data(), key.size());
return k != nullptr ? basic_json_view(m_doc, navigation::value(k + 1)) : basic_json_view();
}
@@ -824,7 +833,7 @@ class basic_json_view
/// the member of this object with @a key (the last one if the key occurs more than once), or nullptr
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key) const
{
return find_key(key, std::integral_constant<bool, Editable> {});
return find_key(key, std::integral_constant<bool, is_editable> {});
}
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key, std::true_type /*editable*/) const
@@ -846,7 +855,7 @@ class basic_json_view
{
return basic_json_view(m_doc, detail::view::element_at<false>(*m_doc, m_node, idx));
}
return basic_json_view(m_doc, navigation::value(detail::view::element_at<Editable>(*m_doc, m_node, idx)));
return basic_json_view(m_doc, navigation::value(detail::view::element_at<is_editable>(*m_doc, m_node, idx)));
}
// --- get() dispatch ---
@@ -919,6 +928,26 @@ class basic_json_view
return detail::view::map_value<std::unordered_map<K, V, H, E, A>>(*this);
}
/// whether the from_json() of T's serializer reads views (see
/// detail::has_view_from_json)
template<typename T>
using reads_view = detail::has_view_from_json<typename BasicJsonType::template json_serializer<T, void>, basic_json_view, T>;
/// how get_to() converts: 2 directly, 1 with a from_json() that reads
/// views, 0 through materialize()
template<typename T>
using get_to_kind = std::integral_constant < int, detail::view::is_direct_value<T, BasicJsonType, basic_json_view>::value
? 2 : static_cast<int>(reads_view<T>::value) >;
/// types whose from_json() reads views, without materialize()
template < typename T, typename std::enable_if < reads_view<T>::value && std::is_default_constructible<T>::value, int >::type = 0 >
T get_impl(detail::view::value_tag<T> /*unused*/, detail::priority_tag<1> /*unused*/) const
{
auto v = T();
BasicJsonType::template json_serializer<T, void>::from_json(*this, v);
return v;
}
/// everything else through the BasicJsonType value (from_json included)
template<typename T>
T get_impl(detail::view::value_tag<T> /*unused*/, detail::priority_tag<0> /*unused*/) const
@@ -929,14 +958,20 @@ class basic_json_view
// --- get_to() dispatch ---
template<typename T>
void get_to_impl(T& v, std::true_type /*direct*/) const
void get_to_impl(T& v, std::integral_constant<int, 2> /*direct*/) const
{
v = get<T>();
}
/// from_json may keep parts of v (members a JSON object lacks, say)
template<typename T>
void get_to_impl(T& v, std::false_type /*direct*/) const
void get_to_impl(T& v, std::integral_constant<int, 1> /*from_json reads views*/) const
{
BasicJsonType::template json_serializer<T, void>::from_json(*this, v);
}
template<typename T>
void get_to_impl(T& v, std::integral_constant<int, 0> /*through materialize()*/) const
{
materialize().get_to(v);
}
@@ -952,16 +987,19 @@ Borrowed parses keep a pointer to the caller's text, which must outlive the
document. Owned parses (parse_copy, rvalue std::string, streams, and inputs
that are not contiguous byte ranges) keep their own copy.
*/
template<typename BasicJsonType, bool Editable = false>
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
class basic_json_document
{
/// whether the document can be edited
static constexpr bool is_editable = Mode == view_mode::editable;
using document_data = detail::view::document_data;
static_assert(sizeof(typename BasicJsonType::number_integer_t) == 8 && sizeof(typename BasicJsonType::number_unsigned_t) == 8,
"json_view supports 64-bit integer types only");
public:
using view_type = basic_json_view<BasicJsonType, Editable>;
using view_type = basic_json_view<BasicJsonType, Mode>;
using value_t = detail::value_t;
/// an empty (discarded) document
@@ -1175,6 +1213,10 @@ class basic_json_document
/// how load() checks an image (full, bounds, or none)
using image_check = detail::view::image_check;
#if NLOHMANN_VIEW_LITTLE_ENDIAN
// (the image format is little-endian: big-endian targets have no save()
// and load(), so that a call fails to compile instead of always throwing)
/// The document as an image that load() reads without parsing: the node
/// index, the text, and the decoded strings. An edited document is
/// written in its current state (floats that are not finite become null,
@@ -1216,6 +1258,7 @@ class basic_json_document
detail::view::load_image(*d.m_data, d.m_data->owned_image.data(), d.m_data->owned_image.size(), check);
return d;
}
#endif
///////////
// edits //
@@ -1357,7 +1400,7 @@ class basic_json_document
detail::view::editor<BasicJsonType, view_type> editor()
{
static_assert(Editable, "only an editable document can be edited: use basic_json_document<BasicJsonType, true> (json_editable_document)");
static_assert(is_editable, "only an editable document can be edited: use basic_json_document<BasicJsonType, view_mode::editable> (json_editable_document)");
if (NLOHMANN_VIEW_UNLIKELY(!m_data || m_data->discarded))
{
detail::view::throw_invalid_iterator(detail::exception_id::iterator_from_other_value, "view does not belong to this document");
@@ -1633,6 +1676,15 @@ class basic_json_document
std::unique_ptr<document_data, document_data::deleter> m_data{}; // NOLINT(readability-redundant-member-init)
};
/*!
@brief whether T is a basic_json_view (of any BasicJsonType and view_mode)
For constraining templates that accept views, e.g. a from_json() written for
both basic_json values and views.
*/
template<typename T>
struct is_json_view : detail::is_json_view<T> {};
/// a parsed JSON text for json
using json_document = basic_json_document<json>;
/// a value of a json_document
@@ -1642,13 +1694,13 @@ using ordered_json_document = basic_json_document<ordered_json>;
/// a value of an ordered_json_document
using ordered_json_view = basic_json_view<ordered_json>;
/// an editable parsed JSON text for json
using json_editable_document = basic_json_document<json, true>;
using json_editable_document = basic_json_document<json, view_mode::editable>;
/// a value of a json_editable_document
using json_editable_view = basic_json_view<json, true>;
using json_editable_view = basic_json_view<json, view_mode::editable>;
/// an editable parsed JSON text for ordered_json
using ordered_json_editable_document = basic_json_document<ordered_json, true>;
using ordered_json_editable_document = basic_json_document<ordered_json, view_mode::editable>;
/// a value of an ordered_json_editable_document
using ordered_json_editable_view = basic_json_view<ordered_json, true>;
using ordered_json_editable_view = basic_json_view<ordered_json, view_mode::editable>;
NLOHMANN_JSON_NAMESPACE_END
-3700
View File
File diff suppressed because it is too large. Load diff
+234 -100
View File
@@ -193,26 +193,14 @@
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
#endif
#ifdef JSON_VIEW_NO_SIMD
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD _vns
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD
#endif
#ifdef JSON_VIEW_USE_SSSE3
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3 _vssse3
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k, l, m) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -226,9 +214,7 @@
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
NLOHMANN_JSON_ABI_TAG_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3)
NLOHMANN_JSON_ABI_TAG_NO_SIMD)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
@@ -286,6 +272,7 @@
#include <algorithm> // min, transform
#include <array> // array
#include <cstddef> // nullptr_t
#include <forward_list> // forward_list
#include <iterator> // inserter, front_inserter, end
#include <map> // map
@@ -2677,15 +2664,17 @@ JSON_HEDLEY_DIAGNOSTIC_POP
}); \
j = ((it != std::end(m)) ? it : std::begin(m))->second; \
} \
template<typename BasicJsonType> \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> \
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
{ \
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
/* (for a view, the table holds basic_json values, which compare with the view) */ \
using nlohmann_json_value_t = nlohmann::detail::json_type_of_t<BasicJsonType>; \
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
static const std::pair<ENUM_TYPE, nlohmann_json_value_t> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
[&j](const std::pair<ENUM_TYPE, nlohmann_json_value_t>& ej_pair) -> bool \
{ \
return ej_pair.second == j; \
}); \
@@ -2716,20 +2705,22 @@ JSON_HEDLEY_DIAGNOSTIC_POP
if (it != std::end(m)) j = it->second; \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range,"enum value out of range for " #ENUM_TYPE, nullptr)); \
} \
template<typename BasicJsonType> \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> \
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
{ \
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
/* (for a view, the table holds basic_json values, which compare with the view) */ \
using nlohmann_json_value_t = nlohmann::detail::json_type_of_t<BasicJsonType>; \
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
static const std::pair<ENUM_TYPE, nlohmann_json_value_t> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
[&j](const std::pair<ENUM_TYPE, nlohmann_json_value_t>& ej_pair) -> bool \
{ \
return ej_pair.second == j; \
}); \
if (it != std::end(m)) e = it->first; \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::from_json_context(j))); \
}
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
@@ -2989,6 +2980,8 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME(v1, v2) nlohmann_json_t.v2 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(v1, nlohmann_json_default_obj.v2) : nlohmann_json_default_obj.v2;
#define NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(...) template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> __VA_ARGS__
// from_json() also reads from the views of <nlohmann/json_view.hpp>
#define NLOHMANN_JSON_FROM_TYPE_TEMPLATE(...) template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> __VA_ARGS__
// Helpers used to dispatch the NLOHMANN_DEFINE_TYPE_*/NLOHMANN_DEFINE_DERIVED_TYPE_*
// macros below between a zero-member and a one-or-more-member implementation
@@ -3041,18 +3034,18 @@ JSON_HEDLEY_DIAGNOSTIC_POP
*/
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_MEMBERS(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY(Type) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type&) { nlohmann_json_j = BasicJsonType::object(); }) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type is used as a declarator type, not in an expression */ \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType&, Type&) noexcept { })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType&, Type&) noexcept { })
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_TYPE_BODY(NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -3062,7 +3055,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
*/
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
// identical to NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY: with no members there is nothing to default
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_EMPTY(Type) NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY(Type)
@@ -3071,7 +3064,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -3098,18 +3091,18 @@ JSON_HEDLEY_DIAGNOSTIC_POP
*/
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_MEMBERS(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY(Type) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type&) { nlohmann_json_j = BasicJsonType::object(); }) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type is used as a declarator type, not in an expression */ \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType&, Type&) noexcept { })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType&, Type&) noexcept { })
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_TYPE_BODY(NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -3119,7 +3112,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
*/
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
// identical to NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY: with no members there is nothing to default
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_EMPTY(Type) NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY(Type)
@@ -3128,7 +3121,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -3155,18 +3148,18 @@ JSON_HEDLEY_DIAGNOSTIC_POP
*/
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_MEMBERS(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY(Type, BaseType) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); }) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type/BaseType are used as declarator types, not in expressions */ \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DERIVED_TYPE_BODY(NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -3176,7 +3169,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
*/
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
// identical to NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY: with no members there is nothing to default
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_EMPTY(Type, BaseType) NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY(Type, BaseType)
@@ -3185,7 +3178,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -3213,18 +3206,18 @@ JSON_HEDLEY_DIAGNOSTIC_POP
*/
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_MEMBERS(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY(Type, BaseType) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); }) \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type/BaseType are used as declarator types, not in expressions */ \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DERIVED_TYPE_BODY(NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -3234,7 +3227,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
*/
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
// identical to NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY: with no members there is nothing to default
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_EMPTY(Type, BaseType) NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY(Type, BaseType)
@@ -3243,7 +3236,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, BaseType, ...) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
/*!
@brief macro
@@ -4530,6 +4523,47 @@ template<class B> struct negation : std::integral_constant < bool, !B::value > {
#endif
///////////////////////
// json_view helpers //
///////////////////////
template<typename T>
using basic_json_type_t = typename T::basic_json_type;
template<typename T>
using materialize_function_t = decltype(std::declval<const T&>().materialize());
// a basic_json_view of <nlohmann/json_view.hpp> (detected by its member type
// basic_json_type, a basic_json, and materialize() returning that type, so that
// json.hpp needs no declaration of the view)
template<typename T, typename = void>
struct is_json_view : std::false_type {};
template<typename T>
struct is_json_view<T, enable_if_t<is_basic_json<detected_t<basic_json_type_t, T>>::value>>
: std::is_same<detected_t<materialize_function_t, T>, basic_json_type_t<T>> {};
// the types from_json() functions of the NLOHMANN_DEFINE_TYPE_* and
// NLOHMANN_JSON_SERIALIZE_ENUM macros read from
template<typename T>
struct is_basic_json_or_view : disjunction<is_basic_json<T>, is_json_view<T>> {};
// the basic_json type of a basic_json value or of a view
template<typename T, typename = void>
struct json_type_of
{
using type = T;
};
template<typename T>
struct json_type_of<T, enable_if_t<is_json_view<T>::value>>
{
using type = typename T::basic_json_type;
};
template<typename T>
using json_type_of_t = typename json_type_of<T>::type;
// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
// This causes compile errors in e.g., Clang 3.5 or GCC 4.9.
@@ -5565,7 +5599,7 @@ enum class exception_id : int
type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format
enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string
document_binary_value = 319, ///< a binary value is stored in a json_document
document_image_unsupported = 320, ///< a json_document image cannot be saved or loaded (discarded document, big-endian target)
document_image_unsupported = 320, ///< a discarded json_document cannot be saved as an image
discarded_value_used = 321, ///< a discarded value is used
// out_of_range
array_index_out_of_range = 401, ///< an array index is out of range
@@ -6049,6 +6083,59 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/meta/type_traits.hpp>
// #include <nlohmann/detail/output/error_handler.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/abi_macros.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{
/// how to treat decoding errors
///
/// @ref basic_json::dump uses this to decide what to do with ill-formed
/// UTF-8 while escaping a string, and the binary writers (@ref
/// basic_json::to_cbor, @ref basic_json::to_ubjson, @ref
/// basic_json::to_bjdata, @ref basic_json::to_bson) use it the same way for
/// string values and object keys. The binary readers (@ref
/// basic_json::from_cbor, @ref basic_json::from_msgpack, @ref
/// basic_json::from_ubjson, @ref basic_json::from_bjdata, @ref
/// basic_json::from_bson) use it to decide whether to check text strings
/// and object keys for well-formed UTF-8 at all, since none of those
/// formats requires a decoder to do so.
enum class error_handler_t
{
strict, ///< throw a type_error/parse_error exception in case of invalid UTF-8
replace, ///< replace invalid UTF-8 sequences with U+FFFD
ignore, ///< ignore invalid UTF-8 sequences
keep ///< keep invalid UTF-8 sequences unchanged
};
/// the default error handler of the CBOR, UBJSON, BJData, and BSON writers:
/// error_handler_t::strict if JSON_STRICT_BINARY_UTF8 is enabled, otherwise
/// error_handler_t::keep (the behavior before version 3.13.0)
constexpr error_handler_t binary_writer_default_error_handler() noexcept
{
#if JSON_STRICT_BINARY_UTF8
return error_handler_t::strict;
#else
return error_handler_t::keep;
#endif
}
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/string_concat.hpp>
// #include <nlohmann/detail/value_t.hpp>
@@ -6689,16 +6776,114 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
}
#endif
struct from_json_fn
namespace from_json_adl
{
template<typename BasicJsonType, typename T>
auto operator()(const BasicJsonType& j, T&& val) const
// hides the library's from_json() overloads above (and the from_json object):
// a call from this namespace finds only the from_json() functions of the
// arguments' own namespaces and classes (ADL); the declaration is never viable
// and never defined (not "= delete", which GCC before 6 reports as a use)
struct hidden;
void from_json(const hidden&);
// a type no from_json() written for JSON values accepts: a from_json() that
// accepts it is not constrained to them (see has_view_from_json; it lives
// here, so that ADL finds no other from_json() for it)
struct probe
{};
struct fn
{
template<typename SourceType, typename T>
auto operator()(const SourceType& j, T&& val) const
noexcept(noexcept(from_json(j, std::forward<T>(val))))
-> decltype(from_json(j, std::forward<T>(val)))
{
return from_json(j, std::forward<T>(val));
}
};
} // namespace from_json_adl
// the sources whose from_json() is only looked up by ADL: views (the library's
// overloads are written for basic_json) and the probe
template<typename T>
struct is_adl_only_from_json_source : disjunction<is_json_view<T>, std::is_same<T, from_json_adl::probe>> {};
struct from_json_fn
{
template < typename BasicJsonType, typename T,
enable_if_t < !is_adl_only_from_json_source<BasicJsonType>::value, int > = 0 >
auto operator()(const BasicJsonType& j, T && val) const
noexcept(noexcept(from_json(j, std::forward<T>(val))))
-> decltype(from_json(j, std::forward<T>(val)))
{
return from_json(j, std::forward<T>(val));
}
template < typename SourceType, typename T,
enable_if_t < is_adl_only_from_json_source<SourceType>::value, int > = 0 >
auto operator()(const SourceType& j, T && val) const
noexcept(noexcept(from_json_adl::fn {}(j, std::forward<T>(val))))
-> decltype(from_json_adl::fn {}(j, std::forward<T>(val)))
{
return from_json_adl::fn {}(j, std::forward<T>(val));
}
};
// Whether JSONSerializer::from_json(view, T&) reads T from a view (of
// <nlohmann/json_view.hpp>) directly: it must accept the view but not the
// probe. An unconstrained from_json() template (written for basic_json, but
// accepting anything) is thus not called with a view, nor are the library's
// own conversions; the view converts such types through materialize().
template<typename Serializer, typename SourceType, typename T>
using serializer_from_json_t = decltype(Serializer::from_json(std::declval<const SourceType&>(), std::declval<T&>()));
template<typename Serializer, typename View, typename T>
struct has_view_from_json
: conjunction < is_detected<serializer_from_json_t, Serializer, View, T>,
negation<is_detected<serializer_from_json_t, Serializer, from_json_adl::probe, T>>> {};
// the base part of a type of the NLOHMANN_DEFINE_DERIVED_TYPE_* macros: from a
// view through its get_to(), which reads the base from the view where the
// base's from_json() accepts views, and from materialize() otherwise
template<typename BasicJsonType, typename T, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
void from_json_base(const BasicJsonType& j, T& base)
{
from_json_fn {}(j, base);
}
template<typename View, typename T, enable_if_t<is_json_view<View>::value, int> = 0>
void from_json_base(const View& v, T& base)
{
v.get_to(base);
}
// the context of an exception thrown by a from_json() of the macros: the value
// itself for basic_json (for JSON_DIAGNOSTICS), none for a view
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
const BasicJsonType * from_json_context(const BasicJsonType& j) noexcept
{
return &j;
}
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
std::nullptr_t from_json_context(const View& /*unused*/) noexcept
{
return nullptr;
}
// a value as an exception message shows it (invalid UTF-8 replaced; the
// strings of a view are always valid UTF-8)
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
typename BasicJsonType::string_t from_json_dump(const BasicJsonType& j)
{
return j.dump(-1, ' ', false, error_handler_t::replace);
}
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
typename View::string_t from_json_dump(const View& v)
{
return v.dump();
}
} // namespace detail
@@ -6793,57 +6978,6 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/macro_scope.hpp>
// #include <nlohmann/detail/output/error_handler.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/abi_macros.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{
/// how to treat decoding errors
///
/// @ref basic_json::dump uses this to decide what to do with ill-formed
/// UTF-8 while escaping a string, and the binary writers (@ref
/// basic_json::to_cbor, @ref basic_json::to_ubjson, @ref
/// basic_json::to_bjdata, @ref basic_json::to_bson) use it the same way for
/// string values and object keys. The binary readers (@ref
/// basic_json::from_cbor, @ref basic_json::from_msgpack, @ref
/// basic_json::from_ubjson, @ref basic_json::from_bjdata, @ref
/// basic_json::from_bson) use it to decide whether to check text strings
/// and object keys for well-formed UTF-8 at all, since none of those
/// formats requires a decoder to do so.
enum class error_handler_t
{
strict, ///< throw a type_error/parse_error exception in case of invalid UTF-8
replace, ///< replace invalid UTF-8 sequences with U+FFFD
ignore, ///< ignore invalid UTF-8 sequences
keep ///< keep invalid UTF-8 sequences unchanged
};
/// the default error handler of the CBOR, UBJSON, BJData, and BSON writers:
/// error_handler_t::strict if JSON_STRICT_BINARY_UTF8 is enabled, otherwise
/// error_handler_t::keep (the behavior before version 3.13.0)
constexpr error_handler_t binary_writer_default_error_handler() noexcept
{
#if JSON_STRICT_BINARY_UTF8
return error_handler_t::strict;
#else
return error_handler_t::keep;
#endif
}
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
NLOHMANN_JSON_NAMESPACE_BEGIN
+4 -18
View File
@@ -145,26 +145,14 @@
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
#endif
#ifdef JSON_VIEW_NO_SIMD
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD _vns
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD
#endif
#ifdef JSON_VIEW_USE_SSSE3
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3 _vssse3
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k, l, m) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -178,9 +166,7 @@
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
NLOHMANN_JSON_ABI_TAG_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3)
NLOHMANN_JSON_ABI_TAG_NO_SIMD)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
+178 -88
View File
@@ -239,9 +239,21 @@ struct node_flags
static constexpr std::uint8_t linked = 32; ///< an entry of a moved sequence links to this value (editable documents): its extent in the parsed layout no longer matters
};
/// kind of an entry of an edited sequence that stands for a value stored
/// elsewhere (the address of the value's node is kept in the len/next bytes)
constexpr std::uint8_t kind_link = 10;
/// the kind of a node: the value_t of its value, or link
enum class node_kind : std::uint8_t
{
null = static_cast<std::uint8_t>(value_t::null),
object = static_cast<std::uint8_t>(value_t::object),
array = static_cast<std::uint8_t>(value_t::array),
string = static_cast<std::uint8_t>(value_t::string),
boolean = static_cast<std::uint8_t>(value_t::boolean),
number_integer = static_cast<std::uint8_t>(value_t::number_integer),
number_unsigned = static_cast<std::uint8_t>(value_t::number_unsigned),
number_float = static_cast<std::uint8_t>(value_t::number_float),
/// an entry of an edited sequence that stands for a value stored elsewhere
/// (the address of the value's node is kept in the len/next bytes)
link = static_cast<std::uint8_t>(value_t::discarded) + 1,
};
/// One entry of the flat index, in document order. An object's members are
/// stored as key node followed by the value's subtree. Integers keep their
@@ -249,7 +261,7 @@ constexpr std::uint8_t kind_link = 10;
/// always the next one, and the token length follows from `extra`).
struct node
{
std::uint8_t kind; ///< value_t, or kind_link
node_kind kind; ///< value_t, or link
std::uint8_t flags; ///< node_flags
std::uint16_t extra; ///< numbers: integer digits (low byte) and fraction digits (high byte), 255 = "many"; objects: number of the object's key hash index (1-based, 0 = none); otherwise 0
std::uint32_t off; ///< source offset (string content, number token, literal, bracket); arena offset if escaped/edited; number of the element sequence if moved
@@ -258,8 +270,9 @@ struct node
};
static_assert(sizeof(node) == 16, "node must stay 16 bytes");
// the node kinds are value_t values; the test below (object and array are 1
// and 2) and those of the number kinds depend on this numbering
// the node kinds are value_t values, and images store them as bytes; the test
// below (object and array are 1 and 2) and those of the number kinds depend
// on this numbering
static_assert(static_cast<std::uint8_t>(value_t::null) == 0 && static_cast<std::uint8_t>(value_t::object) == 1
&& static_cast<std::uint8_t>(value_t::array) == 2 && static_cast<std::uint8_t>(value_t::string) == 3
&& static_cast<std::uint8_t>(value_t::boolean) == 4 && static_cast<std::uint8_t>(value_t::number_integer) == 5
@@ -284,7 +297,7 @@ inline void make_link(node& n, node* target) noexcept
{
target->flags = static_cast<std::uint8_t>(target->flags | node_flags::linked);
n = node{};
n.kind = kind_link;
n.kind = node_kind::link;
std::memcpy(reinterpret_cast<unsigned char*>(&n) + 8, static_cast<const void*>(&target), sizeof(const node*)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
}
@@ -314,8 +327,8 @@ NLOHMANN_VIEW_ALWAYS_INLINE void set_integer_bits(node& n, std::uint64_t v) noex
/// token length of a number node
NLOHMANN_VIEW_ALWAYS_INLINE std::uint32_t number_length(const node& n) noexcept
{
return n.kind == static_cast<std::uint8_t>(value_t::number_float) ? n.len
: (n.extra & 0xFFu) + (n.kind == static_cast<std::uint8_t>(value_t::number_integer) ? 1u : 0u);
return n.kind == node_kind::number_float ? n.len
: (n.extra & 0xFFu) + (n.kind == node_kind::number_integer ? 1u : 0u);
}
/// estimated number of nodes for an input of `size` bytes (one node per ~12
@@ -547,7 +560,7 @@ struct document_data
/// following loads.
static NLOHMANN_VIEW_ALWAYS_INLINE const node* deref(const node* n) noexcept
{
return NLOHMANN_VIEW_LIKELY(n->kind != kind_link) ? n : follow_link(n);
return NLOHMANN_VIEW_LIKELY(n->kind != node_kind::link) ? n : follow_link(n);
}
static NLOHMANN_VIEW_NOINLINE const node* follow_link(const node* n) noexcept
@@ -665,25 +678,25 @@ NLOHMANN_JSON_NAMESPACE_END
// with different flags would have different definitions of the same inline
// functions): the check is compiled for SSSE3 with a function attribute and
// used where the CPU has SSSE3 (all x86-64 CPUs since about 2011), else the
// portable check. JSON_VIEW_USE_SSSE3 skips the CPU check (for code compiled
// for SSSE3 anyway); JSON_VIEW_NO_SIMD selects the portable code.
// portable check. Code compiled for SSSE3 anyway (-mssse3 or more) skips the
// CPU check. JSON_NO_SIMD selects the portable code, as in the lexer.
// NLOHMANN_VIEW_NO_TARGET_ATTRIBUTE (set by the GCC module interface, where GCC
// ignores the target attribute and then rejects the SSSE3 intrinsics) keeps the
// check portable without disabling the SSE2 code.
#if !defined(JSON_VIEW_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
#if !defined(JSON_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
#include <arm_neon.h>
#define NLOHMANN_VIEW_NEON 1
#else
#define NLOHMANN_VIEW_NEON 0
#endif
// (x86 only: other targets can define __SSE2__ as well, e.g., WebAssembly with -msse2, but have no <cpuid.h>)
#if !defined(JSON_VIEW_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#if !defined(JSON_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#include <emmintrin.h>
#define NLOHMANN_VIEW_SSE2 1
#else
#define NLOHMANN_VIEW_SSE2 0
#endif
#if NLOHMANN_VIEW_SSE2 && defined(JSON_VIEW_USE_SSSE3)
#if NLOHMANN_VIEW_SSE2 && defined(__SSSE3__)
#include <tmmintrin.h>
#define NLOHMANN_VIEW_SSSE3 1 // NOLINT(cppcoreguidelines-macro-to-enum,modernize-macro-to-enum)
#else
@@ -2169,7 +2182,7 @@ indent_done:
std::memcpy(reinterpret_cast<unsigned char*>(n), &first, 8);
std::memcpy(reinterpret_cast<unsigned char*>(n) + 8, &second, 8);
#else
n->kind = static_cast<std::uint8_t>(k);
n->kind = static_cast<node_kind>(k);
n->flags = flags;
n->extra = extra;
n->off = static_cast<std::uint32_t>(off);
@@ -3001,7 +3014,7 @@ NLOHMANN_JSON_NAMESPACE_END
// live in chunks that never move; strings and number tokens written by edits
// live in the edit arena. An array/object whose elements change gets
// node_flags::moved: its elements then live in a separate sequence (a header
// node, then the entries), whose entries link to the values (kind_link).
// node, then the entries), whose entries link to the values (node_kind::link).
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
@@ -3159,7 +3172,7 @@ inline node* block_of(document_data& d, node* n, std::size_t extra)
return nh;
}
reserve_moved(d); // (so that set_moved() below cannot throw: the links are marked before)
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
const std::size_t used = 1 + (static_cast<std::size_t>(n->len) * (object ? 2 : 1));
const std::size_t cap = used + extra;
node* const h = alloc_nodes(d, cap);
@@ -3225,7 +3238,7 @@ inline node* find_parent(const document_data& d, const node* target)
{
return nullptr; // LCOV_EXCL_LINE (the value is inside c)
}
const bool object = c->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = c->kind == node_kind::object;
const node* down = nullptr;
for (const node* p = d.first_child_edited(c), *e = d.child_end_edited(c); p != e;)
{
@@ -3692,7 +3705,7 @@ const node* element_at(const document_data& d, const node* array, std::size_t id
template<bool Editable>
const node* last_child(const document_data& d, const node* container) noexcept
{
const std::size_t value_offset = container->kind == static_cast<std::uint8_t>(value_t::object) ? 1 : 0;
const std::size_t value_offset = container->kind == node_kind::object ? 1 : 0;
const node* const end = navigation<Editable>::end(d, container);
const node* last = navigation<Editable>::first(d, container);
if (value_offset == 0 && container->next == container->len + 1u && (!navigation<Editable>::editable() || (container->flags & node_flags::moved) == 0))
@@ -3714,12 +3727,38 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/view/node.hpp>
// #include <nlohmann/detail/view/view_mode.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include <cstdint> // uint8_t
// #include <nlohmann/json.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
template<typename BasicJsonType, bool Editable>
/// whether a basic_json_document and its views can be edited
enum class view_mode : std::uint8_t
{
read_only, ///< parsed once, then only read (the default)
editable, ///< also has set(), push_back(), insert(), and erase()
};
template<typename BasicJsonType, view_mode Mode>
class basic_json_view;
NLOHMANN_JSON_NAMESPACE_END
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{
namespace view
@@ -3808,13 +3847,13 @@ class editor
View set(const View& object, string_view_t key, V&& value)
{
node* const o = own(object);
if (o->kind != static_cast<std::uint8_t>(value_t::object) && o->kind != static_cast<std::uint8_t>(value_t::null))
if (o->kind != node_kind::object && o->kind != node_kind::null)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a string argument with ", object.type_name());
}
check_utf8(key.data(), key.size());
const encoded e = encode(std::forward<V>(value));
if (o->kind == static_cast<std::uint8_t>(value_t::null))
if (o->kind == node_kind::null)
{
become_empty(o, value_t::object);
}
@@ -3859,7 +3898,7 @@ class editor
View set(const View& array, std::size_t idx, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a numeric argument with ", array.type_name());
}
@@ -3876,12 +3915,12 @@ class editor
View push_back(const View& array, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array) && a->kind != static_cast<std::uint8_t>(value_t::null))
if (a->kind != node_kind::array && a->kind != node_kind::null)
{
throw_type_error(exception_id::push_back_wrong_type, "cannot use push_back() with ", array.type_name());
}
const encoded e = encode(std::forward<V>(value));
if (a->kind == static_cast<std::uint8_t>(value_t::null))
if (a->kind == node_kind::null)
{
become_empty(a, value_t::array);
}
@@ -3900,7 +3939,7 @@ class editor
View insert(const View& array, std::size_t idx, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::insert_wrong_type, "cannot use insert() with ", array.type_name());
}
@@ -3920,7 +3959,7 @@ class editor
std::size_t erase(const View& object, string_view_t key)
{
node* const o = own(object);
if (o->kind != static_cast<std::uint8_t>(value_t::object))
if (o->kind != node_kind::object)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", object.type_name());
}
@@ -3938,7 +3977,7 @@ class editor
void erase(const View& array, std::size_t idx)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", array.type_name());
}
@@ -4016,7 +4055,7 @@ class editor
{
const std::uint8_t linked = n->flags & node_flags::linked;
*n = node{};
n->kind = static_cast<std::uint8_t>(k);
n->kind = static_cast<node_kind>(k);
n->flags = static_cast<std::uint8_t>(node_flags::is_new | linked);
n->next = 1;
}
@@ -4093,8 +4132,8 @@ class editor
template<typename T>
struct is_view : std::false_type {};
template<typename J, bool E>
struct is_view<basic_json_view<J, E>> : std::true_type {};
template<typename J, view_mode M>
struct is_view<basic_json_view<J, M>> : std::true_type {};
template<typename V>
encoded encode(V&& v)
@@ -4109,8 +4148,8 @@ class editor
}
/// a view of any document (copied; nothing is shared with it)
template<typename J, bool E>
encoded encode_impl(const basic_json_view<J, E>& v, encode_tag<0> /*view*/)
template<typename J, view_mode M>
encoded encode_impl(const basic_json_view<J, M>& v, encode_tag<0> /*view*/)
{
if (NLOHMANN_VIEW_UNLIKELY(v.m_node == nullptr))
{
@@ -4122,8 +4161,8 @@ class editor
r.scalar = copy_scalar(*v.m_doc, *v.m_node);
return r;
}
r.region = alloc_nodes(m_doc, count_nodes<E>(*v.m_doc, v.m_node));
fill_nodes<E>(*v.m_doc, v.m_node, r.region);
r.region = alloc_nodes(m_doc, count_nodes<M == view_mode::editable>(*v.m_doc, v.m_node));
fill_nodes<M == view_mode::editable>(*v.m_doc, v.m_node, r.region);
edit_state_of(m_doc).regions.emplace(r.region, nullptr);
return r;
}
@@ -4184,7 +4223,7 @@ class editor
static node plain_node(value_t k) noexcept
{
node n{};
n.kind = static_cast<std::uint8_t>(k);
n.kind = static_cast<node_kind>(k);
n.flags = node_flags::is_new;
return n;
}
@@ -4369,7 +4408,7 @@ class editor
++r;
if (is_container(*n))
{
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object)});
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object});
}
// the next value: close finished containers, then step over the key
for (;;)
@@ -4418,7 +4457,7 @@ class editor
node* const self = out++;
*self = plain_node(static_cast<value_t>(n->kind));
self->len = n->len;
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object), self});
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object, self});
}
else
{
@@ -4903,7 +4942,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
r.off = (v->flags & (node_flags::moved | node_flags::is_new)) != 0 ? 0 : v->off;
r.len = 0; // counted below
r.next = 0; // set when the container is complete
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == static_cast<std::uint8_t>(value_t::object)});
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == node_kind::object});
break;
case value_t::string:
r = string_node(*v);
@@ -4924,7 +4963,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
if (t[0] == 'n' || t[0] == 'i' || (v->len > 1 && t[1] == 'i'))
{
r = node{}; // nan and infinity: null, as dump() writes them
r.kind = static_cast<std::uint8_t>(value_t::null);
r.kind = node_kind::null;
break;
}
r.off = static_cast<std::uint32_t>(d.size + text_tail.size());
@@ -4968,12 +5007,10 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
}
}
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no save() elsewhere)
/// the document as an image
inline std::vector<std::uint8_t> save_image(const document_data& d)
{
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
#endif
const std::size_t arena_size = d.arena_size;
std::vector<node> compacted;
std::string text_tail;
@@ -5007,7 +5044,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
// extra of an object, and the same document saves to the same bytes
for (std::size_t i = 0; i < count; ++i)
{
if (nodes[i].kind == static_cast<std::uint8_t>(value_t::object) && nodes[i].extra != 0)
if (nodes[i].kind == node_kind::object && nodes[i].extra != 0)
{
std::memset(o + (i * sizeof(node)) + offsetof(node, extra), 0, sizeof(nodes[i].extra));
}
@@ -5029,6 +5066,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
*o = 0;
return image;
}
#endif
/// the parts of a number token that the checks need
struct number_token
@@ -5123,7 +5161,7 @@ inline bool float_token_finite(const unsigned char* s, std::size_t len, const nu
if (static_cast<std::int64_t>(t.int_digits) + t.exponent > 300)
{
node n{};
n.kind = static_cast<std::uint8_t>(value_t::number_float);
n.kind = node_kind::number_float;
n.len = static_cast<std::uint32_t>(len);
const auto v = float_value<double>(reinterpret_cast<const char*>(s), n); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
return v <= (std::numeric_limits<double>::max)() && v >= -(std::numeric_limits<double>::max)();
@@ -5144,7 +5182,7 @@ inline bool check_integer(const node& n, const unsigned char* text)
}
// the token's value is the stored one; number_integer nodes of edits can
// be non-negative (as basic_json keeps the type of a value)
const bool integer = n.kind == static_cast<std::uint8_t>(value_t::number_integer);
const bool integer = n.kind == node_kind::number_integer;
if (t.is_float || t.int_digits > 20 || (t.negative && !integer))
{
return false;
@@ -5326,7 +5364,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
return false;
}
if (n.kind != static_cast<std::uint8_t>(value_t::number_float))
if (n.kind != node_kind::number_float)
{
return (n.extra >> 8u) == 0;
}
@@ -5367,7 +5405,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
const node& n = nodes[i];
if (!stack.empty() && stack.back().object && stack.back().expect_key)
{
if (n.kind != static_cast<std::uint8_t>(value_t::string) || !check_string(n))
if (n.kind != node_kind::string || !check_string(n))
{
return false;
}
@@ -5408,7 +5446,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
// (the contents of float tokens are checked later; the token of an
// integer has at most 256 characters)
if (n.kind == static_cast<std::uint8_t>(value_t::number_float))
if (n.kind == node_kind::number_float)
{
floats.push_back(float_range{n.off, n.len, n.extra});
}
@@ -5426,7 +5464,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
return false;
}
stack.push_back(frame{i + n.next, n.len, 0, n.kind == static_cast<std::uint8_t>(value_t::object), true});
stack.push_back(frame{i + n.next, n.len, 0, n.kind == node_kind::object, true});
complete = false;
break;
}
@@ -5449,13 +5487,11 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
throw_parse_error(exception_id::invalid_document_image, concat("invalid json_document image: ", what));
}
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no load() elsewhere)
/// Read an image into d. The text and the decoded strings stay in the image;
/// the nodes are copied (so that they are aligned, and edits can change them).
inline void load_image(document_data& d, const std::uint8_t* image, std::size_t size, image_check check)
{
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
#endif
if (image == nullptr || size < sizeof(image_header))
{
throw_invalid_image("too short");
@@ -5515,7 +5551,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
for (std::size_t i = 0; i < count; ++i)
{
const node& n = d.nodes[i];
if (n.kind == static_cast<std::uint8_t>(value_t::object) && n.len >= document_data::index_min_members)
if (n.kind == node_kind::object && n.len >= document_data::index_min_members)
{
d.large_objects.push_back(static_cast<std::uint32_t>(i));
}
@@ -5524,6 +5560,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
std::vector<std::uint32_t>().swap(d.large_objects); // (only needed while building)
d.discarded = false;
}
#endif
} // namespace view
} // namespace detail
@@ -6108,7 +6145,7 @@ BasicJsonType materialize(const document_data& d, const node* n)
case value_t::object:
case value_t::array:
{
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
if (object)
{
sax.start_object(n->len);
@@ -7222,7 +7259,7 @@ class view_serializer
case value_t::object:
case value_t::array:
{
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
room(8);
if (n->len == 0)
{
@@ -7773,6 +7810,8 @@ struct is_direct_value<std::unordered_map<K, V, H, E, A>, BasicJsonType, View> :
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/view/view_mode.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
@@ -7782,15 +7821,20 @@ NLOHMANN_JSON_NAMESPACE_BEGIN
Trivially copyable (two pointers). Valid as long as the document is alive and
has not been re-parsed, and as long as a borrowed source text is alive.
*/
template<typename BasicJsonType, bool Editable = false>
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
class basic_json_view
{
/// whether this is a view of an editable document
static constexpr bool is_editable = Mode == view_mode::editable;
using node = detail::view::node;
using document_data = detail::view::document_data;
/// how the index is walked (with edits only for editable documents)
using navigation = detail::view::navigation<Editable>;
using navigation = detail::view::navigation<is_editable>;
public:
/// the basic_json type of the document (it also marks views for is_json_view)
using basic_json_type = BasicJsonType;
using value_t = detail::value_t;
using string_t = typename BasicJsonType::string_t;
using number_integer_t = typename BasicJsonType::number_integer_t;
@@ -8135,7 +8179,7 @@ class basic_json_view
if (is_structured() && m_node->len != 0)
{
return unedited() ? basic_json_view(m_doc, detail::view::last_child<false>(*m_doc, m_node) + (is_object() ? 1 : 0))
: basic_json_view(m_doc, navigation::value(detail::view::last_child<Editable>(*m_doc, m_node) + (is_object() ? 1 : 0)));
: basic_json_view(m_doc, navigation::value(detail::view::last_child<is_editable>(*m_doc, m_node) + (is_object() ? 1 : 0)));
}
return front();
}
@@ -8193,7 +8237,7 @@ class basic_json_view
/// more than once); 0 if this is not an object
size_type count(string_view_t key) const
{
return is_object() ? detail::view::count_members<Editable>(*m_doc, m_node, key.data(), key.size()) : 0;
return is_object() ? detail::view::count_members<is_editable>(*m_doc, m_node, key.data(), key.size()) : 0;
}
size_type count(const char* key) const
@@ -8252,8 +8296,10 @@ class basic_json_view
/// the value converted to T, as BasicJsonType::get<T>(): arithmetic types,
/// strings (string_view_t without a copy), std::nullptr_t, std::vector,
/// maps with string keys, and views are converted directly; other types
/// through materialize().get<T>()
/// maps with string keys, and views are converted directly; types whose
/// from_json() accepts views (those of the NLOHMANN_DEFINE_TYPE_* and
/// NLOHMANN_JSON_SERIALIZE_ENUM macros, say) read the view; other types
/// go through materialize().get<T>()
template<typename T>
NLOHMANN_VIEW_ALWAYS_INLINE T get() const
{
@@ -8261,11 +8307,12 @@ class basic_json_view
}
/// as BasicJsonType::get_to(): the types get<T>() converts directly are
/// assigned, all others are passed to from_json with v as it is
/// assigned, all others are passed to from_json with v as it is (with
/// the view if from_json() accepts views, else with materialize())
template<typename T>
T& get_to(T& v) const
{
get_to_impl(v, detail::view::is_direct_value<T, BasicJsonType, basic_json_view> {});
get_to_impl(v, get_to_kind<T> {});
return v;
}
@@ -8335,7 +8382,7 @@ class basic_json_view
}
else
{
detail::view::view_serializer<BasicJsonType, Editable>(*m_doc, out, estimate, style).dump(m_node);
detail::view::view_serializer<BasicJsonType, is_editable>(*m_doc, out, estimate, style).dump(m_node);
}
return out;
}
@@ -8371,14 +8418,14 @@ class basic_json_view
}
/// a view of an editable document compares with one of a read-only document
template < bool E, typename std::enable_if < E != Editable, int >::type = 0 >
friend bool operator==(const basic_json_view& a, const basic_json_view<BasicJsonType, E>& b)
template < view_mode M, typename std::enable_if < M != Mode, int >::type = 0 >
friend bool operator==(const basic_json_view& a, const basic_json_view<BasicJsonType, M>& b)
{
return detail::view::equal<BasicJsonType>(side(a), detail::view::view_side<BasicJsonType, basic_json_view<BasicJsonType, E>>(b));
return detail::view::equal<BasicJsonType>(side(a), detail::view::view_side<BasicJsonType, basic_json_view<BasicJsonType, M>>(b));
}
template < bool E, typename std::enable_if < E != Editable, int >::type = 0 >
friend bool operator!=(const basic_json_view& a, const basic_json_view<BasicJsonType, E>& b)
template < view_mode M, typename std::enable_if < M != Mode, int >::type = 0 >
friend bool operator!=(const basic_json_view& a, const basic_json_view<BasicJsonType, M>& b)
{
return !(a == b);
}
@@ -8416,7 +8463,7 @@ class basic_json_view
{
return BasicJsonType(value_t::discarded);
}
return unedited() ? detail::view::materialize<BasicJsonType, false>(*m_doc, m_node) : detail::view::materialize<BasicJsonType, Editable>(*m_doc, m_node);
return unedited() ? detail::view::materialize<BasicJsonType, false>(*m_doc, m_node) : detail::view::materialize<BasicJsonType, is_editable>(*m_doc, m_node);
}
/// byte offset of this value in the source text (for strings: of the
@@ -8429,8 +8476,8 @@ class basic_json_view
}
private:
template<typename, bool> friend class basic_json_document;
template<typename, bool> friend class basic_json_view;
template<typename, view_mode> friend class basic_json_document;
template<typename, view_mode> friend class basic_json_view;
template<typename, typename> friend class detail::view::editor;
friend iterator;
@@ -8446,11 +8493,11 @@ class basic_json_view
}
/// the template argument as a runtime condition: testing it directly in
/// `Editable && ...` makes the condition constant, which MSVC reports as
/// `is_editable && ...` makes the condition constant, which MSVC reports as
/// C4127
static bool editable() noexcept
{
return Editable;
return is_editable;
}
/// the number of source bytes of this value (estimated for values with
@@ -8499,7 +8546,7 @@ class basic_json_view
const node* const k = detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size());
return k != nullptr ? basic_json_view(m_doc, k + 1) : basic_json_view();
}
const node* const k = detail::view::find_member<Editable>(*m_doc, m_node, key.data(), key.size());
const node* const k = detail::view::find_member<is_editable>(*m_doc, m_node, key.data(), key.size());
return k != nullptr ? basic_json_view(m_doc, navigation::value(k + 1)) : basic_json_view();
}
@@ -8513,7 +8560,7 @@ class basic_json_view
/// the member of this object with @a key (the last one if the key occurs more than once), or nullptr
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key) const
{
return find_key(key, std::integral_constant<bool, Editable> {});
return find_key(key, std::integral_constant<bool, is_editable> {});
}
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key, std::true_type /*editable*/) const
@@ -8535,7 +8582,7 @@ class basic_json_view
{
return basic_json_view(m_doc, detail::view::element_at<false>(*m_doc, m_node, idx));
}
return basic_json_view(m_doc, navigation::value(detail::view::element_at<Editable>(*m_doc, m_node, idx)));
return basic_json_view(m_doc, navigation::value(detail::view::element_at<is_editable>(*m_doc, m_node, idx)));
}
// --- get() dispatch ---
@@ -8608,6 +8655,26 @@ class basic_json_view
return detail::view::map_value<std::unordered_map<K, V, H, E, A>>(*this);
}
/// whether the from_json() of T's serializer reads views (see
/// detail::has_view_from_json)
template<typename T>
using reads_view = detail::has_view_from_json<typename BasicJsonType::template json_serializer<T, void>, basic_json_view, T>;
/// how get_to() converts: 2 directly, 1 with a from_json() that reads
/// views, 0 through materialize()
template<typename T>
using get_to_kind = std::integral_constant < int, detail::view::is_direct_value<T, BasicJsonType, basic_json_view>::value
? 2 : static_cast<int>(reads_view<T>::value) >;
/// types whose from_json() reads views, without materialize()
template < typename T, typename std::enable_if < reads_view<T>::value && std::is_default_constructible<T>::value, int >::type = 0 >
T get_impl(detail::view::value_tag<T> /*unused*/, detail::priority_tag<1> /*unused*/) const
{
auto v = T();
BasicJsonType::template json_serializer<T, void>::from_json(*this, v);
return v;
}
/// everything else through the BasicJsonType value (from_json included)
template<typename T>
T get_impl(detail::view::value_tag<T> /*unused*/, detail::priority_tag<0> /*unused*/) const
@@ -8618,14 +8685,20 @@ class basic_json_view
// --- get_to() dispatch ---
template<typename T>
void get_to_impl(T& v, std::true_type /*direct*/) const
void get_to_impl(T& v, std::integral_constant<int, 2> /*direct*/) const
{
v = get<T>();
}
/// from_json may keep parts of v (members a JSON object lacks, say)
template<typename T>
void get_to_impl(T& v, std::false_type /*direct*/) const
void get_to_impl(T& v, std::integral_constant<int, 1> /*from_json reads views*/) const
{
BasicJsonType::template json_serializer<T, void>::from_json(*this, v);
}
template<typename T>
void get_to_impl(T& v, std::integral_constant<int, 0> /*through materialize()*/) const
{
materialize().get_to(v);
}
@@ -8641,16 +8714,19 @@ Borrowed parses keep a pointer to the caller's text, which must outlive the
document. Owned parses (parse_copy, rvalue std::string, streams, and inputs
that are not contiguous byte ranges) keep their own copy.
*/
template<typename BasicJsonType, bool Editable = false>
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
class basic_json_document
{
/// whether the document can be edited
static constexpr bool is_editable = Mode == view_mode::editable;
using document_data = detail::view::document_data;
static_assert(sizeof(typename BasicJsonType::number_integer_t) == 8 && sizeof(typename BasicJsonType::number_unsigned_t) == 8,
"json_view supports 64-bit integer types only");
public:
using view_type = basic_json_view<BasicJsonType, Editable>;
using view_type = basic_json_view<BasicJsonType, Mode>;
using value_t = detail::value_t;
/// an empty (discarded) document
@@ -8864,6 +8940,10 @@ class basic_json_document
/// how load() checks an image (full, bounds, or none)
using image_check = detail::view::image_check;
#if NLOHMANN_VIEW_LITTLE_ENDIAN
// (the image format is little-endian: big-endian targets have no save()
// and load(), so that a call fails to compile instead of always throwing)
/// The document as an image that load() reads without parsing: the node
/// index, the text, and the decoded strings. An edited document is
/// written in its current state (floats that are not finite become null,
@@ -8905,6 +8985,7 @@ class basic_json_document
detail::view::load_image(*d.m_data, d.m_data->owned_image.data(), d.m_data->owned_image.size(), check);
return d;
}
#endif
///////////
// edits //
@@ -9046,7 +9127,7 @@ class basic_json_document
detail::view::editor<BasicJsonType, view_type> editor()
{
static_assert(Editable, "only an editable document can be edited: use basic_json_document<BasicJsonType, true> (json_editable_document)");
static_assert(is_editable, "only an editable document can be edited: use basic_json_document<BasicJsonType, view_mode::editable> (json_editable_document)");
if (NLOHMANN_VIEW_UNLIKELY(!m_data || m_data->discarded))
{
detail::view::throw_invalid_iterator(detail::exception_id::iterator_from_other_value, "view does not belong to this document");
@@ -9322,6 +9403,15 @@ class basic_json_document
std::unique_ptr<document_data, document_data::deleter> m_data{}; // NOLINT(readability-redundant-member-init)
};
/*!
@brief whether T is a basic_json_view (of any BasicJsonType and view_mode)
For constraining templates that accept views, e.g. a from_json() written for
both basic_json values and views.
*/
template<typename T>
struct is_json_view : detail::is_json_view<T> {};
/// a parsed JSON text for json
using json_document = basic_json_document<json>;
/// a value of a json_document
@@ -9331,13 +9421,13 @@ using ordered_json_document = basic_json_document<ordered_json>;
/// a value of an ordered_json_document
using ordered_json_view = basic_json_view<ordered_json>;
/// an editable parsed JSON text for json
using json_editable_document = basic_json_document<json, true>;
using json_editable_document = basic_json_document<json, view_mode::editable>;
/// a value of a json_editable_document
using json_editable_view = basic_json_view<json, true>;
using json_editable_view = basic_json_view<json, view_mode::editable>;
/// an editable parsed JSON text for ordered_json
using ordered_json_editable_document = basic_json_document<ordered_json, true>;
using ordered_json_editable_document = basic_json_document<ordered_json, view_mode::editable>;
/// a value of an ordered_json_editable_document
using ordered_json_editable_view = basic_json_view<ordered_json, true>;
using ordered_json_editable_view = basic_json_view<ordered_json, view_mode::editable>;
NLOHMANN_JSON_NAMESPACE_END
+2 -3
View File
@@ -420,9 +420,9 @@ json_test_add_test_for(src/unit-file_input.cpp
)
# the json_view parser again with the portable string scanning instead of
# NEON/SSE2, and on x86-64 with the SSSE3 UTF-8 check (JSON_VIEW_USE_SSSE3)
# NEON/SSE2 (JSON_NO_SIMD), and on x86-64 compiled for SSSE3 (no CPU check)
json_test_set_test_options(test-json_view_builder_portable
COMPILE_DEFINITIONS JSON_VIEW_NO_SIMD
COMPILE_DEFINITIONS JSON_NO_SIMD
)
json_test_add_test_for(src/unit-json_view_builder.cpp
NAME test-json_view_builder_portable
@@ -430,7 +430,6 @@ json_test_add_test_for(src/unit-json_view_builder.cpp
)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64)$" AND NOT MSVC)
json_test_set_test_options(test-json_view_builder_ssse3
COMPILE_DEFINITIONS JSON_VIEW_USE_SSSE3
COMPILE_OPTIONS -mssse3
)
json_test_add_test_for(src/unit-json_view_builder.cpp
+1 -3
View File
@@ -24,9 +24,7 @@ foreach(test default noversion)
JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1
JSON_DISABLE_STREAM_BULK_SCAN=1
JSON_DISABLE_UNLOCKED_FILE_IO=1
JSON_NO_SIMD
JSON_VIEW_NO_SIMD
JSON_VIEW_USE_SSSE3)
JSON_NO_SIMD)
target_link_libraries(abi_config_${test}_all_tags PRIVATE abi_compat_main)
add_test(
NAME test-abi_config_${test}_all_tags
-8
View File
@@ -64,14 +64,6 @@ TEST_CASE("default namespace")
expected += "_ns";
#endif
#ifdef JSON_VIEW_NO_SIMD
expected += "_vns";
#endif
#ifdef JSON_VIEW_USE_SSSE3
expected += "_vssse3";
#endif
expected += "_v" STRINGIZE(NLOHMANN_JSON_VERSION_MAJOR);
expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_MINOR);
expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_PATCH) "::basic_json";
-8
View File
@@ -65,14 +65,6 @@ TEST_CASE("default namespace without version component")
expected += "_ns";
#endif
#ifdef JSON_VIEW_NO_SIMD
expected += "_vns";
#endif
#ifdef JSON_VIEW_USE_SSSE3
expected += "_vssse3";
#endif
expected += "::basic_json";
// fallback for Clang
+6
View File
@@ -59,6 +59,12 @@ An editable `json_document` edits in place; yyjson copies its immutable document
(`yyjson_doc_mut_copy`); Boost.JSON and `json::parse` build mutable DOMs; simdjson cannot edit a document. All
outputs are checked to describe the same value.
`bench_decode.cpp` measures decoding into structs whose `from_json()` comes from the `NLOHMANN_DEFINE_TYPE_*` macros
(twitter statuses, citm_catalog performances, and 20,000 synthetic records): `get<T>()` on a view, which reads the
view directly, against `materialize().get<T>()`, `json::parse` plus `get<T>()`, and `get<T>()` on an already parsed
`json` value. Only nlohmann/json takes part, as the other libraries have no comparable mapping; all engines are
checked to decode the same values.
Before anything is timed, all engines must accept each document and agree on the traversal: the number of values, the
bytes of all strings and keys, and the sum of all numbers. All engines run interleaved in every round, and the best
round is reported, as time and as a factor of the `json_view` time (below 1 means faster than `json_view`). Each timed
+312
View File
@@ -0,0 +1,312 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// Decoding into structs: the same types, with from_json() generated by the
// NLOHMANN_DEFINE_TYPE_* macros, read three ways. Only nlohmann/json takes
// part; the other libraries have no comparable mapping.
//
// view json_document::parse, then get<T>() on the view (from_json reads the view)
// materialize json_document::parse, then materialize().get<T>() (a json value first)
// json::parse json::parse, then get<T>()
// json::get get<T>() on an already parsed json value (the decoding alone)
//
// Documents: twitter (the statuses with their users and hashtags), citm_catalog
// (the performances with their seat categories), and a synthetic document of
// 20,000 nested records.
//
// Build: see README.md (same flags as bench_view.cpp).
#include <nlohmann/json_view.hpp>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <functional>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
using nlohmann::json;
using nlohmann::json_document;
static volatile std::size_t g_sink;
namespace twitter
{
struct hashtag
{
std::string text;
std::vector<int> indices;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(hashtag, text, indices)
struct entities
{
std::vector<hashtag> hashtags;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(entities, hashtags)
struct user
{
std::uint64_t id = 0;
std::string screen_name;
std::string description;
std::int64_t followers_count = 0;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(user, id, screen_name, description, followers_count)
struct status
{
std::uint64_t id = 0;
std::string text;
user user;
entities entities;
std::int64_t retweet_count = 0;
std::int64_t favorite_count = 0;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(status, id, text, user, entities, retweet_count, favorite_count)
struct document
{
std::vector<status> statuses;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(document, statuses)
std::size_t digest(const document& d)
{
std::size_t n = 0;
for (const auto& s : d.statuses)
{
n += s.text.size() + s.user.screen_name.size() + s.entities.hashtags.size() + static_cast<std::size_t>(s.retweet_count);
}
return n;
}
} // namespace twitter
namespace citm
{
struct area
{
std::int64_t areaId = 0;
std::vector<std::int64_t> blockIds;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(area, areaId, blockIds)
struct seat_category
{
std::vector<area> areas;
std::int64_t seatCategoryId = 0;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(seat_category, areas, seatCategoryId)
struct performance
{
std::int64_t id = 0;
std::int64_t eventId = 0;
std::vector<seat_category> seatCategories;
std::int64_t start = 0;
std::string venueCode;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(performance, id, eventId, seatCategories, start, venueCode)
struct document
{
std::vector<performance> performances;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(document, performances)
std::size_t digest(const document& d)
{
std::size_t n = 0;
for (const auto& p : d.performances)
{
n += p.seatCategories.size() + p.venueCode.size() + static_cast<std::size_t>(p.start % 1000);
for (const auto& c : p.seatCategories)
{
n += c.areas.size();
}
}
return n;
}
} // namespace citm
namespace synthetic
{
struct position
{
double x = 0;
double y = 0;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(position, x, y)
struct child
{
std::int64_t id = 0;
std::string label;
bool active = false;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(child, id, label, active)
struct record
{
std::int64_t id = 0;
std::string name;
std::vector<std::string> tags;
position pos;
std::vector<child> children;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(record, id, name, tags, pos, children)
struct document
{
std::vector<record> records;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(document, records)
std::string make_text(std::size_t n)
{
std::string s = "{\"records\":[";
for (std::size_t i = 0; i < n; ++i)
{
const std::string id = std::to_string(i);
s += (i == 0 ? "" : ",");
s += "{\"id\":" + id + ",\"name\":\"record number " + id + "\",\"tags\":[\"alpha\",\"beta\",\"gamma\"],";
s += "\"pos\":{\"x\":" + id + ".25,\"y\":-" + id + ".5},\"children\":[";
for (std::size_t k = 0; k < 3; ++k)
{
s += (k == 0 ? "" : ",");
s += "{\"id\":" + std::to_string(i * 3 + k) + ",\"label\":\"child " + std::to_string(k) + "\",\"active\":" + (k % 2 == 0 ? "true" : "false") + "}";
}
s += "]}";
}
s += "]}";
return s;
}
std::size_t digest(const document& d)
{
std::size_t n = 0;
for (const auto& r : d.records)
{
n += r.name.size() + r.tags.size() + r.children.size() + static_cast<std::size_t>(r.pos.x);
}
return n;
}
} // namespace synthetic
namespace
{
std::string read_file(const std::string& p)
{
std::ifstream f(p, std::ios::binary);
if (!f)
{
std::fprintf(stderr, "cannot open %s\n", p.c_str());
std::exit(1);
}
std::stringstream ss;
ss << f.rdbuf();
return ss.str();
}
double time_ns(const std::function<void()>& f)
{
const auto t0 = std::chrono::steady_clock::now();
f();
const auto t1 = std::chrono::steady_clock::now();
return static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count());
}
struct engine
{
std::string name;
std::function<std::size_t()> run;
};
template<typename Document>
std::vector<engine> engines(const std::string& text, const json& parsed)
{
return
{
{"view", [&text] { const json_document d = json_document::parse(text); return digest(d.root().get<Document>()); }},
{"materialize", [&text] { const json_document d = json_document::parse(text); return digest(d.root().materialize().get<Document>()); }},
{"json::parse", [&text] { return digest(json::parse(text).get<Document>()); }},
{"json::get", [&parsed] { return digest(parsed.get<Document>()); }},
};
}
} // namespace
int main(int argc, char** argv)
{
if (argc < 2)
{
std::fprintf(stderr, "usage: %s <json_test_data directory> [rounds]\n", argv[0]);
return 1;
}
const std::string dir = argv[1];
const int rounds = argc > 2 ? std::max(1, std::atoi(argv[2])) : 30;
struct document_case
{
std::string name;
std::string text;
json parsed;
std::vector<engine> engines;
};
std::vector<document_case> cases;
cases.push_back({"twitter", read_file(dir + "/nativejson-benchmark/twitter.json"), json(), {}});
cases.push_back({"citm_catalog", read_file(dir + "/nativejson-benchmark/citm_catalog.json"), json(), {}});
cases.push_back({"synthetic", synthetic::make_text(20000), json(), {}});
for (auto& c : cases)
{
c.parsed = json::parse(c.text);
}
cases[0].engines = engines<twitter::document>(cases[0].text, cases[0].parsed);
cases[1].engines = engines<citm::document>(cases[1].text, cases[1].parsed);
cases[2].engines = engines<synthetic::document>(cases[2].text, cases[2].parsed);
std::FILE* csv = std::fopen("bench_decode.csv", "w");
if (csv == nullptr)
{
std::perror("bench_decode.csv");
return 1;
}
std::fprintf(csv, "doc,bytes,engine,ns\n");
for (const auto& c : cases)
{
// all engines must decode the same values
const std::size_t expected = c.engines[0].run();
bool ok = true;
for (const auto& e : c.engines)
{
ok = ok && e.run() == expected;
}
std::vector<double> best(c.engines.size(), 1e300);
for (int r = 0; r < rounds; ++r)
{
for (std::size_t k = 0; k < c.engines.size(); ++k)
{
g_sink = c.engines[k].run(); // untimed: see bench_view.cpp
best[k] = std::min(best[k], time_ns([&] { g_sink = c.engines[k].run(); }));
}
}
std::printf("%-13s %-7s %s", c.name.c_str(), "decode", ok ? "" : "[MISMATCH] ");
for (std::size_t k = 0; k < c.engines.size(); ++k)
{
const double us = best[k] / 1000.0;
std::printf(" %s %.*fus (%.2fx)", c.engines[k].name.c_str(), us < 10 ? 3 : (us < 1000 ? 1 : 0), us, best[k] / best[0]);
std::fprintf(csv, "%s,%zu,%s,%.1f\n", c.name.c_str(), c.text.size(), c.engines[k].name.c_str(), best[k]);
}
std::printf("\n");
}
std::fclose(csv);
return 0;
}
+5 -3
View File
@@ -9,7 +9,7 @@
"""Compare json_view with yyjson, simdjson, Boost.JSON, and json::parse.
Builds bench_view.cpp, bench_corpus.cpp, and bench_edit.cpp against the include/ directory of
Builds bench_view.cpp, bench_corpus.cpp, bench_edit.cpp, and bench_decode.cpp against the include/ directory of
this checkout, runs them, and writes the results with everything needed to
reproduce them (date, commit, CPU, OS, compiler, library versions, flags) to
results/<date>-<host>.md and .csv next to this script.
@@ -283,7 +283,7 @@ def main():
objects.append(obj)
binaries = {}
for bench in ['bench_view', 'bench_corpus', 'bench_edit']:
for bench in ['bench_view', 'bench_corpus', 'bench_edit', 'bench_decode']:
exe = os.path.join(args.build_dir, bench)
run(cxx + flags + include + [os.path.join(HERE, bench + '.cpp')] + objects + link + ['-o', exe])
binaries[bench] = exe
@@ -297,6 +297,8 @@ def main():
capture_output=True, text=True).stdout
outputs['bench_edit'] = run([binaries['bench_edit'], args.data, str(max(1, args.rounds // 2))], cwd=args.build_dir,
capture_output=True, text=True).stdout
outputs['bench_decode'] = run([binaries['bench_decode'], args.data, str(max(1, args.rounds // 2))], cwd=args.build_dir,
capture_output=True, text=True).stdout
for name, text in outputs.items():
print(text)
@@ -330,7 +332,7 @@ def main():
f.write(f'\n## {name}\n\n```\n{text.rstrip()}\n```\n')
with open(stem + '.csv', 'w', encoding='utf-8') as out:
out.write(''.join(f'# {key}: {value}\n' for key, value in meta))
for name in ['bench_view', 'bench_corpus', 'bench_edit']:
for name in ['bench_view', 'bench_corpus', 'bench_edit', 'bench_decode']:
path = os.path.join(args.build_dir, name + '.csv')
if os.path.isfile(path):
with open(path, encoding='utf-8') as f:
+2 -2
View File
@@ -592,7 +592,7 @@ TEST_CASE("json_view node integer bits")
})
{
CAPTURE(v)
n.kind = 0x5A;
n.kind = static_cast<nlohmann::detail::view::node_kind>(0x5A);
n.flags = 0xA5;
n.extra = 0x1234;
n.off = 0x89ABCDEFu;
@@ -601,7 +601,7 @@ TEST_CASE("json_view node integer bits")
CHECK(n.len == static_cast<std::uint32_t>(v));
CHECK(n.next == static_cast<std::uint32_t>(v >> 32));
// the other fields are untouched
CHECK(n.kind == 0x5A);
CHECK(static_cast<std::uint8_t>(n.kind) == 0x5A);
CHECK(n.flags == 0xA5);
CHECK(n.extra == 0x1234);
CHECK(n.off == 0x89ABCDEFu);
+68 -1
View File
@@ -26,12 +26,79 @@ using nlohmann::json_editable_view;
#include <limits>
#include <map>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// These tests were split off unit-json_view_edit.cpp, whose object file got too
// large for the MinGW linker (see json_view_test_helpers.hpp).
namespace
{
// the three ways a function can accept views: editable ones, read-only ones, or both
template<typename BasicJsonType>
int accepts_editable(nlohmann::basic_json_view<BasicJsonType, nlohmann::view_mode::editable> /*unused*/)
{
return 1;
}
template<typename BasicJsonType>
int accepts_read_only(nlohmann::basic_json_view<BasicJsonType, nlohmann::view_mode::read_only> /*unused*/)
{
return 2;
}
template<typename BasicJsonType, nlohmann::view_mode Mode>
int accepts_any(nlohmann::basic_json_view<BasicJsonType, Mode> /*unused*/)
{
return Mode == nlohmann::view_mode::editable ? 3 : 4;
}
template<typename View>
auto overload(View v) -> decltype(accepts_editable(v))
{
return accepts_editable(v);
}
template<typename View>
auto overload(View v) -> decltype(accepts_read_only(v))
{
return accepts_read_only(v);
}
} // namespace
TEST_CASE("json_view modes")
{
using nlohmann::basic_json_document;
using nlohmann::basic_json_view;
using nlohmann::ordered_json;
using nlohmann::view_mode;
SECTION("read-only is the default, and the shortcuts name the modes")
{
static_assert(std::is_same<basic_json_view<json>, basic_json_view<json, view_mode::read_only>>::value, "default mode");
static_assert(std::is_same<basic_json_document<json>, basic_json_document<json, view_mode::read_only>>::value, "default mode");
static_assert(std::is_same<nlohmann::json_view, basic_json_view<json, view_mode::read_only>>::value, "json_view");
static_assert(std::is_same<json_editable_view, basic_json_view<json, view_mode::editable>>::value, "json_editable_view");
static_assert(std::is_same<json_editable_document, basic_json_document<json, view_mode::editable>>::value, "json_editable_document");
static_assert(std::is_same<nlohmann::ordered_json_editable_view, basic_json_view<ordered_json, view_mode::editable>>::value, "ordered_json_editable_view");
static_assert(std::is_same<json_editable_document::view_type, json_editable_view>::value, "view_type");
static_assert(std::is_same<json_document::view_type, nlohmann::json_view>::value, "view_type");
}
SECTION("a function template selects views by their mode")
{
const json_document d = json_document::parse("[1]");
const json_editable_document e = json_editable_document::parse("[1]");
const nlohmann::ordered_json_editable_document o = nlohmann::ordered_json_editable_document::parse("[1]");
CHECK(overload(e.root()) == 1);
CHECK(overload(o.root()) == 1);
CHECK(overload(d.root()) == 2);
CHECK(accepts_any(e.root()) == 3);
CHECK(accepts_any(d.root()) == 4);
}
}
TEST_CASE("json_view edits: views and values")
{
SECTION("a value that is no longer part of the document")
@@ -100,7 +167,7 @@ TEST_CASE("json_view edits: views and values")
// doubles have their own path to the output; other float types are
// written as basic_json writes them, non-finite values as null
using json_float = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
using document_float = nlohmann::basic_json_document<json_float, true>;
using document_float = nlohmann::basic_json_document<json_float, nlohmann::view_mode::editable>;
document_float d = document_float::parse("[1.5]");
d.push_back(d.root(), std::numeric_limits<float>::quiet_NaN());
d.push_back(d.root(), -std::numeric_limits<float>::infinity());
+357
View File
@@ -0,0 +1,357 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include "doctest_compatibility.h"
#include <nlohmann/json_view.hpp>
using nlohmann::json;
using nlohmann::json_document;
using nlohmann::json_view;
using nlohmann::json_editable_document;
using nlohmann::ordered_json_document;
#include "json_view_test_helpers.hpp"
#if !defined(JSON_NOEXCEPTION)
using json_view_test::exception_of_call;
#endif
#include <array>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <set>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <valarray>
#include <vector>
#ifdef JSON_HAS_CPP_17
#include <optional>
#endif
// The from_json() functions of the NLOHMANN_DEFINE_TYPE_* and
// NLOHMANN_JSON_SERIALIZE_ENUM macros read views directly; other from_json()
// functions get the value of materialize().
namespace view_from_json
{
struct point
{
int x = 0;
int y = 0;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(point, x, y)
};
struct shape
{
std::string name;
std::vector<point> points;
point center;
std::map<std::string, point> named;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(shape, name, points, center, named)
};
struct with_defaults
{
int a = 1;
std::string b = "default";
std::vector<int> c = {1, 2};
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(with_defaults, a, b, c)
struct with_names
{
int value = 0;
std::string text;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES(with_names, "Value", value, "Text", text)
struct empty
{
NLOHMANN_DEFINE_TYPE_INTRUSIVE(empty)
};
enum class color
{
red,
green,
blue
};
NLOHMANN_JSON_SERIALIZE_ENUM(color,
{
{color::red, "red"},
{color::green, "green"},
{color::blue, nullptr},
})
enum class strict_color
{
red,
green
};
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(strict_color,
{
{strict_color::red, "red"},
{strict_color::green, 1},
})
struct base
{
int id = 0;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(base, id)
};
struct derived : base
{
color c = color::red;
NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(derived, base, c)
};
struct derived_with_defaults : base
{
std::string label = "none";
NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(derived_with_defaults, base, label)
};
// a base whose from_json() is written for json only: the derived type reads
// its own members from the view and the base part from materialize()
struct legacy_base
{
int id = 0;
};
// NOLINTNEXTLINE(misc-use-internal-linkage): found by ADL, like the from_json() functions of users
inline void from_json(const json& j, legacy_base& b)
{
b.id = j.at("id").get<int>();
}
struct derived_from_legacy : legacy_base
{
int extra = 0;
};
NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(derived_from_legacy, legacy_base, extra)
// from_json() for json only: converted through materialize()
struct legacy
{
int v = 0;
};
// NOLINTNEXTLINE(misc-use-internal-linkage): found by ADL, like the from_json() functions of users
inline void from_json(const json& j, legacy& l)
{
l.v = j.at("v").get<int>();
}
// an unconstrained from_json() template, as in the documentation of
// arbitrary type conversions: converted through materialize()
struct unconstrained
{
int v = 0;
};
template<typename BasicJsonType>
// NOLINTNEXTLINE(misc-use-internal-linkage): found by ADL, like the from_json() functions of users
void from_json(const BasicJsonType& j, unconstrained& u)
{
u.v = j.at("v").template get<int>();
}
// a from_json() constrained by the user to views and json: reads the view
struct constrained
{
int v = 0;
};
template < typename J, typename std::enable_if < nlohmann::is_json_view<J>::value || std::is_same<J, json>::value, int >::type = 0 >
// NOLINTNEXTLINE(misc-use-internal-linkage): found by ADL, like the from_json() functions of users
void from_json(const J& j, constrained& c)
{
c.v = j.at("v").template get<int>();
}
} // namespace view_from_json
namespace
{
template<typename T, typename View = json_view>
struct reads_view : nlohmann::detail::has_view_from_json<nlohmann::adl_serializer<T, void>, View, T> {};
} // namespace
TEST_CASE("json_view from_json")
{
using namespace view_from_json; // NOLINT(google-build-using-namespace)
SECTION("which from_json() functions read views")
{
static_assert(reads_view<point>::value, "macro types read views");
static_assert(reads_view<shape>::value, "macro types read views");
static_assert(reads_view<with_defaults>::value, "macro types read views");
static_assert(reads_view<with_names>::value, "macro types read views");
static_assert(reads_view<empty>::value, "macro types read views");
static_assert(reads_view<derived>::value, "macro types read views");
static_assert(reads_view<derived_from_legacy>::value, "macro types read views");
static_assert(reads_view<color>::value, "enum macro types read views");
static_assert(reads_view<strict_color>::value, "enum macro types read views");
static_assert(reads_view<constrained>::value, "constrained from_json() reads views");
static_assert(reads_view<point, nlohmann::json_editable_view>::value, "editable views as well");
static_assert(reads_view<point, nlohmann::ordered_json_view>::value, "views of ordered_json as well");
static_assert(!reads_view<legacy>::value, "from_json() for json");
static_assert(!reads_view<legacy_base>::value, "from_json() for json");
static_assert(!reads_view<unconstrained>::value, "unconstrained from_json()");
static_assert(nlohmann::is_json_view<json_view>::value, "is_json_view");
static_assert(nlohmann::is_json_view<nlohmann::ordered_json_editable_view>::value, "is_json_view");
static_assert(!nlohmann::is_json_view<json>::value, "is_json_view");
static_assert(!nlohmann::is_json_view<json_document>::value, "is_json_view");
static_assert(!nlohmann::is_json_view<int>::value, "is_json_view");
}
SECTION("the library's own conversions are not called with a view (and the probe compiles for them)")
{
// these go through materialize() (vectors, maps with string keys,
// strings, and numbers are converted by the view itself)
static_assert(!reads_view<std::list<int>>::value, "std types");
static_assert(!reads_view<std::deque<point>>::value, "std types");
static_assert(!reads_view<std::set<std::string>>::value, "std types");
static_assert(!reads_view<std::unordered_set<int>>::value, "std types");
static_assert(!reads_view<std::forward_list<int>>::value, "std types");
static_assert(!reads_view<std::valarray<double>>::value, "std types");
static_assert(!reads_view<std::array<int, 3>>::value, "std types");
static_assert(!reads_view<std::pair<int, std::string>>::value, "std types");
static_assert(!reads_view<std::tuple<int, bool, point>>::value, "std types");
static_assert(!reads_view<std::map<int, int>>::value, "std types");
static_assert(!reads_view<std::unordered_map<int, point>>::value, "std types");
static_assert(!reads_view<std::map<color, int>>::value, "std types");
static_assert(!reads_view<std::map<std::string, int>>::value, "std types");
static_assert(!reads_view<std::vector<point>>::value, "std types");
static_assert(!reads_view<std::vector<bool>>::value, "std types");
static_assert(!reads_view<std::vector<std::uint8_t>>::value, "std types");
static_assert(!reads_view<std::string>::value, "std types");
static_assert(!reads_view<int>::value, "std types");
static_assert(!reads_view<bool>::value, "std types");
static_assert(!reads_view<double>::value, "std types");
static_assert(!reads_view<std::nullptr_t>::value, "std types");
static_assert(!reads_view<json>::value, "std types");
static_assert(!reads_view<json::binary_t>::value, "std types");
#ifdef JSON_HAS_CPP_17
static_assert(!reads_view<std::optional<point>>::value, "std types");
#endif
CHECK(true);
}
SECTION("macro types")
{
const json_document d = json_document::parse(R"({"name": "s", "points": [{"x": 1, "y": 2}, {"x": 3, "y": 4}],
"center": {"x": 5, "y": 6}, "named": {"a": {"x": 7, "y": 8}}})");
const shape s = d.root().get<shape>();
CHECK(s.name == "s");
CHECK(s.points.size() == 2);
CHECK(s.points[1].y == 4);
CHECK(s.center.x == 5);
CHECK(s.named.at("a").y == 8);
point p;
d.root()["center"].get_to(p);
CHECK(p.x == 5);
CHECK(p.y == 6);
static_cast<void>(d.root()["center"].get<empty>());
}
SECTION("defaults and names")
{
const json_document d = json_document::parse(R"({"a": 5, "Value": 3, "Text": "t"})");
const with_defaults w = d.root().get<with_defaults>();
CHECK(w.a == 5);
CHECK(w.b == "default");
CHECK(w.c == std::vector<int> {1, 2});
const json_document null_document = json_document::parse("null");
CHECK(null_document.root().get<with_defaults>().a == 1);
const with_names n = d.root().get<with_names>();
CHECK(n.value == 3);
CHECK(n.text == "t");
}
SECTION("enums")
{
const json_document d = json_document::parse(R"(["green", null, "purple", 1, "red"])");
CHECK(d.root()[0].get<color>() == color::green);
CHECK(d.root()[1].get<color>() == color::blue);
CHECK(d.root()[2].get<color>() == color::red); // unknown values map to the first entry
CHECK(d.root()[3].get<strict_color>() == strict_color::green);
CHECK(d.root()[4].get<strict_color>() == strict_color::red);
#if !defined(JSON_NOEXCEPTION)
const json j = d.root().materialize();
CHECK(exception_of_call([&] { static_cast<void>(d.root()[2].get<strict_color>()); }) == "[json.exception.out_of_range.410] enum value out of range for strict_color: \"purple\"");
#if !JSON_DIAGNOSTICS
CHECK(exception_of_call([&] { static_cast<void>(d.root()[2].get<strict_color>()); }) == exception_of_call([&] { static_cast<void>(j[2].get<strict_color>()); }));
#endif
#endif
}
SECTION("derived types")
{
const json_document d = json_document::parse(R"({"id": 7, "c": "green", "extra": 3})");
const derived x = d.root().get<derived>();
CHECK(x.id == 7);
CHECK(x.c == color::green);
const derived_with_defaults y = d.root().get<derived_with_defaults>();
CHECK(y.id == 7);
CHECK(y.label == "none");
const derived_from_legacy z = d.root().get<derived_from_legacy>();
CHECK(z.id == 7);
CHECK(z.extra == 3);
}
SECTION("other from_json() functions get the value of materialize()")
{
const json_document d = json_document::parse(R"({"v": 4})");
CHECK(d.root().get<legacy>().v == 4);
CHECK(d.root().get<unconstrained>().v == 4);
CHECK(d.root().get<constrained>().v == 4);
legacy l;
d.root().get_to(l);
CHECK(l.v == 4);
}
SECTION("duplicate keys: members are looked up in the view, where the first one wins")
{
const json_document d = json_document::parse(R"({"x": 1, "y": 2, "x": 3})");
CHECK(d.root().get<point>().x == 1);
// materialize() keeps the last value, like parse()
CHECK(d.root().materialize().get<point>().x == 3);
}
SECTION("editable documents and ordered_json")
{
json_editable_document e = json_editable_document::parse(R"({"x": 1, "y": 2})");
e.set(e.root(), "x", 10);
CHECK(e.root().get<point>().x == 10);
const ordered_json_document o = ordered_json_document::parse(R"({"name": "o", "points": [], "center": {"x": 1, "y": 2}, "named": {}})");
CHECK(o.root().get<shape>().center.y == 2);
}
#if !defined(JSON_NOEXCEPTION) && !JSON_DIAGNOSTICS
SECTION("errors are those of the same conversion of a json value")
{
// (with JSON_DIAGNOSTICS, those of json name the path of the value)
const json_document d = json_document::parse(R"([{"x": 1}, {"x": "1", "y": 2}, [1, 2], {"id": "7", "c": "red"}])");
const json j = d.root().materialize();
for (std::size_t i = 0; i < 3; ++i)
{
CAPTURE(i)
CHECK(exception_of_call([&] { static_cast<void>(d.root()[i].get<point>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<point>()); }));
}
CHECK(exception_of_call([&] { static_cast<void>(d.root()[3].get<derived>()); }) == exception_of_call([&] { static_cast<void>(j[3].get<derived>()); }));
}
#endif
}
+31 -10
View File
@@ -28,11 +28,25 @@ using nlohmann::detail::view::node;
#include <random>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <test_data.hpp>
namespace json_view_image_test
{
// whether a document type has save() and load() (only on little-endian targets)
template<typename T, typename = void>
struct has_save : std::false_type {};
template<typename T>
struct has_save<T, decltype(static_cast<void>(std::declval<const T&>().save()))> : std::true_type {};
template<typename T, typename = void>
struct has_load : std::false_type {};
template<typename T>
struct has_load<T, decltype(static_cast<void>(T::load(std::declval<const std::vector<std::uint8_t>&>())))> : std::true_type {};
} // namespace json_view_image_test
#if !(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
namespace
@@ -171,6 +185,9 @@ std::uint32_t rng()
TEST_CASE("json_view images: round trips")
{
static_assert(json_view_image_test::has_save<json_document>::value && json_view_image_test::has_load<json_document>::value, "save() and load() on a little-endian target");
static_assert(json_view_image_test::has_save<ordered_json_editable_document>::value && json_view_image_test::has_load<ordered_json_editable_document>::value, "save() and load() on a little-endian target");
SECTION("small documents")
{
for (const char* text :
@@ -480,7 +497,7 @@ TEST_CASE("json_view images: edited documents")
{
CAPTURE(i)
CHECK((node_at(image, i).flags & nlohmann::detail::view::node_flags::linked) == 0);
CHECK(node_at(image, i).kind != nlohmann::detail::view::kind_link);
CHECK((node_at(image, i).kind != nlohmann::detail::view::node_kind::link));
}
for (const image_check check :
{
@@ -810,13 +827,13 @@ TEST_CASE("json_view images: check")
{
rejected(corrupted(image, 12, [&](node & n)
{
n.kind = kind;
n.kind = static_cast<nlohmann::detail::view::node_kind>(kind);
}), true);
}
// a key that is not a string
rejected(corrupted(image, 1, [](node & n)
{
n.kind = 0;
n.kind = nlohmann::detail::view::node_kind::null;
n.len = 0;
n.off = 0;
}), true);
@@ -960,11 +977,11 @@ TEST_CASE("json_view images: check")
}), true);
rejected(corrupted(image, 0, [](node & n)
{
n.kind = 2; // an array: the "keys" are values, and the counts do not match
n.kind = nlohmann::detail::view::node_kind::array; // an array: the "keys" are values, and the counts do not match
}), true);
const std::vector<std::uint8_t> as_array = corrupted(image, 16, [](node & n)
{
n.kind = 2; // {} as []: fine
n.kind = nlohmann::detail::view::node_kind::array; // {} as []: fine
});
CHECK(load_result(as_array, image_check::full).empty());
const std::string expected_dump = R"({"s":"x\"y","i":-12,"u":7,"f":1.5e+300,"b":true,"n":null,"a":["t",[]]})";
@@ -1013,13 +1030,13 @@ TEST_CASE("json_view images: check")
rejected(at_token(u6, 0, '8'), false); // 8 != 7
rejected(corrupted(image, 4, [](node & n)
{
n.kind = 6; // "-12" as unsigned: a sign
n.kind = nlohmann::detail::view::node_kind::number_unsigned; // "-12" as unsigned: a sign
n.extra = 3;
}), false);
// a non-negative number_integer (as edits write it): fine
const std::vector<std::uint8_t> positive = corrupted(image, 6, [](node & n)
{
n.kind = 5;
n.kind = nlohmann::detail::view::node_kind::number_integer;
n.extra = 0;
});
CHECK(load_result(positive, image_check::full).empty());
@@ -1027,7 +1044,7 @@ TEST_CASE("json_view images: check")
CHECK(pos.root()["u"].is_number_integer());
rejected(corrupted(image, 8, [](node & n)
{
n.kind = 6; // a float token as integer
n.kind = nlohmann::detail::view::node_kind::number_unsigned; // a float token as integer
n.extra = 7;
}), false);
}
@@ -1197,7 +1214,7 @@ TEST_CASE("json_view images: check")
{
std::vector<std::uint8_t> b = img;
node n = node_at(b, i);
n.kind = kind;
n.kind = static_cast<nlohmann::detail::view::node_kind>(kind);
n.extra = extra;
set_node(b, i, n);
return load_result(b, image_check::full);
@@ -1275,8 +1292,12 @@ TEST_CASE("json_view images: damaged images")
TEST_CASE("json_view images: big-endian targets")
{
// the image format is little-endian: save() and load() do not exist here
static_assert(!json_view_image_test::has_save<json_document>::value, "no save() on a big-endian target");
static_assert(!json_view_image_test::has_load<json_document>::value, "no load() on a big-endian target");
static_assert(!json_view_image_test::has_save<json_editable_document>::value, "no save() on a big-endian target");
const json_document d = json_document::parse("[1]");
CHECK_THROWS_WITH_AS(d.save(), "[json.exception.type_error.320] json_document images need a little-endian target", json::type_error&);
CHECK(d.root().size() == 1);
}
#endif
+4 -4
View File
@@ -34,11 +34,11 @@ version other than the one in `abi_macros.hpp`.
| Option | Description |
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `--list-tags` | Print every ABI tag (in namespace order) with the macro that enables it and the `NLOHMANN_JSON_ABI_TAG_*` identifier, then exit. |
| `--abi-tags TAGS` | Add the namespaces of one configuration, given as a comma-separated list of ABI tags (`_diag,_dp,_vns`; the leading underscore is optional, and the order does not matter). Can be repeated for several configurations. Unknown tags are an error. |
| `--abi-tags TAGS` | Add the namespaces of one configuration, given as a comma-separated list of ABI tags (`_diag,_dp,_ns`; the leading underscore is optional, and the order does not matter). Can be repeated for several configurations. Unknown tags are an error. |
| `--all` | Generate the namespaces for every combination of ABI tags. The file size doubles with each tag (about 60 MB for 12 tags). Cannot be combined with `--abi-tags`. |
| `--output FILE` | Write the Natvis file to `FILE` instead of `nlohmann_json.natvis` in the repository root. |
Each configuration gets both the versioned (`json_abi_diag_dp_vns_v3_12_0`) and the unversioned (`json_abi_diag_dp_vns`,
Each configuration gets both the versioned (`json_abi_diag_dp_ns_v3_12_0`) and the unversioned (`json_abi_diag_dp_ns`,
used with `NLOHMANN_JSON_NAMESPACE_NO_VERSION`) namespace. The default namespaces (up to two ABI tags) are always
included, so a generated file can replace the checked-in one.
@@ -52,10 +52,10 @@ included, so a generated file can replace the checked-in one.
```
3. Generate a Natvis file with them, for example for `JSON_DIAGNOSTICS`, `JSON_DIAGNOSTIC_POSITIONS`, and
`JSON_VIEW_NO_SIMD`:
`JSON_NO_SIMD`:
```shell
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my_nlohmann_json.natvis"
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my_nlohmann_json.natvis"
```
4. Use `my_nlohmann_json.natvis` instead of the shipped `nlohmann_json.natvis`, for example by adding it to your Visual
+1 -1
View File
@@ -91,7 +91,7 @@ if __name__ == '__main__':
'include/nlohmann/detail/abi_macros.hpp below "repo_root")')
selection = parser.add_mutually_exclusive_group()
selection.add_argument('--abi-tags', action='append', default=[], metavar='TAGS',
help='Comma-separated list of ABI tags (e.g. "_diag,_dp,_vns", leading underscores are '
help='Comma-separated list of ABI tags (e.g. "_diag,_dp,_ns", leading underscores are '
'optional) of one configuration to add to the default namespaces; can be repeated')
selection.add_argument('--all', action='store_true',
help='Generate the namespaces for every combination of ABI tags; the file size doubles '