summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libadhocutil/plugins.cpp36
-rw-r--r--libadhocutil/plugins.h44
-rw-r--r--libadhocutil/plugins.impl.h16
-rw-r--r--libadhocutil/unittests/testPluginsRuntime.cpp21
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());
+}
+