Compare commits

...
Author SHA1 Message Date
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
33 changed files with 459 additions and 185 deletions

No files matched your search

+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",
@@ -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
@@ -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
@@ -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
@@ -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
+2 -2
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.
+1
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
+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;)
{
+10 -10
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());
@@ -221,7 +221,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));
}
@@ -337,7 +337,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 +358,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 +540,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 +581,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 +622,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 +640,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;
}
@@ -729,7 +729,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));
}
+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)
{
@@ -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
+32 -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
@@ -1357,7 +1364,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 +1649,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
+118 -71
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
@@ -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());
@@ -5007,7 +5046,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));
}
@@ -5123,7 +5162,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 +5183,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 +5365,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 +5406,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 +5447,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 +5465,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;
}
@@ -5515,7 +5554,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));
}
@@ -6108,7 +6147,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 +7261,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 +7812,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 +7823,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 +8179,7 @@ class basic_json_view
if (is_structured() && m_node->len != 0)
{
return unedited() ? basic_json_view(m_doc, detail::view::last_child<false>(*m_doc, m_node) + (is_object() ? 1 : 0))
: basic_json_view(m_doc, navigation::value(detail::view::last_child<Editable>(*m_doc, m_node) + (is_object() ? 1 : 0)));
: basic_json_view(m_doc, navigation::value(detail::view::last_child<is_editable>(*m_doc, m_node) + (is_object() ? 1 : 0)));
}
return front();
}
@@ -8193,7 +8237,7 @@ class basic_json_view
/// more than once); 0 if this is not an object
size_type count(string_view_t key) const
{
return is_object() ? detail::view::count_members<Editable>(*m_doc, m_node, key.data(), key.size()) : 0;
return is_object() ? detail::view::count_members<is_editable>(*m_doc, m_node, key.data(), key.size()) : 0;
}
size_type count(const char* key) const
@@ -8335,7 +8379,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 +8415,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 +8460,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 +8473,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 +8490,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 +8543,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 +8557,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 +8579,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 +8685,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
@@ -9046,7 +9093,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 +9378,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 -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());
+9 -9
View File
@@ -480,7 +480,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 +810,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 +960,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 +1013,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 +1027,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 +1197,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);