Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion core/config/property_tree.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
// SPDX-FileCopyrightText: 2017 - 2025 The Ginkgo authors
//
// SPDX-License-Identifier: BSD-3-Clause

Expand Down Expand Up @@ -37,6 +37,36 @@ pnode::pnode(const map_type& map) : tag_(tag_t::map), map_(map) {}

pnode::operator bool() const noexcept { return tag_ != tag_t::empty; }

bool pnode::operator==(const pnode& rhs) const
{
if (tag_ == rhs.tag_) {
switch (tag_) {
case pnode::tag_t::empty:
return true;
case pnode::tag_t::array:
return array_ == rhs.array_;
case pnode::tag_t::map:
return map_ == rhs.map_;
case pnode::tag_t::string:
return str_ == rhs.str_;
case pnode::tag_t::boolean:
return union_data_.boolean_ == rhs.union_data_.boolean_;
case pnode::tag_t::real:
return union_data_.real_ == rhs.union_data_.real_;
case pnode::tag_t::integer:
return union_data_.integer_ == rhs.union_data_.integer_;
default:
GKO_NOT_IMPLEMENTED;
}
}
return false;
}

bool pnode::operator!=(const pnode& rhs) const
{
return !(this->operator==(rhs));
}


pnode::tag_t pnode::get_tag() const { return tag_; }

Expand Down
151 changes: 150 additions & 1 deletion core/test/config/property_tree.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
// SPDX-FileCopyrightText: 2017 - 2025 The Ginkgo authors
//
// SPDX-License-Identifier: BSD-3-Clause

Expand Down Expand Up @@ -181,3 +181,152 @@ TEST(PropertyTree, UseInCondition)
ASSERT_EQ(first, 2);
ASSERT_EQ(second, 1);
}


class PropertyTreeEquality : public ::testing::Test {
protected:
PropertyTreeEquality()
{
auto generator = [](auto&& vector) {
// empty node
vector.emplace_back(pnode());
// boolean
vector.emplace_back(pnode(true));
// real
vector.emplace_back(pnode(1.2));
// integer
vector.emplace_back(pnode(4));
// string
vector.emplace_back(pnode("123"));
// array
vector.emplace_back(
pnode(pnode::array_type{pnode{"1"}, pnode{4}, pnode{true}}));
// array2
vector.emplace_back(
pnode(pnode::array_type{pnode{"2"}, pnode{4}, pnode{true}}));
// array3
vector.emplace_back(
pnode(pnode::array_type{pnode{"3"}, pnode{4}, pnode{true}}));
// array4 with map
vector.emplace_back(pnode(pnode::array_type{
pnode(pnode::map_type{{"first", pnode{"1"}}})}));
// array5 with array
vector.emplace_back(
pnode(pnode::array_type{pnode(pnode::array_type{pnode{"1"}})}));
// map
vector.emplace_back(pnode(pnode::map_type{{"first", pnode{"1"}},
{"second", pnode{1.2}}}));
// map2
vector.emplace_back(pnode(pnode::map_type{{"first", pnode{"2"}},
{"second", pnode{1.2}}}));
// map3
vector.emplace_back(pnode(pnode::map_type{{"first", pnode{"3"}},
{"second", pnode{1.2}}}));
// map4 with array
vector.emplace_back(pnode(pnode::map_type{
{"first", pnode(pnode::array_type{pnode{"1"}})}}));
// map5 with map
vector.emplace_back(pnode(pnode::map_type{
{"first", pnode(pnode::map_type{{"first", pnode{"1"}}})}}));
};
// first and second have the same content
generator(first);
generator(second);
// diff_content have different content but type still the same
// still keep the empty node here for easy index mapping.
// empty node
diff_content.emplace_back(pnode());
// boolean
diff_content.emplace_back(pnode(false));
// real
diff_content.emplace_back(pnode(2.4));
// integer
diff_content.emplace_back(pnode(3));
// string
diff_content.emplace_back(pnode("456"));
// array1 with different content
diff_content.emplace_back(
pnode(pnode::array_type{pnode{"456"}, pnode{3}, pnode{false}}));
// array2 with different number of item
diff_content.emplace_back(
pnode(pnode::array_type{pnode{"2"}, pnode{4}}));
// array3 with different order
diff_content.emplace_back(
pnode(pnode::array_type{pnode{4}, pnode{"3"}, pnode{true}}));
// array4 with different map
diff_content.emplace_back(pnode(
pnode::array_type{pnode(pnode::map_type{{"first", pnode{"2"}}})}));
// array5 with different array
diff_content.emplace_back(
pnode(pnode::array_type{pnode(pnode::array_type{pnode{"2"}})}));
// map1 with different key
diff_content.emplace_back(pnode(
pnode::map_type{{"second", pnode{"1"}}, {"first", pnode{1.2}}}));
// map2 with different number of item
diff_content.emplace_back(
pnode(pnode::map_type{{"first", pnode{"2"}}}));
// map3 with different content
diff_content.emplace_back(pnode(
pnode::map_type{{"first", pnode{"456"}}, {"second", pnode{2.4}}}));
// map4 with different array
diff_content.emplace_back(pnode(
pnode::map_type{{"first", pnode(pnode::array_type{pnode{"2"}})}}));
// map5 with different map
diff_content.emplace_back(pnode(pnode::map_type{
{"first", pnode(pnode::map_type{{"first", pnode{"2"}}})}}));
}
std::vector<pnode> first;
std::vector<pnode> second;
std::vector<pnode> diff_content;
};


