implementation of QskMetaFunction continued - still several issues to

solve
This commit is contained in:
Uwe Rathmann 2018-02-27 17:47:23 +01:00
parent 1d086d9051
commit 28660cca7d
9 changed files with 176 additions and 106 deletions

View File

@ -13,12 +13,13 @@ Invoker::Invoker( QObject* parent ):
void Invoker::addCallback( const QObject* object, void Invoker::addCallback( const QObject* object,
const QskMetaFunction& function ) const QskMetaFunction& function )
{ {
m_callbacks += QskMetaCallback( object, function, Qt::DirectConnection ); m_callbacks += QskMetaCallback( object, function );
} }
void Invoker::invoke( qreal realValue, int intValue ) void Invoker::invoke( qreal realValue, int intValue,
Qt::ConnectionType connectionType )
{ {
for ( auto callback : qskAsConst( m_callbacks ) ) for ( auto& callback : m_callbacks )
{ {
void* args[3] = { nullptr }; void* args[3] = { nullptr };
@ -44,6 +45,11 @@ void Invoker::invoke( qreal realValue, int intValue )
} }
} }
callback.setConnectionType( connectionType );
if ( connectionType == Qt::DirectConnection )
callback.invoke( args );
else if ( callback.object() )
callback.invoke( args ); callback.invoke( args );
} }
} }

View File

@ -20,7 +20,7 @@ public:
void addCallback( const QskMetaFunction& ); void addCallback( const QskMetaFunction& );
void addCallback( const QObject*, const QskMetaFunction& ); void addCallback( const QObject*, const QskMetaFunction& );
void invoke( qreal d, int i ); void invoke( qreal d, int i, Qt::ConnectionType );
private: private:
QVector< QskMetaCallback > m_callbacks; QVector< QskMetaCallback > m_callbacks;

View File

