non working ideas removed

This commit is contained in:
Uwe Rathmann 2018-03-02 11:26:25 +01:00
parent 686f4ff2d8
commit a9f5e0a528
6 changed files with 192 additions and 298 deletions

View File

@ -4,6 +4,7 @@
*****************************************************************************/ *****************************************************************************/
#include "Invoker.h" #include "Invoker.h"
#include <QThread>
Invoker::Invoker( QObject* parent ): Invoker::Invoker( QObject* parent ):
QObject( parent ) QObject( parent )
@ -47,9 +48,28 @@ void Invoker::invoke( qreal realValue, int intValue,
callback.setConnectionType( connectionType ); callback.setConnectionType( connectionType );
if ( connectionType == Qt::DirectConnection ) const int callType = connectionType & 0x3;
callback.invoke( args ); switch( callType )
else if ( callback.object() ) {
callback.invoke( args ); case Qt::DirectConnection:
{
callback.invoke( args );
break;
}
case Qt::QueuedConnection:
{
if ( callback.object() )
callback.invoke( args );
break;
}
case Qt::BlockingQueuedConnection:
{
const auto receiver = callback.object();
if ( receiver && receiver->thread() != QThread::currentThread() )
callback.invoke( args );
break;
}
}
} }
} }

View File

@ -7,6 +7,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QTimer> #include <QTimer>
#include <QThread>
static void debugNone1() static void debugNone1()
{ {
@ -40,17 +41,20 @@ static void debugValue( qreal d, int i )
class MyObject : public QObject class MyObject : public QObject
{ {
Q_OBJECT
public: public:
MyObject( QObject* parent = nullptr ): MyObject( QObject* parent = nullptr ):
QObject( parent ) QObject( parent )
{ {
} }
void print0( double d, int i ) const
{
qDebug() << "print0" << d << i;
}
void print1( double d, int i ) const void print1( double d, int i ) const
{ {
qDebug() << d << i; qDebug() << "print1" << d << i;
} }
void print2( int i, double d ) const void print2( int i, double d ) const
@ -67,83 +71,96 @@ public:
{ {
qDebug() << i; qDebug() << i;
} }
Q_SIGNALS:
void done( double, int );
};
class MyObject2: public MyObject
{
public:
MyObject2( QObject* parent = nullptr ):
MyObject( parent )
{
}
virtual ~MyObject2()
{
}
virtual void noop()
{
}
}; };
static auto fs = []( int i, double d ) { qDebug() << i << d; }; static auto fs = []( int i, double d ) { qDebug() << i << d; };
class Application: public QCoreApplication
{
public:
Application( int &argc, char *argv[] ):
QCoreApplication( argc, argv ),
m_object( new MyObject() ),
m_thread( new QThread( this ) )
{
auto f = [this]( int i, double d ) { qDebug() << i << d << (++m_num); };
m_invoker.addCallback( m_object, &MyObject::print0 );
m_invoker.addCallback( m_object, &MyObject::print1 );
m_invoker.addCallback( QskMetaFunction() );
m_invoker.addCallback( debugNone1 );
m_invoker.addCallback( debugNone2 );
m_invoker.addCallback( debugValue );
m_invoker.addCallback( debugValueI1 );
m_invoker.addCallback( debugValueI2 );
m_invoker.addCallback( debugValueD );
m_invoker.addCallback( m_object, &MyObject::print0 );
m_invoker.addCallback( m_object, &MyObject::print1 );
m_invoker.addCallback( m_object, &MyObject::print2 );
m_invoker.addCallback( m_object, &MyObject::print3 );
m_invoker.addCallback( m_object, &MyObject::print4 );
m_invoker.addCallback( m_object, []( double d, int i ) { qDebug() << d << i; } );
m_invoker.addCallback( m_object, f );
m_invoker.addCallback( m_object, fs );
m_invoker.addCallback( m_object, []( double d ) { qDebug() << d; } );
m_invoker.addCallback( []() { qDebug() << "HERE"; } );
m_invoker.addCallback( []( int i, double d ) { qDebug() << i << d; } );
m_invoker.addCallback( []( int i ) { qDebug() << "I1" << i; } );
m_invoker.addCallback( []( int i ) { qDebug() << "I2" << i; } );
m_invoker.addCallback( []( double d ) { qDebug() << "V" << d; } );
m_invoker.addCallback( []( const double& d ) { qDebug() << "R" << d; } );
}
virtual ~Application()
{
delete m_object;
}
void invokeDirect()
{
qDebug() << "== Direct Connections";
m_invoker.invoke( 3.14, 35, Qt::DirectConnection );
}
void invokeQueued()
{
qDebug() << "== Queued Connections";
m_invoker.invoke( 0.07, 42, Qt::QueuedConnection );
}
void invokeBlockingQueued()
{
m_thread->start();
m_object->moveToThread( m_thread );
qDebug() << "== Blocking Queued Connections";
m_invoker.invoke( 0.54, 88, Qt::BlockingQueuedConnection );
QTimer::singleShot( 10, m_thread, &QThread::quit );
}
private:
Invoker m_invoker;
MyObject* m_object;
QThread* m_thread;
int m_num = 111;
};
int main( int argc, char* argv[] ) int main( int argc, char* argv[] )
{ {
QCoreApplication app( argc, argv ); Application app( argc, argv );
MyObject object; app.invokeDirect();
MyObject2 object2;
int num = 111; QTimer::singleShot( 0, &app, &Application::invokeQueued );
auto f = [&num]( int i, double d ) { qDebug() << i << d << (++num); }; QTimer::singleShot( 20, &app, &Application::invokeBlockingQueued );
Invoker invoker; QTimer::singleShot( 50, &app, QCoreApplication::quit );
#if 1
invoker.addCallback( QskMetaFunction() );
invoker.addCallback( debugNone1 );
invoker.addCallback( debugNone2 );
invoker.addCallback( debugValue );
invoker.addCallback( debugValueI1 );
invoker.addCallback( debugValueI2 );
invoker.addCallback( debugValueD );
invoker.addCallback( &object, &MyObject::print1 );
invoker.addCallback( &object2, &MyObject2::print1 );
invoker.addCallback( &object, &MyObject::print2 );
invoker.addCallback( &object, &MyObject::print3 );
invoker.addCallback( &object, &MyObject::print4 );
invoker.addCallback( &object, []( double d, int i ) { qDebug() << d << i; } );
invoker.addCallback( &object, f );
invoker.addCallback( &object2, f );
invoker.addCallback( &object, fs );
invoker.addCallback( &object2, fs );
invoker.addCallback( &object, []( double d ) { qDebug() << d; } );
invoker.addCallback( []() { qDebug() << "HERE"; } );
invoker.addCallback( []( int i, double d ) { qDebug() << i << d; } );
invoker.addCallback( []( int i ) { qDebug() << "I1" << i; } );
invoker.addCallback( []( int i ) { qDebug() << "I2" << i; } );
invoker.addCallback( []( double d ) { qDebug() << d; } );
#endif
#if 1
qDebug() << "== Direct Connections";
invoker.invoke( 3.14, 35, Qt::DirectConnection );
qDebug() << "\n\n== Queued Connections";
QTimer::singleShot( 0,
[&invoker] { invoker.invoke( 0.07, 42, Qt::QueuedConnection ); } );
#endif
QTimer::singleShot( 100, &app, QCoreApplication::quit );
return app.exec(); return app.exec();
} }
#include "main.moc"

View File

@ -33,13 +33,6 @@ QskMetaFunction::QskMetaFunction():
{ {
} }
QskMetaFunction::QskMetaFunction( void(*function)() ):
m_invokable( QskMetaInvokable::instance(
QskMetaFunctionInvokable0::invoke, nullptr,
reinterpret_cast< void** >( &function ) ) )
{
}
QskMetaFunction::QskMetaFunction( QskMetaInvokable* invokable ): QskMetaFunction::QskMetaFunction( QskMetaInvokable* invokable ):
m_invokable( invokable ) m_invokable( invokable )
{ {
@ -122,6 +115,10 @@ QskMetaFunction::Type QskMetaFunction::functionType() const
void QskMetaFunction::invoke( void QskMetaFunction::invoke(
QObject* object, void* argv[], Qt::ConnectionType connectionType ) QObject* object, void* argv[], Qt::ConnectionType connectionType )
{ {
// code is not thread safe - TODO ...
QPointer<QObject> receiver( object );
if ( m_invokable == nullptr ) if ( m_invokable == nullptr )
return; return;
@ -129,72 +126,73 @@ void QskMetaFunction::invoke(
if ( invokeType == Qt::AutoConnection ) if ( invokeType == Qt::AutoConnection )
{ {
invokeType = ( object && object->thread() != QThread::currentThread() ) invokeType = ( receiver && receiver->thread() != QThread::currentThread() )
? Qt::QueuedConnection : Qt::DirectConnection; ? Qt::QueuedConnection : Qt::DirectConnection;
} }
else if ( invokeType == Qt::BlockingQueuedConnection )
switch( invokeType )
{ {
if ( ( object == nullptr ) || object->thread() == QThread::currentThread() ) case Qt::DirectConnection:
{ {
// We would end up in a deadlock, better do nothing m_invokable->call( receiver, argv );
return; break;
} }
} case Qt::BlockingQueuedConnection:
if ( invokeType == Qt::DirectConnection )
{
m_invokable->call( object, argv );
}
else
{
if ( object == nullptr )
{ {
#if 1 if ( receiver.isNull()
/* || ( receiver->thread() == QThread::currentThread() ) )
object might be deleted in another thread
during this call - TODO ...
*/
#endif
return;
}
const auto argc = parameterCount();
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;
const int* parameterTypes = m_invokable->parameterTypes();
for ( uint i = 1; i < argc; i++ )
{
if ( argv[i] == nullptr )
{ {
Q_ASSERT( arguments[i] != nullptr ); // We would end up in a deadlock, better do nothing
free( types );
free( arguments );
return; return;
} }
types[i] = parameterTypes[i - 1];
arguments[i] = QMetaType::create( parameterTypes[i - 1], argv[i] );
}
if ( connectionType == Qt::QueuedConnection )
{
qskInvokeFunctionQueued( object, m_invokable, argc, types, arguments );
}
else // Qt::BlockingQueuedConnection ???
{
QSemaphore semaphore; QSemaphore semaphore;
qskInvokeFunctionQueued( object, qskInvokeFunctionQueued( receiver, m_invokable,
m_invokable, argc, types, arguments, &semaphore ); 0, nullptr, argv, &semaphore );
semaphore.acquire(); semaphore.acquire();
break;
}
case Qt::QueuedConnection:
{
if ( receiver.isNull() )
{
return;
}
const auto argc = parameterCount();
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;
const int* parameterTypes = m_invokable->parameterTypes();
for ( uint i = 1; i < argc; i++ )
{
if ( argv[i] == nullptr )
{
Q_ASSERT( arguments[i] != nullptr );
receiver = nullptr;
break;
}
types[i] = parameterTypes[i - 1];
arguments[i] = QMetaType::create( parameterTypes[i - 1], argv[i] );
}
if ( receiver.isNull() )
{
// object might have died in the meantime
free( types );
free( arguments );
}
qskInvokeFunctionQueued( object, m_invokable, argc, types, arguments );
break;
} }
} }
} }

View File

@ -30,7 +30,6 @@ namespace QskMetaFunctionTraits
template< typename T > template< typename T >
using IsFunction0 = typename std::enable_if< !FunctionPointer< T >::IsPointerToMemberFunction using IsFunction0 = typename std::enable_if< !FunctionPointer< T >::IsPointerToMemberFunction
&& FunctionPointer< T >::ArgumentCount == 0, std::true_type >::type; && FunctionPointer< T >::ArgumentCount == 0, std::true_type >::type;
} }
class QSK_EXPORT QskMetaFunction class QSK_EXPORT QskMetaFunction
@ -59,8 +58,6 @@ public:
QskMetaFunction( const QskMetaFunction& ); QskMetaFunction( const QskMetaFunction& );
QskMetaFunction( QskMetaFunction&& ); QskMetaFunction( QskMetaFunction&& );
QskMetaFunction( void(*function)() );
template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* = nullptr > template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* = nullptr >
QskMetaFunction( T ); QskMetaFunction( T );
@ -115,10 +112,9 @@ inline QskMetaFunction::QskMetaFunction( T function )
constexpr int Argc = Traits::ArgumentCount; constexpr 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 = QskMetaInvokable::instance( m_invokable = new QskMetaMemberInvokable< T, Args, void >( function );
QskMetaMemberInvokable< T, Args, void >::invoke, m_invokable->setParameterTypes(
ConnectionTypes< typename Traits::Arguments >::types(), ConnectionTypes< typename Traits::Arguments >::types() );
reinterpret_cast< void** >( &function ) );
} }
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* > template< typename T, QskMetaFunctionTraits::IsFunctor< T >* >
@ -131,10 +127,9 @@ inline QskMetaFunction::QskMetaFunction( T functor )
constexpr int Argc = Traits::ArgumentCount; constexpr 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 = QskMetaInvokable::instance( m_invokable = new QskMetaFunctorInvokable< T, Argc, Args, void >( functor );
QskMetaFunctorInvokable< T, Argc, Args, void >::invoke, m_invokable->setParameterTypes(
ConnectionTypes< typename Traits::Arguments >::types(), ConnectionTypes< typename Traits::Arguments >::types() );
reinterpret_cast< void** >( &functor ) );
} }
template< typename T, QskMetaFunctionTraits::IsFunction< T >* > template< typename T, QskMetaFunctionTraits::IsFunction< T >* >
@ -146,11 +141,10 @@ inline QskMetaFunction::QskMetaFunction( T function )
constexpr int Argc = Traits::ArgumentCount; constexpr 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 = QskMetaInvokable::instance( m_invokable = new QskMetaFunctionInvokable< T, Args, void >( function );
QskMetaFunctionInvokable< T, Args, void >::invoke, m_invokable->setParameterTypes(
ConnectionTypes< typename Traits::Arguments >::types(), ConnectionTypes< typename Traits::Arguments >::types() );
reinterpret_cast< void** >( &function ) );
} }
Q_DECLARE_METATYPE( QskMetaFunction ) Q_DECLARE_METATYPE( QskMetaFunction )

