-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathsimcpp.cpp
227 lines (169 loc) · 4.38 KB
/
simcpp.cpp
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
// Copyright © 2021 Bjørnar Steinnes Luteberget, Felix Schütz.
// Licensed under the MIT license. See the LICENSE file for details.
#include "simcpp.h"
namespace simcpp {
/* Simulation */
SimulationPtr Simulation::create() { return std::make_shared<Simulation>(); }
void Simulation::run_process(ProcessPtr process, simtime delay /* = 0.0 */) {
auto event = this->event();
event->add_handler(process);
event->trigger(delay);
}
EventPtr Simulation::timeout(simtime delay) {
auto event = this->event();
event->trigger(delay);
return event;
}
EventPtr Simulation::any_of(std::initializer_list<EventPtr> events) {
int n = 1;
for (auto &event : events) {
if (event->is_triggered()) {
n = 0;
break;
}
}
auto process = start_process<Condition>(n);
for (auto &event : events) {
event->add_handler(process);
}
return process;
}
EventPtr Simulation::all_of(std::initializer_list<EventPtr> events) {
int n = 0;
for (auto &event : events) {
if (!event->is_triggered()) {
++n;
}
}
auto process = start_process<Condition>(n);
for (auto &event : events) {
event->add_handler(process);
}
return process;
}
void Simulation::schedule(EventPtr event, simtime delay /* = 0.0 */) {
queued_events.emplace(now + delay, next_id, event);
++next_id;
}
bool Simulation::step() {
if (queued_events.empty()) {
return false;
}
auto queued_event = queued_events.top();
queued_events.pop();
now = queued_event.time;
auto event = queued_event.event;
event->process();
return true;
}
void Simulation::advance_by(simtime duration) {
simtime target = now + duration;
while (has_next() && peek_next_time() <= target) {
step();
}
now = target;
}
bool Simulation::advance_to(EventPtr event) {
while (event->is_pending() && has_next()) {
step();
}
return event->is_triggered();
}
void Simulation::run() {
while (step()) {
}
}
simtime Simulation::get_now() { return now; }
bool Simulation::has_next() { return !queued_events.empty(); }
simtime Simulation::peek_next_time() { return queued_events.top().time; }
/* Simulation::QueuedEvent */
Simulation::QueuedEvent::QueuedEvent(simtime time, size_t id, EventPtr event)
: time(time), id(id), event(event) {}
bool Simulation::QueuedEvent::operator<(const QueuedEvent &other) const {
if (time != other.time) {
return time > other.time;
}
return id > other.id;
}
/* Event */
Event::Event(SimulationPtr sim) : sim(sim) {}
bool Event::add_handler(ProcessPtr process) {
// Handler takes an additional EventPtr arg, but this is ignored by the
// bound function.
return add_handler(std::bind(&Process::resume, process));
}
bool Event::add_handler(Handler handler) {
if (is_triggered()) {
return false;
}
if (is_pending()) {
handlers.push_back(handler);
}
return true;
}
bool Event::trigger(simtime delay /* = 0.0 */) {
if (!is_pending()) {
return false;
}
auto sim = this->sim.lock();
sim->schedule(shared_from_this(), delay);
if (delay == 0.0) {
state = State::Triggered;
}
return true;
}
bool Event::abort() {
if (!is_pending()) {
return false;
}
state = State::Aborted;
handlers.clear();
Aborted();
return true;
}
void Event::process() {
if (is_aborted() || is_processed()) {
return;
}
state = State::Processed;
for (auto &handler : handlers) {
handler(shared_from_this());
}
handlers.clear();
}
bool Event::is_pending() { return state == State::Pending; }
bool Event::is_triggered() {
return state == State::Triggered || state == State::Processed;
}
bool Event::is_processed() { return state == State::Processed; }
bool Event::is_aborted() { return state == State::Aborted; }
Event::State Event::get_state() { return state; }
void Event::Aborted() {}
/* Process */
Process::Process(SimulationPtr sim) : Event(sim), Protothread() {}
void Process::resume() {
// Is the process already finished?
if (!is_pending()) {
return;
}
bool still_running = Run();
// Did the process finish now?
if (!still_running) {
// Process finished
trigger();
}
}
ProcessPtr Process::shared_from_this() {
return std::static_pointer_cast<Process>(Event::shared_from_this());
}
/* Condition */
Condition::Condition(SimulationPtr sim, int n) : Process(sim), n(n) {}
bool Condition::Run() {
PT_BEGIN();
while (n > 0) {
PT_YIELD();
--n;
}
PT_END();
}
} // namespace simcpp