1
0
mirror of https://github.com/clementine-player/Clementine synced 2025-01-29 02:29:56 +01:00

Add support for QSharedPointer in Closure.

This commit is contained in:
John Maguire 2012-03-19 19:36:52 +01:00
parent 1a4bfd3ebe
commit e1d77e0124
3 changed files with 83 additions and 0 deletions

View File

@ -50,6 +50,9 @@ Closure::Closure(QObject* sender,
Connect(sender, signal);
}
Closure::~Closure() {
}
void Closure::Connect(QObject* sender, const char* signal) {
bool success = connect(sender, signal, SLOT(Invoked()));
Q_ASSERT(success);

View File

@ -22,6 +22,7 @@
#include <QMetaMethod>
#include <QObject>
#include <QSharedPointer>
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
@ -62,6 +63,8 @@ class Closure : public QObject, boost::noncopyable {
Closure(QObject* sender, const char* signal,
std::tr1::function<void()> callback);
virtual ~Closure();
private slots:
void Invoked();
void Cleanup();
@ -78,6 +81,46 @@ class Closure : public QObject, boost::noncopyable {
boost::scoped_ptr<const ClosureArgumentWrapper> val3_;
};
class SharedPointerWrapper {
public:
virtual ~SharedPointerWrapper() {}
virtual void* data() const = 0;
};
template<typename T>
class SharedPointer : public SharedPointerWrapper {
public:
SharedPointer(QSharedPointer<T> ptr)
: ptr_(ptr) {
}
void* data() const {
return ptr_.data();
}
private:
QSharedPointer<T> ptr_;
};
// For use with a QSharedPointer as a sender.
class SharedClosure : public Closure {
Q_OBJECT
public:
SharedClosure(SharedPointerWrapper* sender, const char* signal,
QObject* receiver, const char* slot,
const ClosureArgumentWrapper* val0 = 0,
const ClosureArgumentWrapper* val1 = 0,
const ClosureArgumentWrapper* val2 = 0,
const ClosureArgumentWrapper* val3 = 0)
: Closure(reinterpret_cast<QObject*>(sender->data()), signal,
receiver, slot,
val0, val1, val2, val3),
shared_sender_(sender) {
}
private:
boost::scoped_ptr<SharedPointerWrapper> shared_sender_;
};
#define C_ARG(type, data) new ClosureArgument<type>(data)
Closure* NewClosure(
@ -86,6 +129,16 @@ Closure* NewClosure(
QObject* receiver,
const char* slot);
template <typename T>
Closure* NewClosure(
QSharedPointer<T> sender,
const char* signal,
QObject* receiver,
const char* slot) {
Q_ASSERT(sender.data()->metaObject()); // Static check for something QObject-like.
return new SharedClosure(new SharedPointer<T>(sender), signal, receiver, slot);
}
template <typename T>
Closure* NewClosure(
QObject* sender,

View File

@ -1,6 +1,8 @@
#include "gtest/gtest.h"
#include <QCoreApplication>
#include <QPointer>
#include <QSharedPointer>
#include <QSignalSpy>
#include "core/closure.h"
@ -38,3 +40,28 @@ TEST_F(ClosureTest, ClosureDeletesSelf) {
loop.exec();
EXPECT_EQ(1, spy.count());
}
TEST_F(ClosureTest, ClosureDoesNotCrashWithSharedPointerSender) {
TestQObject receiver;
TestQObject* sender;
boost::scoped_ptr<QSignalSpy> spy;
QPointer<Closure> closure;
{
QSharedPointer<TestQObject> sender_shared(new TestQObject);
sender = sender_shared.data();
closure = QPointer<Closure>(NewClosure(
sender_shared, SIGNAL(Emitted()),
&receiver, SLOT(Invoke())));
spy.reset(new QSignalSpy(sender, SIGNAL(destroyed())));
}
EXPECT_EQ(0, receiver.invoked());
sender->Emit();
EXPECT_EQ(1, receiver.invoked());
EXPECT_EQ(0, spy->count());
QEventLoop loop;
QObject::connect(sender, SIGNAL(destroyed()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(1, spy->count());
EXPECT_TRUE(closure.isNull());
}