View File

@ -19,39 +19,6 @@ namespace
"Bad cast: QskMetaInvokable does not match" ); "Bad cast: QskMetaInvokable does not match" );
} }
static inline void qskCallFunction( void (*function)(),
void** args, const int* types )
{
if ( types == nullptr || args == nullptr )
{
function();
return;
}
}
QskMetaInvokable* QskMetaInvokable::instance(
InvokeFunction invoke, const int* parameterTypes, 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 );
invokable->m_parameterTypes = parameterTypes;
return invokable;
}
int QskMetaInvokable::typeInfo() const int QskMetaInvokable::typeInfo() const
{ {
auto that = const_cast< QskMetaInvokable* >( this ); auto that = const_cast< QskMetaInvokable* >( this );
@ -69,47 +36,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();
} }
QskMetaFunctionInvokable0::QskMetaFunctionInvokable0( Function function ):
QskMetaInvokable( &invoke, nullptr ),
m_function( function )
{
}
void QskMetaFunctionInvokable0::invoke(int which, QtPrivate::QSlotObjectBase* invokable,
QObject*, void** args, bool* )
{
switch ( which )
{
case Find:
{
*reinterpret_cast< void** >( args[0] ) = nullptr;
break;
}
case Create:
{
*reinterpret_cast< void** >( args[0] ) =
new Invokable( *reinterpret_cast< Function* >( args[1] ) );
break;
}
case Destroy:
{
delete static_cast< Invokable* >( invokable );
break;
}
case Call:
{
auto invokable01 = static_cast< Invokable* >( invokable );
qskCallFunction( invokable01->m_function,
args, invokable01->parameterTypes() );
break;
}
case TypeInfo:
{
*reinterpret_cast< int* >( args ) = 1; // QskMetaFunction::Function
break;
}
}
}

