diff options
| author | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-09-17 21:34:41 +0100 | 
|---|---|---|
| committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-09-18 02:09:57 +0100 | 
| commit | 8da1334746a7bf34924b1264a309309ea6148027 (patch) | |
| tree | e1b7a3784dd3b3058dd1ebd61194a3483c7f47c2 | |
| parent | Test loading and unloading a library containing a plugin (diff) | |
| download | libadhocutil-8da1334746a7bf34924b1264a309309ea6148027.tar.bz2 libadhocutil-8da1334746a7bf34924b1264a309309ea6148027.tar.xz libadhocutil-8da1334746a7bf34924b1264a309309ea6148027.zip  | |
Support addition and removal of plugin resolver functions
| -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()); +} +  | 
