summaryrefslogtreecommitdiff
path: root/include/module/ModuleLoader.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/module/ModuleLoader.hpp')
-rwxr-xr-xinclude/module/ModuleLoader.hpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/include/module/ModuleLoader.hpp b/include/module/ModuleLoader.hpp
new file mode 100755
index 0000000..a5416bb
--- /dev/null
+++ b/include/module/ModuleLoader.hpp
@@ -0,0 +1,262 @@
+#ifndef __MODULELOADER_H
+#define __MODULELOADER_H
+
+#include <vector>
+#include <map>
+#include <string>
+#include <stdexcept>
+#include <typeinfo>
+#include <sstream>
+
+#ifndef _WIN32
+#include <dlfcn.h>
+#else
+#define WIN32_MEAN_AND_LEAN
+#include <windows.h>
+#include "win32/errormsg.hpp"
+#endif
+
+#include "ModuleRegistry.hpp"
+
+#include "TypeList.hpp"
+#include "TypeInfo.hpp"
+
+template< typename Interface, typename CtorParams = NullType >
+struct Module {
+#ifndef _WIN32
+ void *handle;
+#else
+ HMODULE handle;
+#endif
+ ModuleRegistry< Interface, CtorParams > *registry;
+};
+
+template< typename Interface, typename CtorParams = NullType >
+class BaseModuleLoader {
+
+ public:
+
+ typedef typename std::map<std::string, Module< Interface, CtorParams > > mapType;
+
+ protected:
+
+ mapType m_modules;
+
+ public:
+
+ BaseModuleLoader( const std::vector<std::string> files )
+ {
+ Module< Interface, CtorParams> m;
+
+ for( std::vector<std::string>::const_iterator it = files.begin( ); it != files.end( ); it++ ) {
+#ifndef _WIN32
+ m.handle = dlopen( it->c_str( ), RTLD_NOW );
+#else
+ m.handle = LoadLibrary( it->c_str( ) );
+#endif
+ if( !m.handle ) {
+#ifndef _WIN32
+ throw std::runtime_error( dlerror( ) );
+#else
+ std::ostringstream ss;
+ ss << "Module '" << *it << "' loading error: " << getLastError( );
+ throw std::runtime_error( ss.str( ) );
+#endif
+ }
+
+ std::string registryName = "registry_" + demangle( typeid( Interface ) );
+
+#ifndef _WIN32
+ m.registry = static_cast< ModuleRegistry< Interface, CtorParams > *>( dlsym( m.handle, registryName.c_str( ) ) );
+#else
+ m.registry = ( ModuleRegistry< Interface, CtorParams > *)( GetProcAddress( m.handle, registryName.c_str( ) ) );
+#endif
+ if( !m.registry ) {
+#ifndef _WIN32
+ dlclose( m.handle );
+#else
+ (void)FreeLibrary( m.handle );
+#endif
+ throw std::runtime_error( "missing module registry" );
+ }
+
+ m_modules.insert( std::make_pair( m.registry->name, m ) );
+ }
+ }
+
+ virtual ~BaseModuleLoader< Interface, CtorParams >( )
+ {
+ for( typename mapType::iterator it = m_modules.begin( ); it != m_modules.end( ); it++ ) {
+ if( (*it).second.handle ) {
+#ifndef _WIN32
+ dlclose( (*it).second.handle );
+#else
+ (void)FreeLibrary( (*it).second.handle );
+#endif
+ (*it).second.handle = 0;
+ }
+ }
+ }
+
+ void destroy( Interface *obj )
+ {
+ std::string clazz = demangle( typeid( *obj ) );
+
+ typename mapType::const_iterator it = m_modules.find( clazz );
+ if( it == m_modules.end( ) ) {
+ throw std::runtime_error( "calling unknown destructor" );
+ }
+
+ (*it).second.registry->destroy( obj );
+ }
+};
+
+template< typename Interface, typename CtorParams = NullType >
+class ModuleLoader;
+
+// no param
+
+template< typename Interface >
+class ModuleLoader< Interface, NullType > : public BaseModuleLoader< Interface, NullType >
+{
+ public:
+
+ ModuleLoader< Interface >( const std::vector<std::string> files )
+ : BaseModuleLoader< Interface >(files ) { }
+
+ Interface *create( std::string subclass )
+ {
+ typename BaseModuleLoader< Interface >::mapType::const_iterator it = BaseModuleLoader< Interface >::m_modules.find( subclass );
+ if( it == BaseModuleLoader< Interface >::m_modules.end( ) ) {
+ std::ostringstream ss;
+ ss << "calling unknown constructor for class '" << subclass << "'";
+ throw std::runtime_error( ss.str( ) );
+ }
+
+ Interface *obj = (*it).second.registry->create( );
+
+ std::string clazz = demangle( typeid( *obj ) );
+
+ BaseModuleLoader< Interface >::m_modules.insert( std::make_pair( clazz, (*it).second ) );
+
+ return obj;
+ }
+};
+
+// one param
+
+template< typename Interface, typename T1 >
+class ModuleLoader< Interface, TYPELIST_1( T1 ) > : public BaseModuleLoader< Interface, TYPELIST_1( T1 ) >
+{
+ public:
+
+ ModuleLoader< Interface, TYPELIST_1( T1 ) >( const std::vector<std::string> files )
+ : BaseModuleLoader< Interface, TYPELIST_1( T1 ) >( files ) { }
+
+ Interface *create( std::string subclass, T1 t1 )
+ {
+ typename BaseModuleLoader< Interface, TYPELIST_1( T1 ) >::mapType::const_iterator it = BaseModuleLoader< Interface, TYPELIST_1( T1 ) >::m_modules.find( subclass );
+ if( it == BaseModuleLoader< Interface, TYPELIST_1( T1 ) >::m_modules.end( ) ) {
+ std::ostringstream ss;
+ ss << "calling unknown constructor for class '" << subclass << "'";
+ throw std::runtime_error( ss.str( ) );
+ }
+
+ Interface *obj = (*it).second.registry->create( t1 );
+
+ std::string clazz = demangle( typeid( *obj ) );
+
+ BaseModuleLoader< Interface, TYPELIST_1( T1 ) >::m_modules.insert( std::make_pair( clazz, (*it).second ) );
+
+ return obj;
+ }
+};
+
+// two params
+
+template< typename Interface, typename T1, typename T2 >
+class ModuleLoader< Interface, TYPELIST_2( T1, T2 ) > : public BaseModuleLoader< Interface, TYPELIST_2( T1, T2 ) >
+{
+ public:
+
+ ModuleLoader< Interface, TYPELIST_2( T1, T2 ) >( const std::vector<std::string> files )
+ : BaseModuleLoader< Interface, TYPELIST_2( T1, T2 ) >( files ) { }
+
+ Interface *create( std::string subclass, T1 t1, T2 t2 )
+ {
+ typename BaseModuleLoader< Interface, TYPELIST_2( T1, T2 ) >::mapType::const_iterator it = BaseModuleLoader< Interface, TYPELIST_2( T1, T2 ) >::m_modules.find( subclass );
+ if( it == BaseModuleLoader< Interface, TYPELIST_2( T1, T2 ) >::m_modules.end( ) ) {
+ std::ostringstream ss;
+ ss << "calling unknown constructor for class '" << subclass << "'";
+ throw std::runtime_error( ss.str( ) );
+ }
+
+ Interface *obj = (*it).second.registry->create( t1, t2 );
+
+ std::string clazz = demangle( typeid( *obj ) );
+
+ BaseModuleLoader< Interface, TYPELIST_2( T1, T2 ) >::m_modules.insert( std::make_pair( clazz, (*it).second ) );
+
+ return obj;
+ }
+};
+
+// three params
+
+template< typename Interface, typename T1, typename T2, typename T3 >
+class ModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) > : public BaseModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) >
+{
+ public:
+
+ ModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) >( const std::vector<std::string> files )
+ : BaseModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) >( files ) { }
+
+ Interface *create( std::string subclass, T1 t1, T2 t2, T3 t3 )
+ {
+ typename BaseModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) >::mapType::const_iterator it = BaseModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) >::m_modules.find( subclass );
+ if( it == BaseModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) >::m_modules.end( ) ) {
+ std::ostringstream ss;
+ ss << "calling unknown constructor for class '" << subclass << "'";
+ throw std::runtime_error( ss.str( ) );
+ }
+
+ Interface *obj = (*it).second.registry->create( t1, t2, t3 );
+
+ std::string clazz = demangle( typeid( *obj ) );
+
+ BaseModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) >::m_modules.insert( std::make_pair( clazz, (*it).second ) );
+
+ return obj;
+ }
+};
+
+// four params
+
+template< typename Interface, typename T1, typename T2, typename T3, typename T4 >
+class ModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) > : public BaseModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >
+{
+ public:
+
+ ModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >( const std::vector<std::string> files )
+ : BaseModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >( files ) { }
+
+ Interface *create( std::string subclass, T1 t1, T2 t2, T3 t3, T4 t4 )
+ {
+ typename BaseModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >::mapType::const_iterator it = BaseModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >::m_modules.find( subclass );
+ if( it == BaseModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >::m_modules.end( ) ) {
+ std::ostringstream ss;
+ ss << "calling unknown constructor for class '" << subclass << "'";
+ throw std::runtime_error( ss.str( ) );
+ }
+
+ Interface *obj = (*it).second.registry->create( t1, t2, t3, t4 );
+
+ std::string clazz = demangle( typeid( *obj ) );
+
+ BaseModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >::m_modules.insert( std::make_pair( clazz, (*it).second ) );
+
+ return obj;
+ }
+};
+
+#endif