QskMetaInvokable introduced

This commit is contained in:
Uwe Rathmann 2018-03-04 13:31:49 +01:00
parent b5a5b56a1d
commit 6c9d78c532
9 changed files with 445 additions and 262 deletions

View File

@ -32,7 +32,7 @@ void Invoker::invoke( qreal realValue, int intValue,
{
void* args[4] = { nullptr };
const auto types = callback.parameterTypes();
const auto types = callback.invokable().parameterTypes();
int i = 1;
for ( auto type : types )

View File

@ -4,41 +4,12 @@
*****************************************************************************/
#include "QskMetaCallback.h"
#include "QskMetaFunction.h"
#include "QskMetaMethod.h"
#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 ) ),
m_methodData { method.enclosingMetaObject(), method.methodIndex() },
m_type( MetaMethod ),
m_invokable( method ),
m_hasObject( object != nullptr ),
m_connectionType( static_cast< ushort >( connectionType & 0x3 ) )
{
@ -53,88 +24,14 @@ 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.functionCall(), function.parameterTypes() },
m_type( MetaFunction ),
m_invokable( function ),
m_hasObject( object != nullptr ),
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
{
Function::ref( m_functionData.functionCall );
}
QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
m_object( other.m_object ),
m_type( other.m_type ),
m_hasObject( other.m_hasObject ),
m_connectionType( other.m_connectionType )
{
switch( m_type )
{
case MetaMethod:
{
m_methodData.metaObject = other.m_methodData.metaObject;
m_methodData.methodIndex = other.m_methodData.methodIndex;
break;
}
case MetaFunction:
{
m_functionData.functionCall = other.m_functionData.functionCall;
Function::ref( m_functionData.functionCall );
m_functionData.parameterTypes = other.m_functionData.parameterTypes;
break;
}
default:
break;
}
}
QskMetaCallback::~QskMetaCallback()
{
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
}
QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
{
m_object = other.m_object;
m_hasObject = other.m_hasObject;
m_connectionType = other.m_connectionType;
switch( other.m_type )
{
case MetaMethod:
{
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
m_methodData.metaObject = other.m_methodData.metaObject;
m_methodData.methodIndex = other.m_methodData.methodIndex;
break;
}
case MetaFunction:
{
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
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 )
Function::deref( m_functionData.functionCall );
}
m_type = other.m_type;
return *this;
}
bool QskMetaCallback::isValid() const
@ -142,28 +39,13 @@ bool QskMetaCallback::isValid() const
if ( m_hasObject && m_object.isNull() )
return false;
switch( m_type )
{
case MetaMethod:
{
const auto& d = m_methodData;
if ( d.metaObject && ( d.methodIndex >= 0 )
&& ( d.methodIndex < d.metaObject->methodCount() ) )
{
return true;
}
return !m_invokable.isNull();
}
return false;
}
case MetaFunction:
{
return m_functionData.functionCall != nullptr;
}
default:
return false;
}
void QskMetaCallback::setInvokable( const QskMetaInvokable& invokable )
{
// type checking is m_object matches ???
m_invokable = invokable;
}
void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
@ -171,88 +53,8 @@ void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
m_connectionType = connectionType;
}
void QskMetaCallback::reset()
{
m_object = nullptr;
m_hasObject = false;
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
m_functionData = { nullptr, nullptr }; // for the debugger
m_type = Invalid;
}
QVector< int > QskMetaCallback::parameterTypes() const
{
QVector< int > paramTypes;
switch( m_type )
{
case MetaMethod:
{
const auto& d = m_methodData;
if ( m_methodData.metaObject )
{
#if 1
// should be doable without QMetaMethod. TODO ...
const auto method = d.metaObject->method( d.methodIndex );
#endif
const int paramCount = method.parameterCount();
paramTypes.reserve( paramCount );
for ( int i = 0; i < paramCount; i++ )
paramTypes += method.parameterType( i );
}
break;
}
case MetaFunction:
{
auto types = m_functionData.parameterTypes;
if ( types )
{
while ( *types )
paramTypes += *types++;
}
break;
}
default:
break;
}
return paramTypes;
}
void QskMetaCallback::invoke( void* args[] )
{
if ( !isValid() )
return;
auto object = const_cast< QObject* >( m_object.data() );
switch( m_type )
{
case MetaMethod:
{
QskMetaMethod::invoke( object, m_methodData.metaObject,
m_methodData.methodIndex, args, connectionType() );
break;
}
case MetaFunction:
{
if ( m_functionData.functionCall )
{
Function function( m_functionData.functionCall );
function.invoke( object, args, connectionType() );
}
break;
}
default:
break;
}
if ( isValid() )
m_invokable.invoke( m_object, args, connectionType() );
}

