diff --git a/playground/invoker/Invoker.cpp b/playground/invoker/Invoker.cpp index 59817df3..042c7c0b 100644 --- a/playground/invoker/Invoker.cpp +++ b/playground/invoker/Invoker.cpp @@ -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 ); } } diff --git a/playground/invoker/Invoker.h b/playground/invoker/Invoker.h index aaf6798e..5b2a4a23 100644 --- a/playground/invoker/Invoker.h +++ b/playground/invoker/Invoker.h @@ -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; diff --git a/playground/invoker/main.cpp b/playground/invoker/main.cpp index d5858c56..8377cc2a 100644 --- a/playground/invoker/main.cpp +++ b/playground/invoker/main.cpp @@ -4,7 +4,9 @@ *****************************************************************************/ #include "Invoker.h" +#include #include +#include 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(); } diff --git a/src/common/QskMetaCall.cpp b/src/common/QskMetaCall.cpp index fd83aa20..a6b33121 100644 --- a/src/common/QskMetaCall.cpp +++ b/src/common/QskMetaCall.cpp @@ -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 ); } diff --git a/src/common/QskMetaCall.h b/src/common/QskMetaCall.h index a3a93bd6..cda99b7f 100644 --- a/src/common/QskMetaCall.h +++ b/src/common/QskMetaCall.h @@ -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 ); } diff --git a/src/common/QskMetaCallback.cpp b/src/common/QskMetaCallback.cpp index 016f00fd..14a77a91 100644 --- a/src/common/QskMetaCallback.cpp +++ b/src/common/QskMetaCallback.cpp @@ -4,82 +4,11 @@ *****************************************************************************/ #include "QskMetaCallback.h" -#include -#include #include -#include - -#include - -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 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: diff --git a/src/common/QskMetaCallback.h b/src/common/QskMetaCallback.h index 97be0806..09097434 100644 --- a/src/common/QskMetaCallback.h +++ b/src/common/QskMetaCallback.h @@ -12,6 +12,7 @@ #include #include #include +#include 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; diff --git a/src/common/QskMetaFunction.cpp b/src/common/QskMetaFunction.cpp index ebd0299c..7cbde28c 100644 --- a/src/common/QskMetaFunction.cpp +++ b/src/common/QskMetaFunction.cpp @@ -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 ); + } } diff --git a/src/common/QskMetaFunction.h b/src/common/QskMetaFunction.h index bad1a2ce..13a7369b 100644 --- a/src/common/QskMetaFunction.h +++ b/src/common/QskMetaFunction.h @@ -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 )