Address the review of json_view element access

From gregmarr's review of #5622:

- count() counts every member with the key, so count(key) > 1 detects
  duplicate keys; it was contains() as 0/1 before.
- get_to() passes types that get<T>() does not convert directly to
  from_json with the existing value, as basic_json::get_to() does, so that
  a from_json which sets only the fields present keeps the others.
- array_index() checks the empty token and "-" first; the results are
  unchanged.
- Docs: no "if an exception is thrown" where a view never changes
  anything; the borrowed source must also stay unmodified; items() on a
  temporary view is safe; back()/front() notes shortened; the basic_json
  see-also entries say how the view's results can differ.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-18 10:05:51 +02:00
1 parent f2582daa62
commit 7b755737b4
27 files changed
+239 -114

No files matched your search

+35 -2
View File
@@ -731,7 +731,12 @@ void check_access(const ordered_json_view& v, const ordered_json& j)
++members;
const std::string key(it.key().data(), it.key().size());
CHECK(v.contains(key));
CHECK(v.count(key) == 1);
std::size_t occurrences = 0;
for (auto other = v.begin(); other != v.end(); ++other)
{
occurrences += other.key() == it.key() ? 1 : 0;
}
CHECK(v.count(key) == occurrences);
// lookups find the first member with the key, which is this one if
// there is no earlier one
if (std::find(keys.begin(), keys.end(), key) != keys.end())
@@ -839,7 +844,8 @@ TEST_CASE("json_view element access and iteration")
CHECK(v.find("a") == v.begin());
CHECK(v.find("a").value().materialize() == 1);
CHECK(v.find("b") == std::next(v.begin()));
CHECK(v.count("a") == 1);
CHECK(v.count("a") == 2); // every member, unlike materialize()
CHECK(v.count("b") == 1);
CHECK(v.contains("a"));
CHECK(v.value("a", 0) == 1);
CHECK(v.materialize()["a"] == 3); // materialize() keeps the last value, unlike the lookups
@@ -1248,6 +1254,25 @@ void from_json(const json& j, record& r)
j.at("name").get_to(r.name);
j.at("count").get_to(r.count);
}
struct defaults
{
int a = 1;
int b = 2;
};
// sets only the members the JSON value has
void from_json(const json& j, defaults& d)
{
if (j.contains("a"))
{
j.at("a").get_to(d.a);
}
if (j.contains("b"))
{
j.at("b").get_to(d.b);
}
}
} // namespace
TEST_CASE("json_view values")
@@ -1369,6 +1394,14 @@ TEST_CASE("json_view values")
CHECK(name == "widget");
CHECK(count == 3);
// other types go to from_json with the existing value, as basic_json::get_to()
defaults def;
def.b = 5;
const json_document partial = json_document::parse(R"({"a":4})");
partial.root().get_to(def);
CHECK(def.a == 4);
CHECK(def.b == 5);
// a duplicate key: the last value, as parse()
const json_document dup = json_document::parse(R"({"a":1,"a":2})");
CHECK((dup.root().get<std::map<std::string, int>>() == std::map<std::string, int> {{"a", 2}}));