View File

@ -19,9 +19,7 @@ public:
enum enum
{ {
TypeInfo = NumOperations + 1, TypeInfo = NumOperations + 1
Create,
Find
}; };
int typeInfo() const; int typeInfo() const;
@ -32,8 +30,10 @@ public:
return m_parameterTypes; return m_parameterTypes;
} }
static QskMetaInvokable* instance( InvokeFunction, inline void setParameterTypes( const int* types )
const int* parameterTypes, void** function ); {
m_parameterTypes = types;
}
protected: protected:
explicit inline QskMetaInvokable( InvokeFunction f, explicit inline QskMetaInvokable( InvokeFunction f,
@ -44,22 +44,7 @@ protected:
} }
private: private:
const int* m_parameterTypes; // static array ! const int* m_parameterTypes; // static array, only needed for Qt::QueuedConnection
};
class QSK_EXPORT QskMetaFunctionInvokable0 : public QskMetaInvokable
{
using Function = void(*)();
using Invokable = QskMetaFunctionInvokable0;
public:
explicit QskMetaFunctionInvokable0( Function function );
static void invoke(int which, QtPrivate::QSlotObjectBase*,
QObject* object, void** args, bool* );
private:
Function m_function;
}; };
template< typename Function, typename Args, typename R > template< typename Function, typename Args, typename R >
@ -79,18 +64,6 @@ public:
{ {
switch ( which ) switch ( which )
{ {
case Find:
{
*reinterpret_cast< void** >( args[0] ) = nullptr;
break;
}
case Create:
{
*reinterpret_cast< void** >( args[0] ) =
new Invokable( *reinterpret_cast< Function* >( args[1] ) );
break;
}
case Destroy: case Destroy:
{ {
delete static_cast< Invokable* >( invokable ); delete static_cast< Invokable* >( invokable );
@ -128,30 +101,14 @@ public:
{ {
} }
static void invoke( int which, QtPrivate::QSlotObjectBase*, static void invoke( int which, QtPrivate::QSlotObjectBase* slotObject,
QObject* object, void** args, bool* ) QObject* object, void** args, bool* )
{ {
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:
{ {
delete invokable; delete static_cast< Invokable* >( slotObject );
invokable = nullptr;
break; break;
} }
case Call: case Call:
@ -159,7 +116,7 @@ public:
typedef QtPrivate::FunctionPointer< Function > FuncType; typedef QtPrivate::FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >( FuncType::template call< Args, R >(
invokable->m_function, static_cast< Invokable* >( slotObject )->m_function,
static_cast< typename FuncType::Object* >( object ), args ); static_cast< typename FuncType::Object* >( object ), args );
break; break;
@ -188,29 +145,14 @@ public:
{ {
} }
static void invoke( int which, QSlotObjectBase*, QObject* object, void** args, bool* ) static void invoke( int which, QSlotObjectBase* slotObject,
QObject* object, void** args, bool* )
{ {
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:
{ {
delete invokable; delete static_cast< Invokable* >( slotObject );
invokable = nullptr;
break; break;
} }
case Call: case Call:
@ -218,7 +160,7 @@ public:
typedef QtPrivate::Functor< Function, N > FuncType; typedef QtPrivate::Functor< Function, N > FuncType;
FuncType::template call< Args, R >( FuncType::template call< Args, R >(
invokable->m_function, object, args ); static_cast< Invokable* >( slotObject )->m_function, object, args );
break; break;
} }