Skip to content

Commit

Permalink
Primitives for plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
lisitsyn committed Apr 15, 2018
1 parent 844249b commit 88f9cb7
Show file tree
Hide file tree
Showing 5 changed files with 482 additions and 0 deletions.
104 changes: 104 additions & 0 deletions 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 <shogun/base/library.h>
#include <shogun/lib/common.h>

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 <typename T>
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<LibraryHandle>(filename))
{
}

Library::Library(const Library& other) :
m_handle(Some<LibraryHandle>(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<LibraryHandle> first_handle = first.m_handle;
Some<LibraryHandle> 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>(manifest_accessor_name);
}

Library load_library(const std::string& filename)
{
return Library(filename);
}

const char* Library::manifest_accessor_name = "shogunManifest";

}
86 changes: 86 additions & 0 deletions 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 <shogun/base/manifest.h>
#include <shogun/base/SGObject.h>
#include <string>
#include <dlfcn.h>

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<LibraryHandle> 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_
77 changes: 77 additions & 0 deletions 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 <shogun/base/manifest.h>
#include <shogun/io/SGIO.h>

#include <unordered_map>

namespace shogun
{

class Manifest::Self
{
public:
std::string description;
std::unordered_map<std::string, Any> classes;
};

Manifest::Manifest(const std::string& description,
const std::initializer_list<std::pair<std::string,Any>> 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);
}

}
128 changes: 128 additions & 0 deletions 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 <shogun/base/metaclass.h>
#include <shogun/base/unique.h>
#include <shogun/base/some.h>

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<std::pair<std::string,Any>> 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 <typename T>
MetaClass<T> class_by_name(const std::string& name) const
{
Any clazz = find_class(name);
return any_cast<MetaClass<T>>(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> 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<BASE_CLASSNAME>(erase_type( \
std::function<Some<BASE_CLASSNAME>()>( \
[]() -> Some<BASE_CLASSNAME> \
{ \
return Some<BASE_CLASSNAME>(new CLASSNAME); \
} \
))))), \

/** Ends manifest declaration.
* Always use this macro after @ref BEGIN_MANIFEST
*/
#define END_MANIFEST() \
}); \
return manifest; \
}

}

#endif //_MANIFEST_H_

0 comments on commit 88f9cb7

Please sign in to comment.