Skip to content

Commit

Permalink
Add helper template for metacall event creation
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
vohi committed Apr 17, 2023
1 parent db7dc35 commit c4449c0
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 24 deletions.
24 changes: 11 additions & 13 deletions src/corelib/kernel/qcoreapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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 };
Expand Down
20 changes: 20 additions & 0 deletions src/corelib/kernel/qobject_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,26 @@ class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent

~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_; }
Expand Down
12 changes: 1 addition & 11 deletions src/network/kernel/qhostinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit c4449c0

Please sign in to comment.