TEST_F(PropertyTreeEquality, CheckEquality)
{
ASSERT_EQ(first.size(), second.size());
for (size_t i = 0; i < first.size(); i++) {
for (size_t j = 0; j < second.size(); j++) {
if (i == j) {
ASSERT_EQ(first.at(i), second.at(j));
} else {
ASSERT_NE(first.at(i), second.at(j));
}
}
}
}


TEST_F(PropertyTreeEquality, CheckEqualityOnlyContentDiff)
{
ASSERT_EQ(first.size(), diff_content.size());
for (size_t i = 1; i < diff_content.size(); i++) {
ASSERT_EQ(first.at(i).get_tag(), diff_content.at(i).get_tag());
ASSERT_NE(first.at(i), diff_content.at(i));
}
}


TEST_F(PropertyTreeEquality, CheckEqualityOfDiffOrderMap)
{
pnode map_1{pnode::map_type{{"first", first.at(5)},
{"second", first.at(7)},
{"third", first.at(8)},
{"forth", first.at(9)}}};
pnode map_2{pnode::map_type{{"first", first.at(5)},
{"forth", first.at(9)},
{"third", first.at(8)},
{"second", first.at(7)}}};

// We use std::map is ordered map, so the input order does not affect the
// equality
ASSERT_EQ(map_1, map_2);
}


TEST_F(PropertyTreeEquality, CheckInequalityOfDiffOrderArray)
{
pnode array_1{pnode::array_type{first.at(5), first.at(6)}};
pnode array_2{pnode::array_type{first.at(6), first.at(5)}};

ASSERT_NE(array_1, array_2);
}
12 changes: 11 additions & 1 deletion include/ginkgo/core/config/property_tree.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
// SPDX-FileCopyrightText: 2017 - 2025 The Ginkgo authors
//
// SPDX-License-Identifier: BSD-3-Clause

Expand Down Expand Up @@ -99,6 +99,16 @@ class pnode final {
*/
explicit operator bool() const noexcept;

/**
* Check whether the representing data of two pnodes are the same
*/
bool operator==(const pnode& rhs) const;

/**
* Check whether the representing data of two pnodes are different.
*/
bool operator!=(const pnode& rhs) const;

/**
* Get the current node tag.
*
Expand Down