From 88f9cb70b9b3be26c8f6a1a9261707e228fdac92 Mon Sep 17 00:00:00 2001 From: Sergey Lisitsyn Date: Sun, 15 Apr 2018 10:28:31 +0200 Subject: [PATCH] Primitives for plugins --- src/shogun/base/library.cpp | 104 ++++++++++++++++++++++++++++ src/shogun/base/library.h | 86 +++++++++++++++++++++++ src/shogun/base/manifest.cpp | 77 +++++++++++++++++++++ src/shogun/base/manifest.h | 128 +++++++++++++++++++++++++++++++++++ src/shogun/base/metaclass.h | 87 ++++++++++++++++++++++++ 5 files changed, 482 insertions(+) create mode 100644 src/shogun/base/library.cpp create mode 100644 src/shogun/base/library.h create mode 100644 src/shogun/base/manifest.cpp create mode 100644 src/shogun/base/manifest.h create mode 100644 src/shogun/base/metaclass.h diff --git a/src/shogun/base/library.cpp b/src/shogun/base/library.cpp new file mode 100644 index 00000000000..a06fb9a4807 --- /dev/null +++ b/src/shogun/base/library.cpp @@ -0,0 +1,104 @@ +/* + * This software is distributed under BSD 3-clause license (see LICENSE file). + * + * Authors: Sergey Lisitsyn, Sanuj Sharma + */ + +#include +#include + +namespace shogun +{ + class LibraryHandle : public CSGObject + { + public: + LibraryHandle(const std::string& filename) + { + dlerror(); + handle = dlopen(filename.c_str(), RTLD_NOW | RTLD_LOCAL); + if (handle) + { + SG_INFO("Loaded.\n"); + } + else + { + SG_ERROR("Failed: %s.\n", dlerror()); + } + } + + ~LibraryHandle() + { + if (handle) + { + SG_INFO("Closing library.\n"); + dlclose(handle); + } + } + + template + T call(const std::string& name) + { + dlerror(); + T (*fm)(); + *(void**)(&fm) = dlsym(handle, name.c_str()); + char* potential_error = dlerror(); + if (potential_error) + SG_ERROR("Failed: %s.\n", potential_error); + return fm(); + } + + const char* get_name() const + { + return "LibraryHandle"; + } + + private: + void* handle; + + }; + + Library::Library(const std::string& filename) : + m_handle(some(filename)) + { + } + + Library::Library(const Library& other) : + m_handle(Some(other.m_handle)) + { + } + + Library& Library::operator=(const Library& other) + { + m_handle = other.m_handle; + return *this; + } + + bool operator==(const Library& first, const Library& second) + { + Some first_handle = first.m_handle; + Some second_handle = second.m_handle; + return first_handle == second_handle; + } + + bool operator!=(const Library& first, const Library& second) + { + return !(first == second); + } + + Library::~Library() + { + } + + Manifest Library::manifest() + { + return m_handle->call(manifest_accessor_name); + } + + Library load_library(const std::string& filename) + { + return Library(filename); + } + + const char* Library::manifest_accessor_name = "shogunManifest"; + +} diff --git a/src/shogun/base/library.h b/src/shogun/base/library.h new file mode 100644 index 00000000000..6774e7baa84 --- /dev/null +++ b/src/shogun/base/library.h @@ -0,0 +1,86 @@ +/* + * This software is distributed under BSD 3-clause license (see LICENSE file). + * + * Authors: Sergey Lisitsyn, Sanuj Sharma + */ + +#ifndef _LIBRARY_H_ +#define _LIBRARY_H_ + +#include +#include +#include +#include + +namespace shogun +{ + + /** @brief + * Handles loading, calling and closing of plugins from shared object files. + */ + class LibraryHandle; + + /** @brief + * Provides an API for loading plugins as objects of this class + * and accessing Manifest of the loaded plugins. + * Uses LibraryHandle under the hood. + */ + class Library + { + public: + /** Constructor to initialize library + * @param filename name of shared object file + */ + Library(const std::string& filename); + + /** Copy constructor + * @param other library object to be copied + */ + Library(const Library& other); + + /** Class Assignment operator + * @param other library object to be assigned + */ + Library& operator=(const Library& other); + + /** Equality operator + * @param first first Library + * @param second second Library + */ + friend bool operator==(const Library& first, const Library& second); + + /** Inequality operator + * @param first first Library + * @param second second Library + */ + friend bool operator!=(const Library& first, const Library& second); + + /** Destructor */ + ~Library(); + + /** @return manifest of loaded library */ + Manifest manifest(); + + /** @return name of function that accesses Manifest + * of loaded library. + */ + static const char* get_manifest_accessor_name() + { + return manifest_accessor_name; + } + + private: + static const char* manifest_accessor_name; + Some m_handle; + + }; + + /** Loads a plugin into a library object. + * @param filename name of shared object file + * @return library object of loaded plugin + */ + Library load_library(const std::string& filename); + +} + +#endif //_LIBRARY_H_ diff --git a/src/shogun/base/manifest.cpp b/src/shogun/base/manifest.cpp new file mode 100644 index 00000000000..ef0cfc0e016 --- /dev/null +++ b/src/shogun/base/manifest.cpp @@ -0,0 +1,77 @@ +/* + * This software is distributed under BSD 3-clause license (see LICENSE file). + * + * Authors: Sergey Lisitsyn, Sanuj Sharma + */ + +#include +#include + +#include + +namespace shogun +{ + + class Manifest::Self + { + public: + std::string description; + std::unordered_map classes; + }; + + Manifest::Manifest(const std::string& description, + const std::initializer_list> classes) : + self() + { + self->description = description; + for (const auto& m : classes) + add_class(m.first, m.second); + } + + Manifest::Manifest(const Manifest& other) : + self() + { + self->description = other.self->description; + self->classes = other.self->classes; + } + + Manifest& Manifest::operator=(const Manifest& other) + { + self->description = other.self->description; + self->classes = other.self->classes; + return *this; + } + + bool operator==(const Manifest& first, const Manifest& second) + { + return (first.self->description == second.self->description) + and (first.self->classes == second.self->classes); + } + + bool operator!=(const Manifest& first, const Manifest& second) + { + return !(first == second); + } + + Manifest::~Manifest() + { + } + + std::string Manifest::description() const + { + return self->description; + } + + void Manifest::add_class(const std::string& name, Any clazz) + { + self->classes[name] = clazz; + } + + Any Manifest::find_class(const std::string& name) const + { + if (!self->classes.count(name)) + SG_SERROR("MetaClass corresponding to the name '%s' couldn't be found.\n", name.c_str()); + return self->classes.at(name); + } + +} diff --git a/src/shogun/base/manifest.h b/src/shogun/base/manifest.h new file mode 100644 index 00000000000..f9fbb82e63a --- /dev/null +++ b/src/shogun/base/manifest.h @@ -0,0 +1,128 @@ +/* + * This software is distributed under BSD 3-clause license (see LICENSE file). + * + * Authors: Sergey Lisitsyn, Sanuj Sharma + */ + +#ifndef _MANIFEST_H_ +#define _MANIFEST_H_ + +#include +#include +#include + +namespace shogun +{ + + class Library; + + /** @brief Manifest stores meta-data of Library. + * Each manifest has description and a set of meta-classes + * (see @ref MetaClass) which are responsible for + * creating instances of exported classes. + */ + class Manifest + { + public: + /** Constructor to initialize hash from name + * @param description description for the Library + * @param metaclasses list of meta-classes for exported classes + */ + Manifest(const std::string& description, + const std::initializer_list> metaclasses); + + /** Copy constructor + * @param other Manifest object to be copied + */ + Manifest(const Manifest& other); + + /** Class Assignment operator + * @param other manifest object to be assigned + */ + Manifest& operator=(const Manifest& other); + + /** Equality operator + * @param first first Manifest + * @param second second Manifest + */ + friend bool operator==(const Manifest& first, const Manifest& second); + + /** Inequality operator + * @param first first Manifest + * @param second second Manifest + */ + friend bool operator!=(const Manifest& first, const Manifest& second); + + /** Destructor */ + ~Manifest(); + + /** Returns meta-class by its name. + * + * @param name name of meta-class to obtain + * @return object of meta-class + */ + template + MetaClass class_by_name(const std::string& name) const + { + Any clazz = find_class(name); + return any_cast>(clazz); + } + + /** @return description stored in the manifest. */ + std::string description() const; + + protected: + /** Adds mapping from class name to MetaClass object of + * class (stored as Any object) corresponding to the name. + * The map is stored in Self. + * @param name name for class + * @param clazz class + */ + void add_class(const std::string& name, Any clazz); + + /** Finds MetaClass object (stored as Any object) of class + * corresponding to the input name. + * @param name name for class + * @return + */ + Any find_class(const std::string& name) const; + + private: + class Self; + Unique self; + }; + +/** Starts manifest declaration with its description. + * Always immediately follow this macro with + * @ref EXPORT or @ref END_MANIFEST. + */ +#define BEGIN_MANIFEST(DESCRIPTION) \ +extern "C" Manifest shogunManifest() \ +{ \ + static Manifest manifest(DESCRIPTION,{ \ + +/** Declares class to be exported. + * Always use this macro between @ref BEGIN_MANIFEST and + * @ref END_MANIFEST + */ +#define EXPORT(CLASSNAME, BASE_CLASSNAME, IDENTIFIER) \ + std::make_pair(IDENTIFIER, erase_type( \ + MetaClass(erase_type( \ + std::function()>( \ + []() -> Some \ + { \ + return Some(new CLASSNAME); \ + } \ + ))))), \ + +/** Ends manifest declaration. + * Always use this macro after @ref BEGIN_MANIFEST + */ +#define END_MANIFEST() \ + }); \ + return manifest; \ +} + +} + +#endif //_MANIFEST_H_ diff --git a/src/shogun/base/metaclass.h b/src/shogun/base/metaclass.h new file mode 100644 index 00000000000..8bff299ac41 --- /dev/null +++ b/src/shogun/base/metaclass.h @@ -0,0 +1,87 @@ +/* + * This software is distributed under BSD 3-clause license (see LICENSE file). + * + * Authors: Sergey Lisitsyn, Sanuj Sharma + */ + +#ifndef _META_CLASS_H_ +#define _META_CLASS_H_ + +#include +#include +#include + +#include + +namespace shogun +{ + /** @brief Metaclass provides an API to + * spawn shared-pointer-like objects of typename + * of a Metaclass object. + */ + template + class MetaClass + { + typedef std::function()> SpawnFunction; + + public: + /** Constructor + * @param sf Any object of SpawnFunction + */ + MetaClass(Any sf) : + spawn_function(any_cast(sf)) + { + } + + /** Copy Constructor + * @param other MetaClass object to be copied + */ + MetaClass(const MetaClass& other) : + spawn_function(other.spawn_function) + { + } + + /** Assignment operator + * @param other MetaClass object to be assigned + */ + MetaClass& operator=(const MetaClass& other) + { + spawn_function = other.spawn_function; + return *this; + } + + /** Destructor */ + ~MetaClass() + { + } + + /** Equality operator + * @param other MetaClass object + * @return true if both are equal + */ + bool operator==(const MetaClass& other) const + { + return true; + } + + /** Inequality operator + * @param other MetaClass object + * @return false if both are equal + */ + bool operator!=(const MetaClass& other) const + { + return !(*this == other); + } + + /** @return instance of typename of MetaClass object */ + Some instance() const + { + return spawn_function(); + } + + private: + const SpawnFunction spawn_function; + }; +} + +#endif //_META_CLASS_H_