#pragma once #include #include #include namespace mbgl { 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::lock_guard lock(mutex); if (!*canceled) { invoke(std::make_index_sequence::value>{}); } } // 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::lock_guard lock(mutex); *canceled = true; } 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 = false; auto tuple = std::make_tuple(std::forward(args)...); return std::make_shared, decltype(tuple)>>( std::forward(fn), std::move(tuple), flag); } namespace detail { template auto packageArgumentsAndCallback(std::shared_ptr> flag, Tuple&& args, std::index_sequence) { auto callback = std::get(args); // Create a lambda L1 that invokes another lambda L2 on the current RunLoop R, that calls // the callback C. Both lambdas check the flag before proceeding. L1 needs to check the flag // because if the request was cancelled, then R might have been destroyed. L2 needs to check // the flag because the request may have been cancelled after L2 was invoked but before it // began executing. auto l2 = [flag, callback] (auto&&... results) { if (!*flag) { callback(std::forward(results)...); } }; auto l1 = [flag, current = util::RunLoop::Get(), l2_ = l2] (auto&&... results) { if (!*flag) { current->invoke(l2_, std::forward(results)...); } }; return std::make_tuple(std::get(std::forward(args))..., l1); } } // namespace detail template std::shared_ptr WorkTask::makeWithCallback(Fn&& fn, Args&&... args) { auto flag = std::make_shared>(); *flag = false; auto tuple = detail::packageArgumentsAndCallback(flag, std::forward_as_tuple(std::forward(args)...), std::make_index_sequence()); return std::make_shared, decltype(tuple)>>( std::forward(fn), std::move(tuple), flag); } } // namespace mbgl