View File

@ -7,29 +7,14 @@
#define QSK_META_CALLBACK_H 1
#include "QskGlobal.h"
#include "QskMetaInvokable.h"
#include <QPointer>
#include <QVector>
#include <QObject>
class QskMetaFunction;
class QMetaObject;
class QMetaMethod;
class QSK_EXPORT 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&,
@ -41,61 +26,42 @@ public:
QskMetaCallback( const QObject*, const char* methodName,
Qt::ConnectionType = Qt::AutoConnection );
QskMetaCallback( const QskMetaCallback& );
~QskMetaCallback();
QskMetaCallback& operator=( const QskMetaCallback& );
Type type() const;
bool isValid() const;
bool isStale() const;
const QObject* object() const { return m_object; }
void setInvokable( const QskMetaInvokable& );
const QskMetaInvokable& invokable() const;
void setConnectionType( Qt::ConnectionType );
Qt::ConnectionType connectionType() const;
QVector< int > parameterTypes() const;
void invoke( void* args[] );
private:
void reset();
QPointer< QObject > m_object;
QskMetaInvokable m_invokable;
QPointer< const QObject > m_object;
struct FunctionData
{
void* functionCall;
const int* parameterTypes;
};
struct MethodData
{
const QMetaObject* metaObject;
int methodIndex;
};
union
{
FunctionData m_functionData;
MethodData m_methodData;
};
int m_type : 3;
bool m_hasObject : 1;
ushort m_connectionType : 3;
};
inline QskMetaCallback::QskMetaCallback():
m_type( Invalid ),
m_hasObject( false )
{
}
inline QskMetaCallback::Type QskMetaCallback::type() const
inline bool QskMetaCallback::isStale() const
{
return static_cast< Type >( m_type );
return m_hasObject && m_object.isNull();
}
inline const QskMetaInvokable& QskMetaCallback::invokable() const
{
return m_invokable;
}
inline Qt::ConnectionType QskMetaCallback::connectionType() const

View File

