#pragma once #include #include #include #include #include #include namespace mln { template class WorkTaskImpl : public WorkTask { public: WorkTaskImpl(F f, P p, std::shared_ptr> canceled_) : canceled(std::move(canceled_)), func(std::move(f)), params(std::move(p)) {} void operator()() override { // Lock the mutex while processing so that cancel() will block. std::scoped_lock lock(mutex); if (!canceled->load(std::memory_order_acquire)) { invoke(std::make_index_sequence>{}); } } /// If the task has not yet begun, this will cancel it. /// If the task is in progress, this will block until it completed. (Currently /// necessary because of shared state, but should be removed.) It will also /// cancel the after callback. /// If the task has completed, but the after callback has not executed, this /// will cancel the after callback. /// If the task has completed and the after callback has executed, this will /// do nothing. void cancel() override { std::scoped_lock lock(mutex); canceled->store(true, std::memory_order_release); } private: template void invoke(std::index_sequence) { func(std::move(std::get(std::forward

(params)))...); } std::recursive_mutex mutex; std::shared_ptr> canceled; F func; P params; }; template std::shared_ptr WorkTask::make(Fn&& fn, Args&&... args) { auto flag = std::make_shared>(); flag->store(false, std::memory_order_relaxed); auto tuple = std::make_tuple(std::forward(args)...); return std::make_shared, decltype(tuple)>>( std::forward(fn), std::move(tuple), flag); } } // namespace mln