Skip to content

Commit

Permalink
add extension: header only json config
Browse files Browse the repository at this point in the history
  • Loading branch information
yhmtsai committed May 8, 2024
1 parent d1050e2 commit cbcfa66
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 0 deletions.
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)
2 changes: 2 additions & 0 deletions extensions/test/config/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ginkgo_create_test(json_config ADDITIONAL_LIBRARIES nlohmann_json::nlohmann_json)
configure_file("test.json" test.json COPYONLY)
79 changes: 79 additions & 0 deletions extensions/test/config/json_config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
//
// SPDX-License-Identifier: BSD-3-Clause

#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, 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
}
}
88 changes: 88 additions & 0 deletions include/ginkgo/extensions/config/json_config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// 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 <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>())};
}
return gko::config::pnode{};
};

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

0 comments on commit cbcfa66

Please sign in to comment.