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: |
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 | |
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. |
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> |
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> |
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 | |