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 <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,
|
||||
const QMetaMethod& method, Qt::ConnectionType connectionType ):
|
||||
@ -147,8 +168,7 @@ void QskMetaCallback::invoke( void* args[] )
|
||||
{
|
||||
case MetaMethod:
|
||||
{
|
||||
if ( object )
|
||||
QskMetaCall::invoke( object, *m_method, args, connectionType() );
|
||||
qskInvokeMethod( object, *m_method, args, connectionType() );
|
||||
break;
|
||||
}
|
||||
case MetaFunction:
|
||||
@ -161,3 +181,80 @@ void QskMetaCallback::invoke( void* args[] )
|
||||
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 );
|
||||
}
|
||||
|
||||
QSK_EXPORT void qskInvokeMethod(
|
||||
QObject* object, const QMetaMethod&, void* args[],
|
||||
Qt::ConnectionType = Qt::AutoConnection );
|
||||
|
||||
Q_DECLARE_METATYPE( QskMetaCallback )
|
||||
|
||||
#endif
|
||||
|
@ -4,9 +4,30 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include "QskMetaCall.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():
|
||||
m_invokable( nullptr ),
|
||||
m_parameterTypes( nullptr )
|
||||
@ -68,15 +89,10 @@ QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
|
||||
return *this;
|
||||
}
|
||||
|
||||
void QskMetaFunction::init( QskMetaCall::Invokable* invokable,
|
||||
void QskMetaFunction::init( QskMetaInvokable* invokable,
|
||||
const int* parameterTypes )
|
||||
{
|
||||
m_invokable = invokable;
|
||||
#if 0
|
||||
if ( m_invokable )
|
||||
m_invokable->ref();
|
||||
#endif
|
||||
|
||||
m_parameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
@ -111,9 +127,78 @@ QskMetaFunction::Type QskMetaFunction::functionType() const
|
||||
void QskMetaFunction::invoke(
|
||||
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,
|
||||
parameterCount(), parameterTypes(), argv, connectionType );
|
||||
invokeType = ( object->thread() == QThread::currentThread() )
|
||||
? 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
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include "QskMetaCall.h"
|
||||
#include "QskMetaInvokable.h"
|
||||
|
||||
#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
|
||||
{
|
||||
Q_GADGET
|
||||
@ -37,13 +54,13 @@ public:
|
||||
QskMetaFunction( const QskMetaFunction& );
|
||||
QskMetaFunction( QskMetaFunction&& );
|
||||
|
||||
template< typename T, QskMetaCall::IsMemberFunction< T >* = nullptr >
|
||||
template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* = nullptr >
|
||||
QskMetaFunction( T );
|
||||
|
||||
template< typename T, QskMetaCall::IsFunction< T >* = nullptr >
|
||||
template< typename T, QskMetaFunctionTraits::IsFunction< T >* = nullptr >
|
||||
QskMetaFunction( T );
|
||||
|
||||
template< typename T, QskMetaCall::IsFunctor< T >* = nullptr >
|
||||
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* = nullptr >
|
||||
QskMetaFunction( T );
|
||||
|
||||
~QskMetaFunction();
|
||||
@ -62,44 +79,42 @@ public:
|
||||
Type functionType() const;
|
||||
|
||||
private:
|
||||
void init( QskMetaCall::Invokable*, const int* );
|
||||
void init( QskMetaInvokable*, const int* );
|
||||
|
||||
QskMetaCall::Invokable* m_invokable;
|
||||
QskMetaInvokable* m_invokable;
|
||||
const int* m_parameterTypes;
|
||||
};
|
||||
|
||||
|
||||
template< typename T, QskMetaCall::IsMemberFunction< T >* >
|
||||
template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* >
|
||||
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;
|
||||
|
||||
init( new MemberFunctionInvokable< T, Args, void >( function ),
|
||||
init( new QskMetaMemberInvokable< T, Args, void >( function ),
|
||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
||||
}
|
||||
|
||||
template< typename T, QskMetaCall::IsFunction< T >* >
|
||||
template< typename T, QskMetaFunctionTraits::IsFunction< T >* >
|
||||
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;
|
||||
|
||||
init( new FunctionInvokable< T, Args, void >( function ),
|
||||
init( new QskMetaFunctionInvokable< T, Args, void >( function ),
|
||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
||||
}
|
||||
|
||||
template< typename T, QskMetaCall::IsFunctor< T >* >
|
||||
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* >
|
||||
inline QskMetaFunction::QskMetaFunction( T functor )
|
||||
{
|
||||
using namespace QtPrivate;
|
||||
@ -109,7 +124,7 @@ inline QskMetaFunction::QskMetaFunction( T functor )
|
||||
const int Argc = Traits::ArgumentCount;
|
||||
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() );
|
||||
}
|
||||
|
||||
|
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/QskGradient.h \
|
||||
common/QskMargins.h \
|
||||
common/QskMetaCall.h \
|
||||
common/QskMetaCallback.h \
|
||||
common/QskMetaFunction.h \
|
||||
common/QskMetaInvokable.cpp \
|
||||
common/QskModule.h \
|
||||
common/QskNamespace.h \
|
||||
common/QskObjectCounter.h \
|
||||
@ -59,9 +59,9 @@ SOURCES += \
|
||||
common/QskFunctions.cpp \
|
||||
common/QskGradient.cpp \
|
||||
common/QskMargins.cpp \
|
||||
common/QskMetaCall.cpp \
|
||||
common/QskMetaCallback.cpp \
|
||||
common/QskMetaFunction.cpp \
|
||||
common/QskMetaInvokable.cpp \
|
||||
common/QskModule.cpp \
|
||||
common/QskObjectCounter.cpp \
|
||||
common/QskSizePolicy.cpp \
|
||||
|
Loading…
x
Reference in New Issue
Block a user