diff --git a/docs/mkdocs/docs/examples/basic_json_view__cbegin.cpp b/docs/mkdocs/docs/examples/basic_json_view__cbegin.cpp index 811db6267..4e67a8041 100644 --- a/docs/mkdocs/docs/examples/basic_json_view__cbegin.cpp +++ b/docs/mkdocs/docs/examples/basic_json_view__cbegin.cpp @@ -15,7 +15,7 @@ int main() const auto values = measurements.root(); const int sum = std::accumulate(values.cbegin(), values.cend(), 0, - [](int total, const json_view & v) + [](int total, const json_view & v) { return total + v.materialize().get(); }); diff --git a/docs/mkdocs/docs/examples/basic_json_view__cend.cpp b/docs/mkdocs/docs/examples/basic_json_view__cend.cpp index 2999bd684..c72990673 100644 --- a/docs/mkdocs/docs/examples/basic_json_view__cend.cpp +++ b/docs/mkdocs/docs/examples/basic_json_view__cend.cpp @@ -15,7 +15,7 @@ int main() const auto records = batch.root(); const bool all_objects = std::all_of(records.cbegin(), records.cend(), - [](const json_view & v) + [](const json_view & v) { return v.is_object(); }); diff --git a/docs/mkdocs/docs/examples/basic_json_view__type_name.cpp b/docs/mkdocs/docs/examples/basic_json_view__type_name.cpp index 9d59792ca..30661c0fd 100644 --- a/docs/mkdocs/docs/examples/basic_json_view__type_name.cpp +++ b/docs/mkdocs/docs/examples/basic_json_view__type_name.cpp @@ -13,7 +13,10 @@ int main() json_document bad = json_document::parse("[1, 2, 3]"); json_document failed = json_document::parse("not json", /* allow_exceptions */ false); - for (const json_view v : { good.root(), bad.root(), failed.root() }) + for (const json_view v : + { + good.root(), bad.root(), failed.root() + }) { if (v.is_object()) { diff --git a/include/nlohmann/detail/view/builder.hpp b/include/nlohmann/detail/view/builder.hpp index 45f547072..2e0151b31 100644 --- a/include/nlohmann/detail/view/builder.hpp +++ b/include/nlohmann/detail/view/builder.hpp @@ -418,6 +418,14 @@ class builder return w; } + /// a compile-time option as a runtime condition: testing the template + /// argument directly makes a condition like `TrailingCommas && c == ']'` + /// constant when the option is off, which MSVC reports as C4127 + static NLOHMANN_VIEW_ALWAYS_INLINE bool enabled(bool option) noexcept + { + return option; + } + /// The parse state and the parser proper. The cursor is a local object of /// run() whose address never escapes (everything it calls out of line is a /// member of the builder and gets the positions it needs), so that the @@ -547,7 +555,7 @@ arr_next: { return false; } - if (TrailingCommas && cur() == ']') + if (enabled(TrailingCommas) && cur() == ']') { ++p; goto close_container; @@ -614,7 +622,7 @@ obj_next: { return false; } - if (TrailingCommas && cur() == '}') + if (enabled(TrailingCommas) && cur() == '}') { ++p; goto close_container; @@ -756,7 +764,7 @@ indent_done: { ++p; } - if (Comments && cur() == '/') + if (enabled(Comments) && cur() == '/') { const unsigned char* const q = cold.comment(p); if (q == nullptr) diff --git a/single_include/nlohmann/json_view.hpp b/single_include/nlohmann/json_view.hpp index f3d955f22..32b561f58 100644 --- a/single_include/nlohmann/json_view.hpp +++ b/single_include/nlohmann/json_view.hpp @@ -959,6 +959,14 @@ class builder return w; } + /// a compile-time option as a runtime condition: testing the template + /// argument directly makes a condition like `TrailingCommas && c == ']'` + /// constant when the option is off, which MSVC reports as C4127 + static NLOHMANN_VIEW_ALWAYS_INLINE bool enabled(bool option) noexcept + { + return option; + } + /// The parse state and the parser proper. The cursor is a local object of /// run() whose address never escapes (everything it calls out of line is a /// member of the builder and gets the positions it needs), so that the @@ -1088,7 +1096,7 @@ arr_next: { return false; } - if (TrailingCommas && cur() == ']') + if (enabled(TrailingCommas) && cur() == ']') { ++p; goto close_container; @@ -1155,7 +1163,7 @@ obj_next: { return false; } - if (TrailingCommas && cur() == '}') + if (enabled(TrailingCommas) && cur() == '}') { ++p; goto close_container; @@ -1297,7 +1305,7 @@ indent_done: { ++p; } - if (Comments && cur() == '/') + if (enabled(Comments) && cur() == '/') { const unsigned char* const q = cold.comment(p); if (q == nullptr) diff --git a/tests/src/unit-class_lexer.cpp b/tests/src/unit-class_lexer.cpp index e16bf0bf1..e476c08c3 100644 --- a/tests/src/unit-class_lexer.cpp +++ b/tests/src/unit-class_lexer.cpp @@ -1465,7 +1465,8 @@ TEST_CASE("Eisel-Lemire float conversion") // than the distance to the rounding boundary, so it must not change std::string longer = token; const std::size_t e = longer.find('e'); - const std::string extra = longer.find('.') == std::string::npos ? ".000000000000000000001" : "000000000000000000001"; + const std::size_t dot = longer.find('.'); + const std::string extra = dot == std::string::npos ? ".000000000000000000001" : "000000000000000000001"; longer.insert(e == std::string::npos ? longer.size() : e, extra); CAPTURE(longer); if (eisel_lemire(longer, out)) @@ -1488,7 +1489,8 @@ TEST_CASE("Eisel-Lemire float conversion") CHECK(bits_of(json::parse("-65.613616999999977").get()) == bits_of(-65.613616999999977)); CHECK(bits_of(json::parse("2.2250738585072011e-308").get()) == 0x000FFFFFFFFFFFFFu); CHECK(bits_of(json::parse("4.9406564584124654e-324").get()) == 1u); - CHECK_THROWS_WITH_AS(json::parse("1.7976931348623159e308"), + json _; + CHECK_THROWS_WITH_AS(_ = json::parse("1.7976931348623159e308"), "[json.exception.out_of_range.406] number overflow parsing '1.7976931348623159e308'", json::out_of_range&); } } @@ -1555,16 +1557,23 @@ TEST_CASE("string scanning kernels") state ^= state << 17u; return state; }; + // the upper half as a 32-bit value: converts to std::size_t implicitly on + // every platform (a cast of std::uint64_t is useless where both are the + // same type, and required where std::size_t is 32 bits wide) + const auto next_small = [&next]() + { + return static_cast(next() >> 32u); + }; for (int round = 0; round < 100000; ++round) { // mostly ordinary text, so that runs span several words - std::string text(static_cast(next() % 8), '.'); - const auto count = static_cast(next() % 12); + std::string text(next_small() % 8u, '.'); + const std::size_t count = next_small() % 12u; for (std::size_t k = 0; k < count; ++k) { - const std::size_t p = (next() % 4 == 0) ? static_cast(next() % pieces.size()) : 0; + const std::size_t p = (next() % 4 == 0) ? next_small() % pieces.size() : 0; text += pieces[p]; - text += std::string(static_cast(next() % 10), 'x'); + text += std::string(next_small() % 10u, 'x'); } const auto* data = reinterpret_cast(text.data()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) for (std::size_t offset = 0; offset < 3 && offset <= text.size(); ++offset) diff --git a/tests/src/unit-json_view.cpp b/tests/src/unit-json_view.cpp index d643ab53e..2587401bb 100644 --- a/tests/src/unit-json_view.cpp +++ b/tests/src/unit-json_view.cpp @@ -38,6 +38,7 @@ using nlohmann::ordered_json_view; namespace { +#if !defined(JSON_NOEXCEPTION) // the exception parse() throws for a text, or "" if it accepts it std::string parse_exception(const std::string& text, bool comments = false, bool trailing_commas = false) { @@ -66,6 +67,7 @@ std::string view_exception(const std::string& text, bool comments = false, bool } return ""; } +#endif // a small deterministic generator of documents struct generator @@ -155,7 +157,7 @@ TEST_CASE("json_view") CHECK(v.materialize() == j); } - const json_view invalid; + const json_view invalid{}; CHECK(invalid.is_discarded()); CHECK(!static_cast(invalid)); CHECK(invalid.type() == json::value_t::discarded); @@ -200,9 +202,11 @@ TEST_CASE("json_view") }) { CAPTURE(text); +#if !defined(JSON_NOEXCEPTION) const std::string expected = parse_exception(text); REQUIRE(!expected.empty()); CHECK(view_exception(text) == expected); +#endif CHECK(!json_document::accept(text)); const json_document d = json_document::parse(text, false); CHECK(d.is_discarded()); @@ -210,8 +214,9 @@ TEST_CASE("json_view") CHECK(d.node_count() == 0); } // the exception types - CHECK_THROWS_AS(json_document::parse("[1,"), json::parse_error&); - CHECK_THROWS_AS(json_document::parse("1e400"), json::out_of_range&); + json_document _; + CHECK_THROWS_AS(_ = json_document::parse("[1,"), json::parse_error&); + CHECK_THROWS_AS(_ = json_document::parse("1e400"), json::out_of_range&); } SECTION("parse options") @@ -226,7 +231,9 @@ TEST_CASE("json_view") const bool comments = (options & 1) != 0; const bool trailing_commas = (options & 2) != 0; CHECK(json_document::accept(text, comments, trailing_commas) == json::accept(text, comments, trailing_commas)); +#if !defined(JSON_NOEXCEPTION) CHECK(view_exception(text, comments, trailing_commas) == parse_exception(text, comments, trailing_commas)); +#endif } } } @@ -238,7 +245,9 @@ TEST_CASE("json_view") const std::string nul_in_comment("[1, // c\0\n2]", 12); CHECK(json_document::accept(nul_in_comment, true) == json::accept(nul_in_comment, true)); CHECK(json_document::parse("\xEF\xBB\xBF[1]").root().materialize() == json::parse("\xEF\xBB\xBF[1]")); +#if !defined(JSON_NOEXCEPTION) CHECK(view_exception("\xEF\xBB") == parse_exception("\xEF\xBB")); +#endif } SECTION("inputs") @@ -384,6 +393,7 @@ TEST_CASE("json_view") namespace { +#if !defined(JSON_NOEXCEPTION) // the exception a call throws, or "" if it throws none template std::string exception_of(F f) @@ -398,6 +408,7 @@ std::string exception_of(F f) } return ""; } +#endif // compares a view with the ordered_json value materialize() gives for it: // types, sizes, elements and members (by index, key, and iteration), in @@ -566,6 +577,7 @@ TEST_CASE("json_view element access and iteration") const json_document d = json_document::parse(text); const json_view v = d.root(); const json j = v.materialize(); +#if !defined(JSON_NOEXCEPTION) if (!j.is_object()) { CHECK(exception_of([&] { static_cast(v["a"]); }) == exception_of([&] { static_cast(j["a"]); })); @@ -587,6 +599,7 @@ TEST_CASE("json_view element access and iteration") CHECK(exception_of([&] { static_cast(v.front()); }) == exception_of([&] { static_cast(j.front()); })); CHECK(exception_of([&] { static_cast(v.back()); }) == exception_of([&] { static_cast(j.back()); })); } +#endif CHECK(v.contains("a") == j.contains("a")); CHECK(v.count("a") == j.count("a")); CHECK((v.find("a") == v.end()) == (j.find("a") == j.end())); // NOLINT(readability-container-contains): find() is what is tested @@ -598,7 +611,7 @@ TEST_CASE("json_view element access and iteration") CHECK(!d.root()["a"][0]); 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; + const json_view invalid{}; CHECK(invalid.begin() == invalid.end()); CHECK(std::string(invalid.type_name()) == "discarded"); CHECK_THROWS_WITH_AS(invalid["a"], "[json.exception.type_error.305] cannot use operator[] with a string argument with discarded", json::type_error&); diff --git a/tests/src/unit-json_view_builder.cpp b/tests/src/unit-json_view_builder.cpp index 4584e8728..889067bae 100644 --- a/tests/src/unit-json_view_builder.cpp +++ b/tests/src/unit-json_view_builder.cpp @@ -9,8 +9,12 @@ #include "doctest_compatibility.h" #include -#include -#include +#if JSON_TEST_USING_MULTIPLE_HEADERS + #include + #include +#else + #include // the single header contains the internal headers +#endif using nlohmann::json; #include