#ifndef ASYNCEVENT_H #define ASYNCEVENT_H #include "BoostLog.h" #include #include #include #include #include #include #include namespace Amass { template class AsyncEvent : public QEvent { public: using Arguments = std::tuple...>; AsyncEvent(Functor &&functor, Args &&...args) : QEvent(static_cast(QEvent::registerEventType())), m_functor(std::forward(functor)), m_args(std::forward(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 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 && target->thread() == QThread::currentThread()) { std::invoke(std::forward(functor), std::forward(args)...); return; } auto event = new AsyncEvent(std::forward(functor), std::forward(args)...); QCoreApplication::postEvent(target, event, std::is_same_v ? Qt::LowEventPriority : Qt::NormalEventPriority); } template class MemberFunctionArgumentsTraits; template class MemberFunctionArgumentsTraits { public: using FunctionPointerType = Ret (Object::*)(Args...); static auto wrapper(std::shared_ptr 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)...); }, std::forward(args)...); }; } }; template struct LambdaTraits : LambdaTraits {}; template struct LambdaTraits { template static auto wrapper(std::shared_ptr instance, Object &&function) { return [instanceWeakPointer{std::weak_ptr{instance}}, function = std::move(function)](Args &&...args) { if (instanceWeakPointer.expired()) return; auto instance = instanceWeakPointer.lock(); executeAtObjectThread( instance.get(), [instanceWeakPointer, function = std::move(function)](Args &&...args) { if (instanceWeakPointer.expired()) return; auto instance = instanceWeakPointer.lock(); function(std::forward(args)...); }, std::forward(args)...); }; } }; template struct LambdaTraits { template static auto wrapper(std::shared_ptr instance, Object &&function) { return [instanceWeakPointer{std::weak_ptr{instance}}, function = std::move(function)](Args &&...args) { if (instanceWeakPointer.expired()) return; auto instance = instanceWeakPointer.lock(); executeAtObjectThread( instance.get(), [instanceWeakPointer, function = std::move(function)](Args &&...args) mutable { if (instanceWeakPointer.expired()) return; auto instance = instanceWeakPointer.lock(); function(std::forward(args)...); }, std::forward(args)...); }; } }; template boost::signals2::connection connect(SignalType &signal, std::shared_ptr target, Function Object::*function) { using Traits = Amass::MemberFunctionArgumentsTraits; return signal.connect(typename SignalType::slot_type(Traits::wrapper(target, function)).track_foreign(target)); } template boost::signals2::connection connect(SignalType &signal, std::shared_ptr target, Function &&function) { using Traits = LambdaTraits; return signal.connect( typename SignalType::slot_type(Traits::template wrapper(target, std::move(function))).track_foreign(target)); } } // namespace Amass #endif // ASYNCEVENT_H