diff --git a/src/amr/resources_manager/resources_manager.hpp b/src/amr/resources_manager/resources_manager.hpp index 063aefd29..fe357a1c6 100644 --- a/src/amr/resources_manager/resources_manager.hpp +++ b/src/amr/resources_manager/resources_manager.hpp @@ -19,6 +19,7 @@ #include #include +#include namespace PHARE @@ -123,6 +124,36 @@ namespace amr * we ask for them in a tuple, and recursively call registerResources() for all of the * unpacked elements */ + + void static handle_sub_resources(auto fn, auto& obj, auto&&... args) + { + using ResourcesView = decltype(obj); + + if constexpr (has_runtime_subresourceview_list::value) + { + for (auto& runtimeResource : obj.getRunTimeResourcesViewList()) + { + using RuntimeResource = decltype(runtimeResource); + if constexpr (has_sub_resources_v) + { + fn(runtimeResource, args...); + } + else + { + std::visit([&](auto&& val) { fn(val, args...); }, runtimeResource); + } + } + } + + if constexpr (has_compiletime_subresourcesview_list::value) + { + // unpack the tuple subResources and apply for each element registerResources() + // (recursively) + std::apply([&](auto&... subResource) { (fn(subResource, args...), ...); }, + obj.getCompileTimeResourcesViewList()); + } + } + template void registerResources(ResourcesView& obj) { @@ -134,24 +165,8 @@ namespace amr { static_assert(has_sub_resources_v); - if constexpr (has_runtime_subresourceview_list::value) - { - for (auto& resourcesUser : obj.getRunTimeResourcesViewList()) - { - this->registerResources(resourcesUser); - } - } - - if constexpr (has_compiletime_subresourcesview_list::value) - { - // unpack the tuple subResources and apply for each element registerResources() - // (recursively) - std::apply( - [this](auto&... subResource) { - (this->registerResources(subResource), ...); - }, - obj.getCompileTimeResourcesViewList()); - } + handle_sub_resources( // + [&](auto&&... args) { this->registerResources(args...); }, obj); } } @@ -176,21 +191,8 @@ namespace amr { static_assert(has_sub_resources_v); - if constexpr (has_runtime_subresourceview_list::value) - { - for (auto& resourcesUser : obj.getRunTimeResourcesViewList()) - { - this->allocate(resourcesUser, patch, allocateTime); - } - } - - if constexpr (has_compiletime_subresourcesview_list::value) - { - // unpack the tuple subResources and apply for each element registerResources() - std::apply([this, &patch, allocateTime](auto&... subResource) // - { (this->allocate(subResource, patch, allocateTime), ...); }, - obj.getCompileTimeResourcesViewList()); - } + handle_sub_resources( // + [&](auto&&... args) { this->allocate(args...); }, obj, patch, allocateTime); } } @@ -389,24 +391,7 @@ namespace amr { static_assert(has_sub_resources_v); - if constexpr (has_runtime_subresourceview_list::value) - { - for (auto& resourcesUser : obj.getRunTimeResourcesViewList()) - { - // - this->getIDs_(resourcesUser, IDs); - } - } - - if constexpr (has_compiletime_subresourcesview_list::value) - { - // unpack the tuple subResources and apply for each element registerResources() - std::apply( - [this, &IDs](auto&... subResource) { - (this->getIDs_(subResource, IDs), ...); - }, - obj.getCompileTimeResourcesViewList()); - } + handle_sub_resources([&](auto&&... args) { this->getIDs_(args...); }, obj, IDs); } } @@ -450,21 +435,6 @@ namespace amr } - void static handle_sub_resources(auto fn, auto& obj, auto&&... args) - { - using ResourcesView = decltype(obj); - - if constexpr (has_runtime_subresourceview_list::value) - for (auto& runtimeResource : obj.getRunTimeResourcesViewList()) - fn(runtimeResource, args...); - - // unpack the tuple subResources and apply for each element registerResources() - // (recursively) - if constexpr (has_compiletime_subresourcesview_list::value) - std::apply([&](auto&... subResource) { (fn(subResource, args...), ...); }, - obj.getCompileTimeResourcesViewList()); - } - template void setResources_(ResourcesView& obj, SAMRAI::hier::Patch const& patch) const diff --git a/src/core/data/tensorfield/tensorfield.hpp b/src/core/data/tensorfield/tensorfield.hpp index ffc6bed92..076c6a63e 100644 --- a/src/core/data/tensorfield/tensorfield.hpp +++ b/src/core/data/tensorfield/tensorfield.hpp @@ -1,17 +1,18 @@ #ifndef PHARE_TENSORFIELD_HPP #define PHARE_TENSORFIELD_HPP -#include -#include -#include -#include -#include #include "core/def.hpp" -#include "core/data/field/field.hpp" #include "core/utilities/types.hpp" #include "core/data/vecfield/vecfield_component.hpp" + +#include +#include +#include +#include +#include + namespace PHARE::core::detail { template diff --git a/src/core/utilities/variants.hpp b/src/core/utilities/variants.hpp new file mode 100644 index 000000000..5632b3a24 --- /dev/null +++ b/src/core/utilities/variants.hpp @@ -0,0 +1,133 @@ +#ifndef PHARE_CORE_UTILITIES_RESOURCES_VARIANTS_HPP +#define PHARE_CORE_UTILITIES_RESOURCES_VARIANTS_HPP + +#include "core/utilities/types.hpp" + +#include +#include +#include +#include + +namespace PHARE::core +{ +template +auto decay_to_ptr() +{ + return [](T& arg) mutable -> void* { return const_cast*>(&arg); }; +} + +template +struct varient_visitor_overloads : Ts... +{ + using Ts::operator()...; +}; + +template +varient_visitor_overloads(Ts&&...) -> varient_visitor_overloads...>; + + +template +auto constexpr _visit_ptr_overloads(std::tuple*) +{ + return varient_visitor_overloads{decay_to_ptr()..., + [](auto&) mutable -> void* { return nullptr; }}; +} + + +template +struct unique : std::type_identity +{ +}; + +template +struct unique, U, Us...> + : std::conditional_t<(std::is_same_v || ...), unique, Us...>, + unique, Us...>> +{ +}; + +template +using unique_tuple = typename unique, Ts...>::type; + + + +template +auto constexpr visit_ptr_overloads() +{ + return _visit_ptr_overloads(static_cast*>(nullptr)); +} + + + +template +auto& get_as_ref_or_throw(Variants& variants, std::size_t const start = 0) +{ + for (std::size_t idx = start; idx < variants.size(); ++idx) + if (auto type = std::visit(visit_ptr_overloads(), variants[idx])) + return *reinterpret_cast(type); + + throw std::runtime_error("No element in variant for type"); +} + + +// ARGS MUST BE IN THE SAME ORDER AS VARIANT LIST TYPES!!!!! +template +auto get_as_tuple_or_throw(Variants& variants, std::size_t start = 0) +{ + using Tuple = std::tuple; + auto constexpr tuple_size = std::tuple_size_v; + + auto ptr_or_null = visit_ptr_overloads(); + + auto pointer_tuple = for_N([&](auto i) mutable { + using Type = std::tuple_element_t; + + for (std::size_t idx = start; idx < variants.size(); ++idx) + if (auto ptr = std::visit(ptr_or_null, variants[idx])) + { + ++start; + return reinterpret_cast(ptr); + } + return static_cast(nullptr); + }); + + for_N([&](auto i) { + if (std::get(pointer_tuple) == nullptr) + throw std::runtime_error("No element in variant for type"); + }); + + return for_N( + [&](auto i) -> auto& { return *std::get(pointer_tuple); }); +} + +template +auto& get_from_variants(auto& variants, Type& arg) +{ + std::size_t start = 0; + + while (start < variants.size()) + { + if (auto& res = get_as_ref_or_throw(variants, start); res.name() == arg.name()) + return res; + ++start; + } + + if (start == variants.size()) + std::runtime_error("Required name not found in variants: " + arg.name()); +} + + +template +auto get_from_variants(auto& variants, Args&... args) + requires(sizeof...(Args) > 1) +{ + return std::forward_as_tuple(get_from_variants(variants, args)...); +} + + + + +} // namespace PHARE::core + + +#endif /*PHARE_CORE_UTILITIES_RESOURCES_VARIANTS_HPP*/ diff --git a/tests/amr/resources_manager/test_resources_manager.cpp b/tests/amr/resources_manager/test_resources_manager.cpp index c202f9c99..43012aa55 100644 --- a/tests/amr/resources_manager/test_resources_manager.cpp +++ b/tests/amr/resources_manager/test_resources_manager.cpp @@ -8,18 +8,18 @@ #include "core/models/hybrid_state.hpp" #include "core/data/vecfield/vecfield.hpp" #include "core/data/tensorfield/tensorfield.hpp" +#include "core/utilities/variants.hpp" - -#include -#include -#include +#include +#include #include #include - #include "gtest/gtest.h" +#include +#include #include "tests/initializer/init_functions.hpp" @@ -278,6 +278,119 @@ INSTANTIATE_TYPED_TEST_SUITE_P(testResourcesManager, aResourceUserCollection, My + +struct FieldResource +{ + NO_DISCARD auto getCompileTimeResourcesViewList() { return std::forward_as_tuple(rho); } + + std::array cells{5}; + Field1D rho{"name", HybridQuantity::Scalar::rho, nullptr, cells}; +}; +struct VecFieldResource +{ + NO_DISCARD auto getCompileTimeResourcesViewList() { return std::forward_as_tuple(B); } + + VecField1D B{"B", HybridQuantity::Vector::B}; +}; + +struct ResourceUser +{ + using Resources = std::variant; + + ResourceUser() { resources.resize(2, FieldResource{}); } + + NO_DISCARD std::vector& getRunTimeResourcesViewList() { return resources; } + + auto get() { return get_as_tuple_or_throw(resources); } + + std::vector resources; +}; + + +TEST(usingResources, test_variants_helpers) +{ + using Resources = std::variant; + + std::vector resources{FieldResource{}, VecFieldResource{}}; + + { + auto const&& [rho, B] = get_as_tuple_or_throw(resources); + } + { + auto& rho = get_as_ref_or_throw(resources); + } + { + auto& B = get_as_ref_or_throw(resources); + } +} + + +TEST(usingResources, test_variants_resource_helpers) +{ + using Resources = std::variant; + + std::array cells{5}; + Field1D moe_{"moe", HybridQuantity::Scalar::rho, nullptr, cells}; + VecField1D B_{"B", HybridQuantity::Vector::B}; + Field1D rho_{"rho", HybridQuantity::Scalar::rho, nullptr, cells}; + VecField1D E_{"E", HybridQuantity::Vector::E}; + + std::vector resources{rho_, moe_, B_, E_}; + { + auto const& rho = get_from_variants(resources, rho_); + EXPECT_EQ(rho.name(), "rho"); + + auto const& B = get_from_variants(resources, B_); + EXPECT_EQ(B.name(), "B"); + } + auto [rho, B] = get_from_variants(resources, rho_, B_); + EXPECT_EQ(rho.name(), "rho"); + EXPECT_EQ(B.name(), "B"); +} + +TEST(usingResourcesManager, test_variants) +{ + ResourceUser resourceUser; + + std::unique_ptr bhierarchy; + ResourcesManager>, Grid1D> resourcesManager; + + bhierarchy = std::make_unique(inputBase + std::string("/input/input_db_1d")); + bhierarchy->init(); + resourcesManager.registerResources(resourceUser); + auto& hierarchy = bhierarchy->hierarchy; + + for (int iLevel = 0; iLevel < hierarchy->getNumberOfLevels(); ++iLevel) + for (auto const& patch : *hierarchy->getPatchLevel(iLevel)) + resourcesManager.allocate(resourceUser, *patch, 0); + + std::size_t patches = 0, checks = 0; + for (int iLevel = 0; iLevel < hierarchy->getNumberOfLevels(); ++iLevel) + for (auto const& patch : *hierarchy->getPatchLevel(iLevel)) + { + auto dataOnPatch = resourcesManager.setOnPatch(*patch, resourceUser); + auto&& [r0, r1] = resourceUser.get(); + r1.rho.data()[4] = 5; + ++patches; + } + + + for (int iLevel = 0; iLevel < hierarchy->getNumberOfLevels(); ++iLevel) + for (auto const& patch : *hierarchy->getPatchLevel(iLevel)) + { + auto dataOnPatch = resourcesManager.setOnPatch(*patch, resourceUser); + auto&& [r0, r1] = resourceUser.get(); + EXPECT_EQ(r1.rho.data()[4], 5); + ++checks; + } + + EXPECT_GE(patches, 1); + EXPECT_EQ(checks, patches); +} + + + + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv);