diff options
-rw-r--r-- | libadhocutil/plugins.cpp | 36 | ||||
-rw-r--r-- | libadhocutil/plugins.h | 44 | ||||
-rw-r--r-- | libadhocutil/plugins.impl.h | 16 | ||||
-rw-r--r-- | libadhocutil/unittests/testPluginsRuntime.cpp | 21 |
4 files changed, 116 insertions, 1 deletions
diff --git a/libadhocutil/plugins.cpp b/libadhocutil/plugins.cpp index d91b1fc..6caf34f 100644 --- a/libadhocutil/plugins.cpp +++ b/libadhocutil/plugins.cpp @@ -11,6 +11,12 @@ namespace std { return a.hash_code() < b.hash_code(); } + bool + operator<(const AdHoc::PluginManager::PluginResolver & a, const AdHoc::PluginManager::PluginResolver & b) + { + return a.boost::function_base::get_vtable() < b.boost::function_base::get_vtable(); + } + std::ostream & operator<<(std::ostream & s, const std::type_info & t) { @@ -62,13 +68,20 @@ namespace AdHoc { { } + DuplicateResolverException::DuplicateResolverException(const std::type_info & t) : + std::runtime_error(stringbf("Duplicate resolver function for type %s", t)) + { + } + PluginManager::PluginManager() : - plugins(new PluginStore()) + plugins(new PluginStore()), + resolvers(new TypePluginResolvers()) { } PluginManager::~PluginManager() { + delete resolvers; delete plugins; } @@ -126,5 +139,26 @@ namespace AdHoc { { return plugins->size(); } + + void + PluginManager::addResolver(const std::type_info & t, const PluginResolver & f) + { + auto prev = resolvers->insert(TypePluginResolvers::value_type(t.hash_code(), f)); + if (!prev.second) { + throw DuplicateResolverException(t); + } + } + + void + PluginManager::removeResolver(const std::type_info & t) + { + resolvers->erase(t.hash_code()); + } + + size_t + PluginManager::countResolvers() const + { + return resolvers->size(); + } } diff --git a/libadhocutil/plugins.h b/libadhocutil/plugins.h index 5efd5b5..8b8efac 100644 --- a/libadhocutil/plugins.h +++ b/libadhocutil/plugins.h @@ -2,6 +2,8 @@ #define ADHOCUTIL_PLUGINS_H #include <boost/shared_ptr.hpp> +#include <boost/function.hpp> +#include <boost/optional.hpp> #include <boost/multi_index_container_fwd.hpp> #include <boost/multi_index/ordered_index_fwd.hpp> #include <boost/multi_index/member.hpp> @@ -9,6 +11,7 @@ #include <boost/multi_index/composite_key.hpp> #include <typeinfo> #include <set> +#include <map> #include <algorithm> #include "visibility.h" #include "unique.h" @@ -53,6 +56,13 @@ namespace AdHoc { DuplicatePluginException(PluginPtr p1, PluginPtr p2); }; + /// Thrown when a resolver function is added a second time. + class DuplicateResolverException : public std::runtime_error { + public: + /// Constuctor taking resolver type. + DuplicateResolverException(const std::type_info &); + }; + template <typename T> /// Typed plugin and handle to implementation. class DLL_PUBLIC PluginOf : public Plugin { @@ -73,6 +83,8 @@ namespace AdHoc { /// Container for loaded plugins. class DLL_PUBLIC PluginManager { public: + typedef boost::function<boost::optional<std::string> (const std::type_info &, const std::string &)> PluginResolver; + PluginManager(); virtual ~PluginManager(); @@ -125,6 +137,35 @@ namespace AdHoc { size_t count() const; /** + * Add a type plugin resolver function. + * @param t The resolver type. + * @param f The resolver function. + */ + void addResolver(const std::type_info & t, const PluginResolver & f); + + /** + * Add a type plugin resolver function. + * @param f The resolver function. + */ + template<typename T> void addResolver(const PluginResolver & f); + + /** + * Remove a type plugin resolver function. + * @param f The resolver type. + */ + void removeResolver(const std::type_info & t); + + /** + * Remove a type plugin resolver function. + */ + template<typename T> void removeResolver(); + + /** + * The number of installed plugins. + */ + size_t countResolvers() const; + + /** * Get the default plugin manager instance. */ static PluginManager * getDefault(); @@ -142,7 +183,10 @@ namespace AdHoc { >> >> PluginStore; + typedef std::map<size_t, PluginResolver> TypePluginResolvers; + PluginStore * plugins; + TypePluginResolvers * resolvers; }; } diff --git a/libadhocutil/plugins.impl.h b/libadhocutil/plugins.impl.h index aad6b2d..6d69880 100644 --- a/libadhocutil/plugins.impl.h +++ b/libadhocutil/plugins.impl.h @@ -73,6 +73,20 @@ namespace AdHoc { } return all; } + + template<typename T> + void + PluginManager::addResolver(const PluginResolver & f) + { + addResolver(typeid(T), f); + } + + template<typename T> + void + PluginManager::removeResolver() + { + removeResolver(typeid(T)); + } } #define INSTANIATEPLUGINOF(T) \ @@ -82,6 +96,8 @@ namespace AdHoc { template boost::shared_ptr<const AdHoc::PluginOf<T>> AdHoc::PluginManager::get<T>(const std::string &) const; \ template const T * AdHoc::PluginManager::getImplementation<T>(const std::string &) const; \ template std::set<boost::shared_ptr<const AdHoc::PluginOf<T>>> AdHoc::PluginManager::getAll<T>() const; \ + template void AdHoc::PluginManager::addResolver<T>(const AdHoc::PluginManager::PluginResolver & f); \ + template void AdHoc::PluginManager::removeResolver<T>(); \ #endif diff --git a/libadhocutil/unittests/testPluginsRuntime.cpp b/libadhocutil/unittests/testPluginsRuntime.cpp index 0aa9955..2b13913 100644 --- a/libadhocutil/unittests/testPluginsRuntime.cpp +++ b/libadhocutil/unittests/testPluginsRuntime.cpp @@ -13,6 +13,8 @@ auto variant = selfExe.parent_path().leaf(); auto toolset = selfExe.parent_path().parent_path().leaf(); auto lib = rootDir / "bin" / toolset / variant / "libutilTestClasses.so"; +static boost::optional<std::string> resolver(const std::type_info &, const std::string &); + BOOST_AUTO_TEST_CASE( ready ) { BOOST_REQUIRE(PluginManager::getDefault()); @@ -32,3 +34,22 @@ BOOST_AUTO_TEST_CASE( loadAndUnloadlib ) dlclose(handle); BOOST_REQUIRE_EQUAL(0, AdHoc::PluginManager::getDefault()->getAll<BaseThing>().size()); } + +boost::optional<std::string> +resolver(const std::type_info &, const std::string &) +{ + return std::string(); +} + +BOOST_AUTO_TEST_CASE( addAndRemoveResolver ) +{ + auto pm = AdHoc::PluginManager::getDefault(); + BOOST_REQUIRE_EQUAL(0, pm->countResolvers()); + pm->addResolver<BaseThing>(resolver); + BOOST_REQUIRE_EQUAL(1, pm->countResolvers()); + BOOST_REQUIRE_THROW(pm->addResolver<BaseThing>(resolver), DuplicateResolverException); + BOOST_REQUIRE_EQUAL(1, pm->countResolvers()); + pm->removeResolver<BaseThing>(); + BOOST_REQUIRE_EQUAL(0, pm->countResolvers()); +} + |