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,
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 };
@ -44,6 +45,11 @@ void Invoker::invoke( qreal realValue, int intValue )
}
}
callback.invoke( args );
callback.setConnectionType( connectionType );
if ( connectionType == Qt::DirectConnection )
callback.invoke( args );
else if ( callback.object() )
callback.invoke( args );
}
}

View File

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

View File

@ -4,7 +4,9 @@
*****************************************************************************/
#include "Invoker.h"
#include <QCoreApplication>
#include <QDebug>
#include <QTimer>
static void debugValueI( int i )
{
@ -47,8 +49,7 @@ public:
int main( int argc, char* argv[] )
{
Q_UNUSED( argc )
Q_UNUSED( argv )
QCoreApplication app( argc, argv );
MyObject object;
@ -69,5 +70,14 @@ int main( int argc, char* argv[] )
invoker.addCallback( []( int i ) { qDebug() << i; } );
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,
const QMetaMethod& method, void* args[],
Qt::ConnectionType connectionType )
@ -66,22 +106,33 @@ void QskMetaCall::invoke( QObject* object,
const int paramCount = method.parameterCount();
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++ )
{
if ( arguments[i] == nullptr )
{
Q_ASSERT( arguments[i] != nullptr );
free( types );
free( arguments );
return;
}
types[i] = method.parameterType( i );
Q_ASSERT( args[i] != nullptr );
arguments[i] = args[i - 1];
}
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 );
auto event = new MethodCallEvent(
metaObject, methodIndex, paramCount + 1, types, args );
QCoreApplication::postEvent(object, event );
}
@ -89,10 +140,8 @@ void QskMetaCall::invoke( QObject* object,
{
QSemaphore semaphore;
// what about argc + types ???
auto event = new QMetaCallEvent(
methodOffset, methodIndex, metaObject->d.static_metacall,
nullptr, -1, 0, 0, args, &semaphore );
auto event = new MethodCallEvent(
metaObject, methodIndex, paramCount + 1, types, args, &semaphore );
QCoreApplication::postEvent( object, event );
@ -102,7 +151,7 @@ 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 )
{
//connectionType &= ~Qt::UniqueConnection;
@ -117,14 +166,36 @@ void QskMetaCall::invoke( QObject* object,
if ( connectionType == Qt::DirectConnection )
{
invokablePtr->call( object, args );
invokablePtr->call( object, argv );
}
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 )
{
auto event = new QMetaCallEvent(
invokablePtr, nullptr, 0, 0, nullptr, args, nullptr );
auto event = new FunctionCallEvent(
invokablePtr, argc, types, arguments, nullptr );
QCoreApplication::postEvent( object, event );
}

View File

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

View File

@ -4,82 +4,11 @@
*****************************************************************************/
#include "QskMetaCallback.h"
#include <QCoreApplication>
#include <QThread>
#include <QObject>
#include <QSemaphore>
#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();
}
}
}
#include <QVector>
QskMetaCallback::QskMetaCallback( const QObject* object,
const QMetaMethod& method, Qt::ConnectionType connectionType ):
const QMetaMethod& method, Qt::ConnectionType connectionType ):
m_object( const_cast< QObject* >( object ) ),
m_method( method ),
m_type( MetaMethod ),
@ -156,6 +85,11 @@ QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
return *this;
}
void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
{
m_connectionType = connectionType;
}
void QskMetaCallback::reset()
{
switch( m_type )
@ -218,7 +152,7 @@ void QskMetaCallback::invoke( void* args[] )
case MetaMethod:
{
if ( object )
qskInvoke( object, m_method, args, connectionType() );
QskMetaCall::invoke( object, m_method, args, connectionType() );
break;
}
case MetaFunction:

View File

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

View File

@ -68,11 +68,38 @@ QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
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
{
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
{
if ( m_invokable == nullptr )
@ -82,8 +109,11 @@ QskMetaFunction::Type QskMetaFunction::functionType() const
}
void QskMetaFunction::invoke(
QObject* object, void* args[], Qt::ConnectionType connectionType )
QObject* object, void* argv[], Qt::ConnectionType connectionType )
{
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;
// including the return type !
size_t parameterCount() const;
void invoke( QObject*, void* args[],
Qt::ConnectionType = Qt::AutoConnection );
Type functionType() const;
private:
void init( QskMetaCall::Invokable*, const int* );
QskMetaCall::Invokable* m_invokable;
const int* m_parameterTypes;
};
@ -75,8 +80,8 @@ inline QskMetaFunction::QskMetaFunction( T function )
const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
m_invokable = new MemberFunctionInvokable< T, Args, void >( function );
m_parameterTypes = ConnectionTypes< typename Traits::Arguments >::types();
init( new MemberFunctionInvokable< T, Args, void >( function ),
ConnectionTypes< typename Traits::Arguments >::types() );
}
template< typename T, QskMetaCall::IsFunction< T >* >
@ -90,8 +95,8 @@ inline QskMetaFunction::QskMetaFunction( T function )
const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
m_invokable = new FunctionInvokable< T, Args, void >( function );
m_parameterTypes = ConnectionTypes< typename Traits::Arguments >::types();
init( new FunctionInvokable< T, Args, void >( function ),
ConnectionTypes< typename Traits::Arguments >::types() );
}
template< typename T, QskMetaCall::IsFunctor< T >* >
@ -104,8 +109,8 @@ inline QskMetaFunction::QskMetaFunction( T functor )
const int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
m_invokable = new QskMetaCall::FunctorInvokable< T, Argc, Args, void > ( functor );
m_parameterTypes = ConnectionTypes< typename Traits::Arguments >::types();
init( new QskMetaCall::FunctorInvokable< T, Argc, Args, void > ( functor ),
ConnectionTypes< typename Traits::Arguments >::types() );
}
Q_DECLARE_METATYPE( QskMetaFunction )