QskMeta classes reorganized
This commit is contained in:
parent
6b87084678
commit
0075ccbdbd
@ -1,220 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
||||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include "QskMetaCall.h"
|
|
||||||
#include <QMetaMethod>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QSemaphore>
|
|
||||||
|
|
||||||
#include <private/qobject_p.h>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// to get access to the private section of QSlotObjectBase
|
|
||||||
struct SlotObject
|
|
||||||
{
|
|
||||||
QAtomicInt ref;
|
|
||||||
QskMetaCall::Invokable::InvokeFunction invoke;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace QskMetaCall
|
|
||||||
{
|
|
||||||
inline Invokable::InvokeFunction invokeCall( const Invokable* invokable )
|
|
||||||
{
|
|
||||||
return ( ( SlotObject* )( invokable ) )->invoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Invokable::typeInfo() const
|
|
||||||
{
|
|
||||||
int value;
|
|
||||||
|
|
||||||
auto f = invokeCall( this );
|
|
||||||
|
|
||||||
f( TypeInfo, const_cast< Invokable* >( this ),
|
|
||||||
nullptr, reinterpret_cast< void** >( &value ), nullptr );
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Invokable::refCount() const
|
|
||||||
{
|
|
||||||
return ( ( SlotObject* )( this ) )->ref.load();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
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 )
|
|
||||||
{
|
|
||||||
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 ) ) );
|
|
||||||
auto arguments = static_cast< void** >( malloc( paramCount * sizeof( void* ) ) );
|
|
||||||
|
|
||||||
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 );
|
|
||||||
arguments[i] = args[i - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_ASSERT( args[paramCount] == nullptr );
|
|
||||||
|
|
||||||
if ( connectionType == Qt::QueuedConnection )
|
|
||||||
{
|
|
||||||
auto event = new MethodCallEvent(
|
|
||||||
metaObject, methodIndex, paramCount + 1, types, args );
|
|
||||||
|
|
||||||
QCoreApplication::postEvent(object, event );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QSemaphore semaphore;
|
|
||||||
|
|
||||||
auto event = new MethodCallEvent(
|
|
||||||
metaObject, methodIndex, paramCount + 1, types, args, &semaphore );
|
|
||||||
|
|
||||||
QCoreApplication::postEvent( object, event );
|
|
||||||
|
|
||||||
semaphore.acquire();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskMetaCall::invoke( QObject* object,
|
|
||||||
const Invokable& invokable, int argc, const int argTypes[], void* argv[],
|
|
||||||
Qt::ConnectionType connectionType )
|
|
||||||
{
|
|
||||||
//connectionType &= ~Qt::UniqueConnection;
|
|
||||||
|
|
||||||
auto invokablePtr = const_cast< Invokable* >( &invokable );
|
|
||||||
|
|
||||||
if ( connectionType == Qt::AutoConnection )
|
|
||||||
{
|
|
||||||
connectionType = ( object->thread() == QThread::currentThread() )
|
|
||||||
? Qt::DirectConnection : Qt::QueuedConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( connectionType == Qt::DirectConnection )
|
|
||||||
{
|
|
||||||
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 FunctionCallEvent(
|
|
||||||
invokablePtr, argc, types, arguments, nullptr );
|
|
||||||
|
|
||||||
QCoreApplication::postEvent( object, event );
|
|
||||||
}
|
|
||||||
else // Qt::BlockingQueuedConnection ???
|
|
||||||
{
|
|
||||||
// ....
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,198 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
||||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QSK_META_CALL_H
|
|
||||||
#define QSK_META_CALL_H 1
|
|
||||||
|
|
||||||
#include "QskGlobal.h"
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
namespace QskMetaCall
|
|
||||||
{
|
|
||||||
class Invokable;
|
|
||||||
|
|
||||||
QSK_EXPORT void invoke( QObject* object,
|
|
||||||
const QMetaMethod&, void* args[],
|
|
||||||
Qt::ConnectionType = Qt::AutoConnection );
|
|
||||||
|
|
||||||
QSK_EXPORT void invoke( QObject*,
|
|
||||||
const Invokable&, int argc, const int argTypes[], void* args[],
|
|
||||||
Qt::ConnectionType = Qt::AutoConnection );
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace QskMetaCall
|
|
||||||
{
|
|
||||||
using namespace QtPrivate;
|
|
||||||
|
|
||||||
class QSK_EXPORT Invokable : public QSlotObjectBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef void (* InvokeFunction)( int which, QSlotObjectBase*,
|
|
||||||
QObject*, void**, bool* );
|
|
||||||
|
|
||||||
enum { TypeInfo = NumOperations + 1 };
|
|
||||||
|
|
||||||
int typeInfo() const;
|
|
||||||
int refCount() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
explicit Invokable( InvokeFunction f ):
|
|
||||||
QSlotObjectBase( f )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename Func, typename Args, typename R >
|
|
||||||
class FunctionInvokable : public Invokable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef FunctionPointer< Func > FuncType;
|
|
||||||
|
|
||||||
explicit FunctionInvokable( Func f ):
|
|
||||||
Invokable( &invoke ),
|
|
||||||
function(f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void invoke(int which, QSlotObjectBase* invokable,
|
|
||||||
QObject* object, void** args, bool* )
|
|
||||||
{
|
|
||||||
auto f = static_cast< FunctionInvokable* >( invokable );
|
|
||||||
|
|
||||||
switch ( which )
|
|
||||||
{
|
|
||||||
case Destroy:
|
|
||||||
{
|
|
||||||
delete f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Call:
|
|
||||||
{
|
|
||||||
FuncType::template call< Args, R >( f->function, object, args );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TypeInfo:
|
|
||||||
{
|
|
||||||
int* typeInfo = reinterpret_cast< int* >( args );
|
|
||||||
//*typeInfo = QskMetaFunction::Function;
|
|
||||||
*typeInfo = 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Func function;
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename Func, typename Args, typename R >
|
|
||||||
class MemberFunctionInvokable : public Invokable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit MemberFunctionInvokable( Func f ):
|
|
||||||
Invokable( &invoke ),
|
|
||||||
function(f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void invoke( int which, QSlotObjectBase* invokable,
|
|
||||||
QObject* object, void** args, bool* ret )
|
|
||||||
{
|
|
||||||
typedef FunctionPointer< Func > FuncType;
|
|
||||||
|
|
||||||
auto f = static_cast< MemberFunctionInvokable* >( invokable );
|
|
||||||
|
|
||||||
switch (which)
|
|
||||||
{
|
|
||||||
case Destroy:
|
|
||||||
{
|
|
||||||
delete f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Call:
|
|
||||||
{
|
|
||||||
FuncType::template call< Args, R >(
|
|
||||||
f->function, static_cast< typename FuncType::Object* >( object ), args );
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Compare:
|
|
||||||
{
|
|
||||||
*ret = *reinterpret_cast< Func* >( args ) == f->function;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TypeInfo:
|
|
||||||
{
|
|
||||||
int* typeInfo = reinterpret_cast< int* >( args );
|
|
||||||
*typeInfo = 0;
|
|
||||||
//*typeInfo = QskMetaFunction::Member;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Func function;
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename Func, int N, typename Args, typename R >
|
|
||||||
class FunctorInvokable : public Invokable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef Functor< Func, N > FuncType;
|
|
||||||
|
|
||||||
explicit FunctorInvokable( Func f ):
|
|
||||||
Invokable( &invoke ),
|
|
||||||
function( std::move( f ) )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void invoke( int which, QSlotObjectBase* invokable,
|
|
||||||
QObject* object, void** args, bool* )
|
|
||||||
{
|
|
||||||
auto f = static_cast< FunctorInvokable* >( invokable );
|
|
||||||
|
|
||||||
switch (which)
|
|
||||||
{
|
|
||||||
case Destroy:
|
|
||||||
{
|
|
||||||
delete f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Call:
|
|
||||||
{
|
|
||||||
FuncType::template call< Args, R >( f->function, object, args );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TypeInfo:
|
|
||||||
{
|
|
||||||
int* typeInfo = reinterpret_cast< int* >( args );
|
|
||||||
*typeInfo = 2;
|
|
||||||
//*typeInfo = QskMetaFunction::Functor;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Func function;
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
using IsMemberFunction = typename std::enable_if< FunctionPointer< T >::IsPointerToMemberFunction,
|
|
||||||
std::true_type >::type;
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
using IsFunction = typename std::enable_if< !FunctionPointer< T >::IsPointerToMemberFunction
|
|
||||||
&& FunctionPointer< T >::ArgumentCount >= 0, std::true_type >::type;
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
using IsFunctor = typename std::enable_if< !FunctionPointer< T >::IsPointerToMemberFunction
|
|
||||||
&& FunctionPointer< T >::ArgumentCount == -1, std::true_type >::type;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -4,8 +4,29 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "QskMetaCallback.h"
|
#include "QskMetaCallback.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVector>
|
#include <QCoreApplication>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QSemaphore>
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
|
#include <private/qobject_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
|
static inline void qskInvokeMethodQueued( QObject* object,
|
||||||
|
const QMetaObject* metaObject, ushort methodIndex,
|
||||||
|
int nargs, int* types, void* args[], QSemaphore* semaphore = nullptr )
|
||||||
|
{
|
||||||
|
constexpr QObject* sender = nullptr;
|
||||||
|
constexpr int signalId = -1;
|
||||||
|
|
||||||
|
auto event = new QMetaCallEvent(
|
||||||
|
metaObject->methodOffset(), methodIndex, metaObject->d.static_metacall,
|
||||||
|
sender, signalId, nargs, types, args, semaphore );
|
||||||
|
|
||||||
|
QCoreApplication::postEvent( object, event );
|
||||||
|
}
|
||||||
|
|
||||||
QskMetaCallback::QskMetaCallback( const QObject* object,
|
QskMetaCallback::QskMetaCallback( const QObject* object,
|
||||||
const QMetaMethod& method, Qt::ConnectionType connectionType ):
|
const QMetaMethod& method, Qt::ConnectionType connectionType ):
|
||||||
@ -147,8 +168,7 @@ void QskMetaCallback::invoke( void* args[] )
|
|||||||
{
|
{
|
||||||
case MetaMethod:
|
case MetaMethod:
|
||||||
{
|
{
|
||||||
if ( object )
|
qskInvokeMethod( object, *m_method, args, connectionType() );
|
||||||
QskMetaCall::invoke( object, *m_method, args, connectionType() );
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaFunction:
|
case MetaFunction:
|
||||||
@ -161,3 +181,80 @@ void QskMetaCallback::invoke( void* args[] )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void qskInvokeMethod( QObject* object,
|
||||||
|
const QMetaMethod& method, void* args[],
|
||||||
|
Qt::ConnectionType connectionType )
|
||||||
|
{
|
||||||
|
if ( object == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
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 ) ) );
|
||||||
|
auto arguments = static_cast< void** >( malloc( paramCount * sizeof( void* ) ) );
|
||||||
|
|
||||||
|
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 );
|
||||||
|
arguments[i] = args[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT( args[paramCount] == nullptr );
|
||||||
|
|
||||||
|
if ( connectionType == Qt::QueuedConnection )
|
||||||
|
{
|
||||||
|
qskInvokeMethodQueued( object,
|
||||||
|
metaObject, methodIndex, paramCount + 1, types, args );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QSemaphore semaphore;
|
||||||
|
|
||||||
|
qskInvokeMethodQueued( object,
|
||||||
|
metaObject, methodIndex, paramCount + 1, types, args, &semaphore );
|
||||||
|
|
||||||
|
semaphore.acquire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -89,6 +89,10 @@ inline Qt::ConnectionType QskMetaCallback::connectionType() const
|
|||||||
return static_cast< Qt::ConnectionType >( m_connectionType );
|
return static_cast< Qt::ConnectionType >( m_connectionType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSK_EXPORT void qskInvokeMethod(
|
||||||
|
QObject* object, const QMetaMethod&, void* args[],
|
||||||
|
Qt::ConnectionType = Qt::AutoConnection );
|
||||||
|
|
||||||
Q_DECLARE_METATYPE( QskMetaCallback )
|
Q_DECLARE_METATYPE( QskMetaCallback )
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,9 +4,30 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "QskGlobal.h"
|
#include "QskGlobal.h"
|
||||||
#include "QskMetaCall.h"
|
|
||||||
#include "QskMetaFunction.h"
|
#include "QskMetaFunction.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSemaphore>
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
|
#include <private/qobject_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
|
static inline void qskInvokeFunctionQueued( QObject* object,
|
||||||
|
QskMetaInvokable* invokable, int argc, int* types, void* argv[],
|
||||||
|
QSemaphore* semaphore = nullptr )
|
||||||
|
{
|
||||||
|
constexpr QObject* sender = nullptr;
|
||||||
|
constexpr int signalId = 0;
|
||||||
|
|
||||||
|
auto event = new QMetaCallEvent(
|
||||||
|
invokable, sender, signalId, argc, types, argv, semaphore );
|
||||||
|
|
||||||
|
QCoreApplication::postEvent( object, event );
|
||||||
|
}
|
||||||
|
|
||||||
QskMetaFunction::QskMetaFunction():
|
QskMetaFunction::QskMetaFunction():
|
||||||
m_invokable( nullptr ),
|
m_invokable( nullptr ),
|
||||||
m_parameterTypes( nullptr )
|
m_parameterTypes( nullptr )
|
||||||
@ -68,15 +89,10 @@ QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskMetaFunction::init( QskMetaCall::Invokable* invokable,
|
void QskMetaFunction::init( QskMetaInvokable* invokable,
|
||||||
const int* parameterTypes )
|
const int* parameterTypes )
|
||||||
{
|
{
|
||||||
m_invokable = invokable;
|
m_invokable = invokable;
|
||||||
#if 0
|
|
||||||
if ( m_invokable )
|
|
||||||
m_invokable->ref();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_parameterTypes = parameterTypes;
|
m_parameterTypes = parameterTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,9 +127,78 @@ 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 )
|
||||||
{
|
{
|
||||||
if ( m_invokable )
|
if ( m_invokable == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
int invokeType = connectionType & 0x3;
|
||||||
|
|
||||||
|
if ( invokeType == Qt::AutoConnection )
|
||||||
{
|
{
|
||||||
QskMetaCall::invoke( object, *m_invokable,
|
invokeType = ( object->thread() == QThread::currentThread() )
|
||||||
parameterCount(), parameterTypes(), argv, connectionType );
|
? Qt::DirectConnection : Qt::QueuedConnection;
|
||||||
|
}
|
||||||
|
else if ( invokeType == Qt::BlockingQueuedConnection )
|
||||||
|
{
|
||||||
|
if ( object->thread() == QThread::currentThread() )
|
||||||
|
{
|
||||||
|
// We would end up in a deadlock, better do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( invokeType == Qt::DirectConnection )
|
||||||
|
{
|
||||||
|
m_invokable->call( object, argv );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( object == nullptr )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
/*
|
||||||
|
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;
|
||||||
|
|
||||||
|
for ( uint i = 1; i < argc; i++ )
|
||||||
|
{
|
||||||
|
if ( argv[i] == nullptr )
|
||||||
|
{
|
||||||
|
Q_ASSERT( arguments[i] != nullptr );
|
||||||
|
|
||||||
|
free( types );
|
||||||
|
free( arguments );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
types[i] = m_parameterTypes[i - 1];
|
||||||
|
arguments[i] = QMetaType::create( m_parameterTypes[i - 1], argv[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( connectionType == Qt::QueuedConnection )
|
||||||
|
{
|
||||||
|
qskInvokeFunctionQueued( object, m_invokable, argc, types, arguments );
|
||||||
|
}
|
||||||
|
else // Qt::BlockingQueuedConnection ???
|
||||||
|
{
|
||||||
|
QSemaphore semaphore;
|
||||||
|
|
||||||
|
qskInvokeFunctionQueued( object,
|
||||||
|
m_invokable, argc, types, arguments, &semaphore );
|
||||||
|
|
||||||
|
semaphore.acquire();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,27 @@
|
|||||||
#define QSK_META_FUNCTION_H 1
|
#define QSK_META_FUNCTION_H 1
|
||||||
|
|
||||||
#include "QskGlobal.h"
|
#include "QskGlobal.h"
|
||||||
#include "QskMetaCall.h"
|
#include "QskMetaInvokable.h"
|
||||||
|
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
|
||||||
|
namespace QskMetaFunctionTraits
|
||||||
|
{
|
||||||
|
using namespace QtPrivate;
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
using IsMemberFunction = typename std::enable_if< FunctionPointer< T >::IsPointerToMemberFunction,
|
||||||
|
std::true_type >::type;
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
using IsFunction = typename std::enable_if< !FunctionPointer< T >::IsPointerToMemberFunction
|
||||||
|
&& FunctionPointer< T >::ArgumentCount >= 0, std::true_type >::type;
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
using IsFunctor = typename std::enable_if< !FunctionPointer< T >::IsPointerToMemberFunction
|
||||||
|
&& FunctionPointer< T >::ArgumentCount == -1, std::true_type >::type;
|
||||||
|
}
|
||||||
|
|
||||||
class QSK_EXPORT QskMetaFunction
|
class QSK_EXPORT QskMetaFunction
|
||||||
{
|
{
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
@ -37,13 +54,13 @@ public:
|
|||||||
QskMetaFunction( const QskMetaFunction& );
|
QskMetaFunction( const QskMetaFunction& );
|
||||||
QskMetaFunction( QskMetaFunction&& );
|
QskMetaFunction( QskMetaFunction&& );
|
||||||
|
|
||||||
template< typename T, QskMetaCall::IsMemberFunction< T >* = nullptr >
|
template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* = nullptr >
|
||||||
QskMetaFunction( T );
|
QskMetaFunction( T );
|
||||||
|
|
||||||
template< typename T, QskMetaCall::IsFunction< T >* = nullptr >
|
template< typename T, QskMetaFunctionTraits::IsFunction< T >* = nullptr >
|
||||||
QskMetaFunction( T );
|
QskMetaFunction( T );
|
||||||
|
|
||||||
template< typename T, QskMetaCall::IsFunctor< T >* = nullptr >
|
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* = nullptr >
|
||||||
QskMetaFunction( T );
|
QskMetaFunction( T );
|
||||||
|
|
||||||
~QskMetaFunction();
|
~QskMetaFunction();
|
||||||
@ -62,44 +79,42 @@ public:
|
|||||||
Type functionType() const;
|
Type functionType() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init( QskMetaCall::Invokable*, const int* );
|
void init( QskMetaInvokable*, const int* );
|
||||||
|
|
||||||
QskMetaCall::Invokable* m_invokable;
|
QskMetaInvokable* m_invokable;
|
||||||
const int* m_parameterTypes;
|
const int* m_parameterTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template< typename T, QskMetaCall::IsMemberFunction< T >* >
|
template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* >
|
||||||
inline QskMetaFunction::QskMetaFunction( T function )
|
inline QskMetaFunction::QskMetaFunction( T function )
|
||||||
{
|
{
|
||||||
using namespace QtPrivate;
|
using namespace QtPrivate;
|
||||||
using namespace QskMetaCall;
|
|
||||||
|
|
||||||
using Traits = FunctionPointer< T >;
|
using Traits = FunctionPointer< T >;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
init( new MemberFunctionInvokable< T, Args, void >( function ),
|
init( new QskMetaMemberInvokable< T, Args, void >( function ),
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T, QskMetaCall::IsFunction< T >* >
|
template< typename T, QskMetaFunctionTraits::IsFunction< T >* >
|
||||||
inline QskMetaFunction::QskMetaFunction( T function )
|
inline QskMetaFunction::QskMetaFunction( T function )
|
||||||
{
|
{
|
||||||
using namespace QtPrivate;
|
using namespace QtPrivate;
|
||||||
using namespace QskMetaCall;
|
|
||||||
|
|
||||||
using Traits = FunctionPointer< T >;
|
using Traits = FunctionPointer< T >;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
init( new FunctionInvokable< T, Args, void >( function ),
|
init( new QskMetaFunctionInvokable< T, Args, void >( function ),
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T, QskMetaCall::IsFunctor< T >* >
|
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* >
|
||||||
inline QskMetaFunction::QskMetaFunction( T functor )
|
inline QskMetaFunction::QskMetaFunction( T functor )
|
||||||
{
|
{
|
||||||
using namespace QtPrivate;
|
using namespace QtPrivate;
|
||||||
@ -109,7 +124,7 @@ 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;
|
||||||
|
|
||||||
init( new QskMetaCall::FunctorInvokable< T, Argc, Args, void > ( functor ),
|
init( new QskMetaFunctorInvokable< T, Argc, Args, void > ( functor ),
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
src/common/QskMetaInvokable.cpp
Normal file
37
src/common/QskMetaInvokable.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskMetaInvokable.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// to have access to the private section of QSlotObjectBase
|
||||||
|
struct SlotObject
|
||||||
|
{
|
||||||
|
QAtomicInt ref;
|
||||||
|
QskMetaInvokable::InvokeFunction invoke;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert( sizeof( SlotObject ) == sizeof( QskMetaInvokable ),
|
||||||
|
"Bad cast: QskMetaInvokable does not match" );
|
||||||
|
}
|
||||||
|
|
||||||
|
int QskMetaInvokable::typeInfo() const
|
||||||
|
{
|
||||||
|
auto that = const_cast< QskMetaInvokable* >( this );
|
||||||
|
|
||||||
|
int value;
|
||||||
|
|
||||||
|
reinterpret_cast< SlotObject* >( that )->invoke( TypeInfo, that,
|
||||||
|
nullptr, reinterpret_cast< void** >( &value ), nullptr );
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QskMetaInvokable::refCount() const
|
||||||
|
{
|
||||||
|
auto that = const_cast< QskMetaInvokable* >( this );
|
||||||
|
return reinterpret_cast< SlotObject* >( that )->ref.load();
|
||||||
|
}
|
167
src/common/QskMetaInvokable.h
Normal file
167
src/common/QskMetaInvokable.h
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_META_INVOKABLE_H
|
||||||
|
#define QSK_META_INVOKABLE_H 1
|
||||||
|
|
||||||
|
#include "QskGlobal.h"
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
// helper classes for QskMetaFunction
|
||||||
|
|
||||||
|
class QskMetaInvokable : public QtPrivate::QSlotObjectBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef void (* InvokeFunction)(
|
||||||
|
int which, QtPrivate::QSlotObjectBase*, QObject*, void**, bool* );
|
||||||
|
|
||||||
|
enum { TypeInfo = NumOperations + 1 };
|
||||||
|
|
||||||
|
int typeInfo() const;
|
||||||
|
int refCount() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit QskMetaInvokable( InvokeFunction f ):
|
||||||
|
QSlotObjectBase( f )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename Func, typename Args, typename R >
|
||||||
|
class QskMetaFunctionInvokable : public QskMetaInvokable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef QtPrivate::FunctionPointer< Func > FuncType;
|
||||||
|
|
||||||
|
explicit QskMetaFunctionInvokable( Func f ):
|
||||||
|
QskMetaInvokable( &invoke ),
|
||||||
|
function(f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void invoke(int which, QtPrivate::QSlotObjectBase* invokable,
|
||||||
|
QObject* object, void** args, bool* )
|
||||||
|
{
|
||||||
|
auto f = static_cast< QskMetaFunctionInvokable* >( invokable );
|
||||||
|
|
||||||
|
switch ( which )
|
||||||
|
{
|
||||||
|
case Destroy:
|
||||||
|
{
|
||||||
|
delete f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Call:
|
||||||
|
{
|
||||||
|
FuncType::template call< Args, R >( f->function, object, args );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeInfo:
|
||||||
|
{
|
||||||
|
int* typeInfo = reinterpret_cast< int* >( args );
|
||||||
|
*typeInfo = 1; // = QskMetaFunction::Function
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Func function;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename Func, typename Args, typename R >
|
||||||
|
class QskMetaMemberInvokable : public QskMetaInvokable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit QskMetaMemberInvokable( Func f ):
|
||||||
|
QskMetaInvokable( &invoke ),
|
||||||
|
function(f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void invoke( int which, QtPrivate::QSlotObjectBase* invokable,
|
||||||
|
QObject* object, void** args, bool* ret )
|
||||||
|
{
|
||||||
|
typedef QtPrivate::FunctionPointer< Func > FuncType;
|
||||||
|
|
||||||
|
auto f = static_cast< QskMetaMemberInvokable* >( invokable );
|
||||||
|
|
||||||
|
switch (which)
|
||||||
|
{
|
||||||
|
case Destroy:
|
||||||
|
{
|
||||||
|
delete f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Call:
|
||||||
|
{
|
||||||
|
FuncType::template call< Args, R >(
|
||||||
|
f->function, static_cast< typename FuncType::Object* >( object ), args );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Compare:
|
||||||
|
{
|
||||||
|
*ret = *reinterpret_cast< Func* >( args ) == f->function;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeInfo:
|
||||||
|
{
|
||||||
|
int* typeInfo = reinterpret_cast< int* >( args );
|
||||||
|
*typeInfo = 0; // = QskMetaFunction::Member
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Func function;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename Func, int N, typename Args, typename R >
|
||||||
|
class QskMetaFunctorInvokable : public QskMetaInvokable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef QtPrivate::Functor< Func, N > FuncType;
|
||||||
|
|
||||||
|
explicit QskMetaFunctorInvokable( Func f ):
|
||||||
|
QskMetaInvokable( &invoke ),
|
||||||
|
function( std::move( f ) )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void invoke( int which, QSlotObjectBase* invokable,
|
||||||
|
QObject* object, void** args, bool* )
|
||||||
|
{
|
||||||
|
auto f = static_cast< QskMetaFunctorInvokable* >( invokable );
|
||||||
|
|
||||||
|
switch (which)
|
||||||
|
{
|
||||||
|
case Destroy:
|
||||||
|
{
|
||||||
|
delete f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Call:
|
||||||
|
{
|
||||||
|
FuncType::template call< Args, R >( f->function, object, args );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeInfo:
|
||||||
|
{
|
||||||
|
int* typeInfo = reinterpret_cast< int* >( args );
|
||||||
|
*typeInfo = 2; // QskMetaFunction::Functor;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Func function;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -40,9 +40,9 @@ HEADERS += \
|
|||||||
common/QskGlobal.h \
|
common/QskGlobal.h \
|
||||||
common/QskGradient.h \
|
common/QskGradient.h \
|
||||||
common/QskMargins.h \
|
common/QskMargins.h \
|
||||||
common/QskMetaCall.h \
|
|
||||||
common/QskMetaCallback.h \
|
common/QskMetaCallback.h \
|
||||||
common/QskMetaFunction.h \
|
common/QskMetaFunction.h \
|
||||||
|
common/QskMetaInvokable.cpp \
|
||||||
common/QskModule.h \
|
common/QskModule.h \
|
||||||
common/QskNamespace.h \
|
common/QskNamespace.h \
|
||||||
common/QskObjectCounter.h \
|
common/QskObjectCounter.h \
|
||||||
@ -59,9 +59,9 @@ SOURCES += \
|
|||||||
common/QskFunctions.cpp \
|
common/QskFunctions.cpp \
|
||||||
common/QskGradient.cpp \
|
common/QskGradient.cpp \
|
||||||
common/QskMargins.cpp \
|
common/QskMargins.cpp \
|
||||||
common/QskMetaCall.cpp \
|
|
||||||
common/QskMetaCallback.cpp \
|
common/QskMetaCallback.cpp \
|
||||||
common/QskMetaFunction.cpp \
|
common/QskMetaFunction.cpp \
|
||||||
|
common/QskMetaInvokable.cpp \
|
||||||
common/QskModule.cpp \
|
common/QskModule.cpp \
|
||||||
common/QskObjectCounter.cpp \
|
common/QskObjectCounter.cpp \
|
||||||
common/QskSizePolicy.cpp \
|
common/QskSizePolicy.cpp \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user