qskinny/src/common/QskMetaFunction.cpp

279 lines
6.9 KiB
C++
Raw Normal View History

/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskMetaFunction.h"
2018-07-19 14:10:48 +02:00
#include <qcoreapplication.h>
#include <qobject.h>
#include <qsemaphore.h>
2018-08-03 08:15:28 +02:00
#include <qthread.h>
2018-02-28 10:43:15 +01:00
QSK_QT_PRIVATE_BEGIN
#include <private/qobject_p.h>
QSK_QT_PRIVATE_END
2022-04-16 17:02:53 +02:00
static inline void qskInvokeFunctionQueued(
QObject* object, QskMetaFunction::FunctionCall* functionCall,
void* argv[], QSemaphore* semaphore )
2018-02-28 10:43:15 +01:00
{
2019-12-14 19:05:40 +01:00
auto event = new QMetaCallEvent(
2022-04-16 17:02:53 +02:00
functionCall, nullptr, 0, argv, semaphore );
2018-02-28 10:43:15 +01:00
QCoreApplication::postEvent( object, event );
}
2018-03-03 15:52:42 +01:00
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;
2018-08-03 08:15:28 +02:00
reinterpret_cast< SlotObject* >( that )->invoke(
TypeInfo, that, nullptr, reinterpret_cast< void** >( &value ), nullptr );
2018-03-03 15:52:42 +01:00
return value;
}
int QskMetaFunction::FunctionCall::refCount() const
{
auto that = const_cast< FunctionCall* >( this );
2019-12-14 19:05:40 +01:00
#if QT_VERSION >= QT_VERSION_CHECK( 5, 14, 0 )
return reinterpret_cast< SlotObject* >( that )->ref.loadRelaxed();
#else
2018-03-03 15:52:42 +01:00
return reinterpret_cast< SlotObject* >( that )->ref.load();
2019-12-14 19:05:40 +01:00
#endif
2018-03-03 15:52:42 +01:00
}
2018-08-03 08:15:28 +02:00
QskMetaFunction::QskMetaFunction()
: m_functionCall( nullptr )
{
}
2018-08-03 08:15:28 +02:00
QskMetaFunction::QskMetaFunction( FunctionCall* functionCall )
: m_functionCall( functionCall )
2018-02-28 16:48:46 +01:00
{
2018-03-03 15:52:42 +01:00
if ( m_functionCall )
m_functionCall->ref();
2018-02-28 16:48:46 +01:00
}
2018-08-03 08:15:28 +02:00
QskMetaFunction::QskMetaFunction( const QskMetaFunction& other )
: m_functionCall( other.m_functionCall )
{
2018-03-03 15:52:42 +01:00
if ( m_functionCall )
m_functionCall->ref();
}
2018-08-03 08:15:28 +02:00
QskMetaFunction::QskMetaFunction( QskMetaFunction&& other )
: m_functionCall( other.m_functionCall )
{
2018-03-03 15:52:42 +01:00
other.m_functionCall = nullptr;
}
QskMetaFunction::~QskMetaFunction()
{
2018-03-03 15:52:42 +01:00
if ( m_functionCall )
m_functionCall->destroyIfLastRef();
}
QskMetaFunction& QskMetaFunction::operator=( QskMetaFunction&& other )
{
2018-03-03 15:52:42 +01:00
if ( m_functionCall != other.m_functionCall )
{
2018-03-03 15:52:42 +01:00
if ( m_functionCall )
m_functionCall->destroyIfLastRef();
2018-03-03 15:52:42 +01:00
m_functionCall = other.m_functionCall;
other.m_functionCall = nullptr;
}
return *this;
}
QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
{
2018-03-03 15:52:42 +01:00
if ( m_functionCall != other.m_functionCall )
{
2018-03-03 15:52:42 +01:00
if ( m_functionCall )
m_functionCall->destroyIfLastRef();
2018-03-03 15:52:42 +01:00
m_functionCall = other.m_functionCall;
2018-03-03 15:52:42 +01:00
if ( m_functionCall )
m_functionCall->ref();
}
return *this;
}
2018-03-04 13:31:49 +01:00
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() == StaticFunction &&
2019-01-04 13:42:16 +01:00
other.m_functionCall->typeInfo() == StaticFunction )
2018-03-04 13:31:49 +01:00
{
// only static functions can be compared
return m_functionCall->compare(
reinterpret_cast< void** >( other.m_functionCall ) );
}
}
return false;
}
2018-03-08 08:37:44 +01:00
int QskMetaFunction::returnType() const
{
return QMetaType::Void; // TODO ...
}
size_t QskMetaFunction::parameterCount() const
{
2018-03-08 08:37:44 +01:00
int count = 0;
2018-03-02 06:57:08 +01:00
if ( auto types = parameterTypes() )
{
2018-03-08 08:37:44 +01:00
while ( types[ count ] != QMetaType::UnknownType )
count++;
}
2018-03-08 08:37:44 +01:00
return count;
}
QskMetaFunction::Type QskMetaFunction::functionType() const
{
2018-03-03 15:52:42 +01:00
if ( m_functionCall == nullptr )
return Invalid;
2018-03-03 15:52:42 +01:00
return static_cast< QskMetaFunction::Type >( m_functionCall->typeInfo() );
}
2018-08-03 08:15:28 +02:00
void QskMetaFunction::invoke( QObject* object,
void* argv[], Qt::ConnectionType connectionType )
{
2018-05-09 15:45:10 +02:00
#if 1
/*
Since Qt 5.10 we also have QMetaObject::invokeMethod
with functor based callbacks. TODO ...
*/
#endif
2018-03-02 11:26:25 +01:00
// code is not thread safe - TODO ...
2018-03-03 15:52:42 +01:00
if ( m_functionCall == nullptr )
2018-02-28 10:43:15 +01:00
return;
2020-05-09 16:17:27 +02:00
QPointer< QObject > receiver( object );
2018-02-28 10:43:15 +01:00
int invokeType = connectionType & 0x3;
if ( invokeType == Qt::AutoConnection )
{
2018-03-02 11:26:25 +01:00
invokeType = ( receiver && receiver->thread() != QThread::currentThread() )
2018-02-28 16:48:46 +01:00
? Qt::QueuedConnection : Qt::DirectConnection;
2018-02-28 10:43:15 +01:00
}
2018-08-03 08:15:28 +02:00
switch ( invokeType )
{
2018-03-02 11:26:25 +01:00
case Qt::DirectConnection:
2018-02-28 10:43:15 +01:00
{
2018-03-03 15:52:42 +01:00
m_functionCall->call( receiver, argv );
2018-03-02 11:26:25 +01:00
break;
2018-02-28 10:43:15 +01:00
}
2018-03-02 11:26:25 +01:00
case Qt::BlockingQueuedConnection:
{
2018-08-03 08:15:28 +02:00
if ( receiver.isNull() ||
( receiver->thread() == QThread::currentThread() ) )
2018-03-02 11:26:25 +01:00
{
// We would end up in a deadlock, better do nothing
return;
}
2018-02-28 10:43:15 +01:00
2018-03-02 11:26:25 +01:00
QSemaphore semaphore;
2018-02-28 10:43:15 +01:00
2022-04-16 17:02:53 +02:00
qskInvokeFunctionQueued( receiver, m_functionCall, argv, &semaphore );
2018-02-28 10:43:15 +01:00
2018-03-02 11:26:25 +01:00
semaphore.acquire();
2018-02-28 10:43:15 +01:00
2018-03-02 11:26:25 +01:00
break;
}
case Qt::QueuedConnection:
2018-02-28 10:43:15 +01:00
{
2018-03-02 11:26:25 +01:00
if ( receiver.isNull() )
2018-02-28 10:43:15 +01:00
{
return;
}
2018-03-08 08:37:44 +01:00
const auto argc = parameterCount() + 1; // return value + arguments
2018-02-28 10:43:15 +01:00
2020-05-09 16:17:27 +02:00
auto arguments = static_cast< void** >( std::malloc( argc * sizeof( void* ) ) );
2022-04-16 17:02:53 +02:00
if ( arguments == nullptr )
2020-05-09 16:17:27 +02:00
return;
2018-02-28 10:43:15 +01:00
2018-08-03 08:15:28 +02:00
arguments[ 0 ] = nullptr;
2018-02-28 10:43:15 +01:00
2018-03-03 15:52:42 +01:00
const int* parameterTypes = m_functionCall->parameterTypes();
2018-03-02 11:26:25 +01:00
for ( uint i = 1; i < argc; i++ )
{
2018-08-03 08:15:28 +02:00
if ( argv[ i ] == nullptr )
2018-03-02 11:26:25 +01:00
{
2018-08-03 08:15:28 +02:00
Q_ASSERT( arguments[ i ] != nullptr );
2018-03-02 11:26:25 +01:00
receiver = nullptr;
break;
}
2022-04-16 17:02:53 +02:00
const auto type = parameterTypes[ i - 1 ];
2020-10-23 13:54:27 +02:00
2020-12-05 15:09:31 +01:00
arguments[ i ] =
2020-10-23 13:54:27 +02:00
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
2022-04-16 17:02:53 +02:00
QMetaType( type ).create( argv[ i ] );
2020-10-23 13:54:27 +02:00
#else
2022-04-16 17:02:53 +02:00
QMetaType::create( type, argv[ i ] );
2020-10-23 13:54:27 +02:00
#endif
2018-03-02 11:26:25 +01:00
}
if ( receiver.isNull() )
{
// object might have died in the meantime
2020-05-09 16:17:27 +02:00
std::free( arguments );
return;
2018-03-02 11:26:25 +01:00
}
2022-04-16 17:02:53 +02:00
qskInvokeFunctionQueued( object, m_functionCall, arguments, nullptr );
2018-03-02 11:26:25 +01:00
break;
2018-02-28 10:43:15 +01:00
}
}
}
2018-02-28 16:48:46 +01:00
#include "moc_QskMetaFunction.cpp"