diff options
Diffstat (limited to 'include/module/ModuleLoader.hpp')
-rwxr-xr-x | include/module/ModuleLoader.hpp | 262 |
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 |