@ -4,7 +4,9 @@
*****************************************************************************/ *****************************************************************************/
#include "Invoker.h" #include "Invoker.h"
#include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QTimer>
static void debugValueI( int i ) static void debugValueI( int i )
{ {
@ -47,8 +49,7 @@ public:
int main( int argc, char* argv[] ) int main( int argc, char* argv[] )
{ {
Q_UNUSED( argc ) QCoreApplication app( argc, argv );
Q_UNUSED( argv )
MyObject object; MyObject object;
@ -69,5 +70,14 @@ int main( int argc, char* argv[] )
invoker.addCallback( []( int i ) { qDebug() << i; } ); invoker.addCallback( []( int i ) { qDebug() << i; } );
invoker.addCallback( []( double d ) { qDebug() << d; } ); invoker.addCallback( []( double d ) { qDebug() << d; } );
invoker.invoke( 3.14, 35 ); qDebug() << "== Direct Connections";
invoker.invoke( 3.14, 35, Qt::DirectConnection );
qDebug() << "== Queued Connections";
QTimer::singleShot( 0,
[&invoker] { invoker.invoke( 0.07, 42, Qt::QueuedConnection ); } );
QTimer::singleShot( 100, &app, QCoreApplication::quit );
return app.exec();
} }

View File

@ -33,6 +33,46 @@ namespace QskMetaCall
} }
} }
namespace
{
using namespace QskMetaCall;
class FunctionCallEvent : public QMetaCallEvent
{
public:
FunctionCallEvent( Invokable* invokable,
int nargs, int* types, void* args[], QSemaphore* semaphore = nullptr ):
QMetaCallEvent( invokable, nullptr, 0, nargs, types, args, semaphore ),
m_invokable ( invokable )
{
invokable->ref();
}
virtual ~FunctionCallEvent()
{
}
private:
Invokable* m_invokable;
};
class MethodCallEvent : public QMetaCallEvent
{
public:
MethodCallEvent( const QMetaObject* mo, ushort methodIndex,
int nargs, int* types, void* args[], QSemaphore* semaphore = nullptr ):
QMetaCallEvent(
mo->methodOffset(), methodIndex, mo->d.static_metacall,
nullptr, -1, nargs, types, args, semaphore )
{
}
virtual ~MethodCallEvent()
{
}
};
}
void QskMetaCall::invoke( QObject* object, void QskMetaCall::invoke( QObject* object,
const QMetaMethod& method, void* args[], const QMetaMethod& method, void* args[],
Qt::ConnectionType connectionType ) Qt::ConnectionType connectionType )
@ -66,22 +106,33 @@ void QskMetaCall::invoke( QObject* object,
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 ) ) );
auto arguments = static_cast< void** >( malloc( paramCount * sizeof( void* ) ) );
types[0] = QMetaType::UnknownType; // return type types[0] = QMetaType::UnknownType; // a return type is not possible
arguments[0] = nullptr;
for ( int i = 1; i < paramCount; i++ ) for ( int i = 1; i < paramCount; i++ )
{ {
if ( arguments[i] == nullptr )
{
Q_ASSERT( arguments[i] != nullptr );
free( types );
free( arguments );
return;
}
types[i] = method.parameterType( i ); types[i] = method.parameterType( i );
Q_ASSERT( args[i] != nullptr ); arguments[i] = args[i - 1];
} }
Q_ASSERT( args[paramCount] == nullptr ); Q_ASSERT( args[paramCount] == nullptr );
if ( connectionType == Qt::QueuedConnection ) if ( connectionType == Qt::QueuedConnection )
{ {
QMetaCallEvent* event = new QMetaCallEvent( auto event = new MethodCallEvent(
methodOffset, methodIndex, metaObject->d.static_metacall, metaObject, methodIndex, paramCount + 1, types, args );
nullptr, -1, paramCount + 1, types, args );
QCoreApplication::postEvent(object, event ); QCoreApplication::postEvent(object, event );
} }
@ -89,10 +140,8 @@ void QskMetaCall::invoke( QObject* object,
{ {
QSemaphore semaphore; QSemaphore semaphore;
// what about argc + types ??? auto event = new MethodCallEvent(
auto event = new QMetaCallEvent( metaObject, methodIndex, paramCount + 1, types, args, &semaphore );
methodOffset, methodIndex, metaObject->d.static_metacall,
nullptr, -1, 0, 0, args, &semaphore );
QCoreApplication::postEvent( object, event ); QCoreApplication::postEvent( object, event );
@ -102,7 +151,7 @@ void QskMetaCall::invoke( QObject* object,
} }
void QskMetaCall::invoke( QObject* object, void QskMetaCall::invoke( QObject* object,
const Invokable& invokable, void* args[], const Invokable& invokable, int argc, const int argTypes[], void* argv[],
Qt::ConnectionType connectionType ) Qt::ConnectionType connectionType )
{ {
//connectionType &= ~Qt::UniqueConnection; //connectionType &= ~Qt::UniqueConnection;
@ -117,14 +166,36 @@ void QskMetaCall::invoke( QObject* object,
if ( connectionType == Qt::DirectConnection ) if ( connectionType == Qt::DirectConnection )
{ {
invokablePtr->call( object, args ); invokablePtr->call( object, argv );
} }
else else
{ {
auto types = static_cast< int* >( malloc( argc * sizeof( int ) ) );
auto arguments = static_cast< void** >( malloc( argc * sizeof( void* ) ) );
types[0] = QMetaType::UnknownType; // a return type is not possible
arguments[0] = nullptr;
for ( int i = 1; i < argc; i++ )
{
if ( argv[i] == nullptr )
{
Q_ASSERT( arguments[i] != nullptr );
free( types );
free( arguments );
return;
}
types[i] = argTypes[i - 1];
arguments[i] = QMetaType::create( argTypes[i - 1], argv[i] );
}
if ( connectionType == Qt::QueuedConnection ) if ( connectionType == Qt::QueuedConnection )
{ {
auto event = new QMetaCallEvent( auto event = new FunctionCallEvent(
invokablePtr, nullptr, 0, 0, nullptr, args, nullptr ); invokablePtr, argc, types, arguments, nullptr );
QCoreApplication::postEvent( object, event ); QCoreApplication::postEvent( object, event );
} }

View File

@ -18,7 +18,7 @@ namespace QskMetaCall
Qt::ConnectionType = Qt::AutoConnection ); Qt::ConnectionType = Qt::AutoConnection );
QSK_EXPORT void invoke( QObject*, QSK_EXPORT void invoke( QObject*,
const Invokable&, void* args[], const Invokable&, int argc, const int argTypes[], void* args[],
Qt::ConnectionType = Qt::AutoConnection ); Qt::ConnectionType = Qt::AutoConnection );
} }

View File

@ -4,79 +4,8 @@
*****************************************************************************/ *****************************************************************************/
#include "QskMetaCallback.h" #include "QskMetaCallback.h"
#include <QCoreApplication>
#include <QThread>
#include <QObject> #include <QObject>
#include <QSemaphore> #include <QVector>
#include <private/qobject_p.h>
static void qskInvoke( QObject* object,
const QMetaMethod& method, void* args[], Qt::ConnectionType connectionType )
{
auto metaObject = method.enclosingMetaObject();
const int methodOffset = metaObject->methodOffset();
const int methodIndex = method.methodIndex() - methodOffset;
if ( connectionType == Qt::AutoConnection )
{
connectionType = ( object->thread() == QThread::currentThread() )
? Qt::DirectConnection : Qt::QueuedConnection;
}
if ( connectionType == Qt::DirectConnection )
{
if ( metaObject->d.static_metacall )
{
metaObject->d.static_metacall(object,
QMetaObject::InvokeMetaMethod, methodIndex, args );
}
else
{
QMetaObject::metacall( object,
QMetaObject::InvokeMetaMethod, methodIndex, args );
}
}
else
{
const int paramCount = method.parameterCount();
auto types = static_cast< int* >( malloc( paramCount * sizeof( int ) ) );
types[0] = QMetaType::UnknownType; // return type
for ( int i = 1; i < paramCount; i++ )
{
types[i] = method.parameterType( i );
Q_ASSERT( args[i] != nullptr );
}
Q_ASSERT( args[paramCount] == nullptr );
if ( connectionType == Qt::QueuedConnection )
{
QMetaCallEvent* event = new QMetaCallEvent(
methodOffset, methodIndex, metaObject->d.static_metacall,
nullptr, -1, paramCount + 1, types, args );
QCoreApplication::postEvent(object, event );
}
else
{
QSemaphore semaphore;
// what about argc + types ???
auto event = new QMetaCallEvent(
methodOffset, methodIndex, metaObject->d.static_metacall,
nullptr, -1, 0, 0, args, &semaphore );
QCoreApplication::postEvent( object, event );
semaphore.acquire();
}
}
}
QskMetaCallback::QskMetaCallback( const QObject* object, QskMetaCallback::QskMetaCallback( const QObject* object,
const QMetaMethod& method, Qt::ConnectionType connectionType ): const QMetaMethod& method, Qt::ConnectionType connectionType ):
@ -156,6 +85,11 @@ QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
return *this; return *this;
} }
void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
{
m_connectionType = connectionType;
}
void QskMetaCallback::reset() void QskMetaCallback::reset()
{ {
switch( m_type ) switch( m_type )
@ -218,7 +152,7 @@ void QskMetaCallback::invoke( void* args[] )
case MetaMethod: case MetaMethod:
{ {
if ( object ) if ( object )
qskInvoke( object, m_method, args, connectionType() ); QskMetaCall::invoke( object, m_method, args, connectionType() );
break; break;
} }
case MetaFunction: case MetaFunction:

View File

@ -12,6 +12,7 @@
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
#include <QMetaMethod> #include <QMetaMethod>
#include <QVector>
class QskMetaCallback class QskMetaCallback
{ {
@ -28,8 +29,13 @@ public:
}; };
QskMetaCallback(); QskMetaCallback();
QskMetaCallback( const QObject*, const QskMetaFunction&, Qt::ConnectionType );
QskMetaCallback( const QObject*, const QMetaMethod&, Qt::ConnectionType ); QskMetaCallback( const QObject*, const QskMetaFunction&,
Qt::ConnectionType = Qt::AutoConnection );
QskMetaCallback( const QObject*, const QMetaMethod&,
Qt::ConnectionType = Qt::AutoConnection );
QskMetaCallback( const QskMetaCallback& ); QskMetaCallback( const QskMetaCallback& );
~QskMetaCallback(); ~QskMetaCallback();
@ -40,6 +46,8 @@ public:
bool isValid() const; bool isValid() const;
const QObject* object() const { return m_object; } const QObject* object() const { return m_object; }
void setConnectionType( Qt::ConnectionType );
Qt::ConnectionType connectionType() const; Qt::ConnectionType connectionType() const;
QVector< int > parameterTypes() const; QVector< int > parameterTypes() const;
@ -51,11 +59,17 @@ private:
QPointer< const QObject > m_object; QPointer< const QObject > m_object;
#if 1
/*
This union does not work - call of constructors
are missing
*/
union union
{ {
QskMetaFunction m_function; QskMetaFunction m_function;
QMetaMethod m_method; QMetaMethod m_method;
}; };
#endif
int m_type : 3; int m_type : 3;
ushort m_connectionType : 3; ushort m_connectionType : 3;

View File

@ -68,11 +68,38 @@ QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
return *this; return *this;
} }
void QskMetaFunction::init( QskMetaCall::Invokable* invokable,
const int* parameterTypes )
{
m_invokable = invokable;
#if 0
if ( m_invokable )
m_invokable->ref();
#endif
m_parameterTypes = parameterTypes;
}
const int* QskMetaFunction::parameterTypes() const const int* QskMetaFunction::parameterTypes() const
{ {
return m_parameterTypes; return m_parameterTypes;
} }
size_t QskMetaFunction::parameterCount() const
{
if ( m_parameterTypes )
{
for ( int i = 1; ; i++ )
{
if ( m_parameterTypes[ i ] == QMetaType::UnknownType )
return i + 1; // including the return type
}
}
return 1; // we always have a return type
}
QskMetaFunction::Type QskMetaFunction::functionType() const QskMetaFunction::Type QskMetaFunction::functionType() const
{ {
if ( m_invokable == nullptr ) if ( m_invokable == nullptr )
@ -82,8 +109,11 @@ QskMetaFunction::Type QskMetaFunction::functionType() const
} }
void QskMetaFunction::invoke( void QskMetaFunction::invoke(
QObject* object, void* args[], Qt::ConnectionType connectionType ) QObject* object, void* argv[], Qt::ConnectionType connectionType )
{ {
if ( m_invokable ) if ( m_invokable )
QskMetaCall::invoke( object, *m_invokable, args, connectionType ); {
QskMetaCall::invoke( object, *m_invokable,
parameterCount(), parameterTypes(), argv, connectionType );
}
} }

