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 }; void* args[4] = { nullptr };
const auto types = callback.parameterTypes(); const auto types = callback.invokable().parameterTypes();
int i = 1; int i = 1;
for ( auto type : types ) for ( auto type : types )

View File

@ -4,41 +4,12 @@
*****************************************************************************/ *****************************************************************************/
#include "QskMetaCallback.h" #include "QskMetaCallback.h"
#include "QskMetaFunction.h"
#include "QskMetaMethod.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, QskMetaCallback::QskMetaCallback( const QObject* object,
const QMetaMethod& method, Qt::ConnectionType connectionType ): const QMetaMethod& method, Qt::ConnectionType connectionType ):
m_object( const_cast< QObject* >( object ) ), m_object( const_cast< QObject* >( object ) ),
m_methodData { method.enclosingMetaObject(), method.methodIndex() }, m_invokable( method ),
m_type( MetaMethod ),
m_hasObject( object != nullptr ), m_hasObject( object != nullptr ),
m_connectionType( static_cast< ushort >( connectionType & 0x3 ) ) m_connectionType( static_cast< ushort >( connectionType & 0x3 ) )
{ {
@ -53,88 +24,14 @@ QskMetaCallback::QskMetaCallback( const QObject* object,
QskMetaCallback::QskMetaCallback( const QObject* object, QskMetaCallback::QskMetaCallback( const QObject* object,
const QskMetaFunction& function, Qt::ConnectionType connectionType ): const QskMetaFunction& function, Qt::ConnectionType connectionType ):
m_object( const_cast< QObject* >( object ) ), m_object( const_cast< QObject* >( object ) ),
m_functionData { function.functionCall(), function.parameterTypes() }, m_invokable( function ),
m_type( MetaFunction ),
m_hasObject( object != nullptr ), m_hasObject( object != nullptr ),
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) ) 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() 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 bool QskMetaCallback::isValid() const
@ -142,28 +39,13 @@ bool QskMetaCallback::isValid() const
if ( m_hasObject && m_object.isNull() ) if ( m_hasObject && m_object.isNull() )
return false; return false;
switch( m_type ) return !m_invokable.isNull();
{ }
case MetaMethod:
{
const auto& d = m_methodData;
if ( d.metaObject && ( d.methodIndex >= 0 )
&& ( d.methodIndex < d.metaObject->methodCount() ) )
{
return true;
}
return false; void QskMetaCallback::setInvokable( const QskMetaInvokable& invokable )
} {
// type checking is m_object matches ???
case MetaFunction: m_invokable = invokable;
{
return m_functionData.functionCall != nullptr;
}
default:
return false;
}
} }
void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType ) void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
@ -171,88 +53,8 @@ void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
m_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[] ) void QskMetaCallback::invoke( void* args[] )
{ {
if ( !isValid() ) if ( isValid() )
return; m_invokable.invoke( m_object, args, connectionType() );
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;
}
} }

View File

