QskMetaFunction.hpp introduced

This commit is contained in:
Uwe Rathmann 2018-03-03 15:52:42 +01:00
parent 05e2b91c01
commit b5a5b56a1d
8 changed files with 317 additions and 292 deletions

View File

@ -9,6 +9,31 @@
#include <QMetaMethod>
namespace
{
class Function: public QskMetaFunction
{
public:
inline Function( void* functionCall ):
QskMetaFunction( static_cast< FunctionCall* >( functionCall ) )
{
}
static inline void ref( void* functionCall )
{
if ( functionCall )
static_cast< FunctionCall* >( functionCall )->ref();
}
static inline void deref( void* functionCall )
{
if ( functionCall )
static_cast< FunctionCall* >( functionCall )->destroyIfLastRef();
}
};
}
QskMetaCallback::QskMetaCallback( const QObject* object,
const QMetaMethod& method, Qt::ConnectionType connectionType ):
m_object( const_cast< QObject* >( object ) ),
@ -28,13 +53,12 @@ QskMetaCallback::QskMetaCallback( const QObject* object,
QskMetaCallback::QskMetaCallback( const QObject* object,
const QskMetaFunction& function, Qt::ConnectionType connectionType ):
m_object( const_cast< QObject* >( object ) ),
m_functionData { function.invokable(), function.parameterTypes() },
m_functionData { function.functionCall(), function.parameterTypes() },
m_type( MetaFunction ),
m_hasObject( object != nullptr ),
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
{
if ( m_functionData.invokable )
m_functionData.invokable->ref();
Function::ref( m_functionData.functionCall );
}
QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
@ -54,9 +78,8 @@ QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
}
case MetaFunction:
{
m_functionData.invokable = other.m_functionData.invokable;
if ( m_functionData.invokable )
m_functionData.invokable->ref();
m_functionData.functionCall = other.m_functionData.functionCall;
Function::ref( m_functionData.functionCall );
m_functionData.parameterTypes = other.m_functionData.parameterTypes;
break;
@ -69,8 +92,8 @@ QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
QskMetaCallback::~QskMetaCallback()
{
if ( ( m_type == MetaFunction ) && m_functionData.invokable )
m_functionData.invokable->destroyIfLastRef();
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
}
QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
@ -84,8 +107,8 @@ QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
{
case MetaMethod:
{
if ( m_type == MetaFunction && m_functionData.invokable )
m_functionData.invokable->destroyIfLastRef();
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
m_methodData.metaObject = other.m_methodData.metaObject;
m_methodData.methodIndex = other.m_methodData.methodIndex;
@ -94,21 +117,19 @@ QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
}
case MetaFunction:
{
if ( ( m_type == MetaFunction ) && m_functionData.invokable )
m_functionData.invokable->destroyIfLastRef();
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
m_functionData.invokable = other.m_functionData.invokable;
if ( m_functionData.invokable )
m_functionData.invokable->ref();
m_functionData.functionCall = other.m_functionData.functionCall;
Function::ref( m_functionData.functionCall );
m_functionData.parameterTypes = other.m_functionData.parameterTypes;
break;
}
default:
if ( ( m_type == MetaFunction ) && m_functionData.invokable )
m_functionData.invokable->destroyIfLastRef();
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
}
m_type = other.m_type;
@ -137,7 +158,7 @@ bool QskMetaCallback::isValid() const
case MetaFunction:
{
return m_functionData.invokable != nullptr;
return m_functionData.functionCall != nullptr;
}
default:
@ -155,8 +176,8 @@ void QskMetaCallback::reset()
m_object = nullptr;
m_hasObject = false;
if ( m_type == MetaFunction && m_functionData.invokable )
m_functionData.invokable->destroyIfLastRef();
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
m_functionData = { nullptr, nullptr }; // for the debugger
m_type = Invalid;
@ -222,8 +243,11 @@ void QskMetaCallback::invoke( void* args[] )
}
case MetaFunction:
{
QskMetaFunction function( m_functionData.invokable );
if ( m_functionData.functionCall )
{
Function function( m_functionData.functionCall );
function.invoke( object, args, connectionType() );
}
break;
}

View File

