Remove NewClosure
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
set(SOURCES
|
||||
core/closure.cpp
|
||||
core/logging.cpp
|
||||
core/messagehandler.cpp
|
||||
core/messagereply.cpp
|
||||
@@ -9,7 +8,6 @@ set(SOURCES
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
core/closure.h
|
||||
core/messagehandler.h
|
||||
core/messagereply.h
|
||||
core/workerpool.h
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/* This file is part of Strawberry.
|
||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||
|
||||
Strawberry is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Strawberry is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include <QGenericArgument>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
# include <QRandomGenerator>
|
||||
#endif
|
||||
|
||||
#include "closure.h"
|
||||
|
||||
#include "core/timeconstants.h"
|
||||
|
||||
namespace _detail {
|
||||
|
||||
ClosureBase::ClosureBase(ObjectHelper *helper) : helper_(helper) {}
|
||||
|
||||
ClosureBase::~ClosureBase() {}
|
||||
|
||||
CallbackClosure::CallbackClosure(QObject *sender, const char *signal, std::function<void()> callback)
|
||||
: ClosureBase(new ObjectHelper(sender, signal, this)),
|
||||
callback_(callback) {
|
||||
}
|
||||
|
||||
void CallbackClosure::Invoke() {
|
||||
callback_();
|
||||
}
|
||||
|
||||
ObjectHelper* ClosureBase::helper() const {
|
||||
return helper_;
|
||||
}
|
||||
|
||||
ObjectHelper::ObjectHelper(QObject *sender, const char *signal, ClosureBase *closure) : closure_(closure) {
|
||||
|
||||
QObject::connect(sender, signal, SLOT(Invoked()));
|
||||
QObject::connect(sender, &QObject::destroyed, this, &ObjectHelper::deleteLater);
|
||||
|
||||
}
|
||||
|
||||
ObjectHelper::~ObjectHelper() {}
|
||||
|
||||
void ObjectHelper::Invoked() {
|
||||
closure_->Invoke();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void Unpack(QList<QGenericArgument>*) {}
|
||||
|
||||
} // namespace _detail
|
||||
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void()> callback) {
|
||||
return new _detail::CallbackClosure(sender, signal, callback);
|
||||
}
|
||||
|
||||
void DoAfter(QObject *receiver, const char *slot, int msec) {
|
||||
QTimer::singleShot(msec, receiver, slot);
|
||||
}
|
||||
|
||||
void DoInAMinuteOrSo(QObject *receiver, const char *slot) {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
int msec = (60 + QRandomGenerator::global()->bounded(1, 60)) * kMsecPerSec;
|
||||
#else
|
||||
int msec = (60 + (qrand() % 60)) * kMsecPerSec;
|
||||
#endif
|
||||
|
||||
DoAfter(receiver, slot, msec);
|
||||
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
/* This file is part of Strawberry.
|
||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||
|
||||
Strawberry is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Strawberry is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CLOSURE_H
|
||||
#define CLOSURE_H
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaMethod>
|
||||
#include <QSharedPointer>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
|
||||
#include "core/logging.h"
|
||||
|
||||
namespace _detail {
|
||||
|
||||
class ObjectHelper;
|
||||
|
||||
// Interface for ObjectHelper to call on signal emission.
|
||||
class ClosureBase {
|
||||
public:
|
||||
virtual ~ClosureBase();
|
||||
virtual void Invoke() = 0;
|
||||
|
||||
// Tests only.
|
||||
ObjectHelper *helper() const;
|
||||
|
||||
protected:
|
||||
explicit ClosureBase(ObjectHelper*);
|
||||
ObjectHelper *helper_;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(ClosureBase)
|
||||
|
||||
};
|
||||
|
||||
// QObject helper as templated QObjects do not work.
|
||||
// Connects to the given signal and invokes the closure when called.
|
||||
// Deletes itself and the Closure after being invoked.
|
||||
class ObjectHelper : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ObjectHelper(QObject *sender, const char *signal, ClosureBase *closure);
|
||||
~ObjectHelper() override;
|
||||
|
||||
private slots:
|
||||
void Invoked();
|
||||
|
||||
private:
|
||||
std::unique_ptr<ClosureBase> closure_;
|
||||
Q_DISABLE_COPY(ObjectHelper)
|
||||
|
||||
};
|
||||
|
||||
// Helpers for unpacking a variadic template list.
|
||||
|
||||
// Base case of no arguments.
|
||||
void Unpack(QList<QGenericArgument>*);
|
||||
|
||||
template <typename Arg>
|
||||
void Unpack(QList<QGenericArgument> *list, const Arg &arg) {
|
||||
list->append(Q_ARG(Arg, arg));
|
||||
}
|
||||
|
||||
template <typename Head, typename... Tail>
|
||||
void Unpack(QList<QGenericArgument> *list, const Head &head, const Tail&... tail) {
|
||||
Unpack(list, head);
|
||||
Unpack(list, tail...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
class Closure : public ClosureBase {
|
||||
public:
|
||||
Closure(
|
||||
QObject *sender,
|
||||
const char *signal,
|
||||
QObject *receiver,
|
||||
const char *slot,
|
||||
const Args&... args)
|
||||
: ClosureBase(new ObjectHelper(sender, signal, this)),
|
||||
// std::bind is the easiest way to store an argument list.
|
||||
function_(std::bind(&Closure<Args...>::Call, this, args...)),
|
||||
receiver_(receiver) {
|
||||
const QMetaObject *meta_receiver = receiver->metaObject();
|
||||
QByteArray normalised_slot = QMetaObject::normalizedSignature(slot + 1);
|
||||
const int index = meta_receiver->indexOfSlot(normalised_slot.constData());
|
||||
Q_ASSERT(index != -1);
|
||||
slot_ = meta_receiver->method(index);
|
||||
QObject::connect(receiver_, &QObject::destroyed, helper_, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
void Invoke() override {
|
||||
function_();
|
||||
}
|
||||
|
||||
private:
|
||||
void Call(const Args&... args) {
|
||||
QList<QGenericArgument> arg_list;
|
||||
Unpack(&arg_list, args...);
|
||||
|
||||
slot_.invoke(
|
||||
receiver_,
|
||||
arg_list.size() > 0 ? arg_list[0] : QGenericArgument(),
|
||||
arg_list.size() > 1 ? arg_list[1] : QGenericArgument(),
|
||||
arg_list.size() > 2 ? arg_list[2] : QGenericArgument(),
|
||||
arg_list.size() > 3 ? arg_list[3] : QGenericArgument(),
|
||||
arg_list.size() > 4 ? arg_list[4] : QGenericArgument(),
|
||||
arg_list.size() > 5 ? arg_list[5] : QGenericArgument(),
|
||||
arg_list.size() > 6 ? arg_list[6] : QGenericArgument(),
|
||||
arg_list.size() > 7 ? arg_list[7] : QGenericArgument(),
|
||||
arg_list.size() > 8 ? arg_list[8] : QGenericArgument(),
|
||||
arg_list.size() > 9 ? arg_list[9] : QGenericArgument());
|
||||
}
|
||||
|
||||
std::function<void()> function_;
|
||||
QObject *receiver_;
|
||||
QMetaMethod slot_;
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
class SharedClosure : public Closure<Args...> {
|
||||
public:
|
||||
SharedClosure(
|
||||
QSharedPointer<T> sender,
|
||||
const char *signal,
|
||||
QObject *receiver,
|
||||
const char *slot,
|
||||
const Args&... args)
|
||||
: Closure<Args...>(
|
||||
sender.data(),
|
||||
signal,
|
||||
receiver,
|
||||
slot,
|
||||
args...),
|
||||
data_(sender) {
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<T> data_;
|
||||
};
|
||||
|
||||
class CallbackClosure : public ClosureBase {
|
||||
public:
|
||||
CallbackClosure(QObject *sender, const char *signal, std::function<void()> callback);
|
||||
|
||||
void Invoke() override;
|
||||
|
||||
private:
|
||||
std::function<void()> callback_;
|
||||
};
|
||||
|
||||
} // namespace _detail
|
||||
|
||||
template <typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, QObject *receiver, const char *slot, const Args&... args) {
|
||||
return new _detail::Closure<Args...>(sender, signal, receiver, slot, args...);
|
||||
}
|
||||
|
||||
// QSharedPointer variant
|
||||
template <typename T, typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QSharedPointer<T> sender, const char *signal, QObject *receiver, const char *slot, const Args&... args) {
|
||||
return new _detail::SharedClosure<T, Args...>(sender, signal, receiver, slot, args...);
|
||||
}
|
||||
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void()> callback);
|
||||
|
||||
template <typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void(Args...)> callback, const Args&... args) {
|
||||
return NewClosure(sender, signal, std::bind(callback, args...));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, void (*callback)(Args...), const Args&... args) {
|
||||
return NewClosure(sender, signal, std::bind(callback, args...));
|
||||
}
|
||||
|
||||
template <typename T, typename Unused, typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, T *receiver, Unused (T::*callback)(Args...), const Args&... args) {
|
||||
return NewClosure(sender, signal, std::bind(callback, receiver, args...));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QFuture<T> future, QObject *receiver, const char *slot, const Args&... args) {
|
||||
QFutureWatcher<T> *watcher = new QFutureWatcher<T>;
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, &QFutureWatcher<T>::deleteLater);
|
||||
return NewClosure(watcher, SIGNAL(finished()), receiver, slot, args...);
|
||||
}
|
||||
|
||||
template <typename T, typename F, typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QFuture<T> future, const F &callback, const Args&... args) {
|
||||
QFutureWatcher<T> *watcher = new QFutureWatcher<T>;
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, &QFutureWatcher<T>::deleteLater);
|
||||
return NewClosure(watcher, SIGNAL(finished()), callback, args...);
|
||||
}
|
||||
|
||||
void DoAfter(QObject *receiver, const char *slot, int msec);
|
||||
void DoAfter(std::function<void()> callback, std::chrono::milliseconds msec);
|
||||
void DoInAMinuteOrSo(QObject *receiver, const char *slot);
|
||||
|
||||
template <typename R, typename P>
|
||||
void DoAfter(std::function<void()> callback, std::chrono::duration<R, P> duration) {
|
||||
QTimer *timer = new QTimer;
|
||||
timer->setSingleShot(true);
|
||||
QObject::connect(timer, &QTimer::timeout, callback);
|
||||
QObject::connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater);
|
||||
std::chrono::milliseconds msec = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
|
||||
timer->start(msec.count());
|
||||
}
|
||||
|
||||
#endif // CLOSURE_H
|
||||
Reference in New Issue
Block a user