QskMetaFunction added - similar to QMetaMethod but for what Qt calls
"functor based" callbacks
This commit is contained in:
parent
d58732d5ac
commit
0c1cfa3453
136
src/common/QskMetaCall.cpp
Normal file
136
src/common/QskMetaCall.cpp
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* 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 QskMetaCall
|
||||||
|
{
|
||||||
|
inline Invokable::InvokeFunction invokeCall( const Invokable* invokable )
|
||||||
|
{
|
||||||
|
struct Data { QAtomicInt dummy; Invokable::InvokeFunction invoke; };
|
||||||
|
return ( ( Data* )( 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ) ) );
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskMetaCall::invoke( QObject* object,
|
||||||
|
const Invokable& invokable, void* args[],
|
||||||
|
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, args );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( connectionType == Qt::QueuedConnection )
|
||||||
|
{
|
||||||
|
auto event = new QMetaCallEvent(
|
||||||
|
invokablePtr, nullptr, 0, 0, nullptr, args, nullptr );
|
||||||
|
|
||||||
|
QCoreApplication::postEvent( object, event );
|
||||||
|
}
|
||||||
|
else // Qt::BlockingQueuedConnection ???
|
||||||
|
{
|
||||||
|
// ....
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
197
src/common/QskMetaCall.h
Normal file
197
src/common/QskMetaCall.h
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* 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&, 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;
|
||||||
|
|
||||||
|
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
|
233
src/common/QskMetaCallback.cpp
Normal file
233
src/common/QskMetaCallback.cpp
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaCallback::QskMetaCallback( const QObject* object,
|
||||||
|
const QMetaMethod& method, Qt::ConnectionType connectionType ):
|
||||||
|
m_object( const_cast< QObject* >( object ) ),
|
||||||
|
m_method( method ),
|
||||||
|
m_type( MetaMethod ),
|
||||||
|
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaCallback::QskMetaCallback( const QObject* object,
|
||||||
|
const QskMetaFunction& function, Qt::ConnectionType connectionType ):
|
||||||
|
m_object( const_cast< QObject* >( object ) ),
|
||||||
|
m_function( function ),
|
||||||
|
m_type( MetaFunction ),
|
||||||
|
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
|
||||||
|
m_object( other.m_object ),
|
||||||
|
m_function(),
|
||||||
|
m_type( Invalid ),
|
||||||
|
m_connectionType( other.m_connectionType )
|
||||||
|
{
|
||||||
|
if ( other.m_type != m_type )
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
m_type = other.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( m_type )
|
||||||
|
{
|
||||||
|
case MetaMethod:
|
||||||
|
m_method = other.m_method;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MetaFunction:
|
||||||
|
m_function = other.m_function;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaCallback::~QskMetaCallback()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
|
||||||
|
{
|
||||||
|
m_object = other.m_object;
|
||||||
|
m_connectionType = other.m_connectionType;
|
||||||
|
|
||||||
|
if ( other.m_type != m_type )
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
m_type = other.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( m_type )
|
||||||
|
{
|
||||||
|
case MetaMethod:
|
||||||
|
m_method = other.m_method;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MetaFunction:
|
||||||
|
m_function = other.m_function;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskMetaCallback::reset()
|
||||||
|
{
|
||||||
|
switch( m_type )
|
||||||
|
{
|
||||||
|
case MetaMethod:
|
||||||
|
m_method.~QMetaMethod();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MetaFunction:
|
||||||
|
m_function.~QskMetaFunction();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_type = Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector< int > QskMetaCallback::parameterTypes() const
|
||||||
|
{
|
||||||
|
QVector< int > paramTypes;
|
||||||
|
|
||||||
|
switch( m_type )
|
||||||
|
{
|
||||||
|
case MetaMethod:
|
||||||
|
{
|
||||||
|
const int paramCount = m_method.parameterCount();
|
||||||
|
|
||||||
|
paramTypes.reserve( paramCount );
|
||||||
|
for ( int i = 0; i < paramCount; i++ )
|
||||||
|
paramTypes += m_method.parameterType( i );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MetaFunction:
|
||||||
|
{
|
||||||
|
auto types = m_function.parameterTypes();
|
||||||
|
if ( types )
|
||||||
|
{
|
||||||
|
while ( *types )
|
||||||
|
paramTypes += *types++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paramTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QskMetaCallback::invoke( void* args[] )
|
||||||
|
{
|
||||||
|
auto object = const_cast< QObject* >( m_object.data() );
|
||||||
|
|
||||||
|
switch( m_type )
|
||||||
|
{
|
||||||
|
case MetaMethod:
|
||||||
|
{
|
||||||
|
if ( object )
|
||||||
|
qskInvoke( object, m_method, args, connectionType() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MetaFunction:
|
||||||
|
{
|
||||||
|
m_function.invoke( object, args, connectionType() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
86
src/common/QskMetaCallback.h
Normal file
86
src/common/QskMetaCallback.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_META_CALLBACK_H
|
||||||
|
#define QSK_META_CALLBACK_H 1
|
||||||
|
|
||||||
|
#include "QskGlobal.h"
|
||||||
|
#include "QskMetaFunction.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QMetaMethod>
|
||||||
|
|
||||||
|
class QskMetaCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Invalid = 0,
|
||||||
|
|
||||||
|
// A QMetaMethod
|
||||||
|
MetaMethod,
|
||||||
|
|
||||||
|
// A function pointer, for what Qt calls "functor based" callbacks
|
||||||
|
MetaFunction
|
||||||
|
};
|
||||||
|
|
||||||
|
QskMetaCallback();
|
||||||
|
QskMetaCallback( const QObject*, const QskMetaFunction&, Qt::ConnectionType );
|
||||||
|
QskMetaCallback( const QObject*, const QMetaMethod&, Qt::ConnectionType );
|
||||||
|
QskMetaCallback( const QskMetaCallback& );
|
||||||
|
|
||||||
|
~QskMetaCallback();
|
||||||
|
|
||||||
|
QskMetaCallback& operator=( const QskMetaCallback& );
|
||||||
|
|
||||||
|
Type type() const;
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
const QObject* object() const { return m_object; }
|
||||||
|
Qt::ConnectionType connectionType() const;
|
||||||
|
|
||||||
|
QVector< int > parameterTypes() const;
|
||||||
|
|
||||||
|
void invoke( void* args[] );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
QPointer< const QObject > m_object;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
QskMetaFunction m_function;
|
||||||
|
QMetaMethod m_method;
|
||||||
|
};
|
||||||
|
|
||||||
|
int m_type : 3;
|
||||||
|
ushort m_connectionType : 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline QskMetaCallback::QskMetaCallback():
|
||||||
|
m_type( Invalid )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool QskMetaCallback::isValid() const
|
||||||
|
{
|
||||||
|
return m_type > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QskMetaCallback::Type QskMetaCallback::type() const
|
||||||
|
{
|
||||||
|
return static_cast< Type >( m_type );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Qt::ConnectionType QskMetaCallback::connectionType() const
|
||||||
|
{
|
||||||
|
return static_cast< Qt::ConnectionType >( m_connectionType );
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE( QskMetaCallback )
|
||||||
|
|
||||||
|
#endif
|
89
src/common/QskMetaFunction.cpp
Normal file
89
src/common/QskMetaFunction.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskGlobal.h"
|
||||||
|
#include "QskMetaCall.h"
|
||||||
|
#include "QskMetaFunction.h"
|
||||||
|
|
||||||
|
QskMetaFunction::QskMetaFunction():
|
||||||
|
m_invokable( nullptr ),
|
||||||
|
m_parameterTypes( nullptr )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaFunction::QskMetaFunction( const QskMetaFunction& other ):
|
||||||
|
m_invokable( other.m_invokable ),
|
||||||
|
m_parameterTypes( other.m_parameterTypes )
|
||||||
|
{
|
||||||
|
if ( m_invokable )
|
||||||
|
m_invokable->ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaFunction::QskMetaFunction( QskMetaFunction&& other ):
|
||||||
|
m_invokable( other.m_invokable ),
|
||||||
|
m_parameterTypes( other.m_parameterTypes )
|
||||||
|
{
|
||||||
|
other.m_invokable = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaFunction::~QskMetaFunction()
|
||||||
|
{
|
||||||
|
if ( m_invokable )
|
||||||
|
m_invokable->destroyIfLastRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaFunction& QskMetaFunction::operator=( QskMetaFunction&& other )
|
||||||
|
{
|
||||||
|
if ( m_invokable != other.m_invokable )
|
||||||
|
{
|
||||||
|
if ( m_invokable )
|
||||||
|
m_invokable->destroyIfLastRef();
|
||||||
|
|
||||||
|
m_invokable = other.m_invokable;
|
||||||
|
other.m_invokable = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_parameterTypes = other.m_parameterTypes;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
|
||||||
|
{
|
||||||
|
if ( m_invokable != other.m_invokable )
|
||||||
|
{
|
||||||
|
if ( m_invokable )
|
||||||
|
m_invokable->destroyIfLastRef();
|
||||||
|
|
||||||
|
m_invokable = other.m_invokable;
|
||||||
|
|
||||||
|
if ( m_invokable )
|
||||||
|
m_invokable->ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_parameterTypes = other.m_parameterTypes;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int* QskMetaFunction::parameterTypes() const
|
||||||
|
{
|
||||||
|
return m_parameterTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
QskMetaFunction::Type QskMetaFunction::functionType() const
|
||||||
|
{
|
||||||
|
if ( m_invokable == nullptr )
|
||||||
|
return Invalid;
|
||||||
|
|
||||||
|
return static_cast< QskMetaFunction::Type >( m_invokable->typeInfo() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskMetaFunction::invoke(
|
||||||
|
QObject* object, void* args[], Qt::ConnectionType connectionType )
|
||||||
|
{
|
||||||
|
if ( m_invokable )
|
||||||
|
QskMetaCall::invoke( object, *m_invokable, args, connectionType );
|
||||||
|
}
|
113
src/common/QskMetaFunction.h
Normal file
113
src/common/QskMetaFunction.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_META_FUNCTION_H
|
||||||
|
#define QSK_META_FUNCTION_H 1
|
||||||
|
|
||||||
|
#include "QskGlobal.h"
|
||||||
|
#include "QskMetaCall.h"
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
|
class QSK_EXPORT QskMetaFunction
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Invalid = -1,
|
||||||
|
|
||||||
|
// a non static method of class
|
||||||
|
Member,
|
||||||
|
|
||||||
|
// a static function, or static method of a class
|
||||||
|
Function,
|
||||||
|
|
||||||
|
// a functor or lambda
|
||||||
|
Functor
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_ENUM( Type )
|
||||||
|
|
||||||
|
QskMetaFunction();
|
||||||
|
|
||||||
|
QskMetaFunction( const QskMetaFunction& );
|
||||||
|
QskMetaFunction( QskMetaFunction&& );
|
||||||
|
|
||||||
|
template< typename T, QskMetaCall::IsMemberFunction< T >* = nullptr >
|
||||||
|
QskMetaFunction( T );
|
||||||
|
|
||||||
|
template< typename T, QskMetaCall::IsFunction< T >* = nullptr >
|
||||||
|
QskMetaFunction( T );
|
||||||
|
|
||||||
|
template< typename T, QskMetaCall::IsFunctor< T >* = nullptr >
|
||||||
|
QskMetaFunction( T );
|
||||||
|
|
||||||
|
~QskMetaFunction();
|
||||||
|
|
||||||
|
QskMetaFunction& operator=( const QskMetaFunction& );
|
||||||
|
QskMetaFunction& operator=( QskMetaFunction&& );
|
||||||
|
|
||||||
|
const int* parameterTypes() const;
|
||||||
|
|
||||||
|
void invoke( QObject*, void* args[],
|
||||||
|
Qt::ConnectionType = Qt::AutoConnection );
|
||||||
|
|
||||||
|
Type functionType() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QskMetaCall::Invokable* m_invokable;
|
||||||
|
const int* m_parameterTypes;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T, QskMetaCall::IsMemberFunction< T >* = nullptr >
|
||||||
|
inline QskMetaFunction::QskMetaFunction( T function )
|
||||||
|
{
|
||||||
|
using namespace QtPrivate;
|
||||||
|
using namespace QskMetaCall;
|
||||||
|
|
||||||
|
using Traits = FunctionPointer< T >;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T, QskMetaCall::IsFunction< T >* = nullptr >
|
||||||
|
inline QskMetaFunction::QskMetaFunction( T function )
|
||||||
|
{
|
||||||
|
using namespace QtPrivate;
|
||||||
|
using namespace QskMetaCall;
|
||||||
|
|
||||||
|
using Traits = FunctionPointer< T >;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T, QskMetaCall::IsFunctor< T >* = nullptr >
|
||||||
|
inline QskMetaFunction::QskMetaFunction( T functor )
|
||||||
|
{
|
||||||
|
using namespace QtPrivate;
|
||||||
|
|
||||||
|
using Traits = FunctionPointer< decltype( &T::operator() ) >;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE( QskMetaFunction )
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user