Skip to content

Commit

Permalink
fix is_homogeneous with outparam (fixes #231)
Browse files Browse the repository at this point in the history
  • Loading branch information
marzer committed Jul 12, 2024
1 parent b43f8a0 commit 7ddb985
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 133 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 6 additions & 3 deletions include/toml++/impl/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion include/toml++/impl/node_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions include/toml++/impl/table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
10 changes: 5 additions & 5 deletions include/toml++/impl/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ TOML_NAMESPACE_START
return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
}

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<value_type>)
Expand All @@ -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<value_type>)
Expand Down Expand Up @@ -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<T> || can_represent_native<T>)&&!is_cvref<T>,
static_assert((is_native<T> || can_represent_native<T>) && !is_cvref<T>,
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<T> || can_represent_native<T>)&&!is_cvref<T>)
if constexpr ((is_native<T> || can_represent_native<T>) && !is_cvref<T>)
{
if (type() == node_type_of<T>)
return { this->get_value_exact<T>() };
Expand All @@ -1063,7 +1063,7 @@ TOML_NAMESPACE_START
static_assert(!is_wide_string<T> || 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<T> || can_represent_native<T> || can_partially_represent_native<T>)&&!is_cvref<T>,
static_assert((is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()"));

// when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
Expand Down
233 changes: 122 additions & 111 deletions tests/parsing_arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<array>());
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<int64_t>());
CHECK(!tbl["integers"].is_homogeneous<double>());
CHECK(tbl["integers"].as<array>()->is_homogeneous());
CHECK(tbl["integers"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["integers"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers"].as<array>()->is_homogeneous<double>());
CHECK(tbl["integers"].as<array>()->size() == 3);
CHECK(tbl["integers"][0] == 1);
CHECK(tbl["integers"][1] == 2);
CHECK(tbl["integers"][2] == 3);

REQUIRE(tbl["integers2"].as<array>());
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<int64_t>());
CHECK(!tbl["integers2"].is_homogeneous<double>());
CHECK(tbl["integers2"].as<array>()->is_homogeneous());
CHECK(tbl["integers2"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers2"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["integers2"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers2"].as<array>()->is_homogeneous<double>());
CHECK(tbl["integers2"].as<array>()->size() == 3);
CHECK(tbl["integers2"][0] == 1);
CHECK(tbl["integers2"][1] == 2);
CHECK(tbl["integers2"][2] == 3);

REQUIRE(tbl["integers3"].as<array>());
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<int64_t>());
CHECK(!tbl["integers3"].is_homogeneous<double>());
CHECK(tbl["integers3"].as<array>()->is_homogeneous());
CHECK(tbl["integers3"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers3"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["integers3"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers3"].as<array>()->is_homogeneous<double>());
CHECK(tbl["integers3"].as<array>()->size() == 2);
CHECK(tbl["integers3"][0] == 1);
CHECK(tbl["integers3"][1] == 2);

REQUIRE(tbl["colors"].as<array>());
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<std::string>());
CHECK(!tbl["colors"].is_homogeneous<double>());
CHECK(tbl["colors"].as<array>()->is_homogeneous());
CHECK(tbl["colors"].as<array>()->is_homogeneous(node_type::string));
CHECK(!tbl["colors"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["colors"].as<array>()->is_homogeneous<std::string>());
CHECK(!tbl["colors"].as<array>()->is_homogeneous<double>());
CHECK(tbl["colors"].as<array>()->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<array>());
CHECK(tbl["nested_array_of_int"].as<array>()->is_homogeneous());
CHECK(tbl["nested_array_of_int"].as<array>()->size() == 2);
REQUIRE(tbl["nested_array_of_int"][0].as<array>());
CHECK(tbl["nested_array_of_int"][0].as<array>()->is_homogeneous());
CHECK(tbl["nested_array_of_int"][0].as<array>()->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<array>());
CHECK(tbl["nested_array_of_int"][1].as<array>()->is_homogeneous());
CHECK(tbl["nested_array_of_int"][1].as<array>()->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<array>());
CHECK(tbl["nested_mixed_array"].as<array>()->is_homogeneous());
CHECK(tbl["nested_mixed_array"].as<array>()->size() == 2);
REQUIRE(tbl["nested_mixed_array"][0].as<array>());
CHECK(tbl["nested_mixed_array"][0].as<array>()->is_homogeneous());
CHECK(tbl["nested_mixed_array"][0].as<array>()->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<array>());
CHECK(tbl["nested_mixed_array"][1].as<array>()->is_homogeneous());
CHECK(tbl["nested_mixed_array"][1].as<array>()->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<array>());
CHECK(tbl["string_array"].as<array>()->is_homogeneous());
CHECK(tbl["string_array"].as<array>()->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<array>());
CHECK(tbl["integers"].as<array>()->is_homogeneous());
CHECK(tbl["integers"].as<array>()->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<array>());
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<int64_t>());
CHECK(!tbl["integers"].is_homogeneous<double>());
CHECK(tbl["integers"].as<array>()->is_homogeneous());
CHECK(tbl["integers"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(!tbl["integers"].as<array>()->is_homogeneous(node_type::floating_point, first_nonmatch));
CHECK(first_nonmatch != nullptr);
first_nonmatch = {};

CHECK(tbl["integers"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers"].as<array>()->is_homogeneous<double>());

CHECK(tbl["integers"].as<array>()->size() == 3);
CHECK(tbl["integers"][0] == 1);
CHECK(tbl["integers"][1] == 2);
CHECK(tbl["integers"][2] == 3);

REQUIRE(tbl["integers2"].as<array>());
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<int64_t>());
CHECK(!tbl["integers2"].is_homogeneous<double>());
CHECK(tbl["integers2"].as<array>()->is_homogeneous());
CHECK(tbl["integers2"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers2"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["integers2"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers2"].as<array>()->is_homogeneous<double>());
CHECK(tbl["integers2"].as<array>()->size() == 3);
CHECK(tbl["integers2"][0] == 1);
CHECK(tbl["integers2"][1] == 2);
CHECK(tbl["integers2"][2] == 3);

REQUIRE(tbl["integers3"].as<array>());
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<int64_t>());
CHECK(!tbl["integers3"].is_homogeneous<double>());
CHECK(tbl["integers3"].as<array>()->is_homogeneous());
CHECK(tbl["integers3"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers3"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["integers3"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers3"].as<array>()->is_homogeneous<double>());
CHECK(tbl["integers3"].as<array>()->size() == 2);
CHECK(tbl["integers3"][0] == 1);
CHECK(tbl["integers3"][1] == 2);

REQUIRE(tbl["colors"].as<array>());
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<std::string>());
CHECK(!tbl["colors"].is_homogeneous<double>());
CHECK(tbl["colors"].as<array>()->is_homogeneous());
CHECK(tbl["colors"].as<array>()->is_homogeneous(node_type::string));
CHECK(!tbl["colors"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["colors"].as<array>()->is_homogeneous<std::string>());
CHECK(!tbl["colors"].as<array>()->is_homogeneous<double>());
CHECK(tbl["colors"].as<array>()->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<array>());
CHECK(tbl["nested_array_of_int"].as<array>()->is_homogeneous());
CHECK(tbl["nested_array_of_int"].as<array>()->size() == 2);
REQUIRE(tbl["nested_array_of_int"][0].as<array>());
CHECK(tbl["nested_array_of_int"][0].as<array>()->is_homogeneous());
CHECK(tbl["nested_array_of_int"][0].as<array>()->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<array>());
CHECK(tbl["nested_array_of_int"][1].as<array>()->is_homogeneous());
CHECK(tbl["nested_array_of_int"][1].as<array>()->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<array>());
CHECK(tbl["nested_mixed_array"].as<array>()->is_homogeneous());
CHECK(tbl["nested_mixed_array"].as<array>()->size() == 2);
REQUIRE(tbl["nested_mixed_array"][0].as<array>());
CHECK(tbl["nested_mixed_array"][0].as<array>()->is_homogeneous());
CHECK(tbl["nested_mixed_array"][0].as<array>()->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<array>());
CHECK(tbl["nested_mixed_array"][1].as<array>()->is_homogeneous());
CHECK(tbl["nested_mixed_array"][1].as<array>()->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<array>());
CHECK(tbl["string_array"].as<array>()->is_homogeneous());
CHECK(tbl["string_array"].as<array>()->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<array>());
CHECK(tbl["integers"].as<array>()->is_homogeneous());
CHECK(tbl["integers"].as<array>()->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)
Expand Down
Loading

0 comments on commit 7ddb985

Please sign in to comment.