#ifndef __MODULELOADER_H #define __MODULELOADER_H #include #include #include #include #include #include #include #ifndef _WIN32 #include #else #define WIN32_MEAN_AND_LEAN #include #include "win32/errormsg.hpp" #endif #include "ModuleRegistry.hpp" #include "TypeList.hpp" #include "TypeInfo.hpp" #ifndef _WIN32 typedef void * ModuleHandle; #else typedef HMODULE ModuleHandle; #endif template< typename Interface, typename CtorParams = NullType > struct Module { ModuleHandle handle; void *user_data; ModuleRegistry< Interface, CtorParams > *registry; Module( ) : handle( 0 ), user_data( 0 ), registry( 0 ) {} Module( const Module &m ) : handle( m.handle ), user_data( m.user_data ), registry( m.registry ) {} Module &operator=( Module m ) { handle = m.handle; user_data = m.user_data; registry = m.registry; } }; static size_t nofDeferredModules = 0; static size_t sizeofDeferredModules = 0; static ModuleHandle* deferredModules = 0; const int CLOSE_ON_DTOR = 0; const int CLOSE_DEFERRED = 1; const int DEFAULT_FLAGS = CLOSE_ON_DTOR; static void deferredClose( void ) { for( size_t i = 0; i < nofDeferredModules; i++ ) { if( deferredModules[i] ) { #ifndef _WIN32 dlclose( deferredModules[i] ); #else (void)FreeLibrary( deferredModules[i] ); #endif deferredModules[i] = 0; } } free( deferredModules ); } template< typename Interface, typename CtorParams = NullType > class BaseModuleLoader { public: typedef typename std::map > mapType; protected: mapType m_modules; int m_flags; public: BaseModuleLoader( const std::vector files, int flags = DEFAULT_FLAGS, void *user_data = 0 ) : m_flags( flags ) { for( std::vector::const_iterator it = files.begin( ); it != files.end( ); it++ ) { Module< Interface, CtorParams> m; #ifndef _WIN32 m.handle = dlopen( it->c_str( ), RTLD_NOW | RTLD_LOCAL ); #else m.handle = LoadLibrary( it->c_str( ) ); #endif if( !m.handle ) { std::ostringstream ss; #ifndef _WIN32 ss << "Module '" << *it << "' loading error: " << dlerror( ); #else ss << "Module '" << *it << "' loading error: " << getLastError( ); #endif throw std::runtime_error( ss.str( ) ); } 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" ); } if( m.registry->initModule != 0 ) { m.registry->initModule( user_data ); } m.user_data = user_data; m_modules.insert( std::make_pair( std::string( m.registry->name ), m ) ); } } virtual ~BaseModuleLoader< Interface, CtorParams >( ) { // KLUDGE: we (ab)use the list of modules to remember the destructors // of derived classes to be called, This should be changed.. // So we inspect only the being of the module list here. typename mapType::iterator it = m_modules.begin( ); if( it == m_modules.end( ) ) return; if( (*it).second.registry ) { if( (*it).second.registry->destroyModule != 0 ) { (*it).second.registry->destroyModule( (*it).second.user_data ); } } if( (*it).second.handle ) { if( m_flags & CLOSE_DEFERRED ) { if( nofDeferredModules == 0 ) { atexit( &deferredClose ); } if( nofDeferredModules + 1 >= sizeofDeferredModules ) { sizeofDeferredModules = ( sizeofDeferredModules + 1 ) * 2; deferredModules = (ModuleHandle *)realloc( deferredModules, sizeofDeferredModules * sizeof( ModuleHandle * ) ); deferredModules[nofDeferredModules++] = (*it).second.handle; } } else { #ifndef _WIN32 dlclose( (*it).second.handle ); #else (void)FreeLibrary( (*it).second.handle ); #endif } } } 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 ); } }; // TODO: later: variadic template, too soon to be supported everywhere.. 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 files, int flags = DEFAULT_FLAGS, void *user_data = 0 ) : BaseModuleLoader< Interface >( files, flags, user_data ) { } 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 files, int flags = DEFAULT_FLAGS, void *user_data = 0 ) : BaseModuleLoader< Interface, TYPELIST_1( T1 ) >( files, flags, user_data ) { } 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 ) ); (void)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 files, int flags = DEFAULT_FLAGS, void *user_data = 0 ) : BaseModuleLoader< Interface, TYPELIST_2( T1, T2 ) >( files, flags, user_data ) { } 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 ) ); (void)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 files, int flags = DEFAULT_FLAGS, void *user_data = 0 ) : BaseModuleLoader< Interface, TYPELIST_3( T1, T2, T3 ) >( files, flags, user_data ) { } 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 ) ); (void)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 files, int flags = DEFAULT_FLAGS, void *user_data = 0 ) : BaseModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >( files, flags, user_data ) { } 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 ) ); (void)BaseModuleLoader< Interface, TYPELIST_4( T1, T2, T3, T4 ) >::m_modules.insert( std::make_pair( clazz, (*it).second ) ); return obj; } }; #endif