[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

@ -100,12 +100,12 @@ inline Qt::ConnectionType QskMetaCallback::connectionType() const
} }
QSK_EXPORT void qskInvokeMethod( QSK_EXPORT void qskInvokeMethod(
QObject* object, const QMetaMethod&, void* args[], QObject* object, const QMetaMethod&, void* args[],
Qt::ConnectionType = Qt::AutoConnection ); Qt::ConnectionType = Qt::AutoConnection );
QSK_EXPORT void qskInvokeMethod( QSK_EXPORT void qskInvokeMethod(
QObject* object, const QMetaObject*, int methodIndex, void* args[], QObject* object, const QMetaObject*, int methodIndex, void* args[],
Qt::ConnectionType = Qt::AutoConnection ); Qt::ConnectionType = Qt::AutoConnection );
Q_DECLARE_METATYPE( QskMetaCallback ) Q_DECLARE_METATYPE( QskMetaCallback )

View File

@ -109,7 +109,7 @@ size_t QskMetaFunction::parameterCount() const
{ {
if ( m_parameterTypes ) if ( m_parameterTypes )
{ {
for ( int i = 1; ; i++ ) for ( int i = 1;; i++ )
{ {
if ( m_parameterTypes[ i ] == QMetaType::UnknownType ) if ( m_parameterTypes[ i ] == QMetaType::UnknownType )
return i + 1; // including the return type return i + 1; // including the return type

View File

@ -87,29 +87,6 @@ protected:
QskMetaInvokable* invokable() const; QskMetaInvokable* invokable() const;
private: 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; QskMetaInvokable* m_invokable;
const int* m_parameterTypes; const int* m_parameterTypes;
}; };
@ -133,10 +110,12 @@ inline QskMetaFunction::QskMetaFunction( T function )
const int Argc = Traits::ArgumentCount; const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value; using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
using Invokable = QskMetaMemberInvokable< T, Args, void >;
init( findInvokable<Invokable>( function ), auto invokable = QskMetaInvokable::instance(
ConnectionTypes< typename Traits::Arguments >::types() ); QskMetaMemberInvokable< T, Args, void >::invoke,
reinterpret_cast< void** >( &function ) );
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
} }
template< typename T, QskMetaFunctionTraits::IsFunction< T >* > template< typename T, QskMetaFunctionTraits::IsFunction< T >* >
@ -148,10 +127,12 @@ inline QskMetaFunction::QskMetaFunction( T function )
const int Argc = Traits::ArgumentCount; const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value; using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
using Invokable = QskMetaFunctionInvokable< T, Args, void >;
init( findInvokable<Invokable>( function ), auto invokable = QskMetaInvokable::instance(
ConnectionTypes< typename Traits::Arguments >::types() ); QskMetaFunctionInvokable< T, Args, void >::invoke,
reinterpret_cast< void** >( &function ) );
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
} }
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* > template< typename T, QskMetaFunctionTraits::IsFunctor< T >* >
@ -163,10 +144,12 @@ inline QskMetaFunction::QskMetaFunction( T functor )
const int Argc = Traits::ArgumentCount; const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value; using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
using Invokable = QskMetaFunctorInvokable< T, Argc, Args, void >;
init( findInvokable<Invokable>( functor ), auto invokable = QskMetaInvokable::instance(
ConnectionTypes< typename Traits::Arguments >::types() ); QskMetaFunctorInvokable< T, Argc, Args, void >::invoke,
reinterpret_cast< void** >( &functor ) );
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
} }
Q_DECLARE_METATYPE( QskMetaFunction ) Q_DECLARE_METATYPE( QskMetaFunction )

View File

