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
@@ -592,7 +592,7 @@ TEST_CASE("json_view node integer bits")
|
||||
})
|
||||
{
|
||||
CAPTURE(v)
|
||||
n.kind = 0x5A;
|
||||
n.kind = static_cast<nlohmann::detail::view::node_kind>(0x5A);
|
||||
n.flags = 0xA5;
|
||||
n.extra = 0x1234;
|
||||
n.off = 0x89ABCDEFu;
|
||||
@@ -601,7 +601,7 @@ TEST_CASE("json_view node integer bits")
|
||||
CHECK(n.len == static_cast<std::uint32_t>(v));
|
||||
CHECK(n.next == static_cast<std::uint32_t>(v >> 32));
|
||||
// the other fields are untouched
|
||||
CHECK(n.kind == 0x5A);
|
||||
CHECK(static_cast<std::uint8_t>(n.kind) == 0x5A);
|
||||
CHECK(n.flags == 0xA5);
|
||||
CHECK(n.extra == 0x1234);
|
||||
CHECK(n.off == 0x89ABCDEFu);
|
||||
|
||||
@@ -26,12 +26,119 @@ 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);
|
||||
}
|
||||
|
||||
// a function (no template) that takes an editable view also accepts a read-only one
|
||||
std::size_t sum_of(json_editable_view v)
|
||||
{
|
||||
std::size_t sum = 0;
|
||||
for (const json_editable_view x : v.at("values"))
|
||||
{
|
||||
sum += x.get<std::size_t>();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
} // 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);
|
||||
}
|
||||
|
||||
SECTION("a view of a read-only document converts to an editable view, not the other way")
|
||||
{
|
||||
static_assert(std::is_convertible<nlohmann::json_view, json_editable_view>::value, "read-only to editable");
|
||||
static_assert(!std::is_convertible<json_editable_view, nlohmann::json_view>::value, "not editable to read-only");
|
||||
static_assert(!std::is_convertible<nlohmann::json_view, nlohmann::ordered_json_editable_view>::value, "same BasicJsonType only");
|
||||
|
||||
const json_document d = json_document::parse(R"({"values": [1, 2, 3], "name": "a"})");
|
||||
json_editable_document e = json_editable_document::parse(R"({"values": [1, 2, 3], "name": "a"})");
|
||||
CHECK(sum_of(d.root()) == 6);
|
||||
CHECK(sum_of(e.root()) == 6);
|
||||
|
||||
const json_editable_view v = d.root();
|
||||
CHECK(v.size() == 2);
|
||||
CHECK(v.at("name").get<std::string>() == "a");
|
||||
CHECK(v.source_offset() == d.root().source_offset());
|
||||
CHECK((v == e.root()));
|
||||
CHECK((v == d.root()));
|
||||
|
||||
e.push_back(e.root().at("values"), 4);
|
||||
CHECK(sum_of(e.root()) == 10);
|
||||
CHECK((v != e.root()));
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
// the converted view still belongs to the read-only document
|
||||
CHECK_THROWS_WITH_AS(e.push_back(v.at("values"), 5), "[json.exception.invalid_iterator.202] view does not belong to this document", json::invalid_iterator&);
|
||||
#endif
|
||||
CHECK(sum_of(d.root()) == 6);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("json_view edits: views and values")
|
||||
{
|
||||
SECTION("a value that is no longer part of the document")
|
||||
@@ -100,7 +207,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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user