View File

@ -53,12 +53,17 @@ public:
const int* parameterTypes() const; const int* parameterTypes() const;
// including the return type !
size_t parameterCount() const;
void invoke( QObject*, void* args[], void invoke( QObject*, void* args[],
Qt::ConnectionType = Qt::AutoConnection ); Qt::ConnectionType = Qt::AutoConnection );
Type functionType() const; Type functionType() const;
private: private:
void init( QskMetaCall::Invokable*, const int* );
QskMetaCall::Invokable* m_invokable; QskMetaCall::Invokable* m_invokable;
const int* m_parameterTypes; const int* m_parameterTypes;
}; };
@ -75,8 +80,8 @@ 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;
m_invokable = new MemberFunctionInvokable< T, Args, void >( function ); init( new MemberFunctionInvokable< T, Args, void >( function ),
m_parameterTypes = ConnectionTypes< typename Traits::Arguments >::types(); ConnectionTypes< typename Traits::Arguments >::types() );
} }
template< typename T, QskMetaCall::IsFunction< T >* > template< typename T, QskMetaCall::IsFunction< T >* >
@ -90,8 +95,8 @@ 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;
m_invokable = new FunctionInvokable< T, Args, void >( function ); init( new FunctionInvokable< T, Args, void >( function ),
m_parameterTypes = ConnectionTypes< typename Traits::Arguments >::types(); ConnectionTypes< typename Traits::Arguments >::types() );
} }
template< typename T, QskMetaCall::IsFunctor< T >* > template< typename T, QskMetaCall::IsFunctor< T >* >
@ -104,8 +109,8 @@ 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;
m_invokable = new QskMetaCall::FunctorInvokable< T, Argc, Args, void > ( functor ); init( new QskMetaCall::FunctorInvokable< T, Argc, Args, void > ( functor ),
m_parameterTypes = ConnectionTypes< typename Traits::Arguments >::types(); ConnectionTypes< typename Traits::Arguments >::types() );
} }
Q_DECLARE_METATYPE( QskMetaFunction ) Q_DECLARE_METATYPE( QskMetaFunction )