[Misc] QskMeta classes improved

This commit is contained in:
Uwe Rathmann 2018-03-01 12:18:58 +01:00
parent 02639e5d04
commit 3079698d63
6 changed files with 126 additions and 138 deletions

View File

@ -87,29 +87,6 @@ protected:
QskMetaInvokable* invokable() const;
private:
template< typename T, typename F >
static inline QskMetaInvokable* findInvokable( F function )
{
QskMetaInvokable* invokable;
#if QSK_SHARED_META_INVOKABLE
invokable = QskMetaInvokable::find( typeid( T ) );
if ( invokable )
{
invokable->ref();
}
else
{
invokable = new T( function );
QskMetaInvokable::insert( typeid( T ), invokable );
}
#else
invokable = new T( function );
#endif
return invokable;
}
QskMetaInvokable* m_invokable;
const int* m_parameterTypes;
};
@ -133,10 +110,12 @@ inline QskMetaFunction::QskMetaFunction( T function )
const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
using Invokable = QskMetaMemberInvokable< T, Args, void >;
init( findInvokable<Invokable>( function ),
ConnectionTypes< typename Traits::Arguments >::types() );
auto invokable = QskMetaInvokable::instance(
QskMetaMemberInvokable< T, Args, void >::invoke,
reinterpret_cast< void** >( &function ) );
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
}
template< typename T, QskMetaFunctionTraits::IsFunction< T >* >
@ -148,10 +127,12 @@ inline QskMetaFunction::QskMetaFunction( T function )
const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
using Invokable = QskMetaFunctionInvokable< T, Args, void >;
init( findInvokable<Invokable>( function ),
ConnectionTypes< typename Traits::Arguments >::types() );
auto invokable = QskMetaInvokable::instance(
QskMetaFunctionInvokable< T, Args, void >::invoke,
reinterpret_cast< void** >( &function ) );
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
}
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* >
@ -163,10 +144,12 @@ inline QskMetaFunction::QskMetaFunction( T functor )
const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
using Invokable = QskMetaFunctorInvokable< T, Argc, Args, void >;
init( findInvokable<Invokable>( functor ),
ConnectionTypes< typename Traits::Arguments >::types() );
auto invokable = QskMetaInvokable::instance(
QskMetaFunctorInvokable< T, Argc, Args, void >::invoke,
reinterpret_cast< void** >( &functor ) );
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
}
Q_DECLARE_METATYPE( QskMetaFunction )

View File

@ -18,6 +18,27 @@ namespace
"Bad cast: QskMetaInvokable does not match" );
}
QskMetaInvokable* QskMetaInvokable::instance(
InvokeFunction invoke, void** functor )
{
/*
In opposite to QObject::connect we share the Invokable for callbacks to the same
function/functor - like f.e QQuickItem::update(). But we have to pay an extra static
pointer inside of each callback instance.
*/
QskMetaInvokable* invokable;
void* args[] = { &invokable, functor };
invoke( Find, nullptr, nullptr, args, nullptr );
if ( invokable )
invokable->ref();
else
invoke( Create, nullptr, nullptr, args, nullptr );
return invokable;
}
int QskMetaInvokable::typeInfo() const
{
auto that = const_cast< QskMetaInvokable* >( this );
@ -35,28 +56,3 @@ int QskMetaInvokable::refCount() const
auto that = const_cast< QskMetaInvokable* >( this );
return reinterpret_cast< SlotObject* >( that )->ref.load();
}
#if QSK_SHARED_META_INVOKABLE
#include <unordered_map>
#include <typeindex>
static std::unordered_map< std::type_index, QskMetaInvokable* > qskInvokableTab;
QskMetaInvokable* QskMetaInvokable::find( const std::type_info& info )
{
const auto it = qskInvokableTab.find( info );
return ( it != qskInvokableTab.end() ) ? it->second : nullptr;
}
void QskMetaInvokable::insert( const std::type_info& info, QskMetaInvokable* invokable )
{
qskInvokableTab.emplace( info, invokable );
}
void QskMetaInvokable::remove( const std::type_info& info )
{
qskInvokableTab.erase( info );
}
#endif // QSK_SHARED_META_INVOKABLE

View File

