mirror of
https://github.com/nlohmann/json.git
synced 2026-10-25 15:28:54 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64a5d233d0 | ||
|
|
315bd04c55 | ||
|
|
ea3dca202b | ||
|
|
bcc19dca3f |
No files matched your search
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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`.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
Generated
-3700
File diff suppressed because it is too large.
Load diff
Generated
+234
-100
@@ -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
|
||||
|
||||
Generated
+4
-18
@@ -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) \
|
||||
|
||||
Generated
+178
-88
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 '
|
||||
|
||||
Reference in new issue
Block a user