Add helper template for metacall event creation

Setting up the args and types arrays is cumbersome and error prone, and
we do it at least twice in qtbase. Provide a central implementation as a
variadic template function, and make it exception-safe with a unique_ptr
(the destructor of QMetaCallEvent will destroy the cloned arguments).

Change-Id: I5ff400467928446264eaedddb394691e9e23d22e
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Volker Hilsheimer 2023-03-29 15:07:49 +02:00
parent db7dc35897
commit c4449c040c
3 changed files with 32 additions and 24 deletions

View File

@ -2850,6 +2850,13 @@ void QCoreApplication::requestPermission(const QPermission &requestedPermission,
Q_ASSERT(slotObj);
// Used as the signalID in the metacall event and only used to
// verify that we are not processing an unrelated event, not to
// emit the right signal. So using a value that can never clash
// with any signal index. Clang doesn't like this to be a static
// member of the PermissionReceiver.
static constexpr ushort PermissionReceivedID = 0xffff;
// If we have a context object, then we dispatch the permission response
// asynchronously through a received object that lives in the same thread
// as the context object. Otherwise we call the functor synchronously when
@ -2860,11 +2867,12 @@ void QCoreApplication::requestPermission(const QPermission &requestedPermission,
PermissionReceiver(QtPrivate::QSlotObjectBase *slotObject, const QObject *context)
: slotObject(slotObject), context(context)
{}
protected:
bool event(QEvent *event) override {
if (event->type() == QEvent::MetaCall) {
auto metaCallEvent = static_cast<QMetaCallEvent *>(event);
if (metaCallEvent->id() == ushort(-1)) {
if (metaCallEvent->id() == PermissionReceivedID) {
Q_ASSERT(slotObject);
// only execute if context object is still alive
if (context)
@ -2898,18 +2906,8 @@ void QCoreApplication::requestPermission(const QPermission &requestedPermission,
permission.m_status = status;
if (receiver) {
const int nargs = 2;
auto metaCallEvent = new QMetaCallEvent(slotObj, qApp, ushort(-1), nargs);
Q_CHECK_PTR(metaCallEvent);
void **args = metaCallEvent->args();
QMetaType *types = metaCallEvent->types();
const auto voidType = QMetaType::fromType<void>();
const auto permissionType = QMetaType::fromType<QPermission>();
types[0] = voidType;
types[1] = permissionType;
args[0] = nullptr;
args[1] = permissionType.create(&permission);
Q_CHECK_PTR(args[1]);
auto metaCallEvent = QMetaCallEvent::create(slotObj, qApp,
PermissionReceivedID, permission);
qApp->postEvent(receiver, metaCallEvent);
} else {
void *argv[] = { nullptr, &permission };

View File

@ -402,6 +402,26 @@ public:
~QMetaCallEvent() override;
template<typename ...Args>
static QMetaCallEvent *create(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender,
int signal_index, Args ...argv)
{
auto metaCallEvent = std::make_unique<QMetaCallEvent>(slotObj, sender,
signal_index, int(1 + sizeof...(Args)));
void **args = metaCallEvent->args();
QMetaType *types = metaCallEvent->types();
const std::array<void *, sizeof...(Args) + 1> argp{ nullptr, std::addressof(argv)... };
const std::array metaTypes{ QMetaType::fromType<void>(), QMetaType::fromType<Args>()... };
for (size_t i = 0; i < sizeof...(Args) + 1; ++i) {
types[i] = metaTypes[i];
args[i] = types[i].create(argp[i]);
Q_CHECK_PTR(!i || args[i]);
}
return metaCallEvent.release();
}
inline int id() const { return d.method_offset_ + d.method_relative_; }
inline const void * const* args() const { return d.args_; }
inline void ** args() { return d.args_; }

View File

@ -107,18 +107,8 @@ void QHostInfoResult::postResultsReady(const QHostInfo &info)
auto result = new QHostInfoResult(this);
Q_CHECK_PTR(result);
const int nargs = 2;
auto metaCallEvent = new QMetaCallEvent(slotObj, nullptr, signal_index, nargs);
auto metaCallEvent = QMetaCallEvent::create(slotObj, nullptr, signal_index, info);
Q_CHECK_PTR(metaCallEvent);
void **args = metaCallEvent->args();
QMetaType *types = metaCallEvent->types();
auto voidType = QMetaType::fromType<void>();
auto hostInfoType = QMetaType::fromType<QHostInfo>();
types[0] = voidType;
types[1] = hostInfoType;
args[0] = nullptr;
args[1] = hostInfoType.create(&info);
Q_CHECK_PTR(args[1]);
qApp->postEvent(result, metaCallEvent);
}