@ -7,29 +7,14 @@
#define QSK_META_CALLBACK_H 1 #define QSK_META_CALLBACK_H 1
#include "QskGlobal.h" #include "QskGlobal.h"
#include "QskMetaInvokable.h"
#include <QPointer> #include <QPointer>
#include <QVector>
#include <QObject> #include <QObject>
class QskMetaFunction;
class QMetaObject;
class QMetaMethod;
class QSK_EXPORT QskMetaCallback class QSK_EXPORT QskMetaCallback
{ {
public: public:
enum Type
{
Invalid = 0,
// A QMetaMethod
MetaMethod,
// A function pointer, for what Qt calls "functor based" callbacks
MetaFunction
};
QskMetaCallback(); QskMetaCallback();
QskMetaCallback( const QObject*, const QskMetaFunction&, QskMetaCallback( const QObject*, const QskMetaFunction&,
@ -41,61 +26,42 @@ public:
QskMetaCallback( const QObject*, const char* methodName, QskMetaCallback( const QObject*, const char* methodName,
Qt::ConnectionType = Qt::AutoConnection ); Qt::ConnectionType = Qt::AutoConnection );
QskMetaCallback( const QskMetaCallback& );
~QskMetaCallback(); ~QskMetaCallback();
QskMetaCallback& operator=( const QskMetaCallback& );
Type type() const;
bool isValid() const; bool isValid() const;
bool isStale() const;
const QObject* object() const { return m_object; } const QObject* object() const { return m_object; }
void setInvokable( const QskMetaInvokable& );
const QskMetaInvokable& invokable() const;
void setConnectionType( Qt::ConnectionType ); void setConnectionType( Qt::ConnectionType );
Qt::ConnectionType connectionType() const; Qt::ConnectionType connectionType() const;
QVector< int > parameterTypes() const;
void invoke( void* args[] ); void invoke( void* args[] );
private: 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; bool m_hasObject : 1;
ushort m_connectionType : 3; ushort m_connectionType : 3;
}; };
inline QskMetaCallback::QskMetaCallback(): inline QskMetaCallback::QskMetaCallback():
m_type( Invalid ),
m_hasObject( false ) 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 inline Qt::ConnectionType QskMetaCallback::connectionType() const

View File

@ -123,6 +123,34 @@ QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
return *this; 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 size_t QskMetaFunction::parameterCount() const
{ {
if ( auto types = parameterTypes() ) if ( auto types = parameterTypes() )

View File

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

View File

@ -63,7 +63,7 @@ namespace QskMetaFunctionCall
} }
static void invoke(int which, QSlotObjectBase* functionCall, static void invoke(int which, QSlotObjectBase* functionCall,
QObject* object, void** args, bool* ) QObject* object, void** args, bool* ret )
{ {
switch ( which ) switch ( which )
{ {
@ -80,6 +80,13 @@ namespace QskMetaFunctionCall
static_cast< MetaCall* >( functionCall )->m_function, object, args ); static_cast< MetaCall* >( functionCall )->m_function, object, args );
break; break;
} }
case Compare:
{
*ret = reinterpret_cast< MetaCall* >( args )->m_function
== static_cast< MetaCall* >( functionCall )->m_function;
break;
}
case TypeInfo: case TypeInfo:
{ {
*reinterpret_cast< int* >( args ) = QskMetaFunction::Function; *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* ) QObject* object, void** args, bool* )
{ {
switch (which) switch (which)
{ {
case Destroy: case Destroy:
{ {
delete static_cast< MetaCall* >( slotObject ); delete static_cast< MetaCall* >( functionCall );
break; break;
} }
case Call: case Call:
@ -163,7 +170,7 @@ namespace QskMetaFunctionCall
typedef Functor< Function, N > FuncType; typedef Functor< Function, N > FuncType;
FuncType::template call< Args, R >( FuncType::template call< Args, R >(
static_cast< MetaCall* >( slotObject )->m_function, object, args ); static_cast< MetaCall* >( functionCall )->m_function, object, args );
break; 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/QskMetaCallback.h \
common/QskMetaFunction.h \ common/QskMetaFunction.h \
common/QskMetaFunction.hpp \ common/QskMetaFunction.hpp \
common/QskMetaInvokable.h \
common/QskMetaMethod.h \ common/QskMetaMethod.h \
common/QskModule.h \ common/QskModule.h \
common/QskNamespace.h \ common/QskNamespace.h \
@ -62,6 +63,7 @@ SOURCES += \
common/QskMargins.cpp \ common/QskMargins.cpp \
common/QskMetaCallback.cpp \ common/QskMetaCallback.cpp \
common/QskMetaFunction.cpp \ common/QskMetaFunction.cpp \
common/QskMetaInvokable.cpp \
common/QskMetaMethod.cpp \ common/QskMetaMethod.cpp \
common/QskModule.cpp \ common/QskModule.cpp \
common/QskObjectCounter.cpp \ common/QskObjectCounter.cpp \