@ -11,132 +11,133 @@
// helper classes for QskMetaFunction
#ifndef QT_NO_RTTI // we rely on hashing type_info
/*
When being enabled the same instance of QskMetaInvokable is used
for all QskMetaFunctions having the same function/method/functor -
f.e. &QQuickItem::update.
Not sure, why QObject::connect does not do the same and always
creates unique QSlotObjectBase objects for each connection.
*/
#ifndef QSK_SHARED_META_INVOKABLE
#define QSK_SHARED_META_INVOKABLE 1
#endif
#endif
class QSK_EXPORT QskMetaInvokable : public QtPrivate::QSlotObjectBase
{
public:
typedef void (* InvokeFunction)(
int which, QtPrivate::QSlotObjectBase*, QObject*, void**, bool* );
enum { TypeInfo = NumOperations + 1 };
enum
{
TypeInfo = NumOperations + 1,
Create,
Find
};
int typeInfo() const;
int refCount() const;
protected:
friend class QskMetaFunction;
static QskMetaInvokable* instance( InvokeFunction, void** function );
protected:
explicit QskMetaInvokable( InvokeFunction f ):
QSlotObjectBase( f )
{
}
#if QSK_SHARED_META_INVOKABLE
/*
To avoid having more QskMetaInvokables for the same
function we have a hash table, where they are registered
*/
static QskMetaInvokable* find( const std::type_info& info );
static void insert( const std::type_info&, QskMetaInvokable* );
static void remove( const std::type_info& );
#else
#endif
};
template< typename Function, typename Args, typename R >
class QskMetaFunctionInvokable : public QskMetaInvokable
{
public:
typedef QtPrivate::FunctionPointer< Function > FuncType;
using Invokable = QskMetaFunctionInvokable< Function, Args, R >;
explicit QskMetaFunctionInvokable( Function function ):
public:
explicit inline QskMetaFunctionInvokable( Function function ):
QskMetaInvokable( &invoke ),
m_function( function )
{
}
static void invoke(int which, QtPrivate::QSlotObjectBase* invokable,
static void invoke(int which, QtPrivate::QSlotObjectBase*,
QObject* object, void** args, bool* )
{
auto invokableFunction = static_cast< QskMetaFunctionInvokable* >( invokable );
static Invokable* invokable = nullptr;
switch ( which )
{
case Find:
{
*reinterpret_cast< void** >( args[0] ) = invokable;
break;
}
case Create:
{
invokable = new Invokable( *reinterpret_cast< Function* >( args[1] ) );
*reinterpret_cast< void** >( args[0] ) = invokable;
break;
}
case Destroy:
{
#if QSK_SHARE_INVOKABLES
remove( typeid( Function ) );
#endif
delete invokableFunction;
delete invokable;
invokable = nullptr;
break;
}
case Call:
{
typedef QtPrivate::FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >(
invokableFunction->m_function, object, args );
invokable->m_function, object, args );
break;
}
case TypeInfo:
{
int* typeInfo = reinterpret_cast< int* >( args );
*typeInfo = 1; // = QskMetaFunction::Function
*reinterpret_cast< int* >( args ) = 1; // QskMetaFunction::Function
break;
}
}
}
private:
Function m_function;
};
template< typename Function, typename Args, typename R >
class QskMetaMemberInvokable : public QskMetaInvokable
{
using Invokable = QskMetaMemberInvokable< Function, Args, R >;
public:
explicit QskMetaMemberInvokable( Function function ):
explicit inline QskMetaMemberInvokable( Function function ):
QskMetaInvokable( &invoke ),
m_function( function )
{
}
static void invoke( int which, QtPrivate::QSlotObjectBase* invokable,
static void invoke( int which, QtPrivate::QSlotObjectBase*,
QObject* object, void** args, bool* ret )
{
typedef QtPrivate::FunctionPointer< Function > FuncType;
auto invokableMember = static_cast< QskMetaMemberInvokable* >( invokable );
static Invokable* invokable = nullptr;
switch (which)
{
case Find:
{
*reinterpret_cast< void** >( args[0] ) = invokable;
break;
}
case Create:
{
invokable = new Invokable( *reinterpret_cast< Function* >( args[1] ) );
*reinterpret_cast< void** >( args[0] ) = invokable;
break;
}
case Destroy:
{
#if QSK_SHARE_INVOKABLES
remove( typeid( Function ) );
#endif
delete invokableMember;
delete invokable;
invokable = nullptr;
break;
}
case Call:
{
typedef QtPrivate::FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >(
invokableMember->m_function,
invokable->m_function,
static_cast< typename FuncType::Object* >( object ), args );
break;
@ -144,14 +145,12 @@ public:
case Compare:
{
const auto function = *reinterpret_cast< Function* >( args );
*ret = function == invokableMember->m_function;
*ret = function == invokable->m_function;
break;
}
case TypeInfo:
{
int* typeInfo = reinterpret_cast< int* >( args );
*typeInfo = 0; // = QskMetaFunction::Member
*reinterpret_cast< int* >( args ) = 0; // = QskMetaFunction::Member
break;
}
}
@ -164,42 +163,52 @@ private:
template< typename Function, int N, typename Args, typename R >
class QskMetaFunctorInvokable : public QskMetaInvokable
{
public:
typedef QtPrivate::Functor< Function, N > FuncType;
using Invokable = QskMetaFunctorInvokable< Function, N, Args, R >;
explicit QskMetaFunctorInvokable( Function function ):
public:
explicit inline QskMetaFunctorInvokable( Function function ):
QskMetaInvokable( &invoke ),
m_function( std::move( function ) )
m_function( function )
{
}
static void invoke( int which, QSlotObjectBase* invokable,
QObject* object, void** args, bool* )
static void invoke( int which, QSlotObjectBase*, QObject* object, void** args, bool* )
{
auto invokableFunctor = static_cast< QskMetaFunctorInvokable* >( invokable );
static Invokable* invokable = nullptr;
switch (which)
{
case Find:
{
*reinterpret_cast< void** >( args[0] ) = invokable;
break;
}
case Create:
{
invokable = new Invokable( *reinterpret_cast< Function* >( args[1] ) );
*reinterpret_cast< void** >( args[0] ) = invokable;
break;
}
case Destroy:
{
#if QSK_SHARE_INVOKABLES
remove( typeid( Function ) );
#endif
delete invokableFunctor;
delete invokable;
invokable = nullptr;
break;
}
case Call:
{
typedef QtPrivate::Functor< Function, N > FuncType;
FuncType::template call< Args, R >(
invokableFunctor->m_function, object, args );
invokable->m_function, object, args );
break;
}
case TypeInfo:
{
int* typeInfo = reinterpret_cast< int* >( args );
*typeInfo = 2; // QskMetaFunction::Functor;
*reinterpret_cast< int* >( args ) = 2; // QskMetaFunction::Functor
break;
}
}