-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpending_task_queue.cpp
More file actions
131 lines (114 loc) · 3.11 KB
/
Copy pathpending_task_queue.cpp
File metadata and controls
131 lines (114 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "../include/dispatch_queue/detail/pending_task_queue.hpp"
namespace dispatch_queue {
namespace detail {
bool pending_task_queue::empty() const {
for (auto&& it : tagged_tasks) {
if (!it.second.empty()) {
return false;
}
}
return background_tasks.empty();
}
bool pending_task_queue::main_empty() const {
return main_loop_tasks.empty()
&& main_loop_delayed_tasks.empty();
}
size_t pending_task_queue::size() const {
size_t count = 0;
for (auto&& it : tagged_tasks) {
count += it.second.size();
}
return count + background_tasks.size();
}
size_t pending_task_queue::main_size() const {
return main_loop_tasks.size()
+ main_loop_delayed_tasks.size();
}
void pending_task_queue::clear() {
for (auto&& it : tagged_tasks) {
it.second.clear();
}
background_tasks.clear();
}
void pending_task_queue::main_clear() {
main_loop_tasks.clear();
main_loop_delayed_tasks.clear();
}
bool pending_task_queue::push(task_type type, task_function&& task, float delay, task_tag tag) {
switch (type) {
case task_type::main:
if (delay > 0) {
main_loop_delayed_tasks.push_back({ std::move(task), delay });
}
else {
main_loop_tasks.push_back({ std::move(task) });
}
return false;
case task_type::tagged:
if (tag != NULL_TAG) {
#ifdef __cpp_lib_unordered_map_try_emplace
auto pair = tagged_tasks.try_emplace(tag, std::list<pending_task>{});
#else
auto pair = tagged_tasks.emplace(tag, std::list<pending_task>{});
#endif
if (pair.second) {
// tag didn't exist, task is readily available to be processed
background_tasks.push_back({ std::move(task), tag });
return true;
}
else {
// tag exists and is being processed: queue task until tag gets unblocked
pair.first->second.push_back({ std::move(task), tag });
return false;
}
}
[[fallthrough]];
case task_type::background:
background_tasks.push_back({ std::move(task), NULL_TAG });
return true;
default:
return false;
}
}
bool pending_task_queue::try_pop(pending_task& task) {
task_tag previous_tag = task.tag;
if (previous_tag != NULL_TAG) {
auto it = tagged_tasks.find(previous_tag);
if (it->second.empty()) {
// when last task with tag is processed, erase the tag: this unblocks the tag
tagged_tasks.erase(it);
}
else {
// otherwise, move the first task for the tag to the end of background_tasks queue
background_tasks.splice(background_tasks.end(), it->second, it->second.begin());
}
}
if (!background_tasks.empty()) {
task = std::move(background_tasks.front());
background_tasks.pop_front();
return true;
}
else {
task = {};
return false;
}
}
std::list<task_function> pending_task_queue::pop_main_loop_tasks(float delta) {
std::list<task_function> result;
main_loop_tasks.swap(result);
if (delta > 0) {
for (auto it = main_loop_delayed_tasks.begin(); it != main_loop_delayed_tasks.end(); ) {
it->delay -= delta;
if (it->delay <= 0) {
result.push_back({ std::move(it->implementation) });
it = main_loop_delayed_tasks.erase(it);
}
else {
++it;
}
}
}
return result;
}
} // end namespace detail
} // end namespace dispatch_queue