From 7ddb98543c7bb01385f69747b028117b73629971 Mon Sep 17 00:00:00 2001 From: Mark Gillard Date: Fri, 12 Jul 2024 11:43:25 +0300 Subject: [PATCH] fix is_homogeneous with outparam (fixes #231) --- CHANGELOG.md | 4 + include/toml++/impl/node.hpp | 9 +- include/toml++/impl/node_view.hpp | 2 +- include/toml++/impl/table.hpp | 4 +- include/toml++/impl/value.hpp | 10 +- tests/parsing_arrays.cpp | 233 ++++++++++++++++-------------- toml.hpp | 25 ++-- 7 files changed, 154 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6e199d3..49f4e3c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,10 @@ template: ## Unreleased +#### Fixes + +- fixed `is_homogeneous()` overloads with `first_nonmatch` outparam being broken in optimized builds (#231) (@Forbinn) + ## v3.4.0 - fixed "unresolved symbol" error with nvc++ (#220) (@Tomcat-42) diff --git a/include/toml++/impl/node.hpp b/include/toml++/impl/node.hpp index e89749cb..6c5c975c 100644 --- a/include/toml++/impl/node.hpp +++ b/include/toml++/impl/node.hpp @@ -11,7 +11,10 @@ // workaround for this: https://github.com/marzer/tomlplusplus/issues/220 #if TOML_NVCC -#define TOML_NVCC_WORKAROUND { return {}; } +#define TOML_NVCC_WORKAROUND \ + { \ + return {}; \ + } #else #define TOML_NVCC_WORKAROUND = 0 #endif @@ -177,11 +180,11 @@ TOML_NAMESPACE_START /// \returns True if the node was homogeneous. /// /// \remarks Always returns `false` for empty tables and arrays. - TOML_PURE_GETTER + TOML_NODISCARD virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0; /// \brief Checks if a node contains values/elements of only one type (const overload). - TOML_PURE_GETTER + TOML_NODISCARD virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0; /// \brief Checks if the node contains values/elements of only one type. diff --git a/include/toml++/impl/node_view.hpp b/include/toml++/impl/node_view.hpp index fb630251..7149594e 100644 --- a/include/toml++/impl/node_view.hpp +++ b/include/toml++/impl/node_view.hpp @@ -290,7 +290,7 @@ TOML_NAMESPACE_START /// /// \remarks Always returns `false` if the view does not reference a node, or if the viewed node is /// an empty table or array. - TOML_NODISCARD + TOML_PURE_GETTER bool is_homogeneous(node_type ntype) const noexcept { return node_ ? node_->is_homogeneous(ntype) : false; diff --git a/include/toml++/impl/table.hpp b/include/toml++/impl/table.hpp index b42ab48d..2ef33d47 100644 --- a/include/toml++/impl/table.hpp +++ b/include/toml++/impl/table.hpp @@ -298,11 +298,11 @@ TOML_NAMESPACE_START TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype) const noexcept final; - TOML_PURE_GETTER + TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; - TOML_PURE_GETTER + TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final; diff --git a/include/toml++/impl/value.hpp b/include/toml++/impl/value.hpp index 6fb35dc7..16cc7a3a 100644 --- a/include/toml++/impl/value.hpp +++ b/include/toml++/impl/value.hpp @@ -377,7 +377,7 @@ TOML_NAMESPACE_START return ntype == node_type::none || ntype == impl::node_type_of; } - TOML_PURE_GETTER + TOML_NODISCARD bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final { if (ntype != node_type::none && ntype != impl::node_type_of) @@ -388,7 +388,7 @@ TOML_NAMESPACE_START return true; } - TOML_PURE_GETTER + TOML_NODISCARD bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final { if (ntype != node_type::none && ntype != impl::node_type_of) @@ -1041,11 +1041,11 @@ TOML_NAMESPACE_START "Retrieving values as wide-character strings with node::value_exact() is only " "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); - static_assert((is_native || can_represent_native)&&!is_cvref, + static_assert((is_native || can_represent_native) && !is_cvref, TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()")); // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr - if constexpr ((is_native || can_represent_native)&&!is_cvref) + if constexpr ((is_native || can_represent_native) && !is_cvref) { if (type() == node_type_of) return { this->get_value_exact() }; @@ -1063,7 +1063,7 @@ TOML_NAMESPACE_START static_assert(!is_wide_string || TOML_ENABLE_WINDOWS_COMPAT, "Retrieving values as wide-character strings with node::value() is only " "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); - static_assert((is_native || can_represent_native || can_partially_represent_native)&&!is_cvref, + static_assert((is_native || can_represent_native || can_partially_represent_native) && !is_cvref, TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()")); // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion diff --git a/tests/parsing_arrays.cpp b/tests/parsing_arrays.cpp index fdd6ffaa..eef9d22e 100644 --- a/tests/parsing_arrays.cpp +++ b/tests/parsing_arrays.cpp @@ -7,8 +7,9 @@ TEST_CASE("parsing - arrays") { - parsing_should_succeed(FILE_LINE_ARGS, - R"( + parsing_should_succeed( + FILE_LINE_ARGS, + R"( integers = [ 1, 2, 3 ] integers2 = [ 1, 2, 3 @@ -22,115 +23,125 @@ TEST_CASE("parsing - arrays") nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ] string_array = [ "all", 'strings', """are the same""", '''type''' ] )"sv, - [](table&& tbl) - { - REQUIRE(tbl["integers"].as()); - CHECK(tbl["integers"].is_homogeneous()); - CHECK(tbl["integers"].is_homogeneous(node_type::integer)); - CHECK(!tbl["integers"].is_homogeneous(node_type::floating_point)); - CHECK(tbl["integers"].is_homogeneous()); - CHECK(!tbl["integers"].is_homogeneous()); - CHECK(tbl["integers"].as()->is_homogeneous()); - CHECK(tbl["integers"].as()->is_homogeneous(node_type::integer)); - CHECK(!tbl["integers"].as()->is_homogeneous(node_type::floating_point)); - CHECK(tbl["integers"].as()->is_homogeneous()); - CHECK(!tbl["integers"].as()->is_homogeneous()); - CHECK(tbl["integers"].as()->size() == 3); - CHECK(tbl["integers"][0] == 1); - CHECK(tbl["integers"][1] == 2); - CHECK(tbl["integers"][2] == 3); - - REQUIRE(tbl["integers2"].as()); - CHECK(tbl["integers2"].is_homogeneous()); - CHECK(tbl["integers2"].is_homogeneous(node_type::integer)); - CHECK(!tbl["integers2"].is_homogeneous(node_type::floating_point)); - CHECK(tbl["integers2"].is_homogeneous()); - CHECK(!tbl["integers2"].is_homogeneous()); - CHECK(tbl["integers2"].as()->is_homogeneous()); - CHECK(tbl["integers2"].as()->is_homogeneous(node_type::integer)); - CHECK(!tbl["integers2"].as()->is_homogeneous(node_type::floating_point)); - CHECK(tbl["integers2"].as()->is_homogeneous()); - CHECK(!tbl["integers2"].as()->is_homogeneous()); - CHECK(tbl["integers2"].as()->size() == 3); - CHECK(tbl["integers2"][0] == 1); - CHECK(tbl["integers2"][1] == 2); - CHECK(tbl["integers2"][2] == 3); - - REQUIRE(tbl["integers3"].as()); - CHECK(tbl["integers3"].is_homogeneous()); - CHECK(tbl["integers3"].is_homogeneous(node_type::integer)); - CHECK(!tbl["integers3"].is_homogeneous(node_type::floating_point)); - CHECK(tbl["integers3"].is_homogeneous()); - CHECK(!tbl["integers3"].is_homogeneous()); - CHECK(tbl["integers3"].as()->is_homogeneous()); - CHECK(tbl["integers3"].as()->is_homogeneous(node_type::integer)); - CHECK(!tbl["integers3"].as()->is_homogeneous(node_type::floating_point)); - CHECK(tbl["integers3"].as()->is_homogeneous()); - CHECK(!tbl["integers3"].as()->is_homogeneous()); - CHECK(tbl["integers3"].as()->size() == 2); - CHECK(tbl["integers3"][0] == 1); - CHECK(tbl["integers3"][1] == 2); - - REQUIRE(tbl["colors"].as()); - CHECK(tbl["colors"].is_homogeneous()); - CHECK(tbl["colors"].is_homogeneous(node_type::string)); - CHECK(!tbl["colors"].is_homogeneous(node_type::floating_point)); - CHECK(tbl["colors"].is_homogeneous()); - CHECK(!tbl["colors"].is_homogeneous()); - CHECK(tbl["colors"].as()->is_homogeneous()); - CHECK(tbl["colors"].as()->is_homogeneous(node_type::string)); - CHECK(!tbl["colors"].as()->is_homogeneous(node_type::floating_point)); - CHECK(tbl["colors"].as()->is_homogeneous()); - CHECK(!tbl["colors"].as()->is_homogeneous()); - CHECK(tbl["colors"].as()->size() == 3); - CHECK(tbl["colors"][0] == "red"sv); - CHECK(tbl["colors"][1] == "yellow"sv); - CHECK(tbl["colors"][2] == "green"sv); - - REQUIRE(tbl["nested_array_of_int"].as()); - CHECK(tbl["nested_array_of_int"].as()->is_homogeneous()); - CHECK(tbl["nested_array_of_int"].as()->size() == 2); - REQUIRE(tbl["nested_array_of_int"][0].as()); - CHECK(tbl["nested_array_of_int"][0].as()->is_homogeneous()); - CHECK(tbl["nested_array_of_int"][0].as()->size() == 2); - CHECK(tbl["nested_array_of_int"][0][0] == 1); - CHECK(tbl["nested_array_of_int"][0][1] == 2); - REQUIRE(tbl["nested_array_of_int"][1].as()); - CHECK(tbl["nested_array_of_int"][1].as()->is_homogeneous()); - CHECK(tbl["nested_array_of_int"][1].as()->size() == 3); - CHECK(tbl["nested_array_of_int"][1][0] == 3); - CHECK(tbl["nested_array_of_int"][1][1] == 4); - CHECK(tbl["nested_array_of_int"][1][2] == 5); - - REQUIRE(tbl["nested_mixed_array"].as()); - CHECK(tbl["nested_mixed_array"].as()->is_homogeneous()); - CHECK(tbl["nested_mixed_array"].as()->size() == 2); - REQUIRE(tbl["nested_mixed_array"][0].as()); - CHECK(tbl["nested_mixed_array"][0].as()->is_homogeneous()); - CHECK(tbl["nested_mixed_array"][0].as()->size() == 2); - CHECK(tbl["nested_mixed_array"][0][0] == 1); - CHECK(tbl["nested_mixed_array"][0][1] == 2); - REQUIRE(tbl["nested_mixed_array"][1].as()); - CHECK(tbl["nested_mixed_array"][1].as()->is_homogeneous()); - CHECK(tbl["nested_mixed_array"][1].as()->size() == 3); - CHECK(tbl["nested_mixed_array"][1][0] == "a"sv); - CHECK(tbl["nested_mixed_array"][1][1] == "b"sv); - CHECK(tbl["nested_mixed_array"][1][2] == "c"sv); - - REQUIRE(tbl["string_array"].as()); - CHECK(tbl["string_array"].as()->is_homogeneous()); - CHECK(tbl["string_array"].as()->size() == 4); - CHECK(tbl["string_array"][0] == "all"sv); - CHECK(tbl["string_array"][1] == "strings"sv); - CHECK(tbl["string_array"][2] == "are the same"sv); - CHECK(tbl["string_array"][3] == "type"sv); - REQUIRE(tbl["integers"].as()); - CHECK(tbl["integers"].as()->is_homogeneous()); - CHECK(tbl["integers"].as()->size() == 3); - CHECK(tbl["integers"][0] == 1); - CHECK(tbl["integers"][1] == 2); - CHECK(tbl["integers"][2] == 3); - }); + [](table&& tbl) + { + node* first_nonmatch = {}; + REQUIRE(tbl["integers"].as()); + CHECK(tbl["integers"].is_homogeneous()); + CHECK(tbl["integers"].is_homogeneous(node_type::integer)); + CHECK(!tbl["integers"].is_homogeneous(node_type::floating_point)); + CHECK(!tbl["integers"].is_homogeneous(node_type::floating_point, first_nonmatch)); + CHECK(first_nonmatch != nullptr); + first_nonmatch = {}; + + CHECK(tbl["integers"].is_homogeneous()); + CHECK(!tbl["integers"].is_homogeneous()); + CHECK(tbl["integers"].as()->is_homogeneous()); + CHECK(tbl["integers"].as()->is_homogeneous(node_type::integer)); + CHECK(!tbl["integers"].as()->is_homogeneous(node_type::floating_point)); + CHECK(!tbl["integers"].as()->is_homogeneous(node_type::floating_point, first_nonmatch)); + CHECK(first_nonmatch != nullptr); + first_nonmatch = {}; + + CHECK(tbl["integers"].as()->is_homogeneous()); + CHECK(!tbl["integers"].as()->is_homogeneous()); + + CHECK(tbl["integers"].as()->size() == 3); + CHECK(tbl["integers"][0] == 1); + CHECK(tbl["integers"][1] == 2); + CHECK(tbl["integers"][2] == 3); + + REQUIRE(tbl["integers2"].as()); + CHECK(tbl["integers2"].is_homogeneous()); + CHECK(tbl["integers2"].is_homogeneous(node_type::integer)); + CHECK(!tbl["integers2"].is_homogeneous(node_type::floating_point)); + CHECK(tbl["integers2"].is_homogeneous()); + CHECK(!tbl["integers2"].is_homogeneous()); + CHECK(tbl["integers2"].as()->is_homogeneous()); + CHECK(tbl["integers2"].as()->is_homogeneous(node_type::integer)); + CHECK(!tbl["integers2"].as()->is_homogeneous(node_type::floating_point)); + CHECK(tbl["integers2"].as()->is_homogeneous()); + CHECK(!tbl["integers2"].as()->is_homogeneous()); + CHECK(tbl["integers2"].as()->size() == 3); + CHECK(tbl["integers2"][0] == 1); + CHECK(tbl["integers2"][1] == 2); + CHECK(tbl["integers2"][2] == 3); + + REQUIRE(tbl["integers3"].as()); + CHECK(tbl["integers3"].is_homogeneous()); + CHECK(tbl["integers3"].is_homogeneous(node_type::integer)); + CHECK(!tbl["integers3"].is_homogeneous(node_type::floating_point)); + CHECK(tbl["integers3"].is_homogeneous()); + CHECK(!tbl["integers3"].is_homogeneous()); + CHECK(tbl["integers3"].as()->is_homogeneous()); + CHECK(tbl["integers3"].as()->is_homogeneous(node_type::integer)); + CHECK(!tbl["integers3"].as()->is_homogeneous(node_type::floating_point)); + CHECK(tbl["integers3"].as()->is_homogeneous()); + CHECK(!tbl["integers3"].as()->is_homogeneous()); + CHECK(tbl["integers3"].as()->size() == 2); + CHECK(tbl["integers3"][0] == 1); + CHECK(tbl["integers3"][1] == 2); + + REQUIRE(tbl["colors"].as()); + CHECK(tbl["colors"].is_homogeneous()); + CHECK(tbl["colors"].is_homogeneous(node_type::string)); + CHECK(!tbl["colors"].is_homogeneous(node_type::floating_point)); + CHECK(tbl["colors"].is_homogeneous()); + CHECK(!tbl["colors"].is_homogeneous()); + CHECK(tbl["colors"].as()->is_homogeneous()); + CHECK(tbl["colors"].as()->is_homogeneous(node_type::string)); + CHECK(!tbl["colors"].as()->is_homogeneous(node_type::floating_point)); + CHECK(tbl["colors"].as()->is_homogeneous()); + CHECK(!tbl["colors"].as()->is_homogeneous()); + CHECK(tbl["colors"].as()->size() == 3); + CHECK(tbl["colors"][0] == "red"sv); + CHECK(tbl["colors"][1] == "yellow"sv); + CHECK(tbl["colors"][2] == "green"sv); + + REQUIRE(tbl["nested_array_of_int"].as()); + CHECK(tbl["nested_array_of_int"].as()->is_homogeneous()); + CHECK(tbl["nested_array_of_int"].as()->size() == 2); + REQUIRE(tbl["nested_array_of_int"][0].as()); + CHECK(tbl["nested_array_of_int"][0].as()->is_homogeneous()); + CHECK(tbl["nested_array_of_int"][0].as()->size() == 2); + CHECK(tbl["nested_array_of_int"][0][0] == 1); + CHECK(tbl["nested_array_of_int"][0][1] == 2); + REQUIRE(tbl["nested_array_of_int"][1].as()); + CHECK(tbl["nested_array_of_int"][1].as()->is_homogeneous()); + CHECK(tbl["nested_array_of_int"][1].as()->size() == 3); + CHECK(tbl["nested_array_of_int"][1][0] == 3); + CHECK(tbl["nested_array_of_int"][1][1] == 4); + CHECK(tbl["nested_array_of_int"][1][2] == 5); + + REQUIRE(tbl["nested_mixed_array"].as()); + CHECK(tbl["nested_mixed_array"].as()->is_homogeneous()); + CHECK(tbl["nested_mixed_array"].as()->size() == 2); + REQUIRE(tbl["nested_mixed_array"][0].as()); + CHECK(tbl["nested_mixed_array"][0].as()->is_homogeneous()); + CHECK(tbl["nested_mixed_array"][0].as()->size() == 2); + CHECK(tbl["nested_mixed_array"][0][0] == 1); + CHECK(tbl["nested_mixed_array"][0][1] == 2); + REQUIRE(tbl["nested_mixed_array"][1].as()); + CHECK(tbl["nested_mixed_array"][1].as()->is_homogeneous()); + CHECK(tbl["nested_mixed_array"][1].as()->size() == 3); + CHECK(tbl["nested_mixed_array"][1][0] == "a"sv); + CHECK(tbl["nested_mixed_array"][1][1] == "b"sv); + CHECK(tbl["nested_mixed_array"][1][2] == "c"sv); + + REQUIRE(tbl["string_array"].as()); + CHECK(tbl["string_array"].as()->is_homogeneous()); + CHECK(tbl["string_array"].as()->size() == 4); + CHECK(tbl["string_array"][0] == "all"sv); + CHECK(tbl["string_array"][1] == "strings"sv); + CHECK(tbl["string_array"][2] == "are the same"sv); + CHECK(tbl["string_array"][3] == "type"sv); + REQUIRE(tbl["integers"].as()); + CHECK(tbl["integers"].as()->is_homogeneous()); + CHECK(tbl["integers"].as()->size() == 3); + CHECK(tbl["integers"][0] == 1); + CHECK(tbl["integers"][1] == 2); + CHECK(tbl["integers"][2] == 3); + }); // toml/issues/665 (heterogeneous arrays) #if TOML_LANG_AT_LEAST(1, 0, 0) diff --git a/toml.hpp b/toml.hpp index 3987fb57..80e10d3f 100644 --- a/toml.hpp +++ b/toml.hpp @@ -3642,7 +3642,10 @@ TOML_PUSH_WARNINGS; // workaround for this: https://github.com/marzer/tomlplusplus/issues/220 #if TOML_NVCC -#define TOML_NVCC_WORKAROUND { return {}; } +#define TOML_NVCC_WORKAROUND \ + { \ + return {}; \ + } #else #define TOML_NVCC_WORKAROUND = 0 #endif @@ -3767,10 +3770,10 @@ TOML_NAMESPACE_START TOML_EXPORTED_MEMBER_FUNCTION virtual ~node() noexcept; - TOML_PURE_GETTER + TOML_NODISCARD virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0; - TOML_PURE_GETTER + TOML_NODISCARD virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0; TOML_PURE_GETTER @@ -4429,7 +4432,7 @@ TOML_NAMESPACE_START return node_->is_homogeneous(ntype, first_nonmatch); } - TOML_NODISCARD + TOML_PURE_GETTER bool is_homogeneous(node_type ntype) const noexcept { return node_ ? node_->is_homogeneous(ntype) : false; @@ -5115,7 +5118,7 @@ TOML_NAMESPACE_START return ntype == node_type::none || ntype == impl::node_type_of; } - TOML_PURE_GETTER + TOML_NODISCARD bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final { if (ntype != node_type::none && ntype != impl::node_type_of) @@ -5126,7 +5129,7 @@ TOML_NAMESPACE_START return true; } - TOML_PURE_GETTER + TOML_NODISCARD bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final { if (ntype != node_type::none && ntype != impl::node_type_of) @@ -5640,11 +5643,11 @@ TOML_NAMESPACE_START "Retrieving values as wide-character strings with node::value_exact() is only " "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); - static_assert((is_native || can_represent_native)&&!is_cvref, + static_assert((is_native || can_represent_native) && !is_cvref, TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()")); // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr - if constexpr ((is_native || can_represent_native)&&!is_cvref) + if constexpr ((is_native || can_represent_native) && !is_cvref) { if (type() == node_type_of) return { this->get_value_exact() }; @@ -5662,7 +5665,7 @@ TOML_NAMESPACE_START static_assert(!is_wide_string || TOML_ENABLE_WINDOWS_COMPAT, "Retrieving values as wide-character strings with node::value() is only " "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); - static_assert((is_native || can_represent_native || can_partially_represent_native)&&!is_cvref, + static_assert((is_native || can_represent_native || can_partially_represent_native) && !is_cvref, TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()")); // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion @@ -7718,11 +7721,11 @@ TOML_NAMESPACE_START TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype) const noexcept final; - TOML_PURE_GETTER + TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; - TOML_PURE_GETTER + TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;