diff --git a/include/pluginplay/module_manager/module_manager.hpp b/include/pluginplay/module_manager/module_manager.hpp new file mode 100644 index 000000000..68fd741e8 --- /dev/null +++ b/include/pluginplay/module_manager/module_manager.hpp @@ -0,0 +1,18 @@ +/* + * Copyright 2024 NWChemEx Community + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include diff --git a/include/pluginplay/module_manager.hpp b/include/pluginplay/module_manager/module_manager_class.hpp similarity index 91% rename from include/pluginplay/module_manager.hpp rename to include/pluginplay/module_manager/module_manager_class.hpp index 91ae90a9d..3249514f4 100644 --- a/include/pluginplay/module_manager.hpp +++ b/include/pluginplay/module_manager/module_manager_class.hpp @@ -17,6 +17,7 @@ #pragma once #include #include +#include #include #include #include @@ -27,7 +28,7 @@ namespace detail_ { struct ModuleManagerPIMPL; } -/** @brief Class responsible for manipulating +/** @brief Class responsible for holding and managing modules. * */ class ModuleManager { @@ -50,12 +51,19 @@ class ModuleManager { /// Type of module key container using key_container_type = std::vector; + /// Type of the cache + using cache_type = cache::ModuleManagerCache; + + /// Type of a pointer to the cache + using cache_pointer = std::shared_ptr; + ///@{ /** @name Ctors and assignment operators * */ ModuleManager(); - ModuleManager(runtime_ptr runtime); + ModuleManager(runtime_ptr runtime, + cache_pointer cache = std::make_shared()); // ModuleManager(const ModuleManager& rhs); // ModuleManager& operator=(const ModuleManager& rhs) { // return *this = std::move(ModuleManager(rhs)); @@ -242,7 +250,25 @@ class ModuleManager { */ key_container_type keys() const; + /** @brief Does *this have a cache set? + * + * + * @return True if *this has a place where it can cache input/result pairs + * and false otherwise. + * + * @throw none No throw guarantee. + */ + bool has_cache() const noexcept; + private: + /** @brief Does *this have a PIMPL? + * + * @return False if pimpl_ is set to a null pointer and true otherwise. + * + * @throw None No throw guarantee. + */ + bool has_pimpl_() const noexcept; + /// Bridges the gap between the set_default and the PIMPL void set_default_(const std::type_info& type, type::input_map inps, type::key key); diff --git a/include/pluginplay/plugin/plugin.hpp b/include/pluginplay/plugin/plugin.hpp index e6ba75c6a..3cfc10202 100644 --- a/include/pluginplay/plugin/plugin.hpp +++ b/include/pluginplay/plugin/plugin.hpp @@ -15,7 +15,7 @@ */ #pragma once -#include +#include #include #define DECLARE_PLUGIN(plugin_name) \ diff --git a/include/pluginplay/pluginplay.hpp b/include/pluginplay/pluginplay.hpp index 69742c3b2..b64a872ce 100644 --- a/include/pluginplay/pluginplay.hpp +++ b/include/pluginplay/pluginplay.hpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/pluginplay/printing/document_modules.hpp b/include/pluginplay/printing/document_modules.hpp index 347ba2c08..e3dc6d212 100644 --- a/include/pluginplay/printing/document_modules.hpp +++ b/include/pluginplay/printing/document_modules.hpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include namespace pluginplay::printing { diff --git a/src/pluginplay/detail_/module_manager_pimpl.hpp b/src/pluginplay/module_manager/detail_/module_manager_pimpl.hpp similarity index 58% rename from src/pluginplay/detail_/module_manager_pimpl.hpp rename to src/pluginplay/module_manager/detail_/module_manager_pimpl.hpp index 5f60ddb18..8ebba6c1e 100644 --- a/src/pluginplay/detail_/module_manager_pimpl.hpp +++ b/src/pluginplay/module_manager/detail_/module_manager_pimpl.hpp @@ -15,16 +15,15 @@ */ #pragma once -#include "../module/detail_/module_pimpl.hpp" +#include "../../module/detail_/module_pimpl.hpp" #include #include #include #include -#include +#include #include -namespace pluginplay { -namespace detail_ { +namespace pluginplay::detail_ { /** @brief The class that implements the ModuleManager. * @@ -35,12 +34,15 @@ namespace detail_ { * that it is easier to test the implementation. */ struct ModuleManagerPIMPL { + /// Type *this implements + using module_manager_type = ModuleManager; + ///@{ /// Type of a pointer to a module's implemenation - using module_base_ptr = typename ModuleManager::module_base_ptr; + using module_base_ptr = module_manager_type::module_base_ptr; /// Type of a pointer to a read-only module implementation - using const_module_base_ptr = typename ModuleManager::const_module_base_ptr; + using const_module_base_ptr = module_manager_type::const_module_base_ptr; /// Type of a map from the module implementation's type to the /// implementation @@ -50,16 +52,22 @@ struct ModuleManagerPIMPL { using shared_module = std::shared_ptr; /// Type of a map holding usable modules - using module_map = utilities::CaseInsensitiveMap; + using module_map = module_manager_type::module_map; /// Type of a map holding the default module key for a given property type using default_map = std::map; /// The type of the runtime - using runtime_type = parallelzone::runtime::RuntimeView; + using runtime_type = module_manager_type::runtime_type; /// A pointer to a runtime - using runtime_ptr = std::shared_ptr; + using runtime_ptr = module_manager_type::runtime_ptr; + + /// Type of the cache + using cache_type = module_manager_type::cache_type; + + /// Type of a pointer to the cache + using cache_pointer = module_manager_type::cache_pointer; /// Type of a map from key to Python implementation // TODO: remove when a more elegant solution is determined @@ -67,9 +75,12 @@ struct ModuleManagerPIMPL { ///@} - ModuleManagerPIMPL(runtime_ptr runtime) : m_runtime_(runtime) {} + ModuleManagerPIMPL() : + ModuleManagerPIMPL(std::make_shared(), + std::make_shared()) {} - ModuleManagerPIMPL() : m_runtime_(std::make_shared()) {} + ModuleManagerPIMPL(runtime_ptr runtime, cache_pointer cache) : + m_pcaches(cache), m_runtime_(runtime) {} /// Makes a deep copy of this instance on the heap // auto clone() { return std::make_unique(*this); } @@ -106,11 +117,7 @@ struct ModuleManagerPIMPL { * @param key The module key for the module to use as the default */ void set_default(const std::type_info& type, type::input_map inputs, - type::key key) { - if(!count(key)) m_modules.at(key); // Throws a consistent error - m_defaults[std::type_index(type)] = key; - m_inputs[std::type_index(type)] = std::move(inputs); - } + type::key key); /** @brief This function actually adds a module to the list of available * modules. @@ -118,31 +125,7 @@ struct ModuleManagerPIMPL { * @param key The key under which the module will be registered. * @param base The instance containing the algorithm */ - void add_module(type::key key, module_base_ptr base) { - assert_unique_key_(key); - auto uuid = utility::generate_uuid(); - auto internal_cache = m_caches.get_or_make_user_cache(uuid); - base->set_cache(internal_cache); - base->set_runtime(m_runtime_); - base->set_uuid(uuid); - auto module_cache = m_caches.get_or_make_module_cache(key); - std::unique_ptr pimpl; - if(base->is_python()) { - // This is a hacky patch to allow multiple python modules to be - // added while avoiding the type_index collisions. - // TODO: remove when a more elegant solution is determined - m_py_bases[key] = base; - pimpl = - std::make_unique(m_py_bases[key], module_cache); - } else { - std::type_index type(base->type()); - if(!m_bases.count(type)) m_bases[type] = base; - pimpl = std::make_unique(m_bases[type], module_cache); - } - auto ptr = std::make_shared(std::move(pimpl)); - ptr->set_name(key); - m_modules.emplace(std::move(key), ptr); - } + void add_module(type::key key, module_base_ptr base); /** @brief Unloads the specified module. * @@ -165,13 +148,7 @@ struct ModuleManagerPIMPL { * @param old_key The key for the module to copy * @param new_key The key under which the new module will live */ - void copy_module(const type::key& old_key, type::key new_key) { - assert_unique_key_(new_key); - Module mod = m_modules.at(old_key)->unlocked_copy(); - auto ptr = std::make_shared(std::move(mod)); - ptr->set_name(new_key); - m_modules.emplace(std::move(new_key), ptr); - } + void copy_module(const type::key& old_key, type::key new_key); /** @brief Returns a module, filling in all non-set submodules with defaults * if a ready default exists. @@ -179,27 +156,7 @@ struct ModuleManagerPIMPL { * @param key The module you want * @return A shared_ptr to the requested module */ - shared_module at(const type::key& key) { - if(!count(key)) { - const std::string msg = - "ModuleManager has no module with key: '" + key + "'"; - throw std::out_of_range(msg); - } - auto mod = m_modules.at(key); - // Loop over submodules filling them in from the defaults - for(auto& [k, v] : mod->submods()) { - const auto& type = v.type(); - // Only change non-ready submodules - if(!v.ready() && m_defaults.count(type)) { - // Recursive to make sure that that module gets filled in - auto default_mod = at(m_defaults.at(type)); - // Only change if the module is also ready - if(default_mod->ready(m_inputs.at(type))) - mod->change_submod(k, default_mod); - } - } - return mod; - } + shared_module at(const type::key& key); ///@{ /** @name Comparison operators @@ -207,35 +164,7 @@ struct ModuleManagerPIMPL { * @param rhs * @return */ - bool operator==(const ModuleManagerPIMPL& rhs) const { - // Try to get out early - if(m_bases.size() != rhs.m_bases.size()) return false; - if(m_modules.size() != rhs.m_modules.size()) return false; - if(m_defaults.size() != rhs.m_defaults.size()) return false; - - // TODO: Remove with the rest of the python hack - if(m_py_bases.size() != rhs.m_py_bases.size()) return false; - for(const auto& [k, v] : rhs.m_py_bases) { - if(!m_py_bases.count(k)) return false; - if(*m_py_bases.at(k) != *v) return false; - } - - // Skip checking the values b/c implementations are compared by type - for(const auto& [k, v] : rhs.m_bases) { - if(!m_bases.count(k)) return false; - } - - // Need to check the values b/c user may have switched options - for(const auto& [k, v] : rhs.m_modules) { - if(!m_modules.count(k)) return false; - if(*m_modules.at(k) != *v) return false; - } - - // Easy since not pointers - if(m_defaults != rhs.m_defaults) return false; - - return true; - } + bool operator==(const ModuleManagerPIMPL& rhs) const; bool operator!=(const ModuleManagerPIMPL& rhs) const { return !((*this) == rhs); @@ -245,12 +174,9 @@ struct ModuleManagerPIMPL { runtime_type& get_runtime() const { return *m_runtime_; } - ModuleManager::key_container_type keys() const { - ModuleManager::key_container_type keys; - keys.reserve(m_modules.size()); - for(const auto& [k, v] : m_modules) keys.push_back(k); - return keys; - } + ModuleManager::key_container_type keys() const; + + bool has_cache() const noexcept { return static_cast(m_pcaches); } ///@} ///@{ @@ -270,7 +196,7 @@ struct ModuleManagerPIMPL { py_base_map m_py_bases; // These are the results of the modules running in the user's states - cache::ModuleManagerCache m_caches; + cache_pointer m_pcaches; // A map of property types default_map m_defaults; @@ -288,5 +214,6 @@ struct ModuleManagerPIMPL { } }; -} // namespace detail_ -} // namespace pluginplay +} // namespace pluginplay::detail_ + +#include "module_manager_pimpl.ipp" diff --git a/src/pluginplay/module_manager/detail_/module_manager_pimpl.ipp b/src/pluginplay/module_manager/detail_/module_manager_pimpl.ipp new file mode 100644 index 000000000..cb43d932f --- /dev/null +++ b/src/pluginplay/module_manager/detail_/module_manager_pimpl.ipp @@ -0,0 +1,132 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file meant only for inclusion in module_manager_pimpl.hpp + +#pragma once + +namespace pluginplay::detail_ { + +inline void ModuleManagerPIMPL::set_default(const std::type_info& type, + type::input_map inputs, + type::key key) { + if(!count(key)) m_modules.at(key); // Throws a consistent error + m_defaults[std::type_index(type)] = key; + m_inputs[std::type_index(type)] = std::move(inputs); +} + +inline void ModuleManagerPIMPL::add_module(type::key key, + module_base_ptr base) { + assert_unique_key_(key); + auto uuid = utility::generate_uuid(); + base->set_runtime(m_runtime_); + base->set_uuid(uuid); + + cache::ModuleManagerCache::module_cache_pointer module_cache; + if(m_pcaches) { + auto internal_cache = m_pcaches->get_or_make_user_cache(uuid); + base->set_cache(internal_cache); + module_cache = m_pcaches->get_or_make_module_cache(key); + } + + std::unique_ptr pimpl; + if(base->is_python()) { + // This is a hacky patch to allow multiple python modules to be + // added while avoiding the type_index collisions. + // TODO: remove when a more elegant solution is determined + m_py_bases[key] = base; + pimpl = std::make_unique(m_py_bases[key], module_cache); + } else { + std::type_index type(base->type()); + if(!m_bases.count(type)) m_bases[type] = base; + pimpl = std::make_unique(m_bases[type], module_cache); + } + auto ptr = std::make_shared(std::move(pimpl)); + ptr->set_name(key); + m_modules.emplace(std::move(key), ptr); +} + +inline void ModuleManagerPIMPL::copy_module(const type::key& old_key, + type::key new_key) { + assert_unique_key_(new_key); + Module mod = m_modules.at(old_key)->unlocked_copy(); + auto ptr = std::make_shared(std::move(mod)); + ptr->set_name(new_key); + m_modules.emplace(std::move(new_key), ptr); +} + +inline ModuleManagerPIMPL::shared_module ModuleManagerPIMPL::at( + const type::key& key) { + if(!count(key)) { + const std::string msg = + "ModuleManager has no module with key: '" + key + "'"; + throw std::out_of_range(msg); + } + auto mod = m_modules.at(key); + // Loop over submodules filling them in from the defaults + for(auto& [k, v] : mod->submods()) { + const auto& type = v.type(); + // Only change non-ready submodules + if(!v.ready() && m_defaults.count(type)) { + // Recursive to make sure that that module gets filled in + auto default_mod = at(m_defaults.at(type)); + // Only change if the module is also ready + if(default_mod->ready(m_inputs.at(type))) + mod->change_submod(k, default_mod); + } + } + return mod; +} + +inline bool ModuleManagerPIMPL::operator==( + const ModuleManagerPIMPL& rhs) const { + // Try to get out early + if(m_bases.size() != rhs.m_bases.size()) return false; + if(m_modules.size() != rhs.m_modules.size()) return false; + if(m_defaults.size() != rhs.m_defaults.size()) return false; + + // TODO: Remove with the rest of the python hack + if(m_py_bases.size() != rhs.m_py_bases.size()) return false; + for(const auto& [k, v] : rhs.m_py_bases) { + if(!m_py_bases.count(k)) return false; + if(*m_py_bases.at(k) != *v) return false; + } + + // Skip checking the values b/c implementations are compared by type + for(const auto& [k, v] : rhs.m_bases) { + if(!m_bases.count(k)) return false; + } + + // Need to check the values b/c user may have switched options + for(const auto& [k, v] : rhs.m_modules) { + if(!m_modules.count(k)) return false; + if(*m_modules.at(k) != *v) return false; + } + + // Easy since not pointers + if(m_defaults != rhs.m_defaults) return false; + + return true; +} + +inline ModuleManager::key_container_type ModuleManagerPIMPL::keys() const { + ModuleManager::key_container_type keys; + keys.reserve(m_modules.size()); + for(const auto& [k, v] : m_modules) keys.push_back(k); + return keys; +} + +} // namespace pluginplay::detail_ \ No newline at end of file diff --git a/src/pluginplay/module_manager.cpp b/src/pluginplay/module_manager/module_manager_class.cpp similarity index 82% rename from src/pluginplay/module_manager.cpp rename to src/pluginplay/module_manager/module_manager_class.cpp index c3de54479..23294778e 100644 --- a/src/pluginplay/module_manager.cpp +++ b/src/pluginplay/module_manager/module_manager_class.cpp @@ -16,7 +16,7 @@ #include "detail_/module_manager_pimpl.hpp" #include "module/detail_/module_pimpl.hpp" -#include "pluginplay/module_manager.hpp" +#include namespace pluginplay { @@ -30,8 +30,8 @@ using CIM = utilities::CaseInsensitiveMap; ModuleManager::ModuleManager() : pimpl_(std::make_unique()) {} -ModuleManager::ModuleManager(runtime_ptr runtime) : - pimpl_(std::make_unique(runtime)) {} +ModuleManager::ModuleManager(runtime_ptr runtime, cache_pointer cache) : + pimpl_(std::make_unique(runtime, cache)) {} ModuleManager::ModuleManager(ModuleManager&& rhs) noexcept = default; ModuleManager& ModuleManager::operator=(ModuleManager&& rhs) noexcept = default; ModuleManager::~ModuleManager() noexcept = default; @@ -82,4 +82,18 @@ ModuleManager::runtime_type& ModuleManager::get_runtime() const noexcept { ModuleManager::key_container_type ModuleManager::keys() const { return pimpl_->keys(); } + +bool ModuleManager::has_cache() const noexcept { + // Relies on short-circuiting to not dereference pimpl + return has_pimpl_() && pimpl_->has_cache(); +} + +// ----------------------------------------------------------------------------- +// -- Private Methods +// ----------------------------------------------------------------------------- + +bool ModuleManager::has_pimpl_() const noexcept { + return static_cast(pimpl_); +} + } // namespace pluginplay diff --git a/src/python/cache/export_cache.hpp b/src/python/cache/export_cache.hpp new file mode 100644 index 000000000..4dd955af4 --- /dev/null +++ b/src/python/cache/export_cache.hpp @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "../export_pluginplay.hpp" + +namespace pluginplay { + +void export_module_manager_cache(py_module_reference m); + +inline void export_cache(py_module_reference m) { + auto m_cache = m.def_submodule("cache"); + export_module_manager_cache(m_cache); +} + +} // namespace pluginplay diff --git a/src/python/cache/export_module_manager_cache.cpp b/src/python/cache/export_module_manager_cache.cpp new file mode 100644 index 000000000..9d8ae2816 --- /dev/null +++ b/src/python/cache/export_module_manager_cache.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "export_cache.hpp" +#include +namespace pluginplay { + +void export_module_manager_cache(py_module_reference m) { + py_class_type>( + m, "ModuleManagerCache") + .def(pybind11::init<>()); +} + +} // namespace pluginplay diff --git a/src/python/export_pluginplay.cpp b/src/python/export_pluginplay.cpp index 982982423..0ab0ff243 100644 --- a/src/python/export_pluginplay.cpp +++ b/src/python/export_pluginplay.cpp @@ -15,8 +15,10 @@ */ #include "any/export_any.hpp" +#include "cache/export_cache.hpp" #include "fields/export_fields.hpp" #include "module/export_module.hpp" +#include "module_manager/export_module_manager.hpp" #include "printing/export_printing.hpp" #include "python/export_python.hpp" #include @@ -25,6 +27,7 @@ namespace pluginplay { PYBIND11_MODULE(pluginplay, m) { any::export_any(m); + export_cache(m); export_fields(m); python::export_python(m); export_module(m); diff --git a/src/python/export_pluginplay.hpp b/src/python/export_pluginplay.hpp index b7852d35d..36c132768 100644 --- a/src/python/export_pluginplay.hpp +++ b/src/python/export_pluginplay.hpp @@ -37,7 +37,6 @@ using py_class_type = pybind11::class_; // -- Declarations of exports for top-level classes // ----------------------------------------------------------------------------- -void export_module_manager(py_module_reference m); void export_submodule_request(py_module_reference m); void export_printing(py_module_reference m); diff --git a/src/python/module_manager/export_module_manager.hpp b/src/python/module_manager/export_module_manager.hpp new file mode 100644 index 000000000..b66f741f2 --- /dev/null +++ b/src/python/module_manager/export_module_manager.hpp @@ -0,0 +1,28 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "../export_pluginplay.hpp" + +namespace pluginplay { + +void export_module_manager_class(py_module_reference m); + +inline void export_module_manager(py_module_reference m) { + export_module_manager_class(m); +} + +} // namespace pluginplay diff --git a/src/python/export_module_manager.cpp b/src/python/module_manager/export_module_manager_class.cpp similarity index 77% rename from src/python/export_module_manager.cpp rename to src/python/module_manager/export_module_manager_class.cpp index 141f44c08..045741ee2 100644 --- a/src/python/export_module_manager.cpp +++ b/src/python/module_manager/export_module_manager_class.cpp @@ -14,25 +14,33 @@ * limitations under the License. */ -#include "export_pluginplay.hpp" +#include "export_module_manager.hpp" #include "module/py_module_base.hpp" #include #include -#include +#include #include #include namespace pluginplay { -void export_module_manager(py_module_reference m) { - using at_fxn = Module& (ModuleManager::*)(const type::key&); - using runtime_type = typename ModuleManager::runtime_type; +void export_module_manager_class(py_module_reference m) { + using at_fxn = Module& (ModuleManager::*)(const type::key&); + using runtime_type = typename ModuleManager::runtime_type; + using cache_type = typename ModuleManager::cache_type; + using cache_pointer = typename ModuleManager::cache_pointer; using py_obj = pybind11::object; using python::PythonWrapper; py_class_type(m, "ModuleManager") .def(pybind11::init<>()) + .def(pybind11::init([](runtime_type rv, cache_pointer cache) { + auto prv = std::make_shared(rv); + return ModuleManager(prv, cache); + }), + pybind11::arg("rv"), + pybind11::arg("cache") = std::make_shared()) .def("count", &ModuleManager::count) .def("size", &ModuleManager::size) .def( @@ -63,6 +71,7 @@ void export_module_manager(py_module_reference m) { .def("get_runtime", &ModuleManager::get_runtime, pybind11::return_value_policy::reference_internal) .def("keys", &ModuleManager::keys) + .def("has_cache", &ModuleManager::has_cache) .def("__getitem__", [](ModuleManager& self, const type::key& key) { return self.at(key); }); diff --git a/tests/cxx/unit_tests/pluginplay/examples/load_modules.hpp b/tests/cxx/unit_tests/pluginplay/examples/load_modules.hpp index 4e40b3578..5527357ef 100644 --- a/tests/cxx/unit_tests/pluginplay/examples/load_modules.hpp +++ b/tests/cxx/unit_tests/pluginplay/examples/load_modules.hpp @@ -26,7 +26,7 @@ #pragma once #include "writing_a_module.hpp" #include "writing_a_property_type.hpp" -#include +#include /* Populating the ModuleManager * ---------------------------- diff --git a/tests/cxx/unit_tests/pluginplay/examples/workflow.hpp b/tests/cxx/unit_tests/pluginplay/examples/workflow.hpp index 694c376ec..07591adfe 100644 --- a/tests/cxx/unit_tests/pluginplay/examples/workflow.hpp +++ b/tests/cxx/unit_tests/pluginplay/examples/workflow.hpp @@ -26,7 +26,7 @@ */ #pragma once #include "load_modules.hpp" -#include +#include /* Running a Computation * --------------------- diff --git a/tests/cxx/unit_tests/pluginplay/detail_/module_manager_pimpl.cpp b/tests/cxx/unit_tests/pluginplay/module_manager/detail_/module_manager_pimpl.cpp similarity index 96% rename from tests/cxx/unit_tests/pluginplay/detail_/module_manager_pimpl.cpp rename to tests/cxx/unit_tests/pluginplay/module_manager/detail_/module_manager_pimpl.cpp index 394a56fc6..5ce286a28 100644 --- a/tests/cxx/unit_tests/pluginplay/detail_/module_manager_pimpl.cpp +++ b/tests/cxx/unit_tests/pluginplay/module_manager/detail_/module_manager_pimpl.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "../examples/writing_a_module.hpp" -#include "pluginplay/detail_/module_manager_pimpl.hpp" +#include "../../examples/writing_a_module.hpp" +#include "pluginplay/module_manager/detail_/module_manager_pimpl.hpp" #include using namespace pluginplay; @@ -38,7 +38,7 @@ TEST_CASE("ModuleManagerPIMPL : Default ctor") { TEST_CASE("ModuleManagerPIMPL : Runtime") { SECTION("ctor") { auto runtime = std::make_shared(); - ModuleManagerPIMPL pimple(runtime); + ModuleManagerPIMPL pimple(runtime, nullptr); auto& internal_runtime = pimple.get_runtime(); REQUIRE(&internal_runtime == runtime.get()); } @@ -246,3 +246,10 @@ TEST_CASE("ModuleManagerPIMPL : keys") { REQUIRE(pimpl1.keys().at(1) == "rectangle"); } } + +TEST_CASE("ModuleManagerPIMPL : has_cache") { + ModuleManagerPIMPL pimpl0; + ModuleManagerPIMPL pimpl1(nullptr, nullptr); + REQUIRE(pimpl0.has_cache()); + REQUIRE_FALSE(pimpl1.has_cache()); +} diff --git a/tests/cxx/unit_tests/pluginplay/module_manager.cpp b/tests/cxx/unit_tests/pluginplay/module_manager/module_manager_class.cpp similarity index 91% rename from tests/cxx/unit_tests/pluginplay/module_manager.cpp rename to tests/cxx/unit_tests/pluginplay/module_manager/module_manager_class.cpp index bd05a0e3c..d1520703c 100644 --- a/tests/cxx/unit_tests/pluginplay/module_manager.cpp +++ b/tests/cxx/unit_tests/pluginplay/module_manager/module_manager_class.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "pluginplay/module_manager.hpp" #include "test_common.hpp" #include +#include TEST_CASE("ModuleManager") { pluginplay::ModuleManager mm; @@ -71,4 +71,10 @@ TEST_CASE("ModuleManager") { REQUIRE(keys[0] == "a key"); REQUIRE(keys[1] == "b key"); } + + SECTION("has_cache") { + REQUIRE(mm.has_cache()); + pluginplay::ModuleManager no_cache(nullptr, nullptr); + REQUIRE_FALSE(no_cache.has_cache()); + } } diff --git a/tests/python/unit_tests/module/__init__.py b/tests/python/unit_tests/module/__init__.py new file mode 100644 index 000000000..15622f72d --- /dev/null +++ b/tests/python/unit_tests/module/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2024 NWChemEx-Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/python/unit_tests/test_module.py b/tests/python/unit_tests/module/test_module.py similarity index 100% rename from tests/python/unit_tests/test_module.py rename to tests/python/unit_tests/module/test_module.py diff --git a/tests/python/unit_tests/test_module_base.py b/tests/python/unit_tests/module/test_module_base.py similarity index 100% rename from tests/python/unit_tests/test_module_base.py rename to tests/python/unit_tests/module/test_module_base.py diff --git a/tests/python/unit_tests/module_manager/__init__.py b/tests/python/unit_tests/module_manager/__init__.py new file mode 100644 index 000000000..15622f72d --- /dev/null +++ b/tests/python/unit_tests/module_manager/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2024 NWChemEx-Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/python/unit_tests/test_module_manager.py b/tests/python/unit_tests/module_manager/test_module_manager_class.py similarity index 94% rename from tests/python/unit_tests/test_module_manager.py rename to tests/python/unit_tests/module_manager/test_module_manager_class.py index c6c0e6f67..621b3c382 100644 --- a/tests/python/unit_tests/test_module_manager.py +++ b/tests/python/unit_tests/module_manager/test_module_manager_class.py @@ -28,11 +28,21 @@ def run_(self, inputs, submods): pt = test_pp.OneInOneOut() i0, = pt.unwrap_inputs(inputs) rv = self.results() - return pt.wrap_results(rv, i0) + return pt.wrap_results(rv, i0) # class TestModuleManager(unittest.TestCase): + def test_ctor(self): + rv = parallelzone.runtime.RuntimeView() + has_runtime_and_cache = pp.ModuleManager(rv) + self.assertEqual(rv, has_runtime_and_cache.get_runtime()) + self.assertTrue(has_runtime_and_cache.has_cache()) + + has_runtime_only = pp.ModuleManager(rv, None) + self.assertEqual(rv, has_runtime_only.get_runtime()) + self.assertFalse(has_runtime_only.has_cache()) + def test_count(self): # Defaulted is always false self.assertFalse(self.defaulted.count('not a key')) @@ -220,4 +230,5 @@ def test_keys(self): def setUp(self): self.defaulted = pp.defaulted_mm() self.has_mods = test_pp.get_mm() + self.corr_total = 10 # This should be the correct number of modules diff --git a/tests/python/unit_tests/modules.hpp b/tests/python/unit_tests/modules.hpp index d3d61d42e..f9ef42afb 100644 --- a/tests/python/unit_tests/modules.hpp +++ b/tests/python/unit_tests/modules.hpp @@ -17,7 +17,7 @@ #pragma once #include "property_types.hpp" #include -#include +#include namespace test_pluginplay { diff --git a/tests/python/unit_tests/test_pluginplay.cpp b/tests/python/unit_tests/test_pluginplay.cpp index 9f720ea03..f42b8ea1f 100644 --- a/tests/python/unit_tests/test_pluginplay.cpp +++ b/tests/python/unit_tests/test_pluginplay.cpp @@ -21,7 +21,7 @@ #include "property_types.hpp" #include "python/test_python.hpp" #include "test_pluginplay.hpp" -#include +#include #include #include