-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
294 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
base: &base_config | ||
key1: 123 | ||
base2: &base_config2 | ||
key2: test | ||
test: | ||
<<: [*base_config, *base_config2] | ||
key3: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
base: &base_config | ||
key1: 123 | ||
base2: &base_config2 | ||
<<: *base_config | ||
key2: test | ||
test: | ||
<<: *base_config2 | ||
key2: override | ||
key3: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
item: 4 | ||
array: | ||
- 3.0 | ||
- 4.5 | ||
map: | ||
bool: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors | ||
// | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
#include <ostream> | ||
#include <stdexcept> | ||
#include <string> | ||
|
||
#include <gtest/gtest.h> | ||
#include <yaml-cpp/yaml.h> | ||
|
||
#include <ginkgo/core/config/property_tree.hpp> | ||
#include <ginkgo/extensions/config/yaml_config.hpp> | ||
|
||
#include "core/test/utils.hpp" | ||
#include "extensions/test/config/file_location.hpp" | ||
|
||
|
||
TEST(YamlConfig, ThrowIfInvalid) | ||
{ | ||
const char yaml[] = "test: null"; | ||
auto d = YAML::Load(yaml); | ||
|
||
ASSERT_THROW(gko::ext::config::parse_yaml(d), std::runtime_error); | ||
} | ||
|
||
|
||
TEST(YamlConfig, ReadMap) | ||
{ | ||
const char yaml[] = R"( | ||
test: A | ||
bool: true | ||
)"; | ||
auto d = YAML::Load(yaml); | ||
|
||
auto ptree = gko::ext::config::parse_yaml(d); | ||
|
||
ASSERT_EQ(ptree.get_map().size(), 2); | ||
ASSERT_EQ(ptree.get("test").get_string(), "A"); | ||
ASSERT_EQ(ptree.get("bool").get_boolean(), true); | ||
} | ||
|
||
|
||
TEST(YamlConfig, ReadArray) | ||
{ | ||
const char yaml[] = R"( | ||
- A | ||
- B | ||
- C | ||
)"; | ||
auto d = YAML::Load(yaml); | ||
|
||
auto ptree = gko::ext::config::parse_yaml(d); | ||
|
||
ASSERT_EQ(ptree.get_array().size(), 3); | ||
ASSERT_EQ(ptree.get(0).get_string(), "A"); | ||
ASSERT_EQ(ptree.get(1).get_string(), "B"); | ||
ASSERT_EQ(ptree.get(2).get_string(), "C"); | ||
} | ||
|
||
|
||
TEST(YamlConfig, ReadInput) | ||
{ | ||
const char yaml[] = R"( | ||
item: 4 | ||
array: | ||
- 3.0 | ||
- 4.5 | ||
map: | ||
bool: false)"; | ||
auto d = YAML::Load(yaml); | ||
|
||
auto ptree = gko::ext::config::parse_yaml(d); | ||
|
||
auto& child_array = ptree.get("array").get_array(); | ||
auto& child_map = ptree.get("map").get_map(); | ||
ASSERT_EQ(ptree.get_map().size(), 3); | ||
ASSERT_EQ(ptree.get("item").get_integer(), 4); | ||
ASSERT_EQ(child_array.size(), 2); | ||
ASSERT_EQ(child_array.at(0).get_real(), 3.0); | ||
ASSERT_EQ(child_array.at(1).get_real(), 4.5); | ||
ASSERT_EQ(child_map.size(), 1); | ||
ASSERT_EQ(child_map.at("bool").get_boolean(), false); | ||
} | ||
|
||
|
||
TEST(YamlConfig, ReadInputFromFile) | ||
{ | ||
auto ptree = | ||
gko::ext::config::parse_yaml_file(gko::ext::config::location_test_yaml); | ||
|
||
auto& child_array = ptree.get("array").get_array(); | ||
auto& child_map = ptree.get("map").get_map(); | ||
ASSERT_EQ(ptree.get_map().size(), 3); | ||
ASSERT_EQ(ptree.get("item").get_integer(), 4); | ||
ASSERT_EQ(child_array.size(), 2); | ||
ASSERT_EQ(child_array.at(0).get_real(), 3.0); | ||
ASSERT_EQ(child_array.at(1).get_real(), 4.5); | ||
ASSERT_EQ(child_map.size(), 1); | ||
ASSERT_EQ(child_map.at("bool").get_boolean(), false); | ||
} | ||
|
||
|
||
TEST(YamlConfig, ReadInputFromFileWithAlias) | ||
{ | ||
auto yaml = YAML::LoadFile(gko::ext::config::location_alias_yaml); | ||
|
||
auto ptree = gko::ext::config::parse_yaml(yaml["test"]); | ||
|
||
ASSERT_EQ(ptree.get_map().size(), 3); | ||
ASSERT_EQ(ptree.get_map().at("key1").get_integer(), 123); | ||
ASSERT_EQ(ptree.get_map().at("key2").get_string(), "test"); | ||
ASSERT_EQ(ptree.get_map().at("key3").get_boolean(), true); | ||
} | ||
|
||
|
||
TEST(YamlConfig, ReadInputFromFileWithNestedAliasAndOverwrite) | ||
{ | ||
auto yaml = YAML::LoadFile(gko::ext::config::location_nested_alias_yaml); | ||
|
||
auto ptree = gko::ext::config::parse_yaml(yaml["test"]); | ||
|
||
ASSERT_EQ(ptree.get_map().size(), 3); | ||
ASSERT_EQ(ptree.get_map().at("key1").get_integer(), 123); | ||
ASSERT_EQ(ptree.get_map().at("key2").get_string(), "override"); | ||
ASSERT_EQ(ptree.get_map().at("key3").get_boolean(), true); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors | ||
// | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
#ifndef GKO_PUBLIC_EXTENSIONS_CONFIG_JSON_CONFIG_HPP_ | ||
#define GKO_PUBLIC_EXTENSIONS_CONFIG_JSON_CONFIG_HPP_ | ||
|
||
#include <iostream> | ||
#include <stdexcept> | ||
#include <string> | ||
|
||
#include <yaml-cpp/yaml.h> | ||
|
||
#include <ginkgo/core/config/property_tree.hpp> | ||
|
||
|
||
namespace gko { | ||
namespace ext { | ||
namespace config { | ||
|
||
|
||
/** | ||
* parse_yaml takes the yaml-cpp node object to generate the property tree | ||
* object | ||
*/ | ||
inline gko::config::pnode parse_yaml(const YAML::Node& input) | ||
{ | ||
auto parse_array = [](const auto& arr) { | ||
gko::config::pnode::array_type nodes; | ||
for (const auto& it : arr) { | ||
nodes.emplace_back(parse_yaml(it)); | ||
} | ||
return gko::config::pnode{nodes}; | ||
}; | ||
auto parse_map = [](const auto& map) { | ||
gko::config::pnode::map_type nodes; | ||
// use [] to get override behavior | ||
for (YAML::const_iterator it = map.begin(); it != map.end(); ++it) { | ||
std::string key = it->first.as<std::string>(); | ||
// yaml-cpp keeps the alias without resolving it when parsing. | ||
// We resolve them here. | ||
if (key == "<<") { | ||
auto node = parse_yaml(it->second); | ||
if (node.get_tag() == gko::config::pnode::tag_t::array) { | ||
for (const auto& arr : node.get_array()) { | ||
for (const auto& item : arr.get_map()) { | ||
nodes[item.first] = item.second; | ||
} | ||
} | ||
} else if (node.get_tag() == gko::config::pnode::tag_t::map) { | ||
for (const auto& item : node.get_map()) { | ||
nodes[item.first] = item.second; | ||
} | ||
} else { | ||
std::runtime_error("can not handle this alias: " + | ||
YAML::Dump(it->second)); | ||
} | ||
} else { | ||
std::string content = it->first.as<std::string>(); | ||
nodes[key] = parse_yaml(it->second); | ||
} | ||
} | ||
return gko::config::pnode{nodes}; | ||
}; | ||
// yaml-cpp does not have type check | ||
auto parse_data = [](const auto& data) { | ||
if (std::int64_t value; | ||
YAML::convert<std::int64_t>::decode(data, value)) { | ||
return gko::config::pnode{value}; | ||
} | ||
if (bool value; YAML::convert<bool>::decode(data, value)) { | ||
return gko::config::pnode{value}; | ||
} | ||
if (double value; YAML::convert<double>::decode(data, value)) { | ||
return gko::config::pnode{value}; | ||
} | ||
if (std::string value; | ||
YAML::convert<std::string>::decode(data, value)) { | ||
return gko::config::pnode{value}; | ||
} | ||
std::string content = YAML::Dump(data); | ||
throw std::runtime_error( | ||
"property_tree can not handle the node with content: " + content); | ||
}; | ||
|
||
if (input.IsSequence()) { | ||
return parse_array(input); | ||
} | ||
if (input.IsMap()) { | ||
return parse_map(input); | ||
} | ||
return parse_data(input); | ||
} | ||
|
||
|
||
/** | ||
* parse_yaml_file takes the yaml file to generate the property tree object | ||
* | ||
* @note Because YAML always needs a entry for reusing, there will be more than | ||
* one entry when putting the anchors in the top level. This function can not | ||
* know which entry is the actual solver, so please use the parse_yaml function. | ||
*/ | ||
inline gko::config::pnode parse_yaml_file(std::string filename) | ||
{ | ||
return parse_yaml(YAML::LoadFile(filename)); | ||
} | ||
|
||
|
||
} // namespace config | ||
} // namespace ext | ||
} // namespace gko | ||
|
||
|
||
#endif // GKO_PUBLIC_EXTENSIONS_CONFIG_JSON_CONFIG_HPP_ |