1 #pragma once
2 
3 #include <mbgl/util/work_task.hpp>
4 #include <mbgl/util/run_loop.hpp>
5 
6 #include <mutex>
7 
8 namespace mbgl {
9 
10 template <class F, class P>
11 class WorkTaskImpl : public WorkTask {
12 public:
WorkTaskImpl(F f,P p,std::shared_ptr<std::atomic<bool>> canceled_)13     WorkTaskImpl(F f, P p, std::shared_ptr<std::atomic<bool>> canceled_)
14       : canceled(std::move(canceled_)),
15         func(std::move(f)),
16         params(std::move(p)) {
17     }
18 
operator ()()19     void operator()() override {
20         // Lock the mutex while processing so that cancel() will block.
21         std::lock_guard<std::recursive_mutex> lock(mutex);
22         if (!*canceled) {
23             invoke(std::make_index_sequence<std::tuple_size<P>::value>{});
24         }
25     }
26 
27     // If the task has not yet begun, this will cancel it.
28     // If the task is in progress, this will block until it completed. (Currently
29     // necessary because of shared state, but should be removed.) It will also
30     // cancel the after callback.
31     // If the task has completed, but the after callback has not executed, this
32     // will cancel the after callback.
33     // If the task has completed and the after callback has executed, this will
34     // do nothing.
cancel()35     void cancel() override {
36         std::lock_guard<std::recursive_mutex> lock(mutex);
37         *canceled = true;
38     }
39 
40 private:
41     template <std::size_t... I>
invoke(std::index_sequence<I...>)42     void invoke(std::index_sequence<I...>) {
43         func(std::move(std::get<I>(std::forward<P>(params)))...);
44     }
45 
46     std::recursive_mutex mutex;
47     std::shared_ptr<std::atomic<bool>> canceled;
48 
49     F func;
50     P params;
51 };
52 
53 template <class Fn, class... Args>
make(Fn && fn,Args &&...args)54 std::shared_ptr<WorkTask> WorkTask::make(Fn&& fn, Args&&... args) {
55     auto flag = std::make_shared<std::atomic<bool>>();
56     *flag = false;
57 
58     auto tuple = std::make_tuple(std::forward<Args>(args)...);
59     return std::make_shared<WorkTaskImpl<std::decay_t<Fn>, decltype(tuple)>>(
60         std::forward<Fn>(fn),
61         std::move(tuple),
62         flag);
63 }
64 
65 } // namespace mbgl
66