Skip to content

Commit

Permalink
Merge Add property tree
Browse files Browse the repository at this point in the history
This PR adds an simple data structure which will be used in file config

Related PR: #1389
  • Loading branch information
yhmtsai authored Apr 13, 2024
2 parents 20f2a7e + ba53609 commit 577caef
Show file tree
Hide file tree
Showing 8 changed files with 551 additions and 0 deletions.
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ target_sources(ginkgo
base/perturbation.cpp
base/timer.cpp
base/version.cpp
config/property_tree.cpp
distributed/partition.cpp
factorization/cholesky.cpp
factorization/elimination_forest.cpp
Expand Down
140 changes: 140 additions & 0 deletions core/config/property_tree.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
//
// SPDX-License-Identifier: BSD-3-Clause

#include <ginkgo/core/config/property_tree.hpp>


#include <ginkgo/core/base/exception_helpers.hpp>


namespace gko {
namespace config {


pnode::pnode() : tag_(tag_t::empty) {}


pnode::pnode(bool boolean) : tag_(tag_t::boolean)
{
union_data_.boolean_ = boolean;
}


pnode::pnode(const std::string& str) : tag_(tag_t::string) { str_ = str; }


pnode::pnode(double real) : tag_(tag_t::real) { union_data_.real_ = real; }


pnode::pnode(const char* str) : pnode(std::string(str)) {}


pnode::pnode(const array_type& array) : tag_(tag_t::array), array_(array) {}


pnode::pnode(const map_type& map) : tag_(tag_t::map), map_(map) {}


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


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

const pnode::array_type& pnode::get_array() const
{
this->throw_if_not_contain(tag_t::array);
return array_;
}


const pnode::map_type& pnode::get_map() const
{
this->throw_if_not_contain(tag_t::map);
return map_;
}


bool pnode::get_boolean() const
{
this->throw_if_not_contain(tag_t::boolean);
return union_data_.boolean_;
}


std::int64_t pnode::get_integer() const
{
this->throw_if_not_contain(tag_t::integer);
return union_data_.integer_;
}


double pnode::get_real() const
{
this->throw_if_not_contain(tag_t::real);
return union_data_.real_;
}


const std::string& pnode::get_string() const
{
this->throw_if_not_contain(tag_t::string);
return str_;
}


const pnode& pnode::get(const std::string& key) const
{
this->throw_if_not_contain(tag_t::map);
auto it = map_.find(key);
if (it != map_.end()) {
return map_.at(key);
} else {
return pnode::empty_node();
}
}

const pnode& pnode::get(int index) const
{
this->throw_if_not_contain(tag_t::array);
return array_.at(index);
}


void pnode::throw_if_not_contain(tag_t tag) const
{
static auto str_tag = [](tag_t tag) -> std::string {
if (tag == tag_t::empty) {
return "empty";
} else if (tag == tag_t::array) {
return "array";
} else if (tag == tag_t::map) {
return "map";
} else if (tag == tag_t::real) {
return "real";
} else if (tag == tag_t::boolean) {
return "boolean";
} else if (tag == tag_t::integer) {
return "integer";
} else if (tag == tag_t::string) {
return "string";
} else {
return "unknown";
}
};
bool is_valid = (tag_ == tag);
std::string msg =
"Contains " + str_tag(tag_) + ", but try to get " + str_tag(tag);
GKO_THROW_IF_INVALID(is_valid, msg);
}


const pnode& pnode::empty_node()
{
static pnode empty_pnode{};
return empty_pnode;
}


} // namespace config
} // namespace gko
1 change: 1 addition & 0 deletions core/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_subdirectory(gtest)
add_subdirectory(accessor)
add_subdirectory(base)
add_subdirectory(components)
add_subdirectory(config)
if(GINKGO_BUILD_MPI)
add_subdirectory(mpi)
endif()
Expand Down
1 change: 1 addition & 0 deletions core/test/config/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ginkgo_create_test(property_tree)
187 changes: 187 additions & 0 deletions core/test/config/property_tree.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
//
// SPDX-License-Identifier: BSD-3-Clause

#include <ginkgo/core/config/property_tree.hpp>


#include <cstdint>
#include <exception>
#include <limits>
#include <memory>


#include <gtest/gtest.h>


#include <ginkgo/core/base/exception.hpp>


using namespace gko::config;


void assert_others_throw(const pnode& node)
{
auto tag = node.get_tag();
if (tag != pnode::tag_t::array) {
ASSERT_THROW(node.get_array(), gko::InvalidStateError);
ASSERT_THROW(node.get(0), gko::InvalidStateError);
}
if (tag != pnode::tag_t::map) {
ASSERT_THROW(node.get_map(), gko::InvalidStateError);
ASSERT_THROW(node.get("random"), gko::InvalidStateError);
}
if (tag != pnode::tag_t::boolean) {
ASSERT_THROW(node.get_boolean(), gko::InvalidStateError);
}
if (tag != pnode::tag_t::integer) {
ASSERT_THROW(node.get_integer(), gko::InvalidStateError);
}
if (tag != pnode::tag_t::real) {
ASSERT_THROW(node.get_real(), gko::InvalidStateError);
}
if (tag != pnode::tag_t::string) {
ASSERT_THROW(node.get_string(), gko::InvalidStateError);
}
}


TEST(PropertyTree, CreateEmpty)
{
pnode root;

ASSERT_EQ(root.get_tag(), pnode::tag_t::empty);
assert_others_throw(root);
}


TEST(PropertyTree, CreateStringData)
{
pnode str(std::string("test_name"));
pnode char_str("test_name");

ASSERT_EQ(str.get_tag(), pnode::tag_t::string);
ASSERT_EQ(str.get_string(), "test_name");
assert_others_throw(str);
ASSERT_EQ(char_str.get_tag(), pnode::tag_t::string);
ASSERT_EQ(char_str.get_string(), "test_name");
assert_others_throw(char_str);
}


TEST(PropertyTree, CreateBoolData)
{
pnode boolean(true);

ASSERT_EQ(boolean.get_tag(), pnode::tag_t::boolean);
ASSERT_EQ(boolean.get_boolean(), true);
assert_others_throw(boolean);
}


TEST(PropertyTree, CreateIntegerData)
{
pnode integer(1);
pnode integer_8(std::int8_t(1));
pnode integer_16(std::int16_t(1));
pnode integer_32(std::int32_t(1));
pnode integer_64(std::int64_t(1));
pnode integer_u8(std::uint8_t(1));
pnode integer_u16(std::uint16_t(1));
pnode integer_u32(std::uint32_t(1));
pnode integer_u64(std::uint64_t(1));


for (auto& node : {integer, integer_8, integer_16, integer_32, integer_64,
integer_u8, integer_u16, integer_u32, integer_u64}) {
ASSERT_EQ(node.get_tag(), pnode::tag_t::integer);
ASSERT_EQ(node.get_integer(), 1);
assert_others_throw(node);
}
ASSERT_THROW(
pnode(std::uint64_t(std::numeric_limits<std::int64_t>::max()) + 1),
std::runtime_error);
}


TEST(PropertyTree, CreateRealData)
{
pnode real(1.0);
pnode real_float(float(1.0));
pnode real_double(double(1.0));

for (auto& node : {real, real_double, real_float}) {
ASSERT_EQ(node.get_tag(), pnode::tag_t::real);
ASSERT_EQ(node.get_real(), 1.0);
assert_others_throw(node);
}
}


TEST(PropertyTree, CreateMap)
{
pnode root({{"p0", pnode{1.0}},
{"p1", pnode{1}},
{"p2", pnode{pnode::map_type{{"p0", pnode{"test"}}}}}});

ASSERT_EQ(root.get_tag(), pnode::tag_t::map);
ASSERT_EQ(root.get("p0").get_real(), 1.0);
ASSERT_EQ(root.get("p1").get_integer(), 1);
ASSERT_EQ(root.get("p2").get_tag(), pnode::tag_t::map);
ASSERT_EQ(root.get("p2").get("p0").get_string(), "test");
assert_others_throw(root);
}


TEST(PropertyTree, CreateArray)
{
pnode root(pnode::array_type{pnode{"123"}, pnode{"456"}, pnode{"789"}});

ASSERT_EQ(root.get_tag(), pnode::tag_t::array);
ASSERT_EQ(root.get(0).get_string(), "123");
ASSERT_EQ(root.get(1).get_string(), "456");
ASSERT_EQ(root.get(2).get_string(), "789");
ASSERT_THROW(root.get(3), std::out_of_range);
ASSERT_EQ(root.get_array().size(), 3);
assert_others_throw(root);
}


TEST(PropertyTree, ConversionToBool)
{
pnode empty;
pnode non_empty{"test"};

ASSERT_FALSE(empty);
ASSERT_TRUE(non_empty);
}


TEST(PropertyTree, ReturnEmptyIfNotFound)
{
pnode ptree(pnode::map_type{{"test", pnode{2}}});

auto obj = ptree.get("na");

ASSERT_EQ(obj.get_tag(), pnode::tag_t::empty);
}


TEST(PropertyTree, UseInCondition)
{
pnode ptree(pnode::map_type{{"test", pnode{2}}});
int first = 0;
int second = 0;

if (auto obj = ptree.get("test")) {
first = static_cast<int>(obj.get_integer());
}
if (auto obj = ptree.get("na")) {
second = -1;
} else {
second = 1;
}

ASSERT_EQ(first, 2);
ASSERT_EQ(second, 1);
}
Loading

0 comments on commit 577caef

Please sign in to comment.