@ -123,6 +123,34 @@ QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
return *this;
}
bool QskMetaFunction::operator==( const QskMetaFunction& other ) const
{
if ( m_functionCall == other.m_functionCall )
return true;
/*
There is no way to compmare functors/members without
std::type_info, what we don't want to use as it is
another template creating symbols.
So this implementation can't do much more than finding
out if one instance is a copy from another.
*/
if ( m_functionCall && other.m_functionCall )
{
if ( m_functionCall->typeInfo() == Function &&
other.m_functionCall->typeInfo() == Function )
{
// only static functions can be compared
return m_functionCall->compare(
reinterpret_cast< void** >( other.m_functionCall ) );
}
}
return false;
}
size_t QskMetaFunction::parameterCount() const
{
if ( auto types = parameterTypes() )

View File

@ -70,6 +70,11 @@ public:
QskMetaFunction& operator=( const QskMetaFunction& );
QskMetaFunction& operator=( QskMetaFunction&& );
bool operator==( const QskMetaFunction& ) const;
bool operator!=( const QskMetaFunction& ) const;
explicit operator bool() const;
const int* parameterTypes() const;
// including the return type !
@ -79,6 +84,7 @@ public:
Qt::ConnectionType = Qt::AutoConnection );
Type functionType() const;
bool isNull() const;
class FunctionCall;
FunctionCall* functionCall() const;
@ -90,13 +96,28 @@ private:
FunctionCall* m_functionCall;
};
#include "QskMetaFunction.hpp"
inline bool QskMetaFunction::operator!=( const QskMetaFunction& other ) const
{
return !( *this == other );
}
inline QskMetaFunction::operator bool() const
{
return !isNull();
}
inline bool QskMetaFunction::isNull() const
{
return m_functionCall == nullptr;
}
inline QskMetaFunction::FunctionCall* QskMetaFunction::functionCall() const
{
return m_functionCall;
}
#include "QskMetaFunction.hpp"
inline const int* QskMetaFunction::parameterTypes() const
{
return m_functionCall ? m_functionCall->parameterTypes() : nullptr;

View File

@ -63,7 +63,7 @@ namespace QskMetaFunctionCall
}
static void invoke(int which, QSlotObjectBase* functionCall,
QObject* object, void** args, bool* )
QObject* object, void** args, bool* ret )
{
switch ( which )
{
@ -80,6 +80,13 @@ namespace QskMetaFunctionCall
static_cast< MetaCall* >( functionCall )->m_function, object, args );
break;
}
case Compare:
{
*ret = reinterpret_cast< MetaCall* >( args )->m_function
== static_cast< MetaCall* >( functionCall )->m_function;
break;
}
case TypeInfo:
{
*reinterpret_cast< int* >( args ) = QskMetaFunction::Function;
@ -148,14 +155,14 @@ namespace QskMetaFunctionCall
{
}
static void invoke( int which, QSlotObjectBase* slotObject,
static void invoke( int which, QSlotObjectBase* functionCall,
QObject* object, void** args, bool* )
{
switch (which)
{
case Destroy:
{
delete static_cast< MetaCall* >( slotObject );
delete static_cast< MetaCall* >( functionCall );
break;
}
case Call:
@ -163,7 +170,7 @@ namespace QskMetaFunctionCall
typedef Functor< Function, N > FuncType;
FuncType::template call< Args, R >(
static_cast< MetaCall* >( slotObject )->m_function, object, args );
static_cast< MetaCall* >( functionCall )->m_function, object, args );
break;
}

View File

@ -0,0 +1,251 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskMetaInvokable.h"
#include "QskMetaFunction.h"
#include "QskMetaMethod.h"
#include <QMetaMethod>
#include <QVector>
#include <QObject>
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();
}
};
}
QskMetaInvokable::QskMetaInvokable( const QMetaMethod& method ):
m_methodData { method.enclosingMetaObject(), method.methodIndex() },
m_type( MetaMethod )
{
}
QskMetaInvokable::QskMetaInvokable( const QObject* object, const char* methodName ):
QskMetaInvokable( QskMetaMethod::method( object, methodName ) )
{
}
QskMetaInvokable::QskMetaInvokable( const QMetaObject* metaObject, const char* methodName ):
QskMetaInvokable( QskMetaMethod::method( metaObject, methodName ) )
{
}
QskMetaInvokable::QskMetaInvokable( const QskMetaFunction& function ):
m_functionData { function.functionCall() },
m_type( MetaFunction )
{
Function::ref( m_functionData.functionCall );
}
QskMetaInvokable::QskMetaInvokable( const QskMetaInvokable& other ):
m_type( other.m_type )
{
switch( m_type )
{
case MetaMethod:
{
m_methodData.metaObject = other.m_methodData.metaObject;
m_methodData.methodIndex = other.m_methodData.methodIndex;
break;
}
case MetaFunction:
{
m_functionData.functionCall = other.m_functionData.functionCall;
Function::ref( m_functionData.functionCall );
break;
}
default:
break;
}
}
QskMetaInvokable::~QskMetaInvokable()
{
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
}
QskMetaInvokable& QskMetaInvokable::operator=( const QskMetaInvokable& other )
{
switch( other.m_type )
{
case MetaMethod:
{
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
m_methodData.metaObject = other.m_methodData.metaObject;
m_methodData.methodIndex = other.m_methodData.methodIndex;
break;
}
case MetaFunction:
{
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
m_functionData.functionCall = other.m_functionData.functionCall;
Function::ref( m_functionData.functionCall );
break;
}
default:
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
}
m_type = other.m_type;
return *this;
}
bool QskMetaInvokable::operator==( const QskMetaInvokable& other ) const
{
if ( m_type == other.m_type )
{
if ( m_type == MetaMethod )
{
return ( m_methodData.metaObject == other.m_methodData.metaObject )
&& ( m_methodData.methodIndex == other.m_methodData.methodIndex );
}
if ( m_type == MetaFunction )
{
return m_functionData.functionCall == other.m_functionData.functionCall;
}
}
return true;
}
bool QskMetaInvokable::isNull() const
{
switch( m_type )
{
case MetaMethod:
{
const auto& d = m_methodData;
if ( d.metaObject && ( d.methodIndex >= 0 )
&& ( d.methodIndex < d.metaObject->methodCount() ) )
{
return false;
}
return true;
}
case MetaFunction:
{
return m_functionData.functionCall == nullptr;
}
default:
return true;
}
}
void QskMetaInvokable::reset()
{
if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall );
m_type = Invalid;
}
QVector< int > QskMetaInvokable::parameterTypes() const
{
QVector< int > paramTypes;
switch( m_type )
{
case MetaMethod:
{
const auto& d = m_methodData;
if ( m_methodData.metaObject )
{
#if 1
// should be doable without QMetaMethod. TODO ...
const auto method = d.metaObject->method( d.methodIndex );
#endif
const int paramCount = method.parameterCount();
paramTypes.reserve( paramCount );
for ( int i = 0; i < paramCount; i++ )
paramTypes += method.parameterType( i );
}
break;
}
case MetaFunction:
{
auto types = Function( m_functionData.functionCall ).parameterTypes();
if ( types )
{
while ( *types )
paramTypes += *types++;
}
break;
}
default:
break;
}
return paramTypes;
}
void QskMetaInvokable::invoke( QObject* object, void* args[],
Qt::ConnectionType connectionType )
{
if ( isNull() )
return;
switch( m_type )
{
case MetaMethod:
{
QskMetaMethod::invoke( object, m_methodData.metaObject,
m_methodData.methodIndex, args, connectionType );
break;
}
case MetaFunction:
{
if ( m_functionData.functionCall )
{
Function function( m_functionData.functionCall );
function.invoke( object, args, connectionType );
}
break;
}
default:
break;
}
}