@ -12,7 +12,6 @@
#include <QVector>
#include <QObject>
class QskMetaInvokable;
class QskMetaFunction;
class QMetaObject;
class QMetaMethod;
@ -67,7 +66,7 @@ private:
struct FunctionData
{
QskMetaInvokable* invokable;
void* functionCall;
const int* parameterTypes;
};

View File

@ -16,58 +16,92 @@ QSK_QT_PRIVATE_BEGIN
QSK_QT_PRIVATE_END
static inline void qskInvokeFunctionQueued( QObject* object,
QskMetaInvokable* invokable, int argc, int* types, void* argv[],
QskMetaFunction::FunctionCall* functionCall, 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 );
functionCall, sender, signalId, argc, types, argv, semaphore );
QCoreApplication::postEvent( object, event );
}
namespace
{
using FunctionCall = QskMetaFunction::FunctionCall;
// to have access to the private section of QSlotObjectBase
struct SlotObject
{
QAtomicInt ref;
FunctionCall::InvokeFunction invoke;
const int* parameterTypes;
};
static_assert( sizeof( SlotObject ) == sizeof( FunctionCall ),
"Bad cast: QskMetaFunction does not match" );
}
int QskMetaFunction::FunctionCall::typeInfo() const
{
auto that = const_cast< FunctionCall* >( this );
int value;
reinterpret_cast< SlotObject* >( that )->invoke( TypeInfo, that,
nullptr, reinterpret_cast< void** >( &value ), nullptr );
return value;
}
int QskMetaFunction::FunctionCall::refCount() const
{
auto that = const_cast< FunctionCall* >( this );
return reinterpret_cast< SlotObject* >( that )->ref.load();
}
QskMetaFunction::QskMetaFunction():
m_invokable( nullptr )
m_functionCall( nullptr )
{
}
QskMetaFunction::QskMetaFunction( QskMetaInvokable* invokable ):
m_invokable( invokable )
QskMetaFunction::QskMetaFunction( FunctionCall* functionCall ):
m_functionCall( functionCall )
{
if ( m_invokable )
m_invokable->ref();
if ( m_functionCall )
m_functionCall->ref();
}
QskMetaFunction::QskMetaFunction( const QskMetaFunction& other ):
m_invokable( other.m_invokable )
m_functionCall( other.m_functionCall )
{
if ( m_invokable )
m_invokable->ref();
if ( m_functionCall )
m_functionCall->ref();
}
QskMetaFunction::QskMetaFunction( QskMetaFunction&& other ):
m_invokable( other.m_invokable )
m_functionCall( other.m_functionCall )
{
other.m_invokable = nullptr;
other.m_functionCall = nullptr;
}
QskMetaFunction::~QskMetaFunction()
{
if ( m_invokable )
m_invokable->destroyIfLastRef();
if ( m_functionCall )
m_functionCall->destroyIfLastRef();
}
QskMetaFunction& QskMetaFunction::operator=( QskMetaFunction&& other )
{
if ( m_invokable != other.m_invokable )
if ( m_functionCall != other.m_functionCall )
{
if ( m_invokable )
m_invokable->destroyIfLastRef();
if ( m_functionCall )
m_functionCall->destroyIfLastRef();
m_invokable = other.m_invokable;
other.m_invokable = nullptr;
m_functionCall = other.m_functionCall;
other.m_functionCall = nullptr;
}
return *this;
@ -75,15 +109,15 @@ QskMetaFunction& QskMetaFunction::operator=( QskMetaFunction&& other )
QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
{
if ( m_invokable != other.m_invokable )
if ( m_functionCall != other.m_functionCall )
{
if ( m_invokable )
m_invokable->destroyIfLastRef();
if ( m_functionCall )
m_functionCall->destroyIfLastRef();
m_invokable = other.m_invokable;
m_functionCall = other.m_functionCall;
if ( m_invokable )
m_invokable->ref();
if ( m_functionCall )
m_functionCall->ref();
}
return *this;
@ -106,10 +140,10 @@ size_t QskMetaFunction::parameterCount() const
QskMetaFunction::Type QskMetaFunction::functionType() const
{
if ( m_invokable == nullptr )
if ( m_functionCall == nullptr )
return Invalid;
return static_cast< QskMetaFunction::Type >( m_invokable->typeInfo() );
return static_cast< QskMetaFunction::Type >( m_functionCall->typeInfo() );
}
void QskMetaFunction::invoke(
@ -119,7 +153,7 @@ void QskMetaFunction::invoke(
QPointer< QObject > receiver( object );
if ( m_invokable == nullptr )
if ( m_functionCall == nullptr )
return;
int invokeType = connectionType & 0x3;
@ -134,7 +168,7 @@ void QskMetaFunction::invoke(
{
case Qt::DirectConnection:
{
m_invokable->call( receiver, argv );
m_functionCall->call( receiver, argv );
break;
}
case Qt::BlockingQueuedConnection:
@ -148,7 +182,7 @@ void QskMetaFunction::invoke(
QSemaphore semaphore;
qskInvokeFunctionQueued( receiver, m_invokable,
qskInvokeFunctionQueued( receiver, m_functionCall,
0, nullptr, argv, &semaphore );
semaphore.acquire();
@ -170,7 +204,7 @@ void QskMetaFunction::invoke(
types[0] = QMetaType::UnknownType; // a return type is not possible
arguments[0] = nullptr;
const int* parameterTypes = m_invokable->parameterTypes();
const int* parameterTypes = m_functionCall->parameterTypes();
for ( uint i = 1; i < argc; i++ )
{
if ( argv[i] == nullptr )
@ -193,7 +227,7 @@ void QskMetaFunction::invoke(
return;
}
qskInvokeFunctionQueued( object, m_invokable, argc, types, arguments );
qskInvokeFunctionQueued( object, m_functionCall, argc, types, arguments );
break;
}
}

View File

@ -7,8 +7,6 @@
#define QSK_META_FUNCTION_H 1
#include "QskGlobal.h"
#include "QskMetaInvokable.h"
#include <QMetaType>
namespace QskMetaFunctionTraits
@ -82,38 +80,41 @@ public:
Type functionType() const;
protected:
friend class QskMetaCallback;
class FunctionCall;
FunctionCall* functionCall() const;
QskMetaFunction( QskMetaInvokable* );
QskMetaInvokable* invokable() const;
protected:
QskMetaFunction( FunctionCall* );
private:
QskMetaInvokable* m_invokable;
FunctionCall* m_functionCall;
};
inline QskMetaInvokable* QskMetaFunction::invokable() const
#include "QskMetaFunction.hpp"
inline QskMetaFunction::FunctionCall* QskMetaFunction::functionCall() const
{
return m_invokable;
return m_functionCall;
}
inline const int* QskMetaFunction::parameterTypes() const
{
return m_invokable ? m_invokable->parameterTypes() : nullptr;
return m_functionCall ? m_functionCall->parameterTypes() : nullptr;
}
template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* >
inline QskMetaFunction::QskMetaFunction( T function )
{
using namespace QtPrivate;
using namespace QskMetaFunctionCall;
using Traits = FunctionPointer< T >;
constexpr int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
m_invokable = new QskMetaMemberInvokable< T, Args, void >( function );
m_invokable->setParameterTypes(
m_functionCall = new MemberFunctionCall< T, Args, void >( function );
m_functionCall->setParameterTypes(
ConnectionTypes< typename Traits::Arguments >::types() );
}
@ -121,14 +122,15 @@ template< typename T, QskMetaFunctionTraits::IsFunctor< T >* >
inline QskMetaFunction::QskMetaFunction( T functor )
{
using namespace QtPrivate;
using namespace QskMetaFunctionCall;
using Traits = FunctionPointer< decltype( &T::operator() ) >;
constexpr int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
m_invokable = new QskMetaFunctorInvokable< T, Argc, Args, void >( functor );
m_invokable->setParameterTypes(
m_functionCall = new FunctorFunctionCall< T, Argc, Args, void >( functor );
m_functionCall->setParameterTypes(
ConnectionTypes< typename Traits::Arguments >::types() );
}
@ -136,14 +138,15 @@ template< typename T, QskMetaFunctionTraits::IsFunction< T >* >
inline QskMetaFunction::QskMetaFunction( T function )
{
using namespace QtPrivate;
using namespace QskMetaFunctionCall;
using Traits = FunctionPointer< T >;
constexpr int Argc = Traits::ArgumentCount;
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
m_invokable = new QskMetaFunctionInvokable< T, Args, void >( function );
m_invokable->setParameterTypes(
m_functionCall = new StaticFunctionCall< T, Args, void >( function );
m_functionCall->setParameterTypes(
ConnectionTypes< typename Traits::Arguments >::types() );
}

View File

@ -0,0 +1,183 @@
/******************************************************************************
* 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_HPP
#define QSK_META_FUNCTION_HPP 1
#include "QskGlobal.h"
#include <QObject>
class QskMetaFunction::FunctionCall : public QtPrivate::QSlotObjectBase
{
public:
typedef void (* InvokeFunction)(
int which, QtPrivate::QSlotObjectBase*, QObject*, void**, bool* );
enum
{
TypeInfo = NumOperations + 1
};
int typeInfo() const;
int refCount() const;
inline const int* parameterTypes() const
{
return m_parameterTypes;
}
inline void setParameterTypes( const int* types )
{
m_parameterTypes = types;
}
protected:
explicit inline FunctionCall( InvokeFunction f,
const int* m_parameterTypes = nullptr ):
QSlotObjectBase( f ),
m_parameterTypes( m_parameterTypes )
{
}
private:
const int* m_parameterTypes; // static array, only needed for Qt::QueuedConnection
};
namespace QskMetaFunctionCall
{
using FunctionCall = QskMetaFunction::FunctionCall;
using namespace QtPrivate;
template< typename Function, typename Args, typename R >
class StaticFunctionCall : public FunctionCall
{
using MetaCall = StaticFunctionCall< Function, Args, R >;
public:
explicit inline StaticFunctionCall( Function function ):
FunctionCall( &invoke ),
m_function( function )
{
}
static void invoke(int which, QSlotObjectBase* functionCall,
QObject* object, void** args, bool* )
{
switch ( which )
{
case Destroy:
{
delete static_cast< MetaCall* >( functionCall );
break;
}
case Call:
{
typedef FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >(
static_cast< MetaCall* >( functionCall )->m_function, object, args );
break;
}
case TypeInfo:
{
*reinterpret_cast< int* >( args ) = QskMetaFunction::Function;
break;
}
}
}
private:
Function m_function;
};
template< typename Function, typename Args, typename R >
class MemberFunctionCall : public FunctionCall
{
using MetaCall = MemberFunctionCall< Function, Args, R >;
public:
explicit inline MemberFunctionCall( Function function ):
FunctionCall( &invoke ),
m_function( function )
{
}
static void invoke( int which, QSlotObjectBase* functionCall,
QObject* object, void** args, bool* )
{
switch (which)
{
case Destroy:
{
delete static_cast< MetaCall* >( functionCall );
break;
}
case Call:
{
typedef FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >(
static_cast< MetaCall* >( functionCall )->m_function,
static_cast< typename FuncType::Object* >( object ), args );
break;
}
case TypeInfo:
{
*reinterpret_cast< int* >( args ) = QskMetaFunction::Member;
break;
}
}
}
private:
Function m_function;
};
template< typename Function, int N, typename Args, typename R >
class FunctorFunctionCall : public FunctionCall
{
using MetaCall = FunctorFunctionCall< Function, N, Args, R >;
public:
explicit inline FunctorFunctionCall( Function function ):
FunctionCall( &invoke ),
m_function( function )
{
}
static void invoke( int which, QSlotObjectBase* slotObject,
QObject* object, void** args, bool* )
{
switch (which)
{
case Destroy:
{
delete static_cast< MetaCall* >( slotObject );
break;
}
case Call:
{
typedef Functor< Function, N > FuncType;
FuncType::template call< Args, R >(
static_cast< MetaCall* >( slotObject )->m_function, object, args );
break;
}
case TypeInfo:
{
*reinterpret_cast< int* >( args ) = QskMetaFunction::Functor;
break;
}
}
}
private:
Function m_function;
};
}
#endif

View File

@ -1,38 +0,0 @@
/******************************************************************************
* 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;
const int* parameterTypes;
};
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();
}

View File

@ -1,179 +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_INVOKABLE_H
#define QSK_META_INVOKABLE_H 1
#include "QskGlobal.h"
#include <QObject>
// helper classes for QskMetaFunction
class QSK_EXPORT 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;
inline const int* parameterTypes() const
{
return m_parameterTypes;
}
inline void setParameterTypes( const int* types )
{
m_parameterTypes = types;
}
protected:
explicit inline QskMetaInvokable( InvokeFunction f,
const int* m_parameterTypes = nullptr ):
QSlotObjectBase( f ),
m_parameterTypes( m_parameterTypes )
{
}
private:
const int* m_parameterTypes; // static array, only needed for Qt::QueuedConnection
};
template< typename Function, typename Args, typename R >
class QskMetaFunctionInvokable : public QskMetaInvokable
{
using Invokable = QskMetaFunctionInvokable< Function, Args, R >;
public:
explicit inline QskMetaFunctionInvokable( Function function ):
QskMetaInvokable( &invoke ),
m_function( function )
{
}
static void invoke(int which, QtPrivate::QSlotObjectBase* invokable,
QObject* object, void** args, bool* )
{
switch ( which )
{
case Destroy:
{
delete static_cast< Invokable* >( invokable );
break;
}
case Call:
{
typedef QtPrivate::FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >(
static_cast< Invokable* >( invokable )->m_function, object, args );
break;
}
case TypeInfo:
{
*reinterpret_cast< int* >( args ) = 1; // QskMetaFunction::Function
break;
}
}
}
private:
Function m_function;
};
template< typename Function, typename Args, typename R >
class QskMetaMemberInvokable : public QskMetaInvokable
{
using Invokable = QskMetaMemberInvokable< Function, Args, R >;
public:
explicit inline QskMetaMemberInvokable( Function function ):
QskMetaInvokable( &invoke ),
m_function( function )
{
}
static void invoke( int which, QtPrivate::QSlotObjectBase* slotObject,
QObject* object, void** args, bool* )
{
switch (which)
{
case Destroy:
{
delete static_cast< Invokable* >( slotObject );
break;
}
case Call:
{
typedef QtPrivate::FunctionPointer< Function > FuncType;
FuncType::template call< Args, R >(
static_cast< Invokable* >( slotObject )->m_function,
static_cast< typename FuncType::Object* >( object ), args );
break;
}
case TypeInfo:
{
*reinterpret_cast< int* >( args ) = 0; // = QskMetaFunction::Member
break;
}
}
}
private:
Function m_function;
};
template< typename Function, int N, typename Args, typename R >
class QskMetaFunctorInvokable : public QskMetaInvokable
{
using Invokable = QskMetaFunctorInvokable< Function, N, Args, R >;
public:
explicit inline QskMetaFunctorInvokable( Function function ):
QskMetaInvokable( &invoke ),
m_function( function )
{
}
static void invoke( int which, QSlotObjectBase* slotObject,
QObject* object, void** args, bool* )
{
switch (which)
{
case Destroy:
{
delete static_cast< Invokable* >( slotObject );
break;
}
case Call:
{
typedef QtPrivate::Functor< Function, N > FuncType;
FuncType::template call< Args, R >(
static_cast< Invokable* >( slotObject )->m_function, object, args );
break;
}
case TypeInfo:
{
*reinterpret_cast< int* >( args ) = 2; // QskMetaFunction::Functor
break;
}
}
}
private:
Function m_function;
};
#endif

View File

@ -42,7 +42,7 @@ HEADERS += \
common/QskMargins.h \
common/QskMetaCallback.h \
common/QskMetaFunction.h \
common/QskMetaInvokable.cpp \
common/QskMetaFunction.hpp \
common/QskMetaMethod.h \
common/QskModule.h \
common/QskNamespace.h \
@ -62,7 +62,6 @@ SOURCES += \
common/QskMargins.cpp \
common/QskMetaCallback.cpp \
common/QskMetaFunction.cpp \
common/QskMetaInvokable.cpp \
common/QskMetaMethod.cpp \
common/QskModule.cpp \
common/QskObjectCounter.cpp \