Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add json config #1607

Merged
merged 2 commits into from
May 10, 2024
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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ if(GINKGO_BUILD_TESTS)
endif()
if(GINKGO_BUILD_BENCHMARKS)
find_package(gflags 2.2.2 QUIET)
endif()
if(GINKGO_BUILD_TESTS OR GINKGO_BUILD_BENCHMARKS)
find_package(nlohmann_json 3.9.1 QUIET)
endif()

Expand Down
2 changes: 2 additions & 0 deletions extensions/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ find_package(Kokkos 4.1.00 QUIET)
if (Kokkos_FOUND)
add_subdirectory(kokkos)
endif ()

add_subdirectory(config)
5 changes: 5 additions & 0 deletions extensions/test/config/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ginkgo_create_test(json_config ADDITIONAL_LIBRARIES nlohmann_json::nlohmann_json)
# set the working directory to the current binary folder for file test
file(RELATIVE_PATH REL_BINARY_DIR ${PROJECT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties("${REL_BINARY_DIR}/json_config" PROPERTIES WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
configure_file(test.json test.json COPYONLY)
91 changes: 91 additions & 0 deletions extensions/test/config/json_config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
//
// SPDX-License-Identifier: BSD-3-Clause

#include <stdexcept>


#include <gtest/gtest.h>
#include <nlohmann/json.hpp>


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


#include "core/test/utils.hpp"


TEST(JsonConfig, ThrowIfInvalid)
{
const char json[] = R"({"test": null})";
auto d = nlohmann::json::parse(json);

ASSERT_THROW(gko::ext::config::parse_json(d), std::runtime_error);
}


TEST(JsonConfig, ReadMap)
{
const char json[] = R"({"test": "A", "bool": true})";
auto d = nlohmann::json::parse(json);

auto ptree = gko::ext::config::parse_json(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(JsonConfig, ReadArray)
{
const char json[] = R"(["A", "B", "C"])";
auto d = nlohmann::json::parse(json);

auto ptree = gko::ext::config::parse_json(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(JsonConfig, ReadInput)
{
const char json[] =
R"({"item": 4,
"array": [3.0, 4.5],
"map": {"bool": false}})";

auto d = nlohmann::json::parse(json);

auto ptree = gko::ext::config::parse_json(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(JsonConfig, ReadInputFromFile)
{
auto ptree = gko::ext::config::parse_json_file("test.json");

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);
}
10 changes: 10 additions & 0 deletions extensions/test/config/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"item": 4,
"array": [
3.0,
4.5
],
"map": {
"bool": false
}
}
91 changes: 91 additions & 0 deletions include/ginkgo/extensions/config/json_config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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 <fstream>
#include <stdexcept>
#include <string>


#include <nlohmann/json.hpp>


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


namespace gko {
namespace ext {
namespace config {


/**
* parse_json takes the nlohmann json object to generate the property tree
* object
*/
inline gko::config::pnode parse_json(const nlohmann::json& input)
{
const auto& dom = input;

auto parse_array = [](const auto& arr) {
gko::config::pnode::array_type nodes;
for (auto it : arr) {
nodes.emplace_back(parse_json(it));
}
return gko::config::pnode{nodes};
};
auto parse_map = [](const auto& map) {
gko::config::pnode::map_type nodes;
for (auto& el : map.items()) {
nodes.emplace(el.key(), parse_json(el.value()));
}
return gko::config::pnode{nodes};
};
auto parse_data = [](const auto& data) {
if (data.is_number_integer()) {
return gko::config::pnode{data.template get<std::int64_t>()};
}
if (data.is_boolean()) {
return gko::config::pnode{data.template get<bool>()};
}
if (data.is_number_float()) {
return gko::config::pnode{data.template get<double>()};
}
if (data.is_string()) {
return gko::config::pnode{
std::string(data.template get<std::string>())};
}
throw std::runtime_error(
"property_tree can not handle the node with content: " +
data.dump());
};

if (dom.is_array()) {
return parse_array(dom);
}
if (dom.is_object()) {
return parse_map(dom);
}
return parse_data(dom);
}


/**
* parse_json_file takes the json file to generate the property tree object
*/
inline gko::config::pnode parse_json_file(std::string filename)
{
std::ifstream fstream(filename);
return parse_json(nlohmann::json::parse(fstream));
}


} // namespace config
} // namespace ext
} // namespace gko


#endif // GKO_PUBLIC_EXTENSIONS_CONFIG_JSON_CONFIG_HPP_
3 changes: 3 additions & 0 deletions third_party/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ if(GINKGO_BUILD_BENCHMARKS)
if (NOT gflags_FOUND)
add_subdirectory(gflags)
endif()
endif()

if(GINKGO_BUILD_TESTS OR GINKGO_BUILD_BENCHMARKS)
if (NOT nlohmann_json_FOUND)
add_subdirectory(nlohmann_json)
endif()
Expand Down
Loading