View File

@ -0,0 +1,106 @@
/******************************************************************************
* 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 <QMetaType>
#include <Qt>
template< typename T > class QVector;
class QskMetaFunction;
class QMetaObject;
class QMetaMethod;
class QObject;
class QSK_EXPORT QskMetaInvokable
{
public:
enum Type
{
Invalid = 0,
// A QMetaMethod
MetaMethod,
// A function pointer, for what Qt calls "functor based" callbacks
MetaFunction
};
QskMetaInvokable();
QskMetaInvokable( const QskMetaFunction& );
QskMetaInvokable( const QMetaMethod& );
QskMetaInvokable( const QObject*, const char* methodName );
QskMetaInvokable( const QMetaObject*, const char* methodName );
QskMetaInvokable( const QskMetaInvokable& );
~QskMetaInvokable();
QskMetaInvokable& operator=( const QskMetaInvokable& );
bool operator==( const QskMetaInvokable& ) const;
bool operator!=( const QskMetaInvokable& ) const;
explicit operator bool() const;
Type type() const;
bool isNull() const;
QVector< int > parameterTypes() const;
void invoke( QObject*, void* args[],
Qt::ConnectionType = Qt::AutoConnection );
void reset();
private:
struct FunctionData
{
void* functionCall;
};
struct MethodData
{
const QMetaObject* metaObject;
int methodIndex;
};
union
{
FunctionData m_functionData;
MethodData m_methodData;
};
int m_type : 3;
};
inline QskMetaInvokable::QskMetaInvokable():
m_type( Invalid )
{
}
inline bool QskMetaInvokable::operator!=( const QskMetaInvokable& other ) const
{
return !( *this == other );
}
inline QskMetaInvokable::operator bool() const
{
return !isNull();
}
inline QskMetaInvokable::Type QskMetaInvokable::type() const
{
return static_cast< Type >( m_type );
}
Q_DECLARE_METATYPE( QskMetaInvokable )
#endif

View File

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