From df2c44401f8dd736a903e73813e5f83fb15b36b6 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Wed, 5 Sep 2012 18:51:26 +0200 Subject: split away util, logger, and module made a liblogger adapted all tests --- include/logger/ConsoleLogSink.hpp | 14 ++ include/logger/FileLogSink.hpp | 23 ++++ include/logger/LogSink.hpp | 23 ++++ include/logger/Logger.hpp | 73 +++++++++++ include/logger/SyslogLogSink.hpp | 25 ++++ include/logger/WinDbgLogSink.hpp | 14 ++ include/module/ModuleLoader.hpp | 262 ++++++++++++++++++++++++++++++++++++++ include/module/ModuleRegistry.hpp | 190 +++++++++++++++++++++++++++ include/util/Exportable.hpp | 21 +++ include/util/NonCopyable.hpp | 24 ++++ include/util/Noreturn.hpp | 11 ++ include/util/ScopedPtr.hpp | 33 +++++ include/util/Singleton.hpp | 65 ++++++++++ include/util/TypeDetect.hpp | 15 +++ include/util/TypeInfo.hpp | 82 ++++++++++++ include/util/TypeList.hpp | 28 ++++ include/util/TypeTraits.hpp | 9 ++ 17 files changed, 912 insertions(+) create mode 100755 include/logger/ConsoleLogSink.hpp create mode 100755 include/logger/FileLogSink.hpp create mode 100755 include/logger/LogSink.hpp create mode 100755 include/logger/Logger.hpp create mode 100755 include/logger/SyslogLogSink.hpp create mode 100755 include/logger/WinDbgLogSink.hpp create mode 100755 include/module/ModuleLoader.hpp create mode 100755 include/module/ModuleRegistry.hpp create mode 100644 include/util/Exportable.hpp create mode 100755 include/util/NonCopyable.hpp create mode 100644 include/util/Noreturn.hpp create mode 100644 include/util/ScopedPtr.hpp create mode 100755 include/util/Singleton.hpp create mode 100644 include/util/TypeDetect.hpp create mode 100755 include/util/TypeInfo.hpp create mode 100644 include/util/TypeList.hpp create mode 100644 include/util/TypeTraits.hpp (limited to 'include') diff --git a/include/logger/ConsoleLogSink.hpp b/include/logger/ConsoleLogSink.hpp new file mode 100755 index 0000000..f700825 --- /dev/null +++ b/include/logger/ConsoleLogSink.hpp @@ -0,0 +1,14 @@ +#ifndef __CONSOLE_LOGSINK_H +#define __CONSOLE_LOGSINK_H + +#include "LogSink.hpp" + +class ConsoleLogSink : public LogSink +{ + public: + ConsoleLogSink( const LogLevel level ) : LogSink( level ) { } + + void log( const LogLevel level, const std::string &msg ); +}; + +#endif diff --git a/include/logger/FileLogSink.hpp b/include/logger/FileLogSink.hpp new file mode 100755 index 0000000..f488a87 --- /dev/null +++ b/include/logger/FileLogSink.hpp @@ -0,0 +1,23 @@ +#ifndef __FILE_LOGSINK_H +#define __FILE_LOGSINK_H + +#include "LogSink.hpp" + +#include +#include + +class FileLogSink : public LogSink +{ + public: + FileLogSink( const LogLevel level, const std::string &filename ); + + ~FileLogSink( ); + + void log( const LogLevel level, const std::string &msg ); + + private: + std::string m_filename; + std::ofstream m_file; +}; + +#endif diff --git a/include/logger/LogSink.hpp b/include/logger/LogSink.hpp new file mode 100755 index 0000000..322e546 --- /dev/null +++ b/include/logger/LogSink.hpp @@ -0,0 +1,23 @@ +#ifndef __LOGSINK_H +#define __LOGSINK_H + +#include "Logger.hpp" + +class LogSink +{ + public: + LogSink( const LogLevel level ) : m_level( level ) { } + + virtual ~LogSink( ) { } + + virtual void log( const LogLevel level, const std::string &msg ) = 0; + + void setReportingLevel( const LogLevel level ) { m_level = level; } + + LogLevel reportingLevel( ) { return m_level; } + + private: + LogLevel m_level; +}; + +#endif diff --git a/include/logger/Logger.hpp b/include/logger/Logger.hpp new file mode 100755 index 0000000..dc514ae --- /dev/null +++ b/include/logger/Logger.hpp @@ -0,0 +1,73 @@ +#ifndef __LOGGER_H +#define __LOGGER_H + +#include "Singleton.hpp" +#include "ScopedPtr.hpp" + +#include + +enum LogLevel { + logNONE, + logFATAL, + logCRITICAL, + logERROR, + logWARNING, + logNOTICE, + logINFO, + logDEBUG, + logDEBUG1, + logDEBUG2, + logDEBUG3, + logDEBUG4 +}; + +class LogSink; +class LoggerImpl; + +class Logger : public Singleton< Logger > +{ + public: + DECLARE_SINGLETON( Logger ) + + void addSink( LogSink *sink ); + void removeSink( LogSink *sink ); + void log( const LogLevel level, const std::string &msg ); + + static std::string toString( const LogLevel level ); + static LogLevel fromString( const std::string &s ); + + void openConsoleLog( const LogLevel level ); + void openFileLog( const LogLevel level, const std::string &filename ); + void openSyslog( const LogLevel level, const std::string &ident, const std::string &facility ); + void openWinDbgLog( const LogLevel level ); + + protected: + Logger( ); + virtual ~Logger( ); + + private: + scopedPtr< LoggerImpl > m_impl; +}; + +DEFINE_SINGLETON( Logger ) + +class LogStream : private noncopyable, public std::ostringstream +{ + public: + LogStream( Logger &logger, const LogLevel level ); + ~LogStream( ); + std::ostream &get( ); + + private: + LogStream( ); + LogStream( const LogStream & ); + LogStream &operator=( const LogStream &); + + private: + Logger &m_logger; + LogLevel m_level; +}; + +#define LOG( level ) LogStream( Logger::instance( ), level ).get( ) + +#endif diff --git a/include/logger/SyslogLogSink.hpp b/include/logger/SyslogLogSink.hpp new file mode 100755 index 0000000..64e52f1 --- /dev/null +++ b/include/logger/SyslogLogSink.hpp @@ -0,0 +1,25 @@ +#ifndef __SYSLOG_LOGSINK_H +#define __SYSLOG_LOGSINK_H + +#include "LogSink.hpp" + +#include + +class SyslogLogSink : public LogSink +{ + public: + SyslogLogSink( const LogLevel level, const std::string &ident, const std::string &facility ); + + ~SyslogLogSink( ); + + void log( const LogLevel level, const std::string &msg ); + + static int levelToSyslogLevel( const LogLevel level ); + static int facilityFromString( const std::string &facility ); + + private: + std::string m_ident; + std::string m_facility; +}; + +#endif diff --git a/include/logger/WinDbgLogSink.hpp b/include/logger/WinDbgLogSink.hpp new file mode 100755 index 0000000..f7caa86 --- /dev/null +++ b/include/logger/WinDbgLogSink.hpp @@ -0,0 +1,14 @@ +#ifndef __WINDBG_LOGSINK_H +#define __WINDBG_LOGSINK_H + +#include "LogSink.hpp" + +class WinDbgLogSink : public LogSink +{ + public: + WinDbgLogSink( const LogLevel level ) : LogSink( level ) { } + + void log( const LogLevel level, const std::string &msg ); +}; + +#endif 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 +#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" + +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 > mapType; + + protected: + + mapType m_modules; + + public: + + BaseModuleLoader( const std::vector files ) + { + Module< Interface, CtorParams> m; + + for( std::vector::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 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 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 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 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 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 diff --git a/include/module/ModuleRegistry.hpp b/include/module/ModuleRegistry.hpp new file mode 100755 index 0000000..e217092 --- /dev/null +++ b/include/module/ModuleRegistry.hpp @@ -0,0 +1,190 @@ +#ifndef __MODULEINTERFACE_H +#define __MODULEINTERFACE_H + +#include + +#include "TypeList.hpp" + +template< typename Interface, typename CtorParams = NullType > +struct ModuleRegistry; + +template< typename Interface> +struct ModuleRegistry< Interface > { + std::string name; + Interface *(*create)( ); + void (*destroy)( Interface *obj ); + + ModuleRegistry( std::string _name, Interface *(*_create)( ), + void (*_destroy)( Interface *obj ) ) + : name( _name ), create( _create ), destroy( _destroy ) + { + } +}; + +template< typename Interface, typename P1 > +struct ModuleRegistry< Interface, TYPELIST_1( P1 ) > { + std::string name; + Interface *(*create)( P1 ); + void (*destroy)( Interface *obj ); + + ModuleRegistry( std::string _name, Interface *(*_create)( P1 ), + void (*_destroy)( Interface *obj ) ) + : name( _name ), create( _create ), destroy( _destroy ) + { + } +}; + +template< typename Interface, typename P1, typename P2 > +struct ModuleRegistry< Interface, TYPELIST_2( P1, P2 ) > { + std::string name; + Interface *(*create)( P1, P2 ); + void (*destroy)( Interface *obj ); + + ModuleRegistry( std::string _name, Interface *(*_create)( P1, P2 ), + void (*_destroy)( Interface *obj ) ) + : name( _name ), create( _create ), destroy( _destroy ) + { + } +}; + +template< typename Interface, typename P1, typename P2, typename P3 > +struct ModuleRegistry< Interface, TYPELIST_3( P1, P2, P3 ) > { + std::string name; + Interface *(*create)( P1, P2, P3 ); + void (*destroy)( Interface *obj ); + + ModuleRegistry( std::string _name, Interface *(*_create)( P1, P2, P3 ), + void (*_destroy)( Interface *obj ) ) + : name( _name ), create( _create ), destroy( _destroy ) + { + } +}; + +template< typename Interface, typename P1, typename P2, typename P3, typename P4 > +struct ModuleRegistry< Interface, TYPELIST_4( P1, P2, P3, P4 ) > { + std::string name; + Interface *(*create)( P1, P2, P3, P4 ); + void (*destroy)( Interface *obj ); + + ModuleRegistry( std::string _name, Interface *(*_create)( P1, P2, P3, P4 ), + void (*_destroy)( Interface *obj ) ) + : name( _name ), create( _create ), destroy( _destroy ) + { + } +}; + +#ifdef SHARED + +#ifndef _WIN32 +#define DLLEXPORT +#else +#define DLLEXPORT __declspec( dllexport ) +#endif + +// no param macro + +#define DECLARE_MODULE( baseClass ) \ + extern "C" DLLEXPORT ModuleRegistry registry ## _ ## baseClass; + +#define REGISTER_MODULE( name, baseClass, subClass ) \ +static baseClass *create( ) \ +{ \ + return new subClass( ); \ +} \ + \ +static void destroy( baseClass *obj ) \ +{ \ + delete obj; \ +} \ + \ +ModuleRegistry registry ## _ ## baseClass( name, &create, &destroy ); + +// 1 param macro + +#define DECLARE_MODULE_1( baseClass, T1 ) \ + extern "C" DLLEXPORT ModuleRegistry registry ## _ ## baseClass; + +#define REGISTER_MODULE_1( name, baseClass, subClass, T1 ) \ +static baseClass *create( T1 t1 ) \ +{ \ + return new subClass( t1 ); \ +} \ + \ +static void destroy( baseClass *obj ) \ +{ \ + delete obj; \ +} \ + \ +ModuleRegistry registry ## _ ## baseClass( name, &create, &destroy ); + +// 2 param macro + +#define DECLARE_MODULE_2( baseClass, T1, T2 ) \ + extern "C" DLLEXPORT ModuleRegistry registry ## _ ## baseClass; + +#define REGISTER_MODULE_2( name, baseClass, subClass, T1, T2 ) \ +static baseClass *create( T1 t1, T2 t2 ) \ +{ \ + return new subClass( t1, t2 ); \ +} \ + \ +static void destroy( baseClass *obj ) \ +{ \ + delete obj; \ +} \ + \ +ModuleRegistry registry ## _ ## baseClass( name, &create, &destroy ); + +// 3 param macro + +#define DECLARE_MODULE_3( baseClass, T1, T2, T3 ) \ + extern "C" DLLEXPORT ModuleRegistry registry ## _ ## baseClass; + +#define REGISTER_MODULE_3( name, baseClass, subClass, T1, T2, T3 ) \ +static baseClass *create( T1 t1, T2 t2, T3 t3 ) \ +{ \ + return new subClass( t1, t2, t3 ); \ +} \ + \ +static void destroy( baseClass *obj ) \ +{ \ + delete obj; \ +} \ + \ +ModuleRegistry registry ## _ ## baseClass( name, &create, &destroy ); + +// 4 param macro + +#define DECLARE_MODULE_4( baseClass, T1, T2, T3, T4 ) \ + extern "C" DLLEXPORT ModuleRegistry registry ## _ ## baseClass; + +#define REGISTER_MODULE_4( name, baseClass, subClass, T1, T2, T3, T4 ) \ +static baseClass *create( T1 t1, T2 t2, T3 t3, T4 t4 ) \ +{ \ + return new subClass( t1, t2, t3, t4 ); \ +} \ + \ +static void destroy( baseClass *obj ) \ +{ \ + delete obj; \ +} \ + \ +ModuleRegistry registry ## _ ## baseClass( name, &create, &destroy ); + +#else // SHARED + +#define DECLARE_MODULE( baseClass ) +#define DECLARE_MODULE_1( baseClass, T1 ) +#define DECLARE_MODULE_2( baseClass, T1, T2 ) +#define DECLARE_MODULE_3( baseClass, T1, T2, T3 ) +#define DECLARE_MODULE_4( baseClass, T1, T2, T3, T4 ) + +#define REGISTER_MODULE( name, baseClass, subClass ) +#define REGISTER_MODULE_1( name, baseClass, subClass, T1 ) +#define REGISTER_MODULE_2( name, baseClass, subClass, T1, T2 ) +#define REGISTER_MODULE_3( name, baseClass, subClass, T1, T2, T3 ) +#define REGISTER_MODULE_4( name, baseClass, subClass, T1, T2, T3, T4 ) + +#endif // SHARED + +#endif // __MODULEINTERFACE_H diff --git a/include/util/Exportable.hpp b/include/util/Exportable.hpp new file mode 100644 index 0000000..28ac7ff --- /dev/null +++ b/include/util/Exportable.hpp @@ -0,0 +1,21 @@ +#ifndef __EXPORTABLE_H +#define __EXPORTABLE_H + +#ifndef _WIN32 + +#define SINGLETON_EXPORT +#define SINGLETON_EXTERN + +#else + +#ifndef SHARED +#define SINGLETON_EXPORT __declspec(dllexport) +#define SINGLETON_EXTERN +#else +#define SINGLETON_EXPORT __declspec(dllimport) +#define SINGLETON_EXTERN extern +#endif + +#endif // _WIN32 + +#endif diff --git a/include/util/NonCopyable.hpp b/include/util/NonCopyable.hpp new file mode 100755 index 0000000..44d1a93 --- /dev/null +++ b/include/util/NonCopyable.hpp @@ -0,0 +1,24 @@ +#ifndef __NONCOPYABLE_H +#define __NONCOPYABLE_H + +#include "Exportable.hpp" + +namespace __dont_touch +{ + +class SINGLETON_EXPORT noncopyable +{ + protected: + noncopyable( ) { } + ~noncopyable( ) { } + + private: + noncopyable( const noncopyable & ); + const noncopyable & operator=( const noncopyable & ); +}; + +} + +typedef __dont_touch::noncopyable noncopyable; + +#endif diff --git a/include/util/Noreturn.hpp b/include/util/Noreturn.hpp new file mode 100644 index 0000000..9f9862c --- /dev/null +++ b/include/util/Noreturn.hpp @@ -0,0 +1,11 @@ +#ifndef __NORETURN_H_ +#define __NORETURN_H + +#ifdef __GNUC__ +#define CRAWLER_NORETURN __attribute__((noreturn)) +#else +#define CRAWLER_NORETURN +#endif + +#endif + diff --git a/include/util/ScopedPtr.hpp b/include/util/ScopedPtr.hpp new file mode 100644 index 0000000..19a41d2 --- /dev/null +++ b/include/util/ScopedPtr.hpp @@ -0,0 +1,33 @@ +#ifndef __SCOPEDPTR_H +#define __SCOPEDPTR_H + +#include "NonCopyable.hpp" + +template< typename T > +class scopedPtr : private noncopyable +{ + public: + explicit scopedPtr( T *p = 0 ) : m_p( p ) { } + + ~scopedPtr( ) { delete m_p; } + + T& operator*( ) const { return *m_p; } + T* operator->( ) const { return m_p; } + T* get( ) const { return m_p; } + + bool operator==( const T* p ) const { return m_p == p; } + bool operator!=( const T* p ) const { return m_p != p; } + + void reset( T *p = 0 ) + { + if( m_p != p ) { + delete m_p; + m_p = p; + } + } + + private: + T *m_p; +}; + +#endif diff --git a/include/util/Singleton.hpp b/include/util/Singleton.hpp new file mode 100755 index 0000000..1bfb460 --- /dev/null +++ b/include/util/Singleton.hpp @@ -0,0 +1,65 @@ +#ifndef __SINGLETON_H +#define __SINGLETON_H + +#include "ScopedPtr.hpp" +#include "NonCopyable.hpp" +#include "Exportable.hpp" +#include "Noreturn.hpp" + +#include +#include + +#define DECLARE_SINGLETON( T ) \ + friend class scopedPtr< T >; \ + friend class Singleton< T >; + +#define DEFINE_SINGLETON( T ) \ + SINGLETON_EXTERN template class SINGLETON_EXPORT Singleton< T >; + +template< class T > +class Singleton : private noncopyable +{ + public: + static T& instance( ) + { + if( destroyed ) { + onDeadReference( ); + } + + if( t == 0 ) { + create( ); + } + + return *t; + } + + protected: + Singleton( ) + { + } + + virtual ~Singleton( ) + { + destroyed = true; + } + + private: + static void create( ) + { + t.reset( new T ); + } + + static void onDeadReference( ) CRAWLER_NORETURN + { + throw std::runtime_error( "singleton has already been destroyed!" ); + } + + static scopedPtr t; + static bool destroyed; +}; + +template< class T > scopedPtr Singleton::t( 0 ); +template< class T > bool Singleton::destroyed( false ); + +#endif + diff --git a/include/util/TypeDetect.hpp b/include/util/TypeDetect.hpp new file mode 100644 index 0000000..7db714b --- /dev/null +++ b/include/util/TypeDetect.hpp @@ -0,0 +1,15 @@ +#ifndef __TYPE_DETECTION_H +#define __TYPE_DETECTION_H + +#include "RewindInputStream.hpp" +#include "MIMEType.hpp" + +class TypeDetect +{ + public: + virtual ~TypeDetect( ) { }; + + virtual MIMEType detect( RewindInputStream *s ) = 0; +}; + +#endif diff --git a/include/util/TypeInfo.hpp b/include/util/TypeInfo.hpp new file mode 100755 index 0000000..3ca4b57 --- /dev/null +++ b/include/util/TypeInfo.hpp @@ -0,0 +1,82 @@ +#ifndef __TYPEINFO_H +#define __TYPEINFO_H + +#include +#include +#include +#include + +#if defined( __GNUG__ ) && defined( __GLIBCXX__ ) + +#include + +std::string demangle( const std::type_info &info ) +{ + enum { BUFLEN = 200 }; + char *buf; + std::size_t buflen = BUFLEN; + int status; + char *res; + + // pass a malloced buffer (required by cxa_demangle) + buf = (char *)malloc( BUFLEN ); + + // res may point to buf or be realloced depending on whether the + // demangling had enough space or not + res = __cxxabiv1::__cxa_demangle( info.name( ), buf, &buflen, &status ); + + // throw exception if this goes wrong, because we don't want to have + // have code reacting on failed demangling or wrong type information! + if( status != 0 || res == NULL ) { + throw std::runtime_error( "__cxa_demangle failed!" ); + } + + // construct string on stack and return it, free original buffer + std::string s( res ); + free( res ); + + return s; +} + +#else + +#ifdef _WIN32 + +// TODO: maybe extract into a generic stringutils module +void replaceAll( std::string &s, const std::string &from, const std::string &to ) +{ + if( from.empty( ) ) { + return; + } + + size_t pos = 0; + while( ( pos = s.find( from, pos ) ) != std::string::npos ) { + s.replace( pos, from.length( ), to ); + pos += to.length( ); + } +} + +std::string demangle( const std::type_info &info ) +{ + std::string name = info.name( ); + + // MSVC marks metatypes, nice, but gcc doesn't, falling + // back as we can't do the same for gcc + replaceAll( name, "class ", "" ); + // TODO: much more to follow, this is currently just enough + // for the module registry structure with base class + // signature only + + return name; +} + +#else + +#error "type.name() demangling not implemented!" + +#endif // _WIN32 + + +#endif // defined( __GNUG__ ) && defined( __GLIBCXX__ ) + +#endif // __TYPEINFO_H diff --git a/include/util/TypeList.hpp b/include/util/TypeList.hpp new file mode 100644 index 0000000..bc8c49b --- /dev/null +++ b/include/util/TypeList.hpp @@ -0,0 +1,28 @@ +#ifndef __TYPELIST_H +#define __TYPELIST_H + +class NullType {}; + +template< class T, class U > +struct TypeList { + typedef T Head; + typedef U Tail; +}; + +#define TYPELIST_1( T1 ) TypeList< T1, NullType > +#define TYPELIST_2( T1, T2 ) TypeList< T1, TYPELIST_1( T2 ) > +#define TYPELIST_3( T1, T2, T3 ) TypeList< T1, TYPELIST_2( T2, T3 ) > +#define TYPELIST_4( T1, T2, T3, T4 ) TypeList< T1, TYPELIST_3( T2, T3, T4 ) > + +template< class T> struct Length; +template< > struct Length< NullType > +{ + enum { value = 0 }; +}; +template< class T, class U > +struct Length< TypeList< T, U > > +{ + enum { value = 1 + Length< U >::value }; +}; + +#endif diff --git a/include/util/TypeTraits.hpp b/include/util/TypeTraits.hpp new file mode 100644 index 0000000..b01051e --- /dev/null +++ b/include/util/TypeTraits.hpp @@ -0,0 +1,9 @@ +#ifndef __TYPETRAITS_H +#define __TYPETRAITS_H + +template< typename T > +class TypeTraits { + typedef typename +}; + +#endif -- cgit v1.2.3-54-g00ecf