Fix the compiler and lint findings of json_view's read side and tests

- find() and contains() dispatch on Editable for the member lookup; for
  documents that cannot be edited both branches were the same call
  (GCC -Wduplicated-branches)
- json_view.hpp includes <cstdio> for the FILE overload (cpplint)
- the arena check macro of the builder is on one line (cpplint read it
  as an if body without braces)
- tests: no nested conditional (also MSVC C4018), no useless cast,
  parentheses around mixed operators, raw string literals, += instead
  of temporary concatenations, and NOLINT for the fixed seeds and a
  find() != npos, as elsewhere in the tests

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-23 06:41:40 +02:00
1 parent b63ec4d82b
commit 0ad42e42c0
5 files changed
+71 -35

No files matched your search

+2 -8
View File
@@ -283,14 +283,8 @@ class builder
const std::size_t start = arena_used();
char* w = m_arena_write;
const char* w_end = m_arena_end;
#define NLOHMANN_VIEW_ENSURE(n) \
if (NLOHMANN_VIEW_UNLIKELY(static_cast<std::size_t>(w_end - w) < (n))) \
{ \
m_arena_write = w; \
arena_grow(n); \
w = m_arena_write; \
w_end = m_arena_end; \
}
#define NLOHMANN_VIEW_ENSURE(n) \
if (NLOHMANN_VIEW_UNLIKELY(static_cast<std::size_t>(w_end - w) < (n))) { m_arena_write = w; arena_grow(n); w = m_arena_write; w_end = m_arena_end; }
{
const auto n = static_cast<std::size_t>(p - s);
if (n <= 16 && end - s >= 16)
+21 -4
View File
@@ -30,6 +30,7 @@
#include <array> // array
#include <cstddef> // nullptr_t, size_t // IWYU pragma: keep
#include <cstdint> // uint8_t, uint32_t
#include <cstdio> // FILE
#include <cstring> // memcpy, strlen
#include <istream> // istream // IWYU pragma: keep
#include <iterator> // distance, input_iterator_tag, iterator_traits
@@ -462,8 +463,7 @@ class basic_json_view
{
return end();
}
const node* const k = unedited() ? detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size())
: detail::view::find_member<Editable>(*m_doc, m_node, key.data(), key.size());
const node* const k = find_key(key);
return k != nullptr ? iterator(m_doc, k, true) : end();
}
@@ -480,8 +480,7 @@ class basic_json_view
/// whether this is an object with a member with this key
bool contains(string_view_t key) const
{
return is_object() && (unedited() ? detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size()) != nullptr
: detail::view::find_member<Editable>(*m_doc, m_node, key.data(), key.size()) != nullptr);
return is_object() && find_key(key) != nullptr;
}
bool contains(const char* key) const
@@ -822,6 +821,24 @@ class basic_json_view
return !navigation::editable() || m_doc->edits == nullptr;
}
/// 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> {});
}
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key, std::true_type /*editable*/) const
{
// (an editable document without edits is looked up as one that cannot be edited)
return unedited() ? detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size())
: detail::view::find_member<true>(*m_doc, m_node, key.data(), key.size());
}
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key, std::false_type /*editable*/) const
{
return detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size());
}
/// the element of an array at an index below its size
NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view element(size_type idx) const
{
+23 -12
View File
@@ -30,6 +30,7 @@
#include <array> // array
#include <cstddef> // nullptr_t, size_t // IWYU pragma: keep
#include <cstdint> // uint8_t, uint32_t
#include <cstdio> // FILE
#include <cstring> // memcpy, strlen
#include <istream> // istream // IWYU pragma: keep
#include <iterator> // distance, input_iterator_tag, iterator_traits
@@ -1473,14 +1474,8 @@ class builder
const std::size_t start = arena_used();
char* w = m_arena_write;
const char* w_end = m_arena_end;
#define NLOHMANN_VIEW_ENSURE(n) \
if (NLOHMANN_VIEW_UNLIKELY(static_cast<std::size_t>(w_end - w) < (n))) \
{ \
m_arena_write = w; \
arena_grow(n); \
w = m_arena_write; \
w_end = m_arena_end; \
}
#define NLOHMANN_VIEW_ENSURE(n) \
if (NLOHMANN_VIEW_UNLIKELY(static_cast<std::size_t>(w_end - w) < (n))) { m_arena_write = w; arena_grow(n); w = m_arena_write; w_end = m_arena_end; }
{
const auto n = static_cast<std::size_t>(p - s);
if (n <= 16 && end - s >= 16)
@@ -8042,8 +8037,7 @@ class basic_json_view
{
return end();
}
const node* const k = unedited() ? detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size())
: detail::view::find_member<Editable>(*m_doc, m_node, key.data(), key.size());
const node* const k = find_key(key);
return k != nullptr ? iterator(m_doc, k, true) : end();
}
@@ -8060,8 +8054,7 @@ class basic_json_view
/// whether this is an object with a member with this key
bool contains(string_view_t key) const
{
return is_object() && (unedited() ? detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size()) != nullptr
: detail::view::find_member<Editable>(*m_doc, m_node, key.data(), key.size()) != nullptr);
return is_object() && find_key(key) != nullptr;
}
bool contains(const char* key) const
@@ -8402,6 +8395,24 @@ class basic_json_view
return !navigation::editable() || m_doc->edits == nullptr;
}
/// 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> {});
}
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key, std::true_type /*editable*/) const
{
// (an editable document without edits is looked up as one that cannot be edited)
return unedited() ? detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size())
: detail::view::find_member<true>(*m_doc, m_node, key.data(), key.size());
}
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key, std::false_type /*editable*/) const
{
return detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size());
}
/// the element of an array at an index below its size
NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view element(size_type idx) const
{
+9 -5
View File
@@ -187,7 +187,7 @@ TEST_CASE("json_view")
CHECK(materialized<ordered_json_document>(R"({"a":1,"b":2,"a":3})").dump() == R"({"a":3,"b":2})");
// scalars (made without the handler), and nesting around the depth up to which the stack of open containers is local
for (const char* scalar :
{"null", "true", "false", "0", "-7", "18446744073709551615", "1.5e300", "-0.0", "\"\"", "\"short\"", "\"a string that is longer than fifteen bytes\"", "\"\\u00e4\\n\""
{"null", "true", "false", "0", "-7", "18446744073709551615", "1.5e300", "-0.0", "\"\"", "\"short\"", "\"a string that is longer than fifteen bytes\"", R"("\u00e4\n")"
})
{
CAPTURE(scalar)
@@ -203,9 +203,13 @@ TEST_CASE("json_view")
})
{
CAPTURE(levels)
const std::string nested = std::string(levels, '[') + "{\"k\":[1,{\"j\":2}]}" + std::string(levels, ']');
const std::string nested = std::string(levels, '[') + R"({"k":[1,{"j":2}]})" + std::string(levels, ']');
CHECK(materialized<json_document>(nested) == json::parse(nested));
const std::string wide = "{\"a\":" + nested + ",\"b\":" + nested + "}";
std::string wide = R"({"a":)";
wide += nested;
wide += R"(,"b":)";
wide += nested;
wide += "}";
CHECK(materialized<json_document>(wide) == json::parse(wide));
}
// very deep nesting (iterative, as parse())
@@ -444,7 +448,7 @@ TEST_CASE("json_view")
if (long_file != nullptr)
{
std::string padded = text;
padded.append((4096 - (padded.size() % 4096)) % 4096 + extra, ' ');
padded.append(((4096 - (padded.size() % 4096)) % 4096) + extra, ' ');
CHECK(std::fwrite(padded.data(), 1, padded.size(), long_file) == padded.size());
CHECK(std::fseek(long_file, 0, SEEK_SET) == 0);
const json_document from_long_file = json_document::parse(long_file);
@@ -1061,7 +1065,7 @@ TEST_CASE("json_view element access and iteration")
const std::vector<std::string> texts =
{
"[]", "[1]", "[1,2,3]", "[1,\"two\",3.5,true,null,-7,18446744073709551615]", "[[]]", "[{}]", "[1,[2],3]",
"[1,2,{\"a\":3}]", "[[1,2],3,4]", "[1,2,3,[4,5,6,7,8],9,10,11,12]", "[{\"a\":[1]},2]", "[\"a\\u00e4\",\"b\"]"
"[1,2,{\"a\":3}]", "[[1,2],3,4]", "[1,2,3,[4,5,6,7,8],9,10,11,12]", "[{\"a\":[1]},2]", R"(["a\u00e4","b"])"
};
for (const std::string& text : texts)
{
+16 -6
View File
@@ -617,7 +617,7 @@ TEST_CASE("json_view large objects")
std::size_t farthest = 0;
for (const std::string& key : keys)
{
std::size_t i = static_cast<std::size_t>(nlohmann::detail::view::key_hash(key.data(), key.size())) & (slots - 1);
std::size_t i = nlohmann::detail::conditional_static_cast<std::size_t>(nlohmann::detail::view::key_hash(key.data(), key.size())) & (slots - 1);
std::size_t distance = 0;
while (used[i])
{
@@ -639,7 +639,7 @@ TEST_CASE("json_view large objects")
std::size_t width = 0;
while (pattern[conversion] >= '0' && pattern[conversion] <= '9')
{
width = width * 10 + static_cast<std::size_t>(pattern[conversion] - '0');
width = (width * 10) + static_cast<std::size_t>(pattern[conversion] - '0');
++conversion;
}
const bool hex = pattern[conversion] == 'x';
@@ -659,10 +659,10 @@ TEST_CASE("json_view large objects")
})
{
CAPTURE(format)
CHECK(max_displacement(numbered(format, std::string(format).find("%02d") != std::string::npos ? 60 : 1000, 1)) < nlohmann::detail::view::index_max_displacement);
CHECK(max_displacement(numbered(format, std::string(format).find("%02d") != std::string::npos ? 60 : 1000, 1)) < nlohmann::detail::view::index_max_displacement); // NOLINT(abseil-string-find-str-contains)
CHECK(max_displacement(numbered(format, 600, 7)) < nlohmann::detail::view::index_max_displacement);
}
std::mt19937_64 rng(7);
std::mt19937_64 rng(7); // NOLINT(cert-msc32-c,cert-msc51-cpp,bugprone-random-generator-seed)
for (const std::size_t length :
{
std::size_t{1}, std::size_t{2}, std::size_t{3}, std::size_t{5}, std::size_t{7}, std::size_t{8}, std::size_t{9}, std::size_t{12}, std::size_t{16}, std::size_t{17}, std::size_t{33}
@@ -670,7 +670,17 @@ TEST_CASE("json_view large objects")
{
CAPTURE(length)
std::set<std::string> distinct;
while (distinct.size() < (length == 1 ? 26 : (length == 2 ? 500 : 700))) // (there are 26 and 676 keys of one and two letters)
// (there are 26 and 676 keys of one and two letters)
std::size_t wanted = 700;
if (length == 1)
{
wanted = 26;
}
else if (length == 2)
{
wanted = 500;
}
while (distinct.size() < wanted)
{
std::string key(length, 'a');
for (char& c : key)
@@ -688,7 +698,7 @@ TEST_CASE("json_view large objects")
// In a large object, a key is found by comparing its bytes with those of the member the
// table points to: up to 16 bytes as two overlapping words, longer ones with memcmp.
// Keys of every length from 0 to 40, and keys that differ from them in one byte.
std::mt19937_64 rng(2026);
std::mt19937_64 rng(2026); // NOLINT(cert-msc32-c,cert-msc51-cpp,bugprone-random-generator-seed)
std::vector<std::string> keys;
std::set<std::string> distinct;
for (std::size_t length = 0; length <= 40; ++length)