mirror of
https://github.com/nlohmann/json.git
synced 2026-10-29 00:55:44 +00:00
json_view: view_mode enum instead of bool Editable, node_kind for node::kind (#5919)
* 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> * json_view: node_kind in the node writers, spell out read_only, comment fixes The builder and the edit functions take and store a node_kind instead of casting a value_t; the numbering assertions and the comments now speak of node_kind, and the link kind notes that it follows value_t::discarded. The read-only aliases name view_mode::read_only like the editable ones. view_mode.md says the mode is a compile-time property of the type. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * json_view: views of read-only documents convert to editable views A read-only document has no edits, so a view of it reads correctly as a view of an editable document before its first edit. The implicit conversion lets a function taking a json_editable_view accept the views of both modes. There is no conversion the other way: a read-only view of an editable document would read wrong values after the next edit. The mode comparisons in the cross-mode operator==/!= use an is_other_mode trait, which astyle keeps compact. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
24078c862d
commit
731f1b5bfb
38 files changed
+704
-293
No files matched your search
@@ -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,15 +118,15 @@ 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);
|
||||
become_empty(o, node_kind::object);
|
||||
}
|
||||
// an existing member: assign it (and drop later duplicates, so that
|
||||
// lookups, iteration, and materialize() agree)
|
||||
@@ -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,14 +186,14 @@ 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);
|
||||
become_empty(a, node_kind::array);
|
||||
}
|
||||
node* const slot = new_slot(e);
|
||||
node* const h = block_of(m_doc, a, 1);
|
||||
@@ -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());
|
||||
}
|
||||
@@ -324,11 +322,11 @@ class editor
|
||||
}
|
||||
|
||||
/// turn a null into an empty array/object in place
|
||||
static void become_empty(node* n, value_t k) noexcept
|
||||
static void become_empty(node* n, node_kind k) noexcept
|
||||
{
|
||||
const std::uint8_t linked = n->flags & node_flags::linked;
|
||||
*n = node{};
|
||||
n->kind = static_cast<std::uint8_t>(k);
|
||||
n->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;
|
||||
}
|
||||
@@ -457,14 +455,14 @@ class editor
|
||||
encoded encode_impl(std::nullptr_t /*unused*/, encode_tag<2> /*null*/)
|
||||
{
|
||||
encoded r;
|
||||
r.scalar = plain_node(value_t::null);
|
||||
r.scalar = plain_node(node_kind::null);
|
||||
return r;
|
||||
}
|
||||
|
||||
encoded encode_impl(bool b, encode_tag<3> /*boolean*/)
|
||||
{
|
||||
encoded r;
|
||||
r.scalar = plain_node(value_t::boolean);
|
||||
r.scalar = plain_node(node_kind::boolean);
|
||||
r.scalar.flags = static_cast<std::uint8_t>(r.scalar.flags | (b ? node_flags::is_true : 0));
|
||||
return r;
|
||||
}
|
||||
@@ -493,10 +491,10 @@ class editor
|
||||
return encode_impl(BasicJsonType(std::forward<T>(x)), encode_tag<1> {});
|
||||
}
|
||||
|
||||
static node plain_node(value_t k) noexcept
|
||||
static node plain_node(node_kind k) noexcept
|
||||
{
|
||||
node n{};
|
||||
n.kind = static_cast<std::uint8_t>(k);
|
||||
n.kind = k;
|
||||
n.flags = node_flags::is_new;
|
||||
return n;
|
||||
}
|
||||
@@ -510,19 +508,19 @@ class editor
|
||||
template<typename T>
|
||||
node number_node(T x, std::integral_constant<int, 1> /*signed*/)
|
||||
{
|
||||
return integer_node(static_cast<std::uint64_t>(static_cast<std::int64_t>(x)), value_t::number_integer);
|
||||
return integer_node(static_cast<std::uint64_t>(static_cast<std::int64_t>(x)), node_kind::number_integer);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
node number_node(T x, std::integral_constant<int, 2> /*unsigned*/)
|
||||
{
|
||||
return integer_node(static_cast<std::uint64_t>(x), value_t::number_unsigned);
|
||||
return integer_node(static_cast<std::uint64_t>(x), node_kind::number_unsigned);
|
||||
}
|
||||
|
||||
/// an integer with its canonical token in the edit arena
|
||||
node integer_node(std::uint64_t bits, value_t k)
|
||||
node integer_node(std::uint64_t bits, node_kind k)
|
||||
{
|
||||
const bool negative = k == value_t::number_integer && static_cast<std::int64_t>(bits) < 0;
|
||||
const bool negative = k == node_kind::number_integer && static_cast<std::int64_t>(bits) < 0;
|
||||
std::uint64_t magnitude = negative ? 0 - bits : bits;
|
||||
std::array<char, 24> buf{};
|
||||
char* p = buf.data() + buf.size(); // NOLINT(misc-const-correctness): digits are written through p
|
||||
@@ -541,7 +539,7 @@ class editor
|
||||
n.flags = static_cast<std::uint8_t>(n.flags | node_flags::edited);
|
||||
n.off = append_text(m_doc, p, len);
|
||||
// number_length() adds one for the sign of number_integer nodes
|
||||
n.extra = static_cast<std::uint16_t>(k == value_t::number_integer ? len - 1 : len);
|
||||
n.extra = static_cast<std::uint16_t>(k == node_kind::number_integer ? len - 1 : len);
|
||||
set_integer_bits(n, bits);
|
||||
return n;
|
||||
}
|
||||
@@ -563,7 +561,7 @@ class editor
|
||||
{
|
||||
text = BasicJsonType(x).dump();
|
||||
}
|
||||
node n = plain_node(value_t::number_float);
|
||||
node n = plain_node(node_kind::number_float);
|
||||
n.flags = static_cast<std::uint8_t>(n.flags | node_flags::edited);
|
||||
n.extra = 0xFFFFu; // (the digit layout is not recorded)
|
||||
n.off = append_text(m_doc, text.data(), text.size());
|
||||
@@ -578,7 +576,7 @@ class editor
|
||||
{
|
||||
throw_out_of_range(exception_id::document_too_large, "strings of 4 GiB or more are not supported by json_document"); // LCOV_EXCL_LINE
|
||||
}
|
||||
node n = plain_node(value_t::string);
|
||||
node n = plain_node(node_kind::string);
|
||||
n.flags = static_cast<std::uint8_t>(n.flags | node_flags::edited);
|
||||
n.off = append_text(m_doc, s, len);
|
||||
n.len = static_cast<std::uint32_t>(len);
|
||||
@@ -600,10 +598,10 @@ class editor
|
||||
return string_node(from.str(n), n.len);
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
return integer_node(integer_bits(n), static_cast<value_t>(n.kind));
|
||||
return integer_node(integer_bits(n), n.kind);
|
||||
case value_t::number_float:
|
||||
{
|
||||
node r = plain_node(value_t::number_float);
|
||||
node r = plain_node(node_kind::number_float);
|
||||
r.flags = static_cast<std::uint8_t>(r.flags | node_flags::edited);
|
||||
r.off = append_text(m_doc, from.str(n), n.len);
|
||||
r.len = n.len;
|
||||
@@ -612,7 +610,7 @@ class editor
|
||||
}
|
||||
case value_t::boolean:
|
||||
{
|
||||
node r = plain_node(value_t::boolean);
|
||||
node r = plain_node(node_kind::boolean);
|
||||
r.flags = static_cast<std::uint8_t>(r.flags | (n.flags & node_flags::is_true));
|
||||
return r;
|
||||
}
|
||||
@@ -622,7 +620,7 @@ class editor
|
||||
case value_t::binary:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
return plain_node(value_t::null);
|
||||
return plain_node(node_kind::null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,17 +629,17 @@ class editor
|
||||
switch (j.type())
|
||||
{
|
||||
case value_t::null:
|
||||
return plain_node(value_t::null);
|
||||
return plain_node(node_kind::null);
|
||||
case value_t::boolean:
|
||||
{
|
||||
node r = plain_node(value_t::boolean);
|
||||
node r = plain_node(node_kind::boolean);
|
||||
r.flags = static_cast<std::uint8_t>(r.flags | (j.template get<bool>() ? node_flags::is_true : 0));
|
||||
return r;
|
||||
}
|
||||
case value_t::number_integer:
|
||||
return integer_node(static_cast<std::uint64_t>(static_cast<std::int64_t>(j.template get<number_integer_t>())), value_t::number_integer);
|
||||
return integer_node(static_cast<std::uint64_t>(static_cast<std::int64_t>(j.template get<number_integer_t>())), node_kind::number_integer);
|
||||
case value_t::number_unsigned:
|
||||
return integer_node(static_cast<std::uint64_t>(j.template get<number_unsigned_t>()), value_t::number_unsigned);
|
||||
return integer_node(static_cast<std::uint64_t>(j.template get<number_unsigned_t>()), node_kind::number_unsigned);
|
||||
case value_t::number_float:
|
||||
return float_node(j.template get<number_float_t>());
|
||||
case value_t::string:
|
||||
@@ -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 (;;)
|
||||
@@ -728,9 +726,9 @@ class editor
|
||||
if (is_container(*n))
|
||||
{
|
||||
node* const self = out++;
|
||||
*self = plain_node(static_cast<value_t>(n->kind));
|
||||
*self = plain_node(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
|
||||
{
|
||||
@@ -819,7 +817,7 @@ class editor
|
||||
if (n->is_structured())
|
||||
{
|
||||
node* const self = out++;
|
||||
*self = plain_node(n->type());
|
||||
*self = plain_node(static_cast<node_kind>(n->type()));
|
||||
self->len = static_cast<std::uint32_t>(n->size());
|
||||
open.push_back(frame{n->cbegin(), n->cend(), n->is_object(), self});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user