Compare commits

...
Author SHA1 Message Date
Niels Lohmann 315bd04c55 json_view: one SIMD macro set with the library
The view's vector code follows JSON_NO_SIMD, like the lexer and the float
writer, and skips the CPU check of SSSE3 when the code is compiled for
SSSE3 anyway (__SSSE3__), like the lexer. JSON_VIEW_NO_SIMD and
JSON_VIEW_USE_SSSE3 and their ABI tags _vns and _vssse3 are removed; they
were never released. JSON_NO_SIMD keeps its tag _ns.

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

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

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

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

No files matched your search

+3 -3
View File
@@ -163,9 +163,9 @@ jobs:
python3 $GENERATOR --list-tags
TAG_COUNT=$(python3 $GENERATOR --list-tags | wc -l)
python3 $GENERATOR --abi-tags diag,_dp,_vns --abi-tags _diag --output $RUNNER_TEMP/abi_tags.natvis
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_vns -->' $RUNNER_TEMP/abi_tags.natvis
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_vns_v[0-9_]* -->' $RUNNER_TEMP/abi_tags.natvis
python3 $GENERATOR --abi-tags diag,_dp,_ns --abi-tags _diag --output $RUNNER_TEMP/abi_tags.natvis
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_ns -->' $RUNNER_TEMP/abi_tags.natvis
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_ns_v[0-9_]* -->' $RUNNER_TEMP/abi_tags.natvis
test $(grep -c '<!-- Namespace ' $RUNNER_TEMP/abi_tags.natvis) -eq $(( $(grep -c '<!-- Namespace ' nlohmann_json.natvis) + 2 ))
python3 $GENERATOR --all --output $RUNNER_TEMP/all.natvis
+1
View File
@@ -90,6 +90,7 @@ cc_library(
"include/nlohmann/detail/view/simd.hpp",
"include/nlohmann/detail/view/string_ref.hpp",
"include/nlohmann/detail/view/value.hpp",
"include/nlohmann/detail/view/view_mode.hpp",
"include/nlohmann/json.hpp",
"include/nlohmann/json_fwd.hpp",
"include/nlohmann/json_literals.hpp",
+1 -1
View File
@@ -309,7 +309,7 @@ The "Check amalgamation" workflow fails if the file is out of date.
The file covers the namespace variants with up to two ABI tags. A Natvis file for other configurations can be
generated with the `--abi-tags` or `--all` options, for example
`make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my_nlohmann_json.natvis"`; see
`make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my_nlohmann_json.natvis"`; see
[`tools/generate_natvis`](tools/generate_natvis/README.md). With MSVC, CMake adds the file to the `nlohmann_json`
target and installs it.
+1 -1
View File
@@ -120,7 +120,7 @@ $(AMALGAMATED_VIEW_FILE): $(SRCS)
tools/amalgamate/amalgamate.py -c tools/amalgamate/config_json_view.json -s . --verbose=yes
NATVIS_VENV=tools/generate_natvis/venv
# extra options for generate_natvis.py, e.g. NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my.natvis"
# extra options for generate_natvis.py, e.g. NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my.natvis"
NATVIS_ARGS=
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
@@ -12,7 +12,7 @@ void erase(view_type array, I idx);
std::size_t erase(const json_pointer& ptr);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
has `erase`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
1. Removes every member of `object` whose key is `key` (see [Notes](#notes) on duplicate keys) and returns how many
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
template<typename BasicJsonType, bool Editable = false>
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
class basic_json_document;
```
@@ -20,9 +20,9 @@ is move-only: a copy would duplicate the whole index, the decoded-string buffer,
enough in every use we know of. The index, the decoded strings, and the owned text live in one heap block that the
document holds through a `#!cpp std::unique_ptr`; this is also why views survive a move of the document.
With `#!cpp Editable == true`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
With `#!cpp Mode == view_mode::editable`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
[`insert`](insert.md), and [`erase`](erase.md) to change values in place, see [Edits](#edits) below. The source text
itself is never written; a read-only document (`#!cpp Editable == false`, the default) does not carry any of the
itself is never written; a read-only document (`#!cpp view_mode::read_only`, the default) does not carry any of the
bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp static_assert`).
## Template parameters
@@ -32,9 +32,10 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
[`ordered_json`](../ordered_json.md). Only 64-bit `number_integer_t`/`number_unsigned_t` types are supported; this
is checked with a `static_assert`.
`Editable`
: whether the document supports [`set`](set.md), [`push_back`](push_back.md), [`insert`](insert.md), and
[`erase`](erase.md) (optional, `#!cpp false` by default). See [Edits](#edits) below.
`Mode`
: a [`view_mode`](../view_mode.md): `#!cpp view_mode::editable` if the document supports [`set`](set.md),
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md) (optional, `#!cpp view_mode::read_only`
by default). See [Edits](#edits) below.
## Specializations
@@ -47,7 +48,7 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
## Member types
- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view<BasicJsonType, Editable>`)
- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view<BasicJsonType, Mode>`)
- **value_t** - the JSON type enumeration, see [`basic_json::value_t`](../basic_json/value_t.md)
- **image_check** - how [`load()`](load.md) validates an image (`full`, `bounds`, `none`), see [`image_check`](load.md#image_check)
@@ -80,15 +81,15 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
### Edits
- [**set**](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers
to (`#!cpp Editable` documents only)
- [**push_back**](push_back.md) - append to an array (`#!cpp Editable` documents only)
- [**insert**](insert.md) - insert an element into an array before a given position (`#!cpp Editable` documents only)
to (editable documents only)
- [**push_back**](push_back.md) - append to an array (editable documents only)
- [**insert**](insert.md) - insert an element into an array before a given position (editable documents only)
- [**erase**](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
(`#!cpp Editable` documents only)
(editable documents only)
## Edits
An editable document (`#!cpp Editable == true`) can be changed after parsing, with [`set`](set.md),
An editable document (`#!cpp view_mode::editable`) can be changed after parsing, with [`set`](set.md),
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md);
[`json_editable_document`](../json_editable_document.md) and
[`ordered_json_editable_document`](../ordered_json_editable_document.md) are the corresponding specializations. A few
@@ -5,7 +5,7 @@ template<typename I, typename V>
view_type insert(view_type array, I idx, V&& value);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
has `insert`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
Inserts `value` into `array` as a new element before position `idx`, which must not be past the end
@@ -55,10 +55,7 @@ validate with overload 2 first, if the original vector must survive a failed loa
## Exceptions
On a big-endian target, throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) -- the same
exception [`save()`](save.md#exceptions) throws there, since the image format is little-endian only.
Otherwise throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
Throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
`save()` could have written, or fails the requested `check`:
| message | when |
@@ -95,6 +92,9 @@ are checked once, however many nodes refer to it.
## Notes
**Little-endian targets only.** On a big-endian target, `load()` does not exist, just like
[`save()`](save.md#notes): the image format is little-endian, so a call fails to compile.
### `image_check` { #image_check }
```cpp
@@ -13,7 +13,7 @@ editable, and it does not have to be `array`'s own document -- which is copied s
source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
has `push_back`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
## Template parameters
@@ -12,7 +12,7 @@ An edited document is written in its *current* state, with its values in documen
parser would have produced them for that JSON text: a member [`set`](set.md) added goes at the end, an
[`erase`](erase.md)d member leaves no trace, and a float that is not finite (NaN or positive/negative infinity)
becomes null, the same substitution [`dump()`](../basic_json_view/dump.md) makes. The same document always saves to
the same bytes -- also across `BasicJsonType` and `#!cpp Editable`, since the image reflects document order and
the same bytes -- also across `BasicJsonType` and the [`view_mode`](../view_mode.md), since the image reflects document order and
values only, not which specialization produced them.
## Return value
@@ -31,9 +31,6 @@ Throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) i
[discarded](is_discarded.md) -- a default-constructed document, or one a failed [`parse()`](parse.md)/
[`read()`](read.md) with `allow_exceptions == false` left discarded.
On a big-endian target, throws `type_error.320` with a different message instead: the image format is little-endian
only (see [Notes](#notes)).
Throws [`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the node count, the text, or
the decoded strings of the image would individually reach 4 GiB -- the same 32-bit offsets
[`parse()`](parse.md#exceptions) and, for edits, [`set`](set.md)/[`push_back`](push_back.md) are already limited to.
@@ -44,9 +41,6 @@ the decoded strings of the image would individually reach 4 GiB -- the same 32-b
[json.exception.type_error.320] cannot save a discarded json_document
```
```
[json.exception.type_error.320] json_document images need a little-endian target
```
```
[json.exception.out_of_range.416] images of 4 GiB or more are not supported by json_document
```
@@ -70,9 +64,9 @@ else -- see [`load`'s Exceptions](load.md#exceptions).
the *same* build on the *same* (little-endian) machine -- not as a long-term storage format. Keep the original
JSON text if you need to read a saved document back with a future library version.
**Little-endian only.** The image is written as raw little-endian bytes, with no byte-swapping. `save()` (and
[`load`](load.md)) throw `type_error.320` on a big-endian target rather than silently produce bytes a big-endian
reader could not interpret correctly.
**Little-endian targets only.** The image is written as raw little-endian bytes, with no byte-swapping. On a
big-endian target, `save()` and [`load`](load.md) do not exist: a call fails to compile rather than produce bytes a
big-endian reader could not interpret correctly.
## Examples
@@ -18,7 +18,7 @@ template<typename V>
view_type set(const json_pointer& ptr, V&& value);
```
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
has `set`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
1. Replaces the value `target` refers to with `value`.
@@ -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
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
using json_editable_document = basic_json_document<json, true>;
using json_editable_document = basic_json_document<json, view_mode::editable>;
```
This type is an **editable** [`basic_json_document`](basic_json_document/index.md) of the default
+1 -1
View File
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
using json_editable_view = basic_json_view<json, true>;
using json_editable_view = basic_json_view<json, view_mode::editable>;
```
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of a
-2
View File
@@ -43,8 +43,6 @@ header. See also the [macro overview page](../../features/macros.md).
- [**JSON_SKIP_UNSUPPORTED_COMPILER_CHECK**](json_skip_unsupported_compiler_check.md) - do not warn about unsupported compilers
- [**JSON_USE_GLOBAL_UDLS**](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace
- [**JSON_USE_SIMDUTF**](json_use_simdutf.md) - use the simdutf library to accelerate UTF-8 validation
- [**JSON_VIEW_NO_SIMD**](json_view_no_simd.md) - use only portable code in the parser of `json_view.hpp`
- [**JSON_VIEW_USE_SSSE3**](json_view_use_ssse3.md) - validate non-ASCII strings with SSSE3 in the parser of `json_view.hpp`
## Library version
+3 -1
View File
@@ -5,7 +5,8 @@
```
When defined, the library uses only portable C++ code where it would otherwise use vector instructions: when scanning
strings during parsing, and when writing floating-point numbers during serialization.
strings during parsing, and when writing floating-point numbers during serialization. This includes the parser of
[`basic_json_document`](../basic_json_document/index.md) (`<nlohmann/json_view.hpp>`).
The macro is an escape hatch, for example for toolchains that cannot compile the vector code, for sanitizers or
analyzers that do not understand it, or to compare the speed of both variants. It does not change any result: values,
@@ -77,6 +78,7 @@ By default, `#!cpp JSON_NO_SIMD` is not defined, and vector instructions are use
- [**JSON_USE_SIMDUTF**](json_use_simdutf.md) - use the simdutf library to accelerate UTF-8 validation
- [**JSON_DISABLE_STREAM_BULK_SCAN**](json_disable_stream_bulk_scan.md) - read a `std::istream` one character at a time
- [Parsing: input sources and performance](../../features/parsing/index.md#input-sources-and-performance)
- [json_view](../../features/json_view.md) - the zero-copy view, whose parser the macro also affects
## Version history
@@ -1,52 +0,0 @@
# JSON_VIEW_NO_SIMD
```cpp
#define JSON_VIEW_NO_SIMD
```
When defined, the parser of [`basic_json_document`](../basic_json_document/index.md) (`<nlohmann/json_view.hpp>`)
uses only portable C++ to scan strings. By default, it scans long runs of string bytes 16 at a time with NEON on
AArch64 (with GCC and Clang) and SSE2 on x86-64, which are part of the baseline instruction sets of these
architectures, and validates non-ASCII text with NEON (or SSSE3, see
[`JSON_VIEW_USE_SSSE3`](json_view_use_ssse3.md)).
The same input is accepted or rejected either way, with the same values, and errors are reported the same way; only
the speed differs. The macro exists for platforms whose compilers lack the intrinsics headers, and to test the portable
code.
!!! note "ABI compatibility"
The macro selects between two definitions of the same inline functions. Whether it is defined is encoded in the
[namespace](../../features/namespace.md) (tag `_vns`), resulting in distinct symbol names. Translation units
compiled with and without it can therefore be linked into the same program without One Definition Rule (ODR)
violations, but they cannot exchange instances of library types.
## Default definition
By default, `#!cpp JSON_VIEW_NO_SIMD` is not defined, and the vector code is used where available.
```cpp
#undef JSON_VIEW_NO_SIMD
```
## Examples
??? example
The code below uses the portable string scanning of the view.
```cpp
#define JSON_VIEW_NO_SIMD
#include <nlohmann/json_view.hpp>
...
```
## See also
- [JSON_VIEW_USE_SSSE3](json_view_use_ssse3.md) - validate non-ASCII strings with SSSE3 on x86-64
- [json_view](../../features/json_view.md) - the zero-copy view
## Version history
- Added in version 3.13.0.
@@ -1,53 +0,0 @@
# JSON_VIEW_USE_SSSE3
```cpp
#define JSON_VIEW_USE_SSSE3
```
When defined on x86-64, the parser of [`basic_json_document`](../basic_json_document/index.md)
(`<nlohmann/json_view.hpp>`) validates non-ASCII text in strings with SSSE3 without asking the CPU first.
By default, the parser checks once at run time whether the CPU has SSSE3 (all x86-64 CPUs since about 2011 have it)
and then validates non-ASCII text 16 bytes at a time, using the "lookup4" algorithm of
[simdjson](https://github.com/simdjson/simdjson); on CPUs without SSSE3, it validates one UTF-8 sequence at a time.
The vector check is compiled for SSSE3 with a function attribute (GCC 4.9 and later, Clang), so this needs no compiler
option. With MSVC, the check uses `__cpuid`. On AArch64, the vector check uses NEON and is always on.
Define the macro only together with a compiler option that enables SSSE3 (e.g. `-mssse3`, or `-march=` with a CPU that
has it), and only for programs that run on such CPUs. It saves the check of the CPU, which costs little. The same
input is accepted or rejected either way; only the speed of non-ASCII text differs.
!!! note "ABI compatibility"
The macro selects between two definitions of the same inline functions. Whether it is defined is encoded in the
[namespace](../../features/namespace.md) (tag `_vssse3`, on every architecture), resulting in distinct symbol
names. Translation units compiled with and without it can therefore be linked into the same program without One
Definition Rule (ODR) violations, but they cannot exchange instances of library types.
## Default definition
By default, `#!cpp JSON_VIEW_USE_SSSE3` is not defined.
```cpp
#undef JSON_VIEW_USE_SSSE3
```
## Examples
??? example
With CMake, for a program that only runs on CPUs with SSSE3:
```cmake
target_compile_definitions(your_target PRIVATE JSON_VIEW_USE_SSSE3)
target_compile_options(your_target PRIVATE -mssse3)
```
## See also
- [JSON_VIEW_NO_SIMD](json_view_no_simd.md) - use only portable code in the view's parser
- [JSON_USE_SIMDUTF](json_use_simdutf.md) - validate UTF-8 with simdutf in `basic_json`'s parser
## Version history
- Added in version 3.13.0.
@@ -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).
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
using ordered_json_editable_document = basic_json_document<ordered_json, true>;
using ordered_json_editable_document = basic_json_document<ordered_json, view_mode::editable>;
```
This type is an **editable** [`basic_json_document`](basic_json_document/index.md) of the
@@ -3,7 +3,7 @@
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
using ordered_json_editable_view = basic_json_view<ordered_json, true>;
using ordered_json_editable_view = basic_json_view<ordered_json, view_mode::editable>;
```
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an
+80
View File
@@ -0,0 +1,80 @@
# <small>nlohmann::</small>view_mode
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
```cpp
enum class view_mode : std::uint8_t
{
read_only,
editable
};
```
The second template parameter of [`basic_json_document`](basic_json_document/index.md) and
[`basic_json_view`](basic_json_view/index.md): whether a document can be changed after parsing, and whether a view is
of such a document.
`read_only`
: the default: the document is parsed once and then only read. It carries none of the bookkeeping edits need, and
calling [`set`](basic_json_document/set.md), [`push_back`](basic_json_document/push_back.md),
[`insert`](basic_json_document/insert.md), or [`erase`](basic_json_document/erase.md) on it fails to compile.
`editable`
: the document also offers [`set`](basic_json_document/set.md), [`push_back`](basic_json_document/push_back.md),
[`insert`](basic_json_document/insert.md), and [`erase`](basic_json_document/erase.md); its views see every edit,
see [Edits](basic_json_document/index.md#edits).
The shortcuts name both modes: [`json_document`](json_document.md) and [`json_view`](json_view.md) are read-only,
[`json_editable_document`](json_editable_document.md) and [`json_editable_view`](json_editable_view.md) are editable
(and likewise for `ordered_json`).
## Notes
The mode is part of the view's type, and there is no conversion between the two modes: a read-only view reads a
container in place, while a view of an editable document follows the links that edits leave behind. A function that
accepts views therefore names the modes it accepts in its signature:
```cpp
// views of editable documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::editable> v);
// views of read-only documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
// either
template<typename BasicJsonType, view_mode Mode>
void f(basic_json_view<BasicJsonType, Mode> v);
```
A function that takes a [`json_view`](json_view.md) accepts neither an [`ordered_json_view`](ordered_json_view.md)
nor a [`json_editable_view`](json_editable_view.md). Views of the two modes still compare with
[`operator==`](basic_json_view/operator_eq.md).
## Examples
??? example
The example below shows a function template that accepts the views of both modes, and one that accepts only
views of editable documents.
```cpp
--8<-- "examples/view_mode.cpp"
```
Output:
```
--8<-- "examples/view_mode.output"
```
## See also
- [basic_json_document](basic_json_document/index.md) - a parsed JSON text
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
- [json_editable_document](json_editable_document.md) - an editable document of `json`
## Version history
Added in version 3.13.0.
@@ -5,7 +5,7 @@ using ordered_json_editable_document = nlohmann::ordered_json_editable_document;
int main()
{
// ordered_json_editable_document is basic_json_document<nlohmann::ordered_json, true>
// ordered_json_editable_document is basic_json_document<nlohmann::ordered_json, nlohmann::view_mode::editable>
ordered_json_editable_document doc = ordered_json_editable_document::parse(R"({"z": 1, "a": 2, "m": 3})");
doc.set(doc.root(), "b", 4); // set() always appends a new member at the end
+29
View File
@@ -0,0 +1,29 @@
#include <iostream>
#include <nlohmann/json_view.hpp>
using nlohmann::basic_json_view;
using nlohmann::view_mode;
// accepts the views of read-only and of editable documents, of json and of ordered_json
template<typename BasicJsonType, view_mode Mode>
std::size_t count_members(basic_json_view<BasicJsonType, Mode> v)
{
return v.is_object() ? v.size() : 0;
}
// accepts only the views of editable documents
template<typename BasicJsonType>
bool is_edited(basic_json_view<BasicJsonType, view_mode::editable> v)
{
return v.is_string() && v.get_string() == "edited";
}
int main()
{
const nlohmann::json_document doc = nlohmann::json_document::parse(R"({"a": 1, "b": 2})");
nlohmann::json_editable_document edoc = nlohmann::json_editable_document::parse(R"({"a": 1})");
edoc.set(edoc.root()["a"], "edited");
std::cout << count_members(doc.root()) << ' ' << count_members(edoc.root()) << '\n';
std::cout << std::boolalpha << is_edited(edoc.root()["a"]) << '\n';
}
@@ -0,0 +1,2 @@
2 1
true
+6 -5
View File
@@ -252,14 +252,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 +354,10 @@ validation entirely, for an image trusted as much as the process's own memory. S
!!! warning "Experimental"
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
stable. It is little-endian only, and tied to the library build that wrote it -- use it to cache a document or to
hand one to another process running the *same* build, not as a long-term storage format; keep the original JSON
text if a saved document needs to be readable by a future library version.
stable. It is little-endian only (on big-endian targets, `save()` and `load()` do not exist), and tied to the
library build that wrote it -- use it to cache a document or to hand one to another process running the *same*
build, not as a long-term storage format; keep the original JSON text if a saved document needs to be readable by
a future library version.
The idea of a document you can read without parsing comes from zero-copy formats such as
[FlatBuffers](https://github.com/google/flatbuffers) and [YaFF](https://github.com/yandex/yaff); the check
-17
View File
@@ -287,23 +287,6 @@ external dependency and is not defined by default.
See [full documentation of `JSON_USE_SIMDUTF`](../api/macros/json_use_simdutf.md).
## `JSON_VIEW_NO_SIMD`
When defined, the parser of [`basic_json_document`](../api/basic_json_document/index.md)
(`<nlohmann/json_view.hpp>`) uses only portable C++ to scan strings, instead of vector instructions (SSE2 on x86-64,
NEON on AArch64). The same input is accepted or rejected either way; only the speed differs. It is not defined by
default.
See [full documentation of `JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md).
## `JSON_VIEW_USE_SSSE3`
When defined on x86-64, the parser of [`basic_json_document`](../api/basic_json_document/index.md)
(`<nlohmann/json_view.hpp>`) validates non-ASCII text in strings with SSSE3 without asking the CPU first. It is not
defined by default.
See [full documentation of `JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md).
## `NLOHMANN_DEFINE_TYPE_*(...)`, `NLOHMANN_DEFINE_DERIVED_TYPE_*(...)`
The library defines 12 macros to simplify the serialization/deserialization of types. See the page on
+2 -6
View File
@@ -28,8 +28,6 @@ The complete default namespace name is derived as follows:
- [`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md) defined non-zero appends
`_dufio`.
- [`JSON_NO_SIMD`](../api/macros/json_no_simd.md) defined appends `_ns`.
- [`JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md) defined appends `_vns`.
- [`JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md) defined appends `_vssse3`.
- The inline namespace ends with the suffix `_v` followed by the 3 components of the version number separated by
underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component)
below.
@@ -115,7 +113,5 @@ follows:
([`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md)), `_ekmo`
([`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md)), `_dsbs`
([`JSON_DISABLE_STREAM_BULK_SCAN`](../api/macros/json_disable_stream_bulk_scan.md)), `_dufio`
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md)), `_ns`
([`JSON_NO_SIMD`](../api/macros/json_no_simd.md)), `_vns`
([`JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md)), and `_vssse3`
([`JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md)) in version 3.13.0.
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md)), and `_ns`
([`JSON_NO_SIMD`](../api/macros/json_no_simd.md)) in version 3.13.0.
+2 -2
View File
@@ -21,10 +21,10 @@ ABI tags are not covered and may show raw internal fields instead. To generate a
```
3. Generate a Natvis file with the tags of your configuration, for example for `JSON_DIAGNOSTICS`,
`JSON_DIAGNOSTIC_POSITIONS`, and `JSON_VIEW_NO_SIMD`:
`JSON_DIAGNOSTIC_POSITIONS`, and `JSON_NO_SIMD`:
```shell
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my_nlohmann_json.natvis"
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my_nlohmann_json.natvis"
```
4. Use the generated file instead of `nlohmann_json.natvis`.
-5
View File
@@ -853,17 +853,12 @@ from JSON text.
[`basic_json_document::save()`](../api/basic_json_document/save.md) cannot write an
[image](../features/json_view.md#images) of a [discarded](../api/basic_json_document/is_discarded.md) document.
[`save()`](../api/basic_json_document/save.md) and [`load()`](../api/basic_json_document/load.md) also throw this
exception on a big-endian target, since the image format is little-endian only.
!!! failure "Example messages"
```
[json.exception.type_error.320] cannot save a discarded json_document
```
```
[json.exception.type_error.320] json_document images need a little-endian target
```
!!! note
+1 -2
View File
@@ -407,6 +407,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 +442,6 @@ nav:
- 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md
- 'JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS': api/macros/json_use_objects_for_enum_keyed_maps.md
- 'JSON_USE_SIMDUTF': api/macros/json_use_simdutf.md
- 'JSON_VIEW_NO_SIMD': api/macros/json_view_no_simd.md
- 'JSON_VIEW_USE_SSSE3': api/macros/json_view_use_ssse3.md
- 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_derived_type.md
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_intrusive.md
- 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_non_intrusive.md
+4 -18
View File
@@ -128,26 +128,14 @@
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
#endif
#ifdef JSON_VIEW_NO_SIMD
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD _vns
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD
#endif
#ifdef JSON_VIEW_USE_SSSE3
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3 _vssse3
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k, l, m) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -161,9 +149,7 @@
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
NLOHMANN_JSON_ABI_TAG_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3)
NLOHMANN_JSON_ABI_TAG_NO_SIMD)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
+1 -1
View File
@@ -102,7 +102,7 @@ enum class exception_id : int
type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format
enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string
document_binary_value = 319, ///< a binary value is stored in a json_document
document_image_unsupported = 320, ///< a json_document image cannot be saved or loaded (discarded document, big-endian target)
document_image_unsupported = 320, ///< a discarded json_document cannot be saved as an image
discarded_value_used = 321, ///< a discarded value is used
// out_of_range
array_index_out_of_range = 401, ///< an array index is out of range
+1 -1
View File
@@ -978,7 +978,7 @@ indent_done:
std::memcpy(reinterpret_cast<unsigned char*>(n), &first, 8);
std::memcpy(reinterpret_cast<unsigned char*>(n) + 8, &second, 8);
#else
n->kind = static_cast<std::uint8_t>(k);
n->kind = static_cast<node_kind>(k);
n->flags = flags;
n->extra = extra;
n->off = static_cast<std::uint32_t>(off);
@@ -232,7 +232,7 @@ struct document_data
/// following loads.
static NLOHMANN_VIEW_ALWAYS_INLINE const node* deref(const node* n) noexcept
{
return NLOHMANN_VIEW_LIKELY(n->kind != kind_link) ? n : follow_link(n);
return NLOHMANN_VIEW_LIKELY(n->kind != node_kind::link) ? n : follow_link(n);
}
static NLOHMANN_VIEW_NOINLINE const node* follow_link(const node* n) noexcept
+19 -21
View File
@@ -26,12 +26,10 @@
#include <nlohmann/detail/view/lookup.hpp>
#include <nlohmann/detail/view/macro_scope.hpp>
#include <nlohmann/detail/view/node.hpp>
#include <nlohmann/detail/view/view_mode.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
template<typename BasicJsonType, bool Editable>
class basic_json_view;
namespace detail
{
namespace view
@@ -120,13 +118,13 @@ class editor
View set(const View& object, string_view_t key, V&& value)
{
node* const o = own(object);
if (o->kind != static_cast<std::uint8_t>(value_t::object) && o->kind != static_cast<std::uint8_t>(value_t::null))
if (o->kind != node_kind::object && o->kind != node_kind::null)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a string argument with ", object.type_name());
}
check_utf8(key.data(), key.size());
const encoded e = encode(std::forward<V>(value));
if (o->kind == static_cast<std::uint8_t>(value_t::null))
if (o->kind == node_kind::null)
{
become_empty(o, value_t::object);
}
@@ -171,7 +169,7 @@ class editor
View set(const View& array, std::size_t idx, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a numeric argument with ", array.type_name());
}
@@ -188,12 +186,12 @@ class editor
View push_back(const View& array, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array) && a->kind != static_cast<std::uint8_t>(value_t::null))
if (a->kind != node_kind::array && a->kind != node_kind::null)
{
throw_type_error(exception_id::push_back_wrong_type, "cannot use push_back() with ", array.type_name());
}
const encoded e = encode(std::forward<V>(value));
if (a->kind == static_cast<std::uint8_t>(value_t::null))
if (a->kind == node_kind::null)
{
become_empty(a, value_t::array);
}
@@ -212,7 +210,7 @@ class editor
View insert(const View& array, std::size_t idx, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::insert_wrong_type, "cannot use insert() with ", array.type_name());
}
@@ -232,7 +230,7 @@ class editor
std::size_t erase(const View& object, string_view_t key)
{
node* const o = own(object);
if (o->kind != static_cast<std::uint8_t>(value_t::object))
if (o->kind != node_kind::object)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", object.type_name());
}
@@ -250,7 +248,7 @@ class editor
void erase(const View& array, std::size_t idx)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", array.type_name());
}
@@ -328,7 +326,7 @@ class editor
{
const std::uint8_t linked = n->flags & node_flags::linked;
*n = node{};
n->kind = static_cast<std::uint8_t>(k);
n->kind = static_cast<node_kind>(k);
n->flags = static_cast<std::uint8_t>(node_flags::is_new | linked);
n->next = 1;
}
@@ -405,8 +403,8 @@ class editor
template<typename T>
struct is_view : std::false_type {};
template<typename J, bool E>
struct is_view<basic_json_view<J, E>> : std::true_type {};
template<typename J, view_mode M>
struct is_view<basic_json_view<J, M>> : std::true_type {};
template<typename V>
encoded encode(V&& v)
@@ -421,8 +419,8 @@ class editor
}
/// a view of any document (copied; nothing is shared with it)
template<typename J, bool E>
encoded encode_impl(const basic_json_view<J, E>& v, encode_tag<0> /*view*/)
template<typename J, view_mode M>
encoded encode_impl(const basic_json_view<J, M>& v, encode_tag<0> /*view*/)
{
if (NLOHMANN_VIEW_UNLIKELY(v.m_node == nullptr))
{
@@ -434,8 +432,8 @@ class editor
r.scalar = copy_scalar(*v.m_doc, *v.m_node);
return r;
}
r.region = alloc_nodes(m_doc, count_nodes<E>(*v.m_doc, v.m_node));
fill_nodes<E>(*v.m_doc, v.m_node, r.region);
r.region = alloc_nodes(m_doc, count_nodes<M == view_mode::editable>(*v.m_doc, v.m_node));
fill_nodes<M == view_mode::editable>(*v.m_doc, v.m_node, r.region);
edit_state_of(m_doc).regions.emplace(r.region, nullptr);
return r;
}
@@ -496,7 +494,7 @@ class editor
static node plain_node(value_t k) noexcept
{
node n{};
n.kind = static_cast<std::uint8_t>(k);
n.kind = static_cast<node_kind>(k);
n.flags = node_flags::is_new;
return n;
}
@@ -681,7 +679,7 @@ class editor
++r;
if (is_container(*n))
{
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object)});
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object});
}
// the next value: close finished containers, then step over the key
for (;;)
@@ -730,7 +728,7 @@ class editor
node* const self = out++;
*self = plain_node(static_cast<value_t>(n->kind));
self->len = n->len;
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object), self});
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object, self});
}
else
{
@@ -27,7 +27,7 @@
// live in chunks that never move; strings and number tokens written by edits
// live in the edit arena. An array/object whose elements change gets
// node_flags::moved: its elements then live in a separate sequence (a header
// node, then the entries), whose entries link to the values (kind_link).
// node, then the entries), whose entries link to the values (node_kind::link).
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
@@ -185,7 +185,7 @@ inline node* block_of(document_data& d, node* n, std::size_t extra)
return nh;
}
reserve_moved(d); // (so that set_moved() below cannot throw: the links are marked before)
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
const std::size_t used = 1 + (static_cast<std::size_t>(n->len) * (object ? 2 : 1));
const std::size_t cap = used + extra;
node* const h = alloc_nodes(d, cap);
@@ -251,7 +251,7 @@ inline node* find_parent(const document_data& d, const node* target)
{
return nullptr; // LCOV_EXCL_LINE (the value is inside c)
}
const bool object = c->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = c->kind == node_kind::object;
const node* down = nullptr;
for (const node* p = d.first_child_edited(c), *e = d.child_end_edited(c); p != e;)
{
+14 -16
View File
@@ -117,7 +117,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
r.off = (v->flags & (node_flags::moved | node_flags::is_new)) != 0 ? 0 : v->off;
r.len = 0; // counted below
r.next = 0; // set when the container is complete
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == static_cast<std::uint8_t>(value_t::object)});
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == node_kind::object});
break;
case value_t::string:
r = string_node(*v);
@@ -138,7 +138,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
if (t[0] == 'n' || t[0] == 'i' || (v->len > 1 && t[1] == 'i'))
{
r = node{}; // nan and infinity: null, as dump() writes them
r.kind = static_cast<std::uint8_t>(value_t::null);
r.kind = node_kind::null;
break;
}
r.off = static_cast<std::uint32_t>(d.size + text_tail.size());
@@ -182,12 +182,10 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
}
}
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no save() elsewhere)
/// the document as an image
inline std::vector<std::uint8_t> save_image(const document_data& d)
{
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
#endif
const std::size_t arena_size = d.arena_size;
std::vector<node> compacted;
std::string text_tail;
@@ -221,7 +219,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
// extra of an object, and the same document saves to the same bytes
for (std::size_t i = 0; i < count; ++i)
{
if (nodes[i].kind == static_cast<std::uint8_t>(value_t::object) && nodes[i].extra != 0)
if (nodes[i].kind == node_kind::object && nodes[i].extra != 0)
{
std::memset(o + (i * sizeof(node)) + offsetof(node, extra), 0, sizeof(nodes[i].extra));
}
@@ -243,6 +241,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
*o = 0;
return image;
}
#endif
/// the parts of a number token that the checks need
struct number_token
@@ -337,7 +336,7 @@ inline bool float_token_finite(const unsigned char* s, std::size_t len, const nu
if (static_cast<std::int64_t>(t.int_digits) + t.exponent > 300)
{
node n{};
n.kind = static_cast<std::uint8_t>(value_t::number_float);
n.kind = node_kind::number_float;
n.len = static_cast<std::uint32_t>(len);
const auto v = float_value<double>(reinterpret_cast<const char*>(s), n); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
return v <= (std::numeric_limits<double>::max)() && v >= -(std::numeric_limits<double>::max)();
@@ -358,7 +357,7 @@ inline bool check_integer(const node& n, const unsigned char* text)
}
// the token's value is the stored one; number_integer nodes of edits can
// be non-negative (as basic_json keeps the type of a value)
const bool integer = n.kind == static_cast<std::uint8_t>(value_t::number_integer);
const bool integer = n.kind == node_kind::number_integer;
if (t.is_float || t.int_digits > 20 || (t.negative && !integer))
{
return false;
@@ -540,7 +539,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
return false;
}
if (n.kind != static_cast<std::uint8_t>(value_t::number_float))
if (n.kind != node_kind::number_float)
{
return (n.extra >> 8u) == 0;
}
@@ -581,7 +580,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
const node& n = nodes[i];
if (!stack.empty() && stack.back().object && stack.back().expect_key)
{
if (n.kind != static_cast<std::uint8_t>(value_t::string) || !check_string(n))
if (n.kind != node_kind::string || !check_string(n))
{
return false;
}
@@ -622,7 +621,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
// (the contents of float tokens are checked later; the token of an
// integer has at most 256 characters)
if (n.kind == static_cast<std::uint8_t>(value_t::number_float))
if (n.kind == node_kind::number_float)
{
floats.push_back(float_range{n.off, n.len, n.extra});
}
@@ -640,7 +639,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
return false;
}
stack.push_back(frame{i + n.next, n.len, 0, n.kind == static_cast<std::uint8_t>(value_t::object), true});
stack.push_back(frame{i + n.next, n.len, 0, n.kind == node_kind::object, true});
complete = false;
break;
}
@@ -663,13 +662,11 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
throw_parse_error(exception_id::invalid_document_image, concat("invalid json_document image: ", what));
}
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no load() elsewhere)
/// Read an image into d. The text and the decoded strings stay in the image;
/// the nodes are copied (so that they are aligned, and edits can change them).
inline void load_image(document_data& d, const std::uint8_t* image, std::size_t size, image_check check)
{
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
#endif
if (image == nullptr || size < sizeof(image_header))
{
throw_invalid_image("too short");
@@ -729,7 +726,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
for (std::size_t i = 0; i < count; ++i)
{
const node& n = d.nodes[i];
if (n.kind == static_cast<std::uint8_t>(value_t::object) && n.len >= document_data::index_min_members)
if (n.kind == node_kind::object && n.len >= document_data::index_min_members)
{
d.large_objects.push_back(static_cast<std::uint32_t>(i));
}
@@ -738,6 +735,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
std::vector<std::uint32_t>().swap(d.large_objects); // (only needed while building)
d.discarded = false;
}
#endif
} // namespace view
} // namespace detail
+1 -1
View File
@@ -182,7 +182,7 @@ const node* element_at(const document_data& d, const node* array, std::size_t id
template<bool Editable>
const node* last_child(const document_data& d, const node* container) noexcept
{
const std::size_t value_offset = container->kind == static_cast<std::uint8_t>(value_t::object) ? 1 : 0;
const std::size_t value_offset = container->kind == node_kind::object ? 1 : 0;
const node* const end = navigation<Editable>::end(d, container);
const node* last = navigation<Editable>::first(d, container);
if (value_offset == 0 && container->next == container->len + 1u && (!navigation<Editable>::editable() || (container->flags & node_flags::moved) == 0))
+1 -1
View File
@@ -101,7 +101,7 @@ BasicJsonType materialize(const document_data& d, const node* n)
case value_t::object:
case value_t::array:
{
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
if (object)
{
sax.start_object(n->len);
+22 -9
View File
@@ -41,9 +41,21 @@ struct node_flags
static constexpr std::uint8_t linked = 32; ///< an entry of a moved sequence links to this value (editable documents): its extent in the parsed layout no longer matters
};
/// kind of an entry of an edited sequence that stands for a value stored
/// elsewhere (the address of the value's node is kept in the len/next bytes)
constexpr std::uint8_t kind_link = 10;
/// the kind of a node: the value_t of its value, or link
enum class node_kind : std::uint8_t
{
null = static_cast<std::uint8_t>(value_t::null),
object = static_cast<std::uint8_t>(value_t::object),
array = static_cast<std::uint8_t>(value_t::array),
string = static_cast<std::uint8_t>(value_t::string),
boolean = static_cast<std::uint8_t>(value_t::boolean),
number_integer = static_cast<std::uint8_t>(value_t::number_integer),
number_unsigned = static_cast<std::uint8_t>(value_t::number_unsigned),
number_float = static_cast<std::uint8_t>(value_t::number_float),
/// an entry of an edited sequence that stands for a value stored elsewhere
/// (the address of the value's node is kept in the len/next bytes)
link = static_cast<std::uint8_t>(value_t::discarded) + 1,
};
/// One entry of the flat index, in document order. An object's members are
/// stored as key node followed by the value's subtree. Integers keep their
@@ -51,7 +63,7 @@ constexpr std::uint8_t kind_link = 10;
/// always the next one, and the token length follows from `extra`).
struct node
{
std::uint8_t kind; ///< value_t, or kind_link
node_kind kind; ///< value_t, or link
std::uint8_t flags; ///< node_flags
std::uint16_t extra; ///< numbers: integer digits (low byte) and fraction digits (high byte), 255 = "many"; objects: number of the object's key hash index (1-based, 0 = none); otherwise 0
std::uint32_t off; ///< source offset (string content, number token, literal, bracket); arena offset if escaped/edited; number of the element sequence if moved
@@ -60,8 +72,9 @@ struct node
};
static_assert(sizeof(node) == 16, "node must stay 16 bytes");
// the node kinds are value_t values; the test below (object and array are 1
// and 2) and those of the number kinds depend on this numbering
// the node kinds are value_t values, and images store them as bytes; the test
// below (object and array are 1 and 2) and those of the number kinds depend
// on this numbering
static_assert(static_cast<std::uint8_t>(value_t::null) == 0 && static_cast<std::uint8_t>(value_t::object) == 1
&& static_cast<std::uint8_t>(value_t::array) == 2 && static_cast<std::uint8_t>(value_t::string) == 3
&& static_cast<std::uint8_t>(value_t::boolean) == 4 && static_cast<std::uint8_t>(value_t::number_integer) == 5
@@ -86,7 +99,7 @@ inline void make_link(node& n, node* target) noexcept
{
target->flags = static_cast<std::uint8_t>(target->flags | node_flags::linked);
n = node{};
n.kind = kind_link;
n.kind = node_kind::link;
std::memcpy(reinterpret_cast<unsigned char*>(&n) + 8, static_cast<const void*>(&target), sizeof(const node*)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
}
@@ -116,8 +129,8 @@ NLOHMANN_VIEW_ALWAYS_INLINE void set_integer_bits(node& n, std::uint64_t v) noex
/// token length of a number node
NLOHMANN_VIEW_ALWAYS_INLINE std::uint32_t number_length(const node& n) noexcept
{
return n.kind == static_cast<std::uint8_t>(value_t::number_float) ? n.len
: (n.extra & 0xFFu) + (n.kind == static_cast<std::uint8_t>(value_t::number_integer) ? 1u : 0u);
return n.kind == node_kind::number_float ? n.len
: (n.extra & 0xFFu) + (n.kind == node_kind::number_integer ? 1u : 0u);
}
/// estimated number of nodes for an input of `size` bytes (one node per ~12
+1 -1
View File
@@ -874,7 +874,7 @@ class view_serializer
case value_t::object:
case value_t::array:
{
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
room(8);
if (n->len == 0)
{
+5 -5
View File
@@ -24,25 +24,25 @@
// with different flags would have different definitions of the same inline
// functions): the check is compiled for SSSE3 with a function attribute and
// used where the CPU has SSSE3 (all x86-64 CPUs since about 2011), else the
// portable check. JSON_VIEW_USE_SSSE3 skips the CPU check (for code compiled
// for SSSE3 anyway); JSON_VIEW_NO_SIMD selects the portable code.
// portable check. Code compiled for SSSE3 anyway (-mssse3 or more) skips the
// CPU check. JSON_NO_SIMD selects the portable code, as in the lexer.
// NLOHMANN_VIEW_NO_TARGET_ATTRIBUTE (set by the GCC module interface, where GCC
// ignores the target attribute and then rejects the SSSE3 intrinsics) keeps the
// check portable without disabling the SSE2 code.
#if !defined(JSON_VIEW_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
#if !defined(JSON_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
#include <arm_neon.h>
#define NLOHMANN_VIEW_NEON 1
#else
#define NLOHMANN_VIEW_NEON 0
#endif
// (x86 only: other targets can define __SSE2__ as well, e.g., WebAssembly with -msse2, but have no <cpuid.h>)
#if !defined(JSON_VIEW_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#if !defined(JSON_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#include <emmintrin.h>
#define NLOHMANN_VIEW_SSE2 1
#else
#define NLOHMANN_VIEW_SSE2 0
#endif
#if NLOHMANN_VIEW_SSE2 && defined(JSON_VIEW_USE_SSSE3)
#if NLOHMANN_VIEW_SSE2 && defined(__SSSE3__)
#include <tmmintrin.h>
#define NLOHMANN_VIEW_SSSE3 1 // NOLINT(cppcoreguidelines-macro-to-enum,modernize-macro-to-enum)
#else
@@ -0,0 +1,27 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#pragma once
#include <cstdint> // uint8_t
#include <nlohmann/json.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
/// whether a basic_json_document and its views can be edited
enum class view_mode : std::uint8_t
{
read_only, ///< parsed once, then only read (the default)
editable, ///< also has set(), push_back(), insert(), and erase()
};
template<typename BasicJsonType, view_mode Mode>
class basic_json_view;
NLOHMANN_JSON_NAMESPACE_END
+37 -25
View File
@@ -84,6 +84,7 @@
#include <nlohmann/detail/view/serializer.hpp>
#include <nlohmann/detail/view/string_ref.hpp>
#include <nlohmann/detail/view/value.hpp>
#include <nlohmann/detail/view/view_mode.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
@@ -93,13 +94,16 @@ 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:
using value_t = detail::value_t;
@@ -446,7 +450,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 +508,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
@@ -646,7 +650,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 +686,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 +731,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 +744,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 +761,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 +814,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 +828,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 +850,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 ---
@@ -952,16 +956,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 +1182,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 +1227,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 +1369,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");
@@ -1642,13 +1654,13 @@ using ordered_json_document = basic_json_document<ordered_json>;
/// a value of an ordered_json_document
using ordered_json_view = basic_json_view<ordered_json>;
/// an editable parsed JSON text for json
using json_editable_document = basic_json_document<json, true>;
using json_editable_document = basic_json_document<json, view_mode::editable>;
/// a value of a json_editable_document
using json_editable_view = basic_json_view<json, true>;
using json_editable_view = basic_json_view<json, view_mode::editable>;
/// an editable parsed JSON text for ordered_json
using ordered_json_editable_document = basic_json_document<ordered_json, true>;
using ordered_json_editable_document = basic_json_document<ordered_json, view_mode::editable>;
/// a value of an ordered_json_editable_document
using ordered_json_editable_view = basic_json_view<ordered_json, true>;
using ordered_json_editable_view = basic_json_view<ordered_json, view_mode::editable>;
NLOHMANN_JSON_NAMESPACE_END
-3700
View File
File diff suppressed because it is too large. Load diff
+5 -19
View File
@@ -193,26 +193,14 @@
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
#endif
#ifdef JSON_VIEW_NO_SIMD
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD _vns
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD
#endif
#ifdef JSON_VIEW_USE_SSSE3
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3 _vssse3
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k, l, m) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -226,9 +214,7 @@
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
NLOHMANN_JSON_ABI_TAG_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3)
NLOHMANN_JSON_ABI_TAG_NO_SIMD)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
@@ -5565,7 +5551,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
+4 -18
View File
@@ -145,26 +145,14 @@
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
#endif
#ifdef JSON_VIEW_NO_SIMD
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD _vns
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD
#endif
#ifdef JSON_VIEW_USE_SSSE3
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3 _vssse3
#else
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k, l, m) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -178,9 +166,7 @@
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
NLOHMANN_JSON_ABI_TAG_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD, \
NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3)
NLOHMANN_JSON_ABI_TAG_NO_SIMD)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
+132 -82
View File
@@ -239,9 +239,21 @@ struct node_flags
static constexpr std::uint8_t linked = 32; ///< an entry of a moved sequence links to this value (editable documents): its extent in the parsed layout no longer matters
};
/// kind of an entry of an edited sequence that stands for a value stored
/// elsewhere (the address of the value's node is kept in the len/next bytes)
constexpr std::uint8_t kind_link = 10;
/// the kind of a node: the value_t of its value, or link
enum class node_kind : std::uint8_t
{
null = static_cast<std::uint8_t>(value_t::null),
object = static_cast<std::uint8_t>(value_t::object),
array = static_cast<std::uint8_t>(value_t::array),
string = static_cast<std::uint8_t>(value_t::string),
boolean = static_cast<std::uint8_t>(value_t::boolean),
number_integer = static_cast<std::uint8_t>(value_t::number_integer),
number_unsigned = static_cast<std::uint8_t>(value_t::number_unsigned),
number_float = static_cast<std::uint8_t>(value_t::number_float),
/// an entry of an edited sequence that stands for a value stored elsewhere
/// (the address of the value's node is kept in the len/next bytes)
link = static_cast<std::uint8_t>(value_t::discarded) + 1,
};
/// One entry of the flat index, in document order. An object's members are
/// stored as key node followed by the value's subtree. Integers keep their
@@ -249,7 +261,7 @@ constexpr std::uint8_t kind_link = 10;
/// always the next one, and the token length follows from `extra`).
struct node
{
std::uint8_t kind; ///< value_t, or kind_link
node_kind kind; ///< value_t, or link
std::uint8_t flags; ///< node_flags
std::uint16_t extra; ///< numbers: integer digits (low byte) and fraction digits (high byte), 255 = "many"; objects: number of the object's key hash index (1-based, 0 = none); otherwise 0
std::uint32_t off; ///< source offset (string content, number token, literal, bracket); arena offset if escaped/edited; number of the element sequence if moved
@@ -258,8 +270,9 @@ struct node
};
static_assert(sizeof(node) == 16, "node must stay 16 bytes");
// the node kinds are value_t values; the test below (object and array are 1
// and 2) and those of the number kinds depend on this numbering
// the node kinds are value_t values, and images store them as bytes; the test
// below (object and array are 1 and 2) and those of the number kinds depend
// on this numbering
static_assert(static_cast<std::uint8_t>(value_t::null) == 0 && static_cast<std::uint8_t>(value_t::object) == 1
&& static_cast<std::uint8_t>(value_t::array) == 2 && static_cast<std::uint8_t>(value_t::string) == 3
&& static_cast<std::uint8_t>(value_t::boolean) == 4 && static_cast<std::uint8_t>(value_t::number_integer) == 5
@@ -284,7 +297,7 @@ inline void make_link(node& n, node* target) noexcept
{
target->flags = static_cast<std::uint8_t>(target->flags | node_flags::linked);
n = node{};
n.kind = kind_link;
n.kind = node_kind::link;
std::memcpy(reinterpret_cast<unsigned char*>(&n) + 8, static_cast<const void*>(&target), sizeof(const node*)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
}
@@ -314,8 +327,8 @@ NLOHMANN_VIEW_ALWAYS_INLINE void set_integer_bits(node& n, std::uint64_t v) noex
/// token length of a number node
NLOHMANN_VIEW_ALWAYS_INLINE std::uint32_t number_length(const node& n) noexcept
{
return n.kind == static_cast<std::uint8_t>(value_t::number_float) ? n.len
: (n.extra & 0xFFu) + (n.kind == static_cast<std::uint8_t>(value_t::number_integer) ? 1u : 0u);
return n.kind == node_kind::number_float ? n.len
: (n.extra & 0xFFu) + (n.kind == node_kind::number_integer ? 1u : 0u);
}
/// estimated number of nodes for an input of `size` bytes (one node per ~12
@@ -547,7 +560,7 @@ struct document_data
/// following loads.
static NLOHMANN_VIEW_ALWAYS_INLINE const node* deref(const node* n) noexcept
{
return NLOHMANN_VIEW_LIKELY(n->kind != kind_link) ? n : follow_link(n);
return NLOHMANN_VIEW_LIKELY(n->kind != node_kind::link) ? n : follow_link(n);
}
static NLOHMANN_VIEW_NOINLINE const node* follow_link(const node* n) noexcept
@@ -665,25 +678,25 @@ NLOHMANN_JSON_NAMESPACE_END
// with different flags would have different definitions of the same inline
// functions): the check is compiled for SSSE3 with a function attribute and
// used where the CPU has SSSE3 (all x86-64 CPUs since about 2011), else the
// portable check. JSON_VIEW_USE_SSSE3 skips the CPU check (for code compiled
// for SSSE3 anyway); JSON_VIEW_NO_SIMD selects the portable code.
// portable check. Code compiled for SSSE3 anyway (-mssse3 or more) skips the
// CPU check. JSON_NO_SIMD selects the portable code, as in the lexer.
// NLOHMANN_VIEW_NO_TARGET_ATTRIBUTE (set by the GCC module interface, where GCC
// ignores the target attribute and then rejects the SSSE3 intrinsics) keeps the
// check portable without disabling the SSE2 code.
#if !defined(JSON_VIEW_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
#if !defined(JSON_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
#include <arm_neon.h>
#define NLOHMANN_VIEW_NEON 1
#else
#define NLOHMANN_VIEW_NEON 0
#endif
// (x86 only: other targets can define __SSE2__ as well, e.g., WebAssembly with -msse2, but have no <cpuid.h>)
#if !defined(JSON_VIEW_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#if !defined(JSON_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#include <emmintrin.h>
#define NLOHMANN_VIEW_SSE2 1
#else
#define NLOHMANN_VIEW_SSE2 0
#endif
#if NLOHMANN_VIEW_SSE2 && defined(JSON_VIEW_USE_SSSE3)
#if NLOHMANN_VIEW_SSE2 && defined(__SSSE3__)
#include <tmmintrin.h>
#define NLOHMANN_VIEW_SSSE3 1 // NOLINT(cppcoreguidelines-macro-to-enum,modernize-macro-to-enum)
#else
@@ -2169,7 +2182,7 @@ indent_done:
std::memcpy(reinterpret_cast<unsigned char*>(n), &first, 8);
std::memcpy(reinterpret_cast<unsigned char*>(n) + 8, &second, 8);
#else
n->kind = static_cast<std::uint8_t>(k);
n->kind = static_cast<node_kind>(k);
n->flags = flags;
n->extra = extra;
n->off = static_cast<std::uint32_t>(off);
@@ -3001,7 +3014,7 @@ NLOHMANN_JSON_NAMESPACE_END
// live in chunks that never move; strings and number tokens written by edits
// live in the edit arena. An array/object whose elements change gets
// node_flags::moved: its elements then live in a separate sequence (a header
// node, then the entries), whose entries link to the values (kind_link).
// node, then the entries), whose entries link to the values (node_kind::link).
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
@@ -3159,7 +3172,7 @@ inline node* block_of(document_data& d, node* n, std::size_t extra)
return nh;
}
reserve_moved(d); // (so that set_moved() below cannot throw: the links are marked before)
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
const std::size_t used = 1 + (static_cast<std::size_t>(n->len) * (object ? 2 : 1));
const std::size_t cap = used + extra;
node* const h = alloc_nodes(d, cap);
@@ -3225,7 +3238,7 @@ inline node* find_parent(const document_data& d, const node* target)
{
return nullptr; // LCOV_EXCL_LINE (the value is inside c)
}
const bool object = c->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = c->kind == node_kind::object;
const node* down = nullptr;
for (const node* p = d.first_child_edited(c), *e = d.child_end_edited(c); p != e;)
{
@@ -3692,7 +3705,7 @@ const node* element_at(const document_data& d, const node* array, std::size_t id
template<bool Editable>
const node* last_child(const document_data& d, const node* container) noexcept
{
const std::size_t value_offset = container->kind == static_cast<std::uint8_t>(value_t::object) ? 1 : 0;
const std::size_t value_offset = container->kind == node_kind::object ? 1 : 0;
const node* const end = navigation<Editable>::end(d, container);
const node* last = navigation<Editable>::first(d, container);
if (value_offset == 0 && container->next == container->len + 1u && (!navigation<Editable>::editable() || (container->flags & node_flags::moved) == 0))
@@ -3714,12 +3727,38 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/view/node.hpp>
// #include <nlohmann/detail/view/view_mode.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include <cstdint> // uint8_t
// #include <nlohmann/json.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
template<typename BasicJsonType, bool Editable>
/// whether a basic_json_document and its views can be edited
enum class view_mode : std::uint8_t
{
read_only, ///< parsed once, then only read (the default)
editable, ///< also has set(), push_back(), insert(), and erase()
};
template<typename BasicJsonType, view_mode Mode>
class basic_json_view;
NLOHMANN_JSON_NAMESPACE_END
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{
namespace view
@@ -3808,13 +3847,13 @@ class editor
View set(const View& object, string_view_t key, V&& value)
{
node* const o = own(object);
if (o->kind != static_cast<std::uint8_t>(value_t::object) && o->kind != static_cast<std::uint8_t>(value_t::null))
if (o->kind != node_kind::object && o->kind != node_kind::null)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a string argument with ", object.type_name());
}
check_utf8(key.data(), key.size());
const encoded e = encode(std::forward<V>(value));
if (o->kind == static_cast<std::uint8_t>(value_t::null))
if (o->kind == node_kind::null)
{
become_empty(o, value_t::object);
}
@@ -3859,7 +3898,7 @@ class editor
View set(const View& array, std::size_t idx, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a numeric argument with ", array.type_name());
}
@@ -3876,12 +3915,12 @@ class editor
View push_back(const View& array, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array) && a->kind != static_cast<std::uint8_t>(value_t::null))
if (a->kind != node_kind::array && a->kind != node_kind::null)
{
throw_type_error(exception_id::push_back_wrong_type, "cannot use push_back() with ", array.type_name());
}
const encoded e = encode(std::forward<V>(value));
if (a->kind == static_cast<std::uint8_t>(value_t::null))
if (a->kind == node_kind::null)
{
become_empty(a, value_t::array);
}
@@ -3900,7 +3939,7 @@ class editor
View insert(const View& array, std::size_t idx, V&& value)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::insert_wrong_type, "cannot use insert() with ", array.type_name());
}
@@ -3920,7 +3959,7 @@ class editor
std::size_t erase(const View& object, string_view_t key)
{
node* const o = own(object);
if (o->kind != static_cast<std::uint8_t>(value_t::object))
if (o->kind != node_kind::object)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", object.type_name());
}
@@ -3938,7 +3977,7 @@ class editor
void erase(const View& array, std::size_t idx)
{
node* const a = own(array);
if (a->kind != static_cast<std::uint8_t>(value_t::array))
if (a->kind != node_kind::array)
{
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", array.type_name());
}
@@ -4016,7 +4055,7 @@ class editor
{
const std::uint8_t linked = n->flags & node_flags::linked;
*n = node{};
n->kind = static_cast<std::uint8_t>(k);
n->kind = static_cast<node_kind>(k);
n->flags = static_cast<std::uint8_t>(node_flags::is_new | linked);
n->next = 1;
}
@@ -4093,8 +4132,8 @@ class editor
template<typename T>
struct is_view : std::false_type {};
template<typename J, bool E>
struct is_view<basic_json_view<J, E>> : std::true_type {};
template<typename J, view_mode M>
struct is_view<basic_json_view<J, M>> : std::true_type {};
template<typename V>
encoded encode(V&& v)
@@ -4109,8 +4148,8 @@ class editor
}
/// a view of any document (copied; nothing is shared with it)
template<typename J, bool E>
encoded encode_impl(const basic_json_view<J, E>& v, encode_tag<0> /*view*/)
template<typename J, view_mode M>
encoded encode_impl(const basic_json_view<J, M>& v, encode_tag<0> /*view*/)
{
if (NLOHMANN_VIEW_UNLIKELY(v.m_node == nullptr))
{
@@ -4122,8 +4161,8 @@ class editor
r.scalar = copy_scalar(*v.m_doc, *v.m_node);
return r;
}
r.region = alloc_nodes(m_doc, count_nodes<E>(*v.m_doc, v.m_node));
fill_nodes<E>(*v.m_doc, v.m_node, r.region);
r.region = alloc_nodes(m_doc, count_nodes<M == view_mode::editable>(*v.m_doc, v.m_node));
fill_nodes<M == view_mode::editable>(*v.m_doc, v.m_node, r.region);
edit_state_of(m_doc).regions.emplace(r.region, nullptr);
return r;
}
@@ -4184,7 +4223,7 @@ class editor
static node plain_node(value_t k) noexcept
{
node n{};
n.kind = static_cast<std::uint8_t>(k);
n.kind = static_cast<node_kind>(k);
n.flags = node_flags::is_new;
return n;
}
@@ -4369,7 +4408,7 @@ class editor
++r;
if (is_container(*n))
{
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object)});
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object});
}
// the next value: close finished containers, then step over the key
for (;;)
@@ -4418,7 +4457,7 @@ class editor
node* const self = out++;
*self = plain_node(static_cast<value_t>(n->kind));
self->len = n->len;
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object), self});
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object, self});
}
else
{
@@ -4903,7 +4942,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
r.off = (v->flags & (node_flags::moved | node_flags::is_new)) != 0 ? 0 : v->off;
r.len = 0; // counted below
r.next = 0; // set when the container is complete
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == static_cast<std::uint8_t>(value_t::object)});
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == node_kind::object});
break;
case value_t::string:
r = string_node(*v);
@@ -4924,7 +4963,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
if (t[0] == 'n' || t[0] == 'i' || (v->len > 1 && t[1] == 'i'))
{
r = node{}; // nan and infinity: null, as dump() writes them
r.kind = static_cast<std::uint8_t>(value_t::null);
r.kind = node_kind::null;
break;
}
r.off = static_cast<std::uint32_t>(d.size + text_tail.size());
@@ -4968,12 +5007,10 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
}
}
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no save() elsewhere)
/// the document as an image
inline std::vector<std::uint8_t> save_image(const document_data& d)
{
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
#endif
const std::size_t arena_size = d.arena_size;
std::vector<node> compacted;
std::string text_tail;
@@ -5007,7 +5044,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
// extra of an object, and the same document saves to the same bytes
for (std::size_t i = 0; i < count; ++i)
{
if (nodes[i].kind == static_cast<std::uint8_t>(value_t::object) && nodes[i].extra != 0)
if (nodes[i].kind == node_kind::object && nodes[i].extra != 0)
{
std::memset(o + (i * sizeof(node)) + offsetof(node, extra), 0, sizeof(nodes[i].extra));
}
@@ -5029,6 +5066,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
*o = 0;
return image;
}
#endif
/// the parts of a number token that the checks need
struct number_token
@@ -5123,7 +5161,7 @@ inline bool float_token_finite(const unsigned char* s, std::size_t len, const nu
if (static_cast<std::int64_t>(t.int_digits) + t.exponent > 300)
{
node n{};
n.kind = static_cast<std::uint8_t>(value_t::number_float);
n.kind = node_kind::number_float;
n.len = static_cast<std::uint32_t>(len);
const auto v = float_value<double>(reinterpret_cast<const char*>(s), n); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
return v <= (std::numeric_limits<double>::max)() && v >= -(std::numeric_limits<double>::max)();
@@ -5144,7 +5182,7 @@ inline bool check_integer(const node& n, const unsigned char* text)
}
// the token's value is the stored one; number_integer nodes of edits can
// be non-negative (as basic_json keeps the type of a value)
const bool integer = n.kind == static_cast<std::uint8_t>(value_t::number_integer);
const bool integer = n.kind == node_kind::number_integer;
if (t.is_float || t.int_digits > 20 || (t.negative && !integer))
{
return false;
@@ -5326,7 +5364,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
return false;
}
if (n.kind != static_cast<std::uint8_t>(value_t::number_float))
if (n.kind != node_kind::number_float)
{
return (n.extra >> 8u) == 0;
}
@@ -5367,7 +5405,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
const node& n = nodes[i];
if (!stack.empty() && stack.back().object && stack.back().expect_key)
{
if (n.kind != static_cast<std::uint8_t>(value_t::string) || !check_string(n))
if (n.kind != node_kind::string || !check_string(n))
{
return false;
}
@@ -5408,7 +5446,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
// (the contents of float tokens are checked later; the token of an
// integer has at most 256 characters)
if (n.kind == static_cast<std::uint8_t>(value_t::number_float))
if (n.kind == node_kind::number_float)
{
floats.push_back(float_range{n.off, n.len, n.extra});
}
@@ -5426,7 +5464,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
{
return false;
}
stack.push_back(frame{i + n.next, n.len, 0, n.kind == static_cast<std::uint8_t>(value_t::object), true});
stack.push_back(frame{i + n.next, n.len, 0, n.kind == node_kind::object, true});
complete = false;
break;
}
@@ -5449,13 +5487,11 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
throw_parse_error(exception_id::invalid_document_image, concat("invalid json_document image: ", what));
}
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no load() elsewhere)
/// Read an image into d. The text and the decoded strings stay in the image;
/// the nodes are copied (so that they are aligned, and edits can change them).
inline void load_image(document_data& d, const std::uint8_t* image, std::size_t size, image_check check)
{
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
#endif
if (image == nullptr || size < sizeof(image_header))
{
throw_invalid_image("too short");
@@ -5515,7 +5551,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
for (std::size_t i = 0; i < count; ++i)
{
const node& n = d.nodes[i];
if (n.kind == static_cast<std::uint8_t>(value_t::object) && n.len >= document_data::index_min_members)
if (n.kind == node_kind::object && n.len >= document_data::index_min_members)
{
d.large_objects.push_back(static_cast<std::uint32_t>(i));
}
@@ -5524,6 +5560,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
std::vector<std::uint32_t>().swap(d.large_objects); // (only needed while building)
d.discarded = false;
}
#endif
} // namespace view
} // namespace detail
@@ -6108,7 +6145,7 @@ BasicJsonType materialize(const document_data& d, const node* n)
case value_t::object:
case value_t::array:
{
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
if (object)
{
sax.start_object(n->len);
@@ -7222,7 +7259,7 @@ class view_serializer
case value_t::object:
case value_t::array:
{
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
const bool object = n->kind == node_kind::object;
room(8);
if (n->len == 0)
{
@@ -7773,6 +7810,8 @@ struct is_direct_value<std::unordered_map<K, V, H, E, A>, BasicJsonType, View> :
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/view/view_mode.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
@@ -7782,13 +7821,16 @@ 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:
using value_t = detail::value_t;
@@ -8135,7 +8177,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 +8235,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
@@ -8335,7 +8377,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 +8413,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 +8458,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 +8471,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 +8488,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 +8541,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 +8555,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 +8577,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 ---
@@ -8641,16 +8683,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 +8909,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 +8954,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 +9096,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");
@@ -9331,13 +9381,13 @@ using ordered_json_document = basic_json_document<ordered_json>;
/// a value of an ordered_json_document
using ordered_json_view = basic_json_view<ordered_json>;
/// an editable parsed JSON text for json
using json_editable_document = basic_json_document<json, true>;
using json_editable_document = basic_json_document<json, view_mode::editable>;
/// a value of a json_editable_document
using json_editable_view = basic_json_view<json, true>;
using json_editable_view = basic_json_view<json, view_mode::editable>;
/// an editable parsed JSON text for ordered_json
using ordered_json_editable_document = basic_json_document<ordered_json, true>;
using ordered_json_editable_document = basic_json_document<ordered_json, view_mode::editable>;
/// a value of an ordered_json_editable_document
using ordered_json_editable_view = basic_json_view<ordered_json, true>;
using ordered_json_editable_view = basic_json_view<ordered_json, view_mode::editable>;
NLOHMANN_JSON_NAMESPACE_END
+2 -3
View File
@@ -420,9 +420,9 @@ json_test_add_test_for(src/unit-file_input.cpp
)
# the json_view parser again with the portable string scanning instead of
# NEON/SSE2, and on x86-64 with the SSSE3 UTF-8 check (JSON_VIEW_USE_SSSE3)
# NEON/SSE2 (JSON_NO_SIMD), and on x86-64 compiled for SSSE3 (no CPU check)
json_test_set_test_options(test-json_view_builder_portable
COMPILE_DEFINITIONS JSON_VIEW_NO_SIMD
COMPILE_DEFINITIONS JSON_NO_SIMD
)
json_test_add_test_for(src/unit-json_view_builder.cpp
NAME test-json_view_builder_portable
@@ -430,7 +430,6 @@ json_test_add_test_for(src/unit-json_view_builder.cpp
)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64)$" AND NOT MSVC)
json_test_set_test_options(test-json_view_builder_ssse3
COMPILE_DEFINITIONS JSON_VIEW_USE_SSSE3
COMPILE_OPTIONS -mssse3
)
json_test_add_test_for(src/unit-json_view_builder.cpp
+1 -3
View File
@@ -24,9 +24,7 @@ foreach(test default noversion)
JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1
JSON_DISABLE_STREAM_BULK_SCAN=1
JSON_DISABLE_UNLOCKED_FILE_IO=1
JSON_NO_SIMD
JSON_VIEW_NO_SIMD
JSON_VIEW_USE_SSSE3)
JSON_NO_SIMD)
target_link_libraries(abi_config_${test}_all_tags PRIVATE abi_compat_main)
add_test(
NAME test-abi_config_${test}_all_tags
-8
View File
@@ -64,14 +64,6 @@ TEST_CASE("default namespace")
expected += "_ns";
#endif
#ifdef JSON_VIEW_NO_SIMD
expected += "_vns";
#endif
#ifdef JSON_VIEW_USE_SSSE3
expected += "_vssse3";
#endif
expected += "_v" STRINGIZE(NLOHMANN_JSON_VERSION_MAJOR);
expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_MINOR);
expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_PATCH) "::basic_json";
-8
View File
@@ -65,14 +65,6 @@ TEST_CASE("default namespace without version component")
expected += "_ns";
#endif
#ifdef JSON_VIEW_NO_SIMD
expected += "_vns";
#endif
#ifdef JSON_VIEW_USE_SSSE3
expected += "_vssse3";
#endif
expected += "::basic_json";
// fallback for Clang
+2 -2
View File
@@ -592,7 +592,7 @@ TEST_CASE("json_view node integer bits")
})
{
CAPTURE(v)
n.kind = 0x5A;
n.kind = static_cast<nlohmann::detail::view::node_kind>(0x5A);
n.flags = 0xA5;
n.extra = 0x1234;
n.off = 0x89ABCDEFu;
@@ -601,7 +601,7 @@ TEST_CASE("json_view node integer bits")
CHECK(n.len == static_cast<std::uint32_t>(v));
CHECK(n.next == static_cast<std::uint32_t>(v >> 32));
// the other fields are untouched
CHECK(n.kind == 0x5A);
CHECK(static_cast<std::uint8_t>(n.kind) == 0x5A);
CHECK(n.flags == 0xA5);
CHECK(n.extra == 0x1234);
CHECK(n.off == 0x89ABCDEFu);
+68 -1
View File
@@ -26,12 +26,79 @@ using nlohmann::json_editable_view;
#include <limits>
#include <map>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// These tests were split off unit-json_view_edit.cpp, whose object file got too
// large for the MinGW linker (see json_view_test_helpers.hpp).
namespace
{
// the three ways a function can accept views: editable ones, read-only ones, or both
template<typename BasicJsonType>
int accepts_editable(nlohmann::basic_json_view<BasicJsonType, nlohmann::view_mode::editable> /*unused*/)
{
return 1;
}
template<typename BasicJsonType>
int accepts_read_only(nlohmann::basic_json_view<BasicJsonType, nlohmann::view_mode::read_only> /*unused*/)
{
return 2;
}
template<typename BasicJsonType, nlohmann::view_mode Mode>
int accepts_any(nlohmann::basic_json_view<BasicJsonType, Mode> /*unused*/)
{
return Mode == nlohmann::view_mode::editable ? 3 : 4;
}
template<typename View>
auto overload(View v) -> decltype(accepts_editable(v))
{
return accepts_editable(v);
}
template<typename View>
auto overload(View v) -> decltype(accepts_read_only(v))
{
return accepts_read_only(v);
}
} // namespace
TEST_CASE("json_view modes")
{
using nlohmann::basic_json_document;
using nlohmann::basic_json_view;
using nlohmann::ordered_json;
using nlohmann::view_mode;
SECTION("read-only is the default, and the shortcuts name the modes")
{
static_assert(std::is_same<basic_json_view<json>, basic_json_view<json, view_mode::read_only>>::value, "default mode");
static_assert(std::is_same<basic_json_document<json>, basic_json_document<json, view_mode::read_only>>::value, "default mode");
static_assert(std::is_same<nlohmann::json_view, basic_json_view<json, view_mode::read_only>>::value, "json_view");
static_assert(std::is_same<json_editable_view, basic_json_view<json, view_mode::editable>>::value, "json_editable_view");
static_assert(std::is_same<json_editable_document, basic_json_document<json, view_mode::editable>>::value, "json_editable_document");
static_assert(std::is_same<nlohmann::ordered_json_editable_view, basic_json_view<ordered_json, view_mode::editable>>::value, "ordered_json_editable_view");
static_assert(std::is_same<json_editable_document::view_type, json_editable_view>::value, "view_type");
static_assert(std::is_same<json_document::view_type, nlohmann::json_view>::value, "view_type");
}
SECTION("a function template selects views by their mode")
{
const json_document d = json_document::parse("[1]");
const json_editable_document e = json_editable_document::parse("[1]");
const nlohmann::ordered_json_editable_document o = nlohmann::ordered_json_editable_document::parse("[1]");
CHECK(overload(e.root()) == 1);
CHECK(overload(o.root()) == 1);
CHECK(overload(d.root()) == 2);
CHECK(accepts_any(e.root()) == 3);
CHECK(accepts_any(d.root()) == 4);
}
}
TEST_CASE("json_view edits: views and values")
{
SECTION("a value that is no longer part of the document")
@@ -100,7 +167,7 @@ TEST_CASE("json_view edits: views and values")
// doubles have their own path to the output; other float types are
// written as basic_json writes them, non-finite values as null
using json_float = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
using document_float = nlohmann::basic_json_document<json_float, true>;
using document_float = nlohmann::basic_json_document<json_float, nlohmann::view_mode::editable>;
document_float d = document_float::parse("[1.5]");
d.push_back(d.root(), std::numeric_limits<float>::quiet_NaN());
d.push_back(d.root(), -std::numeric_limits<float>::infinity());
+31 -10
View File
@@ -28,11 +28,25 @@ using nlohmann::detail::view::node;
#include <random>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <test_data.hpp>
namespace json_view_image_test
{
// whether a document type has save() and load() (only on little-endian targets)
template<typename T, typename = void>
struct has_save : std::false_type {};
template<typename T>
struct has_save<T, decltype(static_cast<void>(std::declval<const T&>().save()))> : std::true_type {};
template<typename T, typename = void>
struct has_load : std::false_type {};
template<typename T>
struct has_load<T, decltype(static_cast<void>(T::load(std::declval<const std::vector<std::uint8_t>&>())))> : std::true_type {};
} // namespace json_view_image_test
#if !(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
namespace
@@ -171,6 +185,9 @@ std::uint32_t rng()
TEST_CASE("json_view images: round trips")
{
static_assert(json_view_image_test::has_save<json_document>::value && json_view_image_test::has_load<json_document>::value, "save() and load() on a little-endian target");
static_assert(json_view_image_test::has_save<ordered_json_editable_document>::value && json_view_image_test::has_load<ordered_json_editable_document>::value, "save() and load() on a little-endian target");
SECTION("small documents")
{
for (const char* text :
@@ -480,7 +497,7 @@ TEST_CASE("json_view images: edited documents")
{
CAPTURE(i)
CHECK((node_at(image, i).flags & nlohmann::detail::view::node_flags::linked) == 0);
CHECK(node_at(image, i).kind != nlohmann::detail::view::kind_link);
CHECK((node_at(image, i).kind != nlohmann::detail::view::node_kind::link));
}
for (const image_check check :
{
@@ -810,13 +827,13 @@ TEST_CASE("json_view images: check")
{
rejected(corrupted(image, 12, [&](node & n)
{
n.kind = kind;
n.kind = static_cast<nlohmann::detail::view::node_kind>(kind);
}), true);
}
// a key that is not a string
rejected(corrupted(image, 1, [](node & n)
{
n.kind = 0;
n.kind = nlohmann::detail::view::node_kind::null;
n.len = 0;
n.off = 0;
}), true);
@@ -960,11 +977,11 @@ TEST_CASE("json_view images: check")
}), true);
rejected(corrupted(image, 0, [](node & n)
{
n.kind = 2; // an array: the "keys" are values, and the counts do not match
n.kind = nlohmann::detail::view::node_kind::array; // an array: the "keys" are values, and the counts do not match
}), true);
const std::vector<std::uint8_t> as_array = corrupted(image, 16, [](node & n)
{
n.kind = 2; // {} as []: fine
n.kind = nlohmann::detail::view::node_kind::array; // {} as []: fine
});
CHECK(load_result(as_array, image_check::full).empty());
const std::string expected_dump = R"({"s":"x\"y","i":-12,"u":7,"f":1.5e+300,"b":true,"n":null,"a":["t",[]]})";
@@ -1013,13 +1030,13 @@ TEST_CASE("json_view images: check")
rejected(at_token(u6, 0, '8'), false); // 8 != 7
rejected(corrupted(image, 4, [](node & n)
{
n.kind = 6; // "-12" as unsigned: a sign
n.kind = nlohmann::detail::view::node_kind::number_unsigned; // "-12" as unsigned: a sign
n.extra = 3;
}), false);
// a non-negative number_integer (as edits write it): fine
const std::vector<std::uint8_t> positive = corrupted(image, 6, [](node & n)
{
n.kind = 5;
n.kind = nlohmann::detail::view::node_kind::number_integer;
n.extra = 0;
});
CHECK(load_result(positive, image_check::full).empty());
@@ -1027,7 +1044,7 @@ TEST_CASE("json_view images: check")
CHECK(pos.root()["u"].is_number_integer());
rejected(corrupted(image, 8, [](node & n)
{
n.kind = 6; // a float token as integer
n.kind = nlohmann::detail::view::node_kind::number_unsigned; // a float token as integer
n.extra = 7;
}), false);
}
@@ -1197,7 +1214,7 @@ TEST_CASE("json_view images: check")
{
std::vector<std::uint8_t> b = img;
node n = node_at(b, i);
n.kind = kind;
n.kind = static_cast<nlohmann::detail::view::node_kind>(kind);
n.extra = extra;
set_node(b, i, n);
return load_result(b, image_check::full);
@@ -1275,8 +1292,12 @@ TEST_CASE("json_view images: damaged images")
TEST_CASE("json_view images: big-endian targets")
{
// the image format is little-endian: save() and load() do not exist here
static_assert(!json_view_image_test::has_save<json_document>::value, "no save() on a big-endian target");
static_assert(!json_view_image_test::has_load<json_document>::value, "no load() on a big-endian target");
static_assert(!json_view_image_test::has_save<json_editable_document>::value, "no save() on a big-endian target");
const json_document d = json_document::parse("[1]");
CHECK_THROWS_WITH_AS(d.save(), "[json.exception.type_error.320] json_document images need a little-endian target", json::type_error&);
CHECK(d.root().size() == 1);
}
#endif
+4 -4
View File
@@ -34,11 +34,11 @@ version other than the one in `abi_macros.hpp`.
| Option | Description |
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `--list-tags` | Print every ABI tag (in namespace order) with the macro that enables it and the `NLOHMANN_JSON_ABI_TAG_*` identifier, then exit. |
| `--abi-tags TAGS` | Add the namespaces of one configuration, given as a comma-separated list of ABI tags (`_diag,_dp,_vns`; the leading underscore is optional, and the order does not matter). Can be repeated for several configurations. Unknown tags are an error. |
| `--abi-tags TAGS` | Add the namespaces of one configuration, given as a comma-separated list of ABI tags (`_diag,_dp,_ns`; the leading underscore is optional, and the order does not matter). Can be repeated for several configurations. Unknown tags are an error. |
| `--all` | Generate the namespaces for every combination of ABI tags. The file size doubles with each tag (about 60 MB for 12 tags). Cannot be combined with `--abi-tags`. |
| `--output FILE` | Write the Natvis file to `FILE` instead of `nlohmann_json.natvis` in the repository root. |
Each configuration gets both the versioned (`json_abi_diag_dp_vns_v3_12_0`) and the unversioned (`json_abi_diag_dp_vns`,
Each configuration gets both the versioned (`json_abi_diag_dp_ns_v3_12_0`) and the unversioned (`json_abi_diag_dp_ns`,
used with `NLOHMANN_JSON_NAMESPACE_NO_VERSION`) namespace. The default namespaces (up to two ABI tags) are always
included, so a generated file can replace the checked-in one.
@@ -52,10 +52,10 @@ included, so a generated file can replace the checked-in one.
```
3. Generate a Natvis file with them, for example for `JSON_DIAGNOSTICS`, `JSON_DIAGNOSTIC_POSITIONS`, and
`JSON_VIEW_NO_SIMD`:
`JSON_NO_SIMD`:
```shell
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my_nlohmann_json.natvis"
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my_nlohmann_json.natvis"
```
4. Use `my_nlohmann_json.natvis` instead of the shipped `nlohmann_json.natvis`, for example by adding it to your Visual
+1 -1
View File
@@ -91,7 +91,7 @@ if __name__ == '__main__':
'include/nlohmann/detail/abi_macros.hpp below "repo_root")')
selection = parser.add_mutually_exclusive_group()
selection.add_argument('--abi-tags', action='append', default=[], metavar='TAGS',
help='Comma-separated list of ABI tags (e.g. "_diag,_dp,_vns", leading underscores are '
help='Comma-separated list of ABI tags (e.g. "_diag,_dp,_ns", leading underscores are '
'optional) of one configuration to add to the default namespaces; can be repeated')
selection.add_argument('--all', action='store_true',
help='Generate the namespaces for every combination of ABI tags; the file size doubles '