From 45045ebb6de0f819281b54a5d7882b8cfa118c09 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 9 Oct 2026 16:53:54 +0200 Subject: [PATCH] Replace the removed operator bool of basic_json_view in the header and its tests A view is tested with is_discarded(); the lookups in at(), value() and contains(json_pointer) and the unit tests no longer rely on the explicit conversion to bool. Signed-off-by: Niels Lohmann --- include/nlohmann/json_view.hpp | 8 ++-- single_include/nlohmann/json_view.hpp | 8 ++-- tests/src/unit-json_view.cpp | 66 +++++++++++++-------------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/include/nlohmann/json_view.hpp b/include/nlohmann/json_view.hpp index e52e5a00a..d71d54488 100644 --- a/include/nlohmann/json_view.hpp +++ b/include/nlohmann/json_view.hpp @@ -302,7 +302,7 @@ class basic_json_view detail::view::throw_type_error(304, "cannot use at() with ", type_name()); } const basic_json_view r = lookup(key); - if (NLOHMANN_VIEW_UNLIKELY(!r)) + if (NLOHMANN_VIEW_UNLIKELY(r.is_discarded())) { detail::view::throw_out_of_range(403, detail::concat("key '", std::string(key.data(), key.size()), "' not found")); } @@ -360,7 +360,7 @@ class basic_json_view detail::view::throw_type_error(306, "cannot use value() with ", type_name()); } const basic_json_view r = lookup(key); - return r ? r.template get() : default_value; + return r.is_discarded() ? default_value : r.template get(); } string_t value(string_view_t key, const char* default_value) const @@ -379,7 +379,7 @@ class basic_json_view detail::view::throw_type_error(306, "cannot use value() with ", type_name()); } const basic_json_view r = detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::value); - return r ? r.template get() : default_value; + return r.is_discarded() ? default_value : r.template get(); } string_t value(const json_pointer& ptr, const char* default_value) const @@ -457,7 +457,7 @@ class basic_json_view /// basic_json::contains()) bool contains(const json_pointer& ptr) const { - return static_cast(detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::contains)); + return !detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::contains).is_discarded(); } /// 1 if this is an object with a member with this key, else 0 (duplicate diff --git a/single_include/nlohmann/json_view.hpp b/single_include/nlohmann/json_view.hpp index a73b94c7e..0d9bc1f15 100644 --- a/single_include/nlohmann/json_view.hpp +++ b/single_include/nlohmann/json_view.hpp @@ -3113,7 +3113,7 @@ class basic_json_view detail::view::throw_type_error(304, "cannot use at() with ", type_name()); } const basic_json_view r = lookup(key); - if (NLOHMANN_VIEW_UNLIKELY(!r)) + if (NLOHMANN_VIEW_UNLIKELY(r.is_discarded())) { detail::view::throw_out_of_range(403, detail::concat("key '", std::string(key.data(), key.size()), "' not found")); } @@ -3171,7 +3171,7 @@ class basic_json_view detail::view::throw_type_error(306, "cannot use value() with ", type_name()); } const basic_json_view r = lookup(key); - return r ? r.template get() : default_value; + return r.is_discarded() ? default_value : r.template get(); } string_t value(string_view_t key, const char* default_value) const @@ -3190,7 +3190,7 @@ class basic_json_view detail::view::throw_type_error(306, "cannot use value() with ", type_name()); } const basic_json_view r = detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::value); - return r ? r.template get() : default_value; + return r.is_discarded() ? default_value : r.template get(); } string_t value(const json_pointer& ptr, const char* default_value) const @@ -3268,7 +3268,7 @@ class basic_json_view /// basic_json::contains()) bool contains(const json_pointer& ptr) const { - return static_cast(detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::contains)); + return !detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::contains).is_discarded(); } /// 1 if this is an object with a member with this key, else 0 (duplicate diff --git a/tests/src/unit-json_view.cpp b/tests/src/unit-json_view.cpp index cf2afcac4..4827e83ff 100644 --- a/tests/src/unit-json_view.cpp +++ b/tests/src/unit-json_view.cpp @@ -593,7 +593,7 @@ void check_access(const ordered_json_view& v, const ordered_json& j) ++i; } CHECK(i == v.size()); - CHECK(!v[v.size()]); + CHECK(v[v.size()].is_discarded()); std::size_t index = 0; for (const auto& item : v.items()) { @@ -659,7 +659,7 @@ void check_access(const ordered_json_view& v, const ordered_json& j) CHECK(v.back().materialize() == j.back()); } } - CHECK(!v["not a key in the generated documents"]); + CHECK(v["not a key in the generated documents"].is_discarded()); CHECK(v.find("not a key in the generated documents") == v.end()); } else @@ -803,8 +803,8 @@ TEST_CASE("json_view element access and iteration") // where basic_json has undefined behavior, the view answers safely const json_document d = json_document::parse(R"({"a":[]})"); - CHECK(!d.root()["b"]); - CHECK(!d.root()["a"][0]); + CHECK(d.root()["b"].is_discarded()); + CHECK(d.root()["a"][0].is_discarded()); CHECK_THROWS_WITH_AS(d.root()["a"].front(), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&); CHECK_THROWS_WITH_AS(d.root()["a"].back(), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&); const json_view invalid{}; @@ -817,24 +817,24 @@ TEST_CASE("json_view element access and iteration") const json_document d = json_document::parse(R"({"a":{"b":[10,20]},"s":"str"})"); const json_view v = d.root(); // missing keys and indexes - CHECK(!v["x"]); - CHECK(!v["x"]["y"]); - CHECK(!v["x"]["y"]["z"]); - CHECK(!v["x"][0]); - CHECK(!v["x"][0u][1L]); - CHECK(!v["a"]["b"][2]); - CHECK(!v["a"]["b"][2]["c"]); - CHECK(!v["a"]["b"][2][json_view::json_pointer("/c")]); - CHECK(!v["x"][json_view::json_pointer("/a/b")]); - CHECK(!v["x"][json_view::json_pointer("")]); + CHECK(v["x"].is_discarded()); CHECK(v["x"]["y"].is_discarded()); - CHECK(!v["x"][std::string("y")]); + CHECK(v["x"]["y"]["z"].is_discarded()); + CHECK(v["x"][0].is_discarded()); + CHECK(v["x"][0u][1L].is_discarded()); + CHECK(v["a"]["b"][2].is_discarded()); + CHECK(v["a"]["b"][2]["c"].is_discarded()); + CHECK(v["a"]["b"][2][json_view::json_pointer("/c")].is_discarded()); + CHECK(v["x"][json_view::json_pointer("/a/b")].is_discarded()); + CHECK(v["x"][json_view::json_pointer("")].is_discarded()); + CHECK(v["x"]["y"].is_discarded()); + CHECK(v["x"][std::string("y")].is_discarded()); // a resolvable path still resolves CHECK(v["a"]["b"][1].materialize() == 20); CHECK(v[json_view::json_pointer("/a/b/1")].materialize() == 20); // the discarded view of an unresolved pointer is discarded too - CHECK(!v[json_view::json_pointer("/x/y")]["z"]); - CHECK(!v[json_view::json_pointer("/a/b/5")][0]); + CHECK(v[json_view::json_pointer("/x/y")]["z"].is_discarded()); + CHECK(v[json_view::json_pointer("/a/b/5")][0].is_discarded()); #if !defined(JSON_NOEXCEPTION) // type errors on values that are not discarded stay CHECK_THROWS_WITH_AS(v[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object", json::type_error&); @@ -845,9 +845,9 @@ TEST_CASE("json_view element access and iteration") CHECK_THROWS_AS(v["s"][json_view::json_pointer("/x")], json::out_of_range&); // at() keeps throwing on a discarded view const json_view invalid{}; - CHECK(!invalid["a"]); - CHECK(!invalid[0]); - CHECK(!invalid[json_view::json_pointer("/a")]); + CHECK(invalid["a"].is_discarded()); + CHECK(invalid[0].is_discarded()); + CHECK(invalid[json_view::json_pointer("/a")].is_discarded()); CHECK_THROWS_WITH_AS(invalid.at("a"), "[json.exception.type_error.304] cannot use at() with discarded", json::type_error&); CHECK_THROWS_WITH_AS(invalid.at(0), "[json.exception.type_error.304] cannot use at() with discarded", json::type_error&); CHECK_THROWS_AS(v.at("x").at("y"), json::out_of_range&); @@ -900,18 +900,18 @@ TEST_CASE("json_view element access and iteration") CHECK(j.at(std::uint32_t(0)) == 10); // as basic_json // out of range, including negative values (no wrap-around) - CHECK(!v[3]); - CHECK(!v[3u]); - CHECK(!v[3L]); - CHECK(!v[-1]); - CHECK(!v[-1L]); - CHECK(!v[-1LL]); - CHECK(!v[static_cast(-1)]); - CHECK(!v[std::int64_t(-3)]); - CHECK(!v[(std::numeric_limits::min)()]); - CHECK(!v[(std::numeric_limits::max)()]); - CHECK(!v[(std::numeric_limits::max)()]); - CHECK(!v[std::numeric_limits::max()]); + CHECK(v[3].is_discarded()); + CHECK(v[3u].is_discarded()); + CHECK(v[3L].is_discarded()); + CHECK(v[-1].is_discarded()); + CHECK(v[-1L].is_discarded()); + CHECK(v[-1LL].is_discarded()); + CHECK(v[static_cast(-1)].is_discarded()); + CHECK(v[std::int64_t(-3)].is_discarded()); + CHECK(v[(std::numeric_limits::min)()].is_discarded()); + CHECK(v[(std::numeric_limits::max)()].is_discarded()); + CHECK(v[(std::numeric_limits::max)()].is_discarded()); + CHECK(v[std::numeric_limits::max()].is_discarded()); #if !defined(JSON_NOEXCEPTION) CHECK_THROWS_WITH_AS(v.at(3), "[json.exception.out_of_range.401] array index 3 is out of range", json::out_of_range&); CHECK_THROWS_WITH_AS(v.at(3u), "[json.exception.out_of_range.401] array index 3 is out of range", json::out_of_range&); @@ -1344,7 +1344,7 @@ TEST_CASE("json_view JSON pointers") else if (at_error.find("out_of_range.401") != std::string::npos || at_error.find("out_of_range.403") != std::string::npos) // NOLINT(abseil-string-find-str-contains) { // undefined behavior for const basic_json::operator[] - CHECK(!v[p]); + CHECK(v[p].is_discarded()); } else {