QskMeta classes improved
This commit is contained in:
parent
0075ccbdbd
commit
02639e5d04
@ -4,11 +4,13 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "QskMetaCallback.h"
|
#include "QskMetaCallback.h"
|
||||||
|
#include "QskMetaFunction.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QSemaphore>
|
#include <QSemaphore>
|
||||||
|
#include <QMetaMethod>
|
||||||
|
|
||||||
QSK_QT_PRIVATE_BEGIN
|
QSK_QT_PRIVATE_BEGIN
|
||||||
#include <private/qobject_p.h>
|
#include <private/qobject_p.h>
|
||||||
@ -31,42 +33,49 @@ static inline void qskInvokeMethodQueued( QObject* object,
|
|||||||
QskMetaCallback::QskMetaCallback( const QObject* object,
|
QskMetaCallback::QskMetaCallback( const QObject* object,
|
||||||
const QMetaMethod& method, Qt::ConnectionType connectionType ):
|
const QMetaMethod& method, Qt::ConnectionType connectionType ):
|
||||||
m_object( const_cast< QObject* >( object ) ),
|
m_object( const_cast< QObject* >( object ) ),
|
||||||
m_method( new QMetaMethod( method ) ),
|
m_methodData { method.enclosingMetaObject(), method.methodIndex() },
|
||||||
m_type( MetaMethod ),
|
m_type( MetaMethod ),
|
||||||
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
|
m_hasObject( object != nullptr ),
|
||||||
|
m_connectionType( static_cast< ushort >( connectionType & 0x3 ) )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QskMetaCallback::QskMetaCallback( const QObject* object,
|
QskMetaCallback::QskMetaCallback( const QObject* object,
|
||||||
const QskMetaFunction& function, Qt::ConnectionType connectionType ):
|
const QskMetaFunction& function, Qt::ConnectionType connectionType ):
|
||||||
m_object( const_cast< QObject* >( object ) ),
|
m_object( const_cast< QObject* >( object ) ),
|
||||||
m_function( new QskMetaFunction( function ) ),
|
m_functionData { function.invokable(), function.parameterTypes() },
|
||||||
m_type( MetaFunction ),
|
m_type( MetaFunction ),
|
||||||
|
m_hasObject( object != nullptr ),
|
||||||
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
|
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
|
||||||
{
|
{
|
||||||
|
if ( m_functionData.invokable )
|
||||||
|
m_functionData.invokable->ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
|
QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
|
||||||
m_object( other.m_object ),
|
m_object( other.m_object ),
|
||||||
m_function(),
|
m_type( other.m_type ),
|
||||||
m_type( Invalid ),
|
m_hasObject( other.m_hasObject ),
|
||||||
m_connectionType( other.m_connectionType )
|
m_connectionType( other.m_connectionType )
|
||||||
{
|
{
|
||||||
if ( other.m_type != m_type )
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
m_type = other.m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch( m_type )
|
switch( m_type )
|
||||||
{
|
{
|
||||||
case MetaMethod:
|
case MetaMethod:
|
||||||
m_method = new QMetaMethod( *other.m_method );
|
{
|
||||||
break;
|
m_methodData.metaObject = other.m_methodData.metaObject;
|
||||||
|
m_methodData.methodIndex = other.m_methodData.methodIndex;
|
||||||
|
|
||||||
case MetaFunction:
|
|
||||||
m_function = new QskMetaFunction( *other.m_function );
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case MetaFunction:
|
||||||
|
{
|
||||||
|
m_functionData.invokable = other.m_functionData.invokable;
|
||||||
|
if ( m_functionData.invokable )
|
||||||
|
m_functionData.invokable->ref();
|
||||||
|
|
||||||
|
m_functionData.parameterTypes = other.m_functionData.parameterTypes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -75,31 +84,82 @@ QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
|
|||||||
|
|
||||||
QskMetaCallback::~QskMetaCallback()
|
QskMetaCallback::~QskMetaCallback()
|
||||||
{
|
{
|
||||||
reset();
|
if ( ( m_type == MetaFunction ) && m_functionData.invokable )
|
||||||
|
m_functionData.invokable->destroyIfLastRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
|
QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
|
||||||
{
|
{
|
||||||
m_object = other.m_object;
|
m_object = other.m_object;
|
||||||
|
m_hasObject = other.m_hasObject;
|
||||||
|
|
||||||
m_connectionType = other.m_connectionType;
|
m_connectionType = other.m_connectionType;
|
||||||
|
|
||||||
if ( other.m_type != m_type )
|
switch( other.m_type )
|
||||||
{
|
{
|
||||||
reset();
|
case MetaMethod:
|
||||||
m_type = other.m_type;
|
{
|
||||||
|
if ( m_type == MetaFunction && m_functionData.invokable )
|
||||||
|
m_functionData.invokable->destroyIfLastRef();
|
||||||
|
|
||||||
|
m_methodData.metaObject = other.m_methodData.metaObject;
|
||||||
|
m_methodData.methodIndex = other.m_methodData.methodIndex;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MetaFunction:
|
||||||
|
{
|
||||||
|
if ( ( m_type == MetaFunction ) && m_functionData.invokable )
|
||||||
|
m_functionData.invokable->destroyIfLastRef();
|
||||||
|
|
||||||
|
m_functionData.invokable = other.m_functionData.invokable;
|
||||||
|
|
||||||
|
if ( m_functionData.invokable )
|
||||||
|
m_functionData.invokable->ref();
|
||||||
|
|
||||||
|
m_functionData.parameterTypes = other.m_functionData.parameterTypes;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( other.m_type != Invalid )
|
default:
|
||||||
{
|
if ( ( m_type == MetaFunction ) && m_functionData.invokable )
|
||||||
if ( other.m_type == MetaMethod )
|
m_functionData.invokable->destroyIfLastRef();
|
||||||
m_method = new QMetaMethod( *other.m_method );
|
|
||||||
else
|
|
||||||
m_function = new QskMetaFunction( *other.m_function );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_type = other.m_type;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QskMetaCallback::isValid() const
|
||||||
|
{
|
||||||
|
if ( m_hasObject && m_object.isNull() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch( m_type )
|
||||||
|
{
|
||||||
|
case MetaMethod:
|
||||||
|
{
|
||||||
|
const auto& d = m_methodData;
|
||||||
|
if ( d.metaObject && ( d.methodIndex >= 0 )
|
||||||
|
&& ( d.methodIndex < d.metaObject->methodCount() ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MetaFunction:
|
||||||
|
{
|
||||||
|
return m_functionData.invokable != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
|
void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
|
||||||
{
|
{
|
||||||
m_connectionType = connectionType;
|
m_connectionType = connectionType;
|
||||||
@ -107,22 +167,13 @@ void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
|
|||||||
|
|
||||||
void QskMetaCallback::reset()
|
void QskMetaCallback::reset()
|
||||||
{
|
{
|
||||||
switch( m_type )
|
m_object = nullptr;
|
||||||
{
|
m_hasObject = false;
|
||||||
case MetaMethod:
|
|
||||||
delete m_method;
|
|
||||||
m_method = nullptr;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MetaFunction:
|
if ( m_type == MetaFunction && m_functionData.invokable )
|
||||||
delete m_function;
|
m_functionData.invokable->destroyIfLastRef();
|
||||||
m_function = nullptr;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
m_functionData = { nullptr, nullptr }; // for the debugger
|
||||||
m_type = Invalid;
|
m_type = Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,17 +185,25 @@ QVector< int > QskMetaCallback::parameterTypes() const
|
|||||||
{
|
{
|
||||||
case MetaMethod:
|
case MetaMethod:
|
||||||
{
|
{
|
||||||
const int paramCount = m_method->parameterCount();
|
const auto& d = m_methodData;
|
||||||
|
if ( m_methodData.metaObject )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// should be doable without QMetaMethod. TODO ...
|
||||||
|
const auto method = d.metaObject->method( d.methodIndex );
|
||||||
|
#endif
|
||||||
|
const int paramCount = method.parameterCount();
|
||||||
|
|
||||||
paramTypes.reserve( paramCount );
|
paramTypes.reserve( paramCount );
|
||||||
for ( int i = 0; i < paramCount; i++ )
|
for ( int i = 0; i < paramCount; i++ )
|
||||||
paramTypes += m_method->parameterType( i );
|
paramTypes += method.parameterType( i );
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaFunction:
|
case MetaFunction:
|
||||||
{
|
{
|
||||||
auto types = m_function->parameterTypes();
|
auto types = m_functionData.parameterTypes;
|
||||||
if ( types )
|
if ( types )
|
||||||
{
|
{
|
||||||
while ( *types )
|
while ( *types )
|
||||||
@ -162,18 +221,25 @@ QVector< int > QskMetaCallback::parameterTypes() const
|
|||||||
|
|
||||||
void QskMetaCallback::invoke( void* args[] )
|
void QskMetaCallback::invoke( void* args[] )
|
||||||
{
|
{
|
||||||
|
if ( !isValid() )
|
||||||
|
return;
|
||||||
|
|
||||||
auto object = const_cast< QObject* >( m_object.data() );
|
auto object = const_cast< QObject* >( m_object.data() );
|
||||||
|
|
||||||
switch( m_type )
|
switch( m_type )
|
||||||
{
|
{
|
||||||
case MetaMethod:
|
case MetaMethod:
|
||||||
{
|
{
|
||||||
qskInvokeMethod( object, *m_method, args, connectionType() );
|
qskInvokeMethod( object, m_methodData.metaObject,
|
||||||
|
m_methodData.methodIndex, args, connectionType() );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaFunction:
|
case MetaFunction:
|
||||||
{
|
{
|
||||||
m_function->invoke( object, args, connectionType() );
|
QskMetaFunction function( m_functionData.invokable, m_functionData.parameterTypes );
|
||||||
|
function.invoke( object, args, connectionType() );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,30 +248,54 @@ void QskMetaCallback::invoke( void* args[] )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void qskInvokeMethod( QObject* object,
|
void qskInvokeMethod( QObject* object,
|
||||||
const QMetaMethod& method, void* args[],
|
const QMetaMethod& method, void* args[],
|
||||||
Qt::ConnectionType connectionType )
|
Qt::ConnectionType connectionType )
|
||||||
{
|
{
|
||||||
if ( object == nullptr )
|
auto metaObject = method.enclosingMetaObject();
|
||||||
|
if ( metaObject == nullptr )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto metaObject = method.enclosingMetaObject();
|
const int methodIndex = method.methodIndex() - metaObject->methodOffset();
|
||||||
|
qskInvokeMethod( object, metaObject, methodIndex, args, connectionType );
|
||||||
|
}
|
||||||
|
|
||||||
const int methodOffset = metaObject->methodOffset();
|
void qskInvokeMethod( QObject* object,
|
||||||
const int methodIndex = method.methodIndex() - methodOffset;
|
const QMetaObject* metaObject, int methodIndex, void* args[],
|
||||||
|
Qt::ConnectionType connectionType )
|
||||||
if ( connectionType == Qt::AutoConnection )
|
{
|
||||||
|
if ( ( metaObject == nullptr ) || ( methodIndex < 0 )
|
||||||
|
|| ( methodIndex > metaObject->methodCount() ) )
|
||||||
{
|
{
|
||||||
connectionType = ( object->thread() == QThread::currentThread() )
|
return;
|
||||||
? Qt::DirectConnection : Qt::QueuedConnection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( connectionType == Qt::DirectConnection )
|
int invokeType = connectionType & 0x3;
|
||||||
|
|
||||||
|
if ( invokeType == Qt::AutoConnection )
|
||||||
{
|
{
|
||||||
|
invokeType = ( object && object->thread() != QThread::currentThread() )
|
||||||
|
? Qt::QueuedConnection : Qt::DirectConnection;
|
||||||
|
}
|
||||||
|
else if ( invokeType == Qt::BlockingQueuedConnection )
|
||||||
|
{
|
||||||
|
if ( ( object == nullptr ) || object->thread() == QThread::currentThread() )
|
||||||
|
{
|
||||||
|
// We would end up in a deadlock, better do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( invokeType == Qt::DirectConnection )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
if ( object == nullptr )
|
||||||
|
return; // do we really need an object here ???
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( metaObject->d.static_metacall )
|
if ( metaObject->d.static_metacall )
|
||||||
{
|
{
|
||||||
metaObject->d.static_metacall(object,
|
metaObject->d.static_metacall( object,
|
||||||
QMetaObject::InvokeMetaMethod, methodIndex, args );
|
QMetaObject::InvokeMetaMethod, methodIndex, args );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -216,6 +306,13 @@ void qskInvokeMethod( QObject* object,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if ( object == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// should be doable without QMetaMethod. TODO ...
|
||||||
|
const auto method = metaObject->method( methodIndex );
|
||||||
|
#endif
|
||||||
const int paramCount = method.parameterCount();
|
const int paramCount = method.parameterCount();
|
||||||
|
|
||||||
auto types = static_cast< int* >( malloc( paramCount * sizeof( int ) ) );
|
auto types = static_cast< int* >( malloc( paramCount * sizeof( int ) ) );
|
||||||
|
@ -7,13 +7,14 @@
|
|||||||
#define QSK_META_CALLBACK_H 1
|
#define QSK_META_CALLBACK_H 1
|
||||||
|
|
||||||
#include "QskGlobal.h"
|
#include "QskGlobal.h"
|
||||||
#include "QskMetaFunction.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QMetaMethod>
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
class QskMetaInvokable;
|
||||||
|
class QskMetaFunction;
|
||||||
|
class QMetaMethod;
|
||||||
|
|
||||||
class QskMetaCallback
|
class QskMetaCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -59,26 +60,35 @@ private:
|
|||||||
|
|
||||||
QPointer< const QObject > m_object;
|
QPointer< const QObject > m_object;
|
||||||
|
|
||||||
|
struct FunctionData
|
||||||
|
{
|
||||||
|
QskMetaInvokable* invokable;
|
||||||
|
const int* parameterTypes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MethodData
|
||||||
|
{
|
||||||
|
const QMetaObject* metaObject;
|
||||||
|
int methodIndex;
|
||||||
|
};
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
QskMetaFunction* m_function;
|
FunctionData m_functionData;
|
||||||
QMetaMethod* m_method;
|
MethodData m_methodData;
|
||||||
};
|
};
|
||||||
|
|
||||||
int m_type : 3;
|
int m_type : 3;
|
||||||
|
bool m_hasObject : 1;
|
||||||
ushort m_connectionType : 3;
|
ushort m_connectionType : 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QskMetaCallback::QskMetaCallback():
|
inline QskMetaCallback::QskMetaCallback():
|
||||||
m_type( Invalid )
|
m_type( Invalid ),
|
||||||
|
m_hasObject( false )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool QskMetaCallback::isValid() const
|
|
||||||
{
|
|
||||||
return m_type > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QskMetaCallback::Type QskMetaCallback::type() const
|
inline QskMetaCallback::Type QskMetaCallback::type() const
|
||||||
{
|
{
|
||||||
return static_cast< Type >( m_type );
|
return static_cast< Type >( m_type );
|
||||||
@ -93,6 +103,10 @@ 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(
|
||||||
|
QObject* object, const QMetaObject*, int methodIndex, void* args[],
|
||||||
|
Qt::ConnectionType = Qt::AutoConnection );
|
||||||
|
|
||||||
Q_DECLARE_METATYPE( QskMetaCallback )
|
Q_DECLARE_METATYPE( QskMetaCallback )
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,6 +34,15 @@ QskMetaFunction::QskMetaFunction():
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QskMetaFunction::QskMetaFunction(
|
||||||
|
QskMetaInvokable* invokable, const int* parameterTypes ):
|
||||||
|
m_invokable( invokable ),
|
||||||
|
m_parameterTypes( parameterTypes )
|
||||||
|
{
|
||||||
|
if ( m_invokable )
|
||||||
|
m_invokable->ref();
|
||||||
|
}
|
||||||
|
|
||||||
QskMetaFunction::QskMetaFunction( const QskMetaFunction& other ):
|
QskMetaFunction::QskMetaFunction( const QskMetaFunction& other ):
|
||||||
m_invokable( other.m_invokable ),
|
m_invokable( other.m_invokable ),
|
||||||
m_parameterTypes( other.m_parameterTypes )
|
m_parameterTypes( other.m_parameterTypes )
|
||||||
@ -96,11 +105,6 @@ void QskMetaFunction::init( QskMetaInvokable* invokable,
|
|||||||
m_parameterTypes = parameterTypes;
|
m_parameterTypes = parameterTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int* QskMetaFunction::parameterTypes() const
|
|
||||||
{
|
|
||||||
return m_parameterTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t QskMetaFunction::parameterCount() const
|
size_t QskMetaFunction::parameterCount() const
|
||||||
{
|
{
|
||||||
if ( m_parameterTypes )
|
if ( m_parameterTypes )
|
||||||
@ -134,12 +138,12 @@ void QskMetaFunction::invoke(
|
|||||||
|
|
||||||
if ( invokeType == Qt::AutoConnection )
|
if ( invokeType == Qt::AutoConnection )
|
||||||
{
|
{
|
||||||
invokeType = ( object->thread() == QThread::currentThread() )
|
invokeType = ( object && object->thread() != QThread::currentThread() )
|
||||||
? Qt::DirectConnection : Qt::QueuedConnection;
|
? Qt::QueuedConnection : Qt::DirectConnection;
|
||||||
}
|
}
|
||||||
else if ( invokeType == Qt::BlockingQueuedConnection )
|
else if ( invokeType == Qt::BlockingQueuedConnection )
|
||||||
{
|
{
|
||||||
if ( object->thread() == QThread::currentThread() )
|
if ( ( object == nullptr ) || object->thread() == QThread::currentThread() )
|
||||||
{
|
{
|
||||||
// We would end up in a deadlock, better do nothing
|
// We would end up in a deadlock, better do nothing
|
||||||
return;
|
return;
|
||||||
@ -202,3 +206,5 @@ void QskMetaFunction::invoke(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "moc_QskMetaFunction.cpp"
|
||||||
|
@ -78,13 +78,51 @@ public:
|
|||||||
|
|
||||||
Type functionType() const;
|
Type functionType() const;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
friend class QskMetaCallback;
|
||||||
|
|
||||||
|
QskMetaFunction( QskMetaInvokable*, const int* );
|
||||||
|
|
||||||
void init( QskMetaInvokable*, const int* );
|
void init( QskMetaInvokable*, const int* );
|
||||||
|
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;
|
QskMetaInvokable* m_invokable;
|
||||||
const int* m_parameterTypes;
|
const int* m_parameterTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline QskMetaInvokable* QskMetaFunction::invokable() const
|
||||||
|
{
|
||||||
|
return m_invokable;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const int* QskMetaFunction::parameterTypes() const
|
||||||
|
{
|
||||||
|
return m_parameterTypes;
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* >
|
template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* >
|
||||||
inline QskMetaFunction::QskMetaFunction( T function )
|
inline QskMetaFunction::QskMetaFunction( T function )
|
||||||
@ -95,8 +133,9 @@ 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( new QskMetaMemberInvokable< T, Args, void >( function ),
|
init( findInvokable<Invokable>( function ),
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,8 +148,9 @@ 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( new QskMetaFunctionInvokable< T, Args, void >( function ),
|
init( findInvokable<Invokable>( function ),
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,8 +163,9 @@ 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( new QskMetaFunctorInvokable< T, Argc, Args, void > ( functor ),
|
init( findInvokable<Invokable>( functor ),
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,3 +35,28 @@ 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
|
||||||
|
@ -11,7 +11,22 @@
|
|||||||
|
|
||||||
// helper classes for QskMetaFunction
|
// helper classes for QskMetaFunction
|
||||||
|
|
||||||
class QskMetaInvokable : public QtPrivate::QSlotObjectBase
|
#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:
|
public:
|
||||||
typedef void (* InvokeFunction)(
|
typedef void (* InvokeFunction)(
|
||||||
@ -23,39 +38,58 @@ public:
|
|||||||
int refCount() const;
|
int refCount() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class QskMetaFunction;
|
||||||
|
|
||||||
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 Func, typename Args, typename R >
|
template< typename Function, typename Args, typename R >
|
||||||
class QskMetaFunctionInvokable : public QskMetaInvokable
|
class QskMetaFunctionInvokable : public QskMetaInvokable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef QtPrivate::FunctionPointer< Func > FuncType;
|
typedef QtPrivate::FunctionPointer< Function > FuncType;
|
||||||
|
|
||||||
explicit QskMetaFunctionInvokable( Func f ):
|
explicit QskMetaFunctionInvokable( Function function ):
|
||||||
QskMetaInvokable( &invoke ),
|
QskMetaInvokable( &invoke ),
|
||||||
function(f)
|
m_function( function )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void invoke(int which, QtPrivate::QSlotObjectBase* invokable,
|
static void invoke(int which, QtPrivate::QSlotObjectBase* invokable,
|
||||||
QObject* object, void** args, bool* )
|
QObject* object, void** args, bool* )
|
||||||
{
|
{
|
||||||
auto f = static_cast< QskMetaFunctionInvokable* >( invokable );
|
auto invokableFunction = static_cast< QskMetaFunctionInvokable* >( invokable );
|
||||||
|
|
||||||
switch ( which )
|
switch ( which )
|
||||||
{
|
{
|
||||||
case Destroy:
|
case Destroy:
|
||||||
{
|
{
|
||||||
delete f;
|
#if QSK_SHARE_INVOKABLES
|
||||||
|
remove( typeid( Function ) );
|
||||||
|
#endif
|
||||||
|
delete invokableFunction;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Call:
|
case Call:
|
||||||
{
|
{
|
||||||
FuncType::template call< Args, R >( f->function, object, args );
|
FuncType::template call< Args, R >(
|
||||||
|
invokableFunction->m_function, object, args );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeInfo:
|
case TypeInfo:
|
||||||
@ -68,43 +102,49 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Func function;
|
Function m_function;
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename Func, typename Args, typename R >
|
template< typename Function, typename Args, typename R >
|
||||||
class QskMetaMemberInvokable : public QskMetaInvokable
|
class QskMetaMemberInvokable : public QskMetaInvokable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit QskMetaMemberInvokable( Func f ):
|
explicit QskMetaMemberInvokable( Function function ):
|
||||||
QskMetaInvokable( &invoke ),
|
QskMetaInvokable( &invoke ),
|
||||||
function(f)
|
m_function( function )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void invoke( int which, QtPrivate::QSlotObjectBase* invokable,
|
static void invoke( int which, QtPrivate::QSlotObjectBase* invokable,
|
||||||
QObject* object, void** args, bool* ret )
|
QObject* object, void** args, bool* ret )
|
||||||
{
|
{
|
||||||
typedef QtPrivate::FunctionPointer< Func > FuncType;
|
typedef QtPrivate::FunctionPointer< Function > FuncType;
|
||||||
|
|
||||||
auto f = static_cast< QskMetaMemberInvokable* >( invokable );
|
auto invokableMember = static_cast< QskMetaMemberInvokable* >( invokable );
|
||||||
|
|
||||||
switch (which)
|
switch (which)
|
||||||
{
|
{
|
||||||
case Destroy:
|
case Destroy:
|
||||||
{
|
{
|
||||||
delete f;
|
#if QSK_SHARE_INVOKABLES
|
||||||
|
remove( typeid( Function ) );
|
||||||
|
#endif
|
||||||
|
delete invokableMember;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Call:
|
case Call:
|
||||||
{
|
{
|
||||||
FuncType::template call< Args, R >(
|
FuncType::template call< Args, R >(
|
||||||
f->function, static_cast< typename FuncType::Object* >( object ), args );
|
invokableMember->m_function,
|
||||||
|
static_cast< typename FuncType::Object* >( object ), args );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Compare:
|
case Compare:
|
||||||
{
|
{
|
||||||
*ret = *reinterpret_cast< Func* >( args ) == f->function;
|
const auto function = *reinterpret_cast< Function* >( args );
|
||||||
|
*ret = function == invokableMember->m_function;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeInfo:
|
case TypeInfo:
|
||||||
@ -118,36 +158,41 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Func function;
|
Function m_function;
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename Func, int N, typename Args, typename R >
|
template< typename Function, int N, typename Args, typename R >
|
||||||
class QskMetaFunctorInvokable : public QskMetaInvokable
|
class QskMetaFunctorInvokable : public QskMetaInvokable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef QtPrivate::Functor< Func, N > FuncType;
|
typedef QtPrivate::Functor< Function, N > FuncType;
|
||||||
|
|
||||||
explicit QskMetaFunctorInvokable( Func f ):
|
explicit QskMetaFunctorInvokable( Function function ):
|
||||||
QskMetaInvokable( &invoke ),
|
QskMetaInvokable( &invoke ),
|
||||||
function( std::move( f ) )
|
m_function( std::move( function ) )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void invoke( int which, QSlotObjectBase* invokable,
|
static void invoke( int which, QSlotObjectBase* invokable,
|
||||||
QObject* object, void** args, bool* )
|
QObject* object, void** args, bool* )
|
||||||
{
|
{
|
||||||
auto f = static_cast< QskMetaFunctorInvokable* >( invokable );
|
auto invokableFunctor = static_cast< QskMetaFunctorInvokable* >( invokable );
|
||||||
|
|
||||||
switch (which)
|
switch (which)
|
||||||
{
|
{
|
||||||
case Destroy:
|
case Destroy:
|
||||||
{
|
{
|
||||||
delete f;
|
#if QSK_SHARE_INVOKABLES
|
||||||
|
remove( typeid( Function ) );
|
||||||
|
#endif
|
||||||
|
delete invokableFunctor;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Call:
|
case Call:
|
||||||
{
|
{
|
||||||
FuncType::template call< Args, R >( f->function, object, args );
|
FuncType::template call< Args, R >(
|
||||||
|
invokableFunctor->m_function, object, args );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeInfo:
|
case TypeInfo:
|
||||||
@ -161,7 +206,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Func function;
|
Function m_function;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user