[Misc] QskMeta classes improved
This commit is contained in:
parent
02639e5d04
commit
3079698d63
|
@ -109,7 +109,7 @@ size_t QskMetaFunction::parameterCount() const
|
||||||
{
|
{
|
||||||
if ( m_parameterTypes )
|
if ( m_parameterTypes )
|
||||||
{
|
{
|
||||||
for ( int i = 1; ; i++ )
|
for ( int i = 1;; i++ )
|
||||||
{
|
{
|
||||||
if ( m_parameterTypes[ i ] == QMetaType::UnknownType )
|
if ( m_parameterTypes[ i ] == QMetaType::UnknownType )
|
||||||
return i + 1; // including the return type
|
return i + 1; // including the return type
|
||||||
|
|
|
@ -87,29 +87,6 @@ protected:
|
||||||
QskMetaInvokable* invokable() const;
|
QskMetaInvokable* invokable() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template< typename T, typename F >
|
|
||||||
static inline QskMetaInvokable* findInvokable( F function )
|
|
||||||
{
|
|
||||||
QskMetaInvokable* invokable;
|
|
||||||
|
|
||||||
#if QSK_SHARED_META_INVOKABLE
|
|
||||||
invokable = QskMetaInvokable::find( typeid( T ) );
|
|
||||||
if ( invokable )
|
|
||||||
{
|
|
||||||
invokable->ref();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
invokable = new T( function );
|
|
||||||
QskMetaInvokable::insert( typeid( T ), invokable );
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
invokable = new T( function );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return invokable;
|
|
||||||
}
|
|
||||||
|
|
||||||
QskMetaInvokable* m_invokable;
|
QskMetaInvokable* m_invokable;
|
||||||
const int* m_parameterTypes;
|
const int* m_parameterTypes;
|
||||||
};
|
};
|
||||||
|
@ -133,10 +110,12 @@ inline QskMetaFunction::QskMetaFunction( T function )
|
||||||
|
|
||||||
const int Argc = Traits::ArgumentCount;
|
const int Argc = Traits::ArgumentCount;
|
||||||
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
|
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
|
||||||
using Invokable = QskMetaMemberInvokable< T, Args, void >;
|
|
||||||
|
|
||||||
init( findInvokable<Invokable>( function ),
|
auto invokable = QskMetaInvokable::instance(
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
QskMetaMemberInvokable< T, Args, void >::invoke,
|
||||||
|
reinterpret_cast< void** >( &function ) );
|
||||||
|
|
||||||
|
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T, QskMetaFunctionTraits::IsFunction< T >* >
|
template< typename T, QskMetaFunctionTraits::IsFunction< T >* >
|
||||||
|
@ -148,10 +127,12 @@ inline QskMetaFunction::QskMetaFunction( T function )
|
||||||
|
|
||||||
const int Argc = Traits::ArgumentCount;
|
const int Argc = Traits::ArgumentCount;
|
||||||
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
|
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
|
||||||
using Invokable = QskMetaFunctionInvokable< T, Args, void >;
|
|
||||||
|
|
||||||
init( findInvokable<Invokable>( function ),
|
auto invokable = QskMetaInvokable::instance(
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
QskMetaFunctionInvokable< T, Args, void >::invoke,
|
||||||
|
reinterpret_cast< void** >( &function ) );
|
||||||
|
|
||||||
|
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* >
|
template< typename T, QskMetaFunctionTraits::IsFunctor< T >* >
|
||||||
|
@ -163,10 +144,12 @@ inline QskMetaFunction::QskMetaFunction( T functor )
|
||||||
|
|
||||||
const int Argc = Traits::ArgumentCount;
|
const int Argc = Traits::ArgumentCount;
|
||||||
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
|
using Args = typename List_Left< typename Traits::Arguments, Argc >::Value;
|
||||||
using Invokable = QskMetaFunctorInvokable< T, Argc, Args, void >;
|
|
||||||
|
|
||||||
init( findInvokable<Invokable>( functor ),
|
auto invokable = QskMetaInvokable::instance(
|
||||||
ConnectionTypes< typename Traits::Arguments >::types() );
|
QskMetaFunctorInvokable< T, Argc, Args, void >::invoke,
|
||||||
|
reinterpret_cast< void** >( &functor ) );
|
||||||
|
|
||||||
|
init( invokable, ConnectionTypes< typename Traits::Arguments >::types() );
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_DECLARE_METATYPE( QskMetaFunction )
|
Q_DECLARE_METATYPE( QskMetaFunction )
|
||||||
|
|
|
@ -18,6 +18,27 @@ namespace
|
||||||
"Bad cast: QskMetaInvokable does not match" );
|
"Bad cast: QskMetaInvokable does not match" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QskMetaInvokable* QskMetaInvokable::instance(
|
||||||
|
InvokeFunction invoke, void** functor )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
In opposite to QObject::connect we share the Invokable for callbacks to the same
|
||||||
|
function/functor - like f.e QQuickItem::update(). But we have to pay an extra static
|
||||||
|
pointer inside of each callback instance.
|
||||||
|
*/
|
||||||
|
QskMetaInvokable* invokable;
|
||||||
|
void* args[] = { &invokable, functor };
|
||||||
|
|
||||||
|
invoke( Find, nullptr, nullptr, args, nullptr );
|
||||||
|
|
||||||
|
if ( invokable )
|
||||||
|
invokable->ref();
|
||||||
|
else
|
||||||
|
invoke( Create, nullptr, nullptr, args, nullptr );
|
||||||
|
|
||||||
|
return invokable;
|
||||||
|
}
|
||||||
|
|
||||||
int QskMetaInvokable::typeInfo() const
|
int QskMetaInvokable::typeInfo() const
|
||||||
{
|
{
|
||||||
auto that = const_cast< QskMetaInvokable* >( this );
|
auto that = const_cast< QskMetaInvokable* >( this );
|
||||||
|
@ -35,28 +56,3 @@ int QskMetaInvokable::refCount() const
|
||||||
auto that = const_cast< QskMetaInvokable* >( this );
|
auto that = const_cast< QskMetaInvokable* >( this );
|
||||||
return reinterpret_cast< SlotObject* >( that )->ref.load();
|
return reinterpret_cast< SlotObject* >( that )->ref.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QSK_SHARED_META_INVOKABLE
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <typeindex>
|
|
||||||
|
|
||||||
static std::unordered_map< std::type_index, QskMetaInvokable* > qskInvokableTab;
|
|
||||||
|
|
||||||
QskMetaInvokable* QskMetaInvokable::find( const std::type_info& info )
|
|
||||||
{
|
|
||||||
const auto it = qskInvokableTab.find( info );
|
|
||||||
return ( it != qskInvokableTab.end() ) ? it->second : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskMetaInvokable::insert( const std::type_info& info, QskMetaInvokable* invokable )
|
|
||||||
{
|
|
||||||
qskInvokableTab.emplace( info, invokable );
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskMetaInvokable::remove( const std::type_info& info )
|
|
||||||
{
|
|
||||||
qskInvokableTab.erase( info );
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // QSK_SHARED_META_INVOKABLE
|
|
||||||
|
|
|
@ -11,132 +11,133 @@
|
||||||
|
|
||||||
// helper classes for QskMetaFunction
|
// helper classes for QskMetaFunction
|
||||||
|
|
||||||
#ifndef QT_NO_RTTI // we rely on hashing type_info
|
|
||||||
|
|
||||||
/*
|
|
||||||
When being enabled the same instance of QskMetaInvokable is used
|
|
||||||
for all QskMetaFunctions having the same function/method/functor -
|
|
||||||
f.e. &QQuickItem::update.
|
|
||||||
|
|
||||||
Not sure, why QObject::connect does not do the same and always
|
|
||||||
creates unique QSlotObjectBase objects for each connection.
|
|
||||||
*/
|
|
||||||
#ifndef QSK_SHARED_META_INVOKABLE
|
|
||||||
#define QSK_SHARED_META_INVOKABLE 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class QSK_EXPORT QskMetaInvokable : public QtPrivate::QSlotObjectBase
|
class QSK_EXPORT QskMetaInvokable : public QtPrivate::QSlotObjectBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef void (* InvokeFunction)(
|
typedef void (* InvokeFunction)(
|
||||||
int which, QtPrivate::QSlotObjectBase*, QObject*, void**, bool* );
|
int which, QtPrivate::QSlotObjectBase*, QObject*, void**, bool* );
|
||||||
|
|
||||||
enum { TypeInfo = NumOperations + 1 };
|
enum
|
||||||
|
{
|
||||||
|
TypeInfo = NumOperations + 1,
|
||||||
|
Create,
|
||||||
|
Find
|
||||||
|
};
|
||||||
|
|
||||||
int typeInfo() const;
|
int typeInfo() const;
|
||||||
int refCount() const;
|
int refCount() const;
|
||||||
|
|
||||||
protected:
|
static QskMetaInvokable* instance( InvokeFunction, void** function );
|
||||||
friend class QskMetaFunction;
|
|
||||||
|
|
||||||
|
protected:
|
||||||
explicit QskMetaInvokable( InvokeFunction f ):
|
explicit QskMetaInvokable( InvokeFunction f ):
|
||||||
QSlotObjectBase( f )
|
QSlotObjectBase( f )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QSK_SHARED_META_INVOKABLE
|
|
||||||
/*
|
|
||||||
To avoid having more QskMetaInvokables for the same
|
|
||||||
function we have a hash table, where they are registered
|
|
||||||
*/
|
|
||||||
static QskMetaInvokable* find( const std::type_info& info );
|
|
||||||
static void insert( const std::type_info&, QskMetaInvokable* );
|
|
||||||
static void remove( const std::type_info& );
|
|
||||||
#else
|
|
||||||
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename Function, typename Args, typename R >
|
template< typename Function, typename Args, typename R >
|
||||||
class QskMetaFunctionInvokable : public QskMetaInvokable
|
class QskMetaFunctionInvokable : public QskMetaInvokable
|
||||||
{
|
{
|
||||||
public:
|
using Invokable = QskMetaFunctionInvokable< Function, Args, R >;
|
||||||
typedef QtPrivate::FunctionPointer< Function > FuncType;
|
|
||||||
|
|
||||||
explicit QskMetaFunctionInvokable( Function function ):
|
public:
|
||||||
|
explicit inline QskMetaFunctionInvokable( Function function ):
|
||||||
QskMetaInvokable( &invoke ),
|
QskMetaInvokable( &invoke ),
|
||||||
m_function( function )
|
m_function( function )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void invoke(int which, QtPrivate::QSlotObjectBase* invokable,
|
static void invoke(int which, QtPrivate::QSlotObjectBase*,
|
||||||
QObject* object, void** args, bool* )
|
QObject* object, void** args, bool* )
|
||||||
{
|
{
|
||||||
auto invokableFunction = static_cast< QskMetaFunctionInvokable* >( invokable );
|
static Invokable* invokable = nullptr;
|
||||||
|
|
||||||
switch ( which )
|
switch ( which )
|
||||||
{
|
{
|
||||||
|
case Find:
|
||||||
|
{
|
||||||
|
*reinterpret_cast< void** >( args[0] ) = invokable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Create:
|
||||||
|
{
|
||||||
|
invokable = new Invokable( *reinterpret_cast< Function* >( args[1] ) );
|
||||||
|
*reinterpret_cast< void** >( args[0] ) = invokable;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Destroy:
|
case Destroy:
|
||||||
{
|
{
|
||||||
#if QSK_SHARE_INVOKABLES
|
delete invokable;
|
||||||
remove( typeid( Function ) );
|
invokable = nullptr;
|
||||||
#endif
|
|
||||||
delete invokableFunction;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Call:
|
case Call:
|
||||||
{
|
{
|
||||||
|
typedef QtPrivate::FunctionPointer< Function > FuncType;
|
||||||
|
|
||||||
FuncType::template call< Args, R >(
|
FuncType::template call< Args, R >(
|
||||||
invokableFunction->m_function, object, args );
|
invokable->m_function, object, args );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeInfo:
|
case TypeInfo:
|
||||||
{
|
{
|
||||||
int* typeInfo = reinterpret_cast< int* >( args );
|
*reinterpret_cast< int* >( args ) = 1; // QskMetaFunction::Function
|
||||||
*typeInfo = 1; // = QskMetaFunction::Function
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
Function m_function;
|
Function m_function;
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename Function, typename Args, typename R >
|
template< typename Function, typename Args, typename R >
|
||||||
class QskMetaMemberInvokable : public QskMetaInvokable
|
class QskMetaMemberInvokable : public QskMetaInvokable
|
||||||
{
|
{
|
||||||
|
using Invokable = QskMetaMemberInvokable< Function, Args, R >;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit QskMetaMemberInvokable( Function function ):
|
explicit inline QskMetaMemberInvokable( Function function ):
|
||||||
QskMetaInvokable( &invoke ),
|
QskMetaInvokable( &invoke ),
|
||||||
m_function( function )
|
m_function( function )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void invoke( int which, QtPrivate::QSlotObjectBase* invokable,
|
static void invoke( int which, QtPrivate::QSlotObjectBase*,
|
||||||
QObject* object, void** args, bool* ret )
|
QObject* object, void** args, bool* ret )
|
||||||
{
|
{
|
||||||
typedef QtPrivate::FunctionPointer< Function > FuncType;
|
static Invokable* invokable = nullptr;
|
||||||
|
|
||||||
auto invokableMember = static_cast< QskMetaMemberInvokable* >( invokable );
|
|
||||||
|
|
||||||
switch (which)
|
switch (which)
|
||||||
{
|
{
|
||||||
|
case Find:
|
||||||
|
{
|
||||||
|
*reinterpret_cast< void** >( args[0] ) = invokable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Create:
|
||||||
|
{
|
||||||
|
invokable = new Invokable( *reinterpret_cast< Function* >( args[1] ) );
|
||||||
|
*reinterpret_cast< void** >( args[0] ) = invokable;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Destroy:
|
case Destroy:
|
||||||
{
|
{
|
||||||
#if QSK_SHARE_INVOKABLES
|
delete invokable;
|
||||||
remove( typeid( Function ) );
|
invokable = nullptr;
|
||||||
#endif
|
|
||||||
delete invokableMember;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Call:
|
case Call:
|
||||||
{
|
{
|
||||||
|
typedef QtPrivate::FunctionPointer< Function > FuncType;
|
||||||
|
|
||||||
FuncType::template call< Args, R >(
|
FuncType::template call< Args, R >(
|
||||||
invokableMember->m_function,
|
invokable->m_function,
|
||||||
static_cast< typename FuncType::Object* >( object ), args );
|
static_cast< typename FuncType::Object* >( object ), args );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -144,14 +145,12 @@ public:
|
||||||
case Compare:
|
case Compare:
|
||||||
{
|
{
|
||||||
const auto function = *reinterpret_cast< Function* >( args );
|
const auto function = *reinterpret_cast< Function* >( args );
|
||||||
*ret = function == invokableMember->m_function;
|
*ret = function == invokable->m_function;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeInfo:
|
case TypeInfo:
|
||||||
{
|
{
|
||||||
int* typeInfo = reinterpret_cast< int* >( args );
|
*reinterpret_cast< int* >( args ) = 0; // = QskMetaFunction::Member
|
||||||
*typeInfo = 0; // = QskMetaFunction::Member
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,42 +163,52 @@ private:
|
||||||
template< typename Function, int N, typename Args, typename R >
|
template< typename Function, int N, typename Args, typename R >
|
||||||
class QskMetaFunctorInvokable : public QskMetaInvokable
|
class QskMetaFunctorInvokable : public QskMetaInvokable
|
||||||
{
|
{
|
||||||
public:
|
using Invokable = QskMetaFunctorInvokable< Function, N, Args, R >;
|
||||||
typedef QtPrivate::Functor< Function, N > FuncType;
|
|
||||||
|
|
||||||
explicit QskMetaFunctorInvokable( Function function ):
|
public:
|
||||||
|
explicit inline QskMetaFunctorInvokable( Function function ):
|
||||||
QskMetaInvokable( &invoke ),
|
QskMetaInvokable( &invoke ),
|
||||||
m_function( std::move( function ) )
|
m_function( function )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void invoke( int which, QSlotObjectBase* invokable,
|
static void invoke( int which, QSlotObjectBase*, QObject* object, void** args, bool* )
|
||||||
QObject* object, void** args, bool* )
|
|
||||||
{
|
{
|
||||||
auto invokableFunctor = static_cast< QskMetaFunctorInvokable* >( invokable );
|
static Invokable* invokable = nullptr;
|
||||||
|
|
||||||
switch (which)
|
switch (which)
|
||||||
{
|
{
|
||||||
|
case Find:
|
||||||
|
{
|
||||||
|
*reinterpret_cast< void** >( args[0] ) = invokable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Create:
|
||||||
|
{
|
||||||
|
invokable = new Invokable( *reinterpret_cast< Function* >( args[1] ) );
|
||||||
|
*reinterpret_cast< void** >( args[0] ) = invokable;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Destroy:
|
case Destroy:
|
||||||
{
|
{
|
||||||
#if QSK_SHARE_INVOKABLES
|
delete invokable;
|
||||||
remove( typeid( Function ) );
|
invokable = nullptr;
|
||||||
#endif
|
|
||||||
delete invokableFunctor;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Call:
|
case Call:
|
||||||
{
|
{
|
||||||
|
typedef QtPrivate::Functor< Function, N > FuncType;
|
||||||
|
|
||||||
FuncType::template call< Args, R >(
|
FuncType::template call< Args, R >(
|
||||||
invokableFunctor->m_function, object, args );
|
invokable->m_function, object, args );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeInfo:
|
case TypeInfo:
|
||||||
{
|
{
|
||||||
int* typeInfo = reinterpret_cast< int* >( args );
|
*reinterpret_cast< int* >( args ) = 2; // QskMetaFunction::Functor
|
||||||
*typeInfo = 2; // QskMetaFunction::Functor;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue