Add class 'AsyncEvent'.
This commit is contained in:
parent
595ee7f98e
commit
10b20c2512
137
QtComponets/AsyncEvent.h
Normal file
137
QtComponets/AsyncEvent.h
Normal file
@ -0,0 +1,137 @@
|
||||
#ifndef ASYNCEVENT_H
|
||||
#define ASYNCEVENT_H
|
||||
|
||||
#include "BoostLog.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QEvent>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <boost/signals2/signal.hpp>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
namespace Amass {
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
class AsyncEvent : public QEvent {
|
||||
public:
|
||||
using Arguments = std::tuple<std::decay_t<Args>...>;
|
||||
AsyncEvent(Functor &&functor, Args &&...args)
|
||||
: QEvent(static_cast<QEvent::Type>(QEvent::registerEventType())), m_functor(std::forward<Functor>(functor)),
|
||||
m_args(std::forward<Args>(args)...) {
|
||||
}
|
||||
|
||||
~AsyncEvent() {
|
||||
// LOG(debug) << "AsyncEvent::~AsyncEvent: " << this;
|
||||
if (QCoreApplication::closingDown()) {
|
||||
LOG(warning) << "QCoreApplication closed,skip handle task.";
|
||||
return;
|
||||
}
|
||||
std::apply(m_functor, std::move(m_args));
|
||||
}
|
||||
|
||||
private:
|
||||
Functor m_functor;
|
||||
Arguments m_args;
|
||||
};
|
||||
|
||||
using HighPriority = std::true_type;
|
||||
using LowPriority = std::false_type;
|
||||
template <typename Priority = LowPriority, typename Functor, typename... Args>
|
||||
inline void executeAtObjectThread(QObject *target, Functor &&functor, Args &&...args) {
|
||||
if (QCoreApplication::closingDown()) {
|
||||
LOG(warning) << "QCoreApplication closed,skip handle task.";
|
||||
return;
|
||||
}
|
||||
if (std::is_same_v<Priority, HighPriority> && target->thread() == QThread::currentThread()) {
|
||||
std::invoke(std::forward<Functor>(functor), std::forward<Args>(args)...);
|
||||
return;
|
||||
}
|
||||
auto event = new AsyncEvent<Functor, Args...>(std::forward<Functor>(functor), std::forward<Args>(args)...);
|
||||
QCoreApplication::postEvent(target, event,
|
||||
std::is_same_v<Priority, LowPriority> ? Qt::LowEventPriority : Qt::NormalEventPriority);
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
class MemberFunctionArgumentsTraits;
|
||||
|
||||
template <typename Object, typename Ret, typename... Args>
|
||||
class MemberFunctionArgumentsTraits<Ret (Object::*)(Args...)> {
|
||||
public:
|
||||
using FunctionPointerType = Ret (Object::*)(Args...);
|
||||
|
||||
static auto wrapper(std::shared_ptr<Object> instance, FunctionPointerType function) {
|
||||
return [instanceWeakPointer{std::weak_ptr{instance}}, function](Args &&...args) {
|
||||
if (instanceWeakPointer.expired()) return;
|
||||
|
||||
auto instance = instanceWeakPointer.lock();
|
||||
executeAtObjectThread(
|
||||
instance.get(),
|
||||
[instanceWeakPointer, function](Args &&...args) {
|
||||
if (instanceWeakPointer.expired()) return;
|
||||
auto instance = instanceWeakPointer.lock();
|
||||
(instance.get()->*function)(std::forward<Args>(args)...);
|
||||
},
|
||||
std::forward<Args>(args)...);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <class Ld>
|
||||
struct LambdaTraits : LambdaTraits<decltype(&Ld::operator())> {};
|
||||
|
||||
template <class Ret, class Object, class... Args>
|
||||
struct LambdaTraits<Ret (Object::*)(Args...) const> {
|
||||
template <typename T = std::false_type>
|
||||
static auto wrapper(std::shared_ptr<QObject> instance, Object &&function) {
|
||||
return [instanceWeakPointer{std::weak_ptr<QObject>{instance}}, function = std::move(function)](Args &&...args) {
|
||||
if (instanceWeakPointer.expired()) return;
|
||||
auto instance = instanceWeakPointer.lock();
|
||||
executeAtObjectThread<T>(
|
||||
instance.get(),
|
||||
[instanceWeakPointer, function = std::move(function)](Args &&...args) {
|
||||
if (instanceWeakPointer.expired()) return;
|
||||
auto instance = instanceWeakPointer.lock();
|
||||
function(std::forward<Args>(args)...);
|
||||
},
|
||||
std::forward<Args>(args)...);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <class Ret, class Object, class... Args>
|
||||
struct LambdaTraits<Ret (Object::*)(Args...)> {
|
||||
|
||||
template <typename T = std::false_type>
|
||||
static auto wrapper(std::shared_ptr<QObject> instance, Object &&function) {
|
||||
return [instanceWeakPointer{std::weak_ptr<QObject>{instance}}, function = std::move(function)](Args &&...args) {
|
||||
if (instanceWeakPointer.expired()) return;
|
||||
auto instance = instanceWeakPointer.lock();
|
||||
executeAtObjectThread<T>(
|
||||
instance.get(),
|
||||
[instanceWeakPointer, function = std::move(function)](Args &&...args) mutable {
|
||||
if (instanceWeakPointer.expired()) return;
|
||||
auto instance = instanceWeakPointer.lock();
|
||||
function(std::forward<Args>(args)...);
|
||||
},
|
||||
std::forward<Args>(args)...);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SignalType, class Function, class Object>
|
||||
boost::signals2::connection connect(SignalType &signal, std::shared_ptr<Object> target, Function Object::*function) {
|
||||
using Traits = Amass::MemberFunctionArgumentsTraits<decltype(function)>;
|
||||
|
||||
return signal.connect(typename SignalType::slot_type(Traits::wrapper(target, function)).track_foreign(target));
|
||||
}
|
||||
|
||||
template <typename T = std::false_type, typename SignalType, class Function>
|
||||
boost::signals2::connection connect(SignalType &signal, std::shared_ptr<QObject> target, Function &&function) {
|
||||
using Traits = LambdaTraits<Function>;
|
||||
return signal.connect(
|
||||
typename SignalType::slot_type(Traits::template wrapper<T>(target, std::move(function))).track_foreign(target));
|
||||
}
|
||||
|
||||
} // namespace Amass
|
||||
#endif // ASYNCEVENT_H
|
@ -3,6 +3,7 @@ find_package(Qt6 COMPONENTS Gui REQUIRED)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
add_library(QtComponets
|
||||
AsyncEvent.h
|
||||
QClassStdStream.h QClassStdStream.cpp
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user