@ -18,6 +18,27 @@ namespace
"Bad cast: QskMetaInvokable does not match" ); "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 int QskMetaInvokable::typeInfo() const
{ {
auto that = const_cast< QskMetaInvokable* >( this ); auto that = const_cast< QskMetaInvokable* >( this );
@ -35,28 +56,3 @@ int QskMetaInvokable::refCount() const
auto that = const_cast< QskMetaInvokable* >( this ); auto that = const_cast< QskMetaInvokable* >( this );
return reinterpret_cast< SlotObject* >( that )->ref.load(); 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 // 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 class QSK_EXPORT QskMetaInvokable : public QtPrivate::QSlotObjectBase
{ {
public: public:
typedef void (* InvokeFunction)( typedef void (* InvokeFunction)(
int which, QtPrivate::QSlotObjectBase*, QObject*, void**, bool* ); int which, QtPrivate::QSlotObjectBase*, QObject*, void**, bool* );
enum { TypeInfo = NumOperations + 1 }; enum
{
TypeInfo = NumOperations + 1,
Create,
Find
};
int typeInfo() const; int typeInfo() const;
int refCount() const; int refCount() const;
protected: static QskMetaInvokable* instance( InvokeFunction, void** function );
friend class QskMetaFunction;
protected:
explicit QskMetaInvokable( InvokeFunction f ): explicit QskMetaInvokable( InvokeFunction f ):
QSlotObjectBase( 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 > template< typename Function, typename Args, typename R >
class QskMetaFunctionInvokable : public QskMetaInvokable class QskMetaFunctionInvokable : public QskMetaInvokable
{ {
public: using Invokable = QskMetaFunctionInvokable< Function, Args, R >;
typedef QtPrivate::FunctionPointer< Function > FuncType;
explicit QskMetaFunctionInvokable( Function function ): public:
explicit inline QskMetaFunctionInvokable( Function function ):
QskMetaInvokable( &invoke ), QskMetaInvokable( &invoke ),
m_function( function ) m_function( function )
{ {
} }
static void invoke(int which, QtPrivate::QSlotObjectBase* invokable, static void invoke(int which, QtPrivate::QSlotObjectBase*,
QObject* object, void** args, bool* ) QObject* object, void** args, bool* )
{ {
auto invokableFunction = static_cast< QskMetaFunctionInvokable* >( invokable ); static Invokable* invokable = nullptr;
switch ( which ) 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: case Destroy:
{ {
#if QSK_SHARE_INVOKABLES delete invokable;
remove( typeid( Function ) ); invokable = nullptr;
#endif
delete invokableFunction;
break; break;
} }
case Call: case Call:
{ {
typedef QtPrivate::FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >( FuncType::template call< Args, R >(
invokableFunction->m_function, object, args ); invokable->m_function, object, args );
break; break;
} }
case TypeInfo: case TypeInfo:
{ {
int* typeInfo = reinterpret_cast< int* >( args ); *reinterpret_cast< int* >( args ) = 1; // QskMetaFunction::Function
*typeInfo = 1; // = QskMetaFunction::Function
break; break;
} }
} }
} }
private:
Function m_function; Function m_function;
}; };
template< typename Function, typename Args, typename R > template< typename Function, typename Args, typename R >
class QskMetaMemberInvokable : public QskMetaInvokable class QskMetaMemberInvokable : public QskMetaInvokable
{ {
using Invokable = QskMetaMemberInvokable< Function, Args, R >;
public: public:
explicit QskMetaMemberInvokable( Function function ): explicit inline QskMetaMemberInvokable( Function function ):
QskMetaInvokable( &invoke ), QskMetaInvokable( &invoke ),
m_function( function ) m_function( function )
{ {
} }
static void invoke( int which, QtPrivate::QSlotObjectBase* invokable, static void invoke( int which, QtPrivate::QSlotObjectBase*,
QObject* object, void** args, bool* ret ) QObject* object, void** args, bool* ret )
{ {
typedef QtPrivate::FunctionPointer< Function > FuncType; static Invokable* invokable = nullptr;
auto invokableMember = static_cast< QskMetaMemberInvokable* >( invokable );
switch (which) 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: case Destroy:
{ {
#if QSK_SHARE_INVOKABLES delete invokable;
remove( typeid( Function ) ); invokable = nullptr;
#endif
delete invokableMember;
break; break;
} }
case Call: case Call:
{ {
typedef QtPrivate::FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >( FuncType::template call< Args, R >(
invokableMember->m_function, invokable->m_function,
static_cast< typename FuncType::Object* >( object ), args ); static_cast< typename FuncType::Object* >( object ), args );
break; break;
@ -144,14 +145,12 @@ public:
case Compare: case Compare:
{ {
const auto function = *reinterpret_cast< Function* >( args ); const auto function = *reinterpret_cast< Function* >( args );
*ret = function == invokableMember->m_function; *ret = function == invokable->m_function;
break; break;
} }
case TypeInfo: case TypeInfo:
{ {
int* typeInfo = reinterpret_cast< int* >( args ); *reinterpret_cast< int* >( args ) = 0; // = QskMetaFunction::Member
*typeInfo = 0; // = QskMetaFunction::Member
break; break;
} }
} }
@ -164,42 +163,52 @@ private:
template< typename Function, int N, typename Args, typename R > template< typename Function, int N, typename Args, typename R >
class QskMetaFunctorInvokable : public QskMetaInvokable class QskMetaFunctorInvokable : public QskMetaInvokable
{ {
public: using Invokable = QskMetaFunctorInvokable< Function, N, Args, R >;
typedef QtPrivate::Functor< Function, N > FuncType;
explicit QskMetaFunctorInvokable( Function function ): public:
explicit inline QskMetaFunctorInvokable( Function function ):
QskMetaInvokable( &invoke ), QskMetaInvokable( &invoke ),
m_function( std::move( function ) ) m_function( function )
{ {
} }
static void invoke( int which, QSlotObjectBase* invokable, static void invoke( int which, QSlotObjectBase*, QObject* object, void** args, bool* )
QObject* object, void** args, bool* )
{ {
auto invokableFunctor = static_cast< QskMetaFunctorInvokable* >( invokable ); static Invokable* invokable = nullptr;
switch (which) 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: case Destroy:
{ {
#if QSK_SHARE_INVOKABLES delete invokable;
remove( typeid( Function ) ); invokable = nullptr;
#endif
delete invokableFunctor;
break; break;
} }
case Call: case Call:
{ {
typedef QtPrivate::Functor< Function, N > FuncType;
FuncType::template call< Args, R >( FuncType::template call< Args, R >(
invokableFunctor->m_function, object, args ); invokable->m_function, object, args );
break; break;
} }
case TypeInfo: case TypeInfo:
{ {
int* typeInfo = reinterpret_cast< int* >( args ); *reinterpret_cast< int* >( args ) = 2; // QskMetaFunction::Functor
*typeInfo = 2; // QskMetaFunction::Functor;
break; break;
} }
} }