EnTT  2.7.3
process.hpp
1 #ifndef ENTT_PROCESS_PROCESS_HPP
2 #define ENTT_PROCESS_PROCESS_HPP
3 
4 
5 #include <type_traits>
6 #include <functional>
7 #include <utility>
8 #include "../config/config.h"
9 
10 
11 namespace entt {
12 
13 
72 template<typename Derived, typename Delta>
73 class Process {
74  enum class State: unsigned int {
75  UNINITIALIZED = 0,
76  RUNNING,
77  PAUSED,
78  SUCCEEDED,
79  FAILED,
80  ABORTED,
81  FINISHED
82  };
83 
84  template<State state>
85  using tag = std::integral_constant<State, state>;
86 
87  template<typename Target = Derived>
88  auto tick(int, tag<State::UNINITIALIZED>, void *data)
89  -> decltype(std::declval<Target>().init(data)) {
90  static_cast<Target *>(this)->init(data);
91  }
92 
93  template<typename Target = Derived>
94  auto tick(int, tag<State::RUNNING>, Delta delta, void *data)
95  -> decltype(std::declval<Target>().update(delta, data)) {
96  static_cast<Target *>(this)->update(delta, data);
97  }
98 
99  template<typename Target = Derived>
100  auto tick(int, tag<State::SUCCEEDED>)
101  -> decltype(std::declval<Target>().succeeded()) {
102  static_cast<Target *>(this)->succeeded();
103  }
104 
105  template<typename Target = Derived>
106  auto tick(int, tag<State::FAILED>)
107  -> decltype(std::declval<Target>().failed()) {
108  static_cast<Target *>(this)->failed();
109  }
110 
111  template<typename Target = Derived>
112  auto tick(int, tag<State::ABORTED>)
113  -> decltype(std::declval<Target>().aborted()) {
114  static_cast<Target *>(this)->aborted();
115  }
116 
117  template<State S, typename... Args>
118  void tick(char, tag<S>, Args &&...) const ENTT_NOEXCEPT {}
119 
120 protected:
127  void succeed() ENTT_NOEXCEPT {
128  if(alive()) {
129  current = State::SUCCEEDED;
130  }
131  }
132 
139  void fail() ENTT_NOEXCEPT {
140  if(alive()) {
141  current = State::FAILED;
142  }
143  }
144 
151  void pause() ENTT_NOEXCEPT {
152  if(current == State::RUNNING) {
153  current = State::PAUSED;
154  }
155  }
156 
163  void unpause() ENTT_NOEXCEPT {
164  if(current == State::PAUSED) {
165  current = State::RUNNING;
166  }
167  }
168 
169 public:
171  using delta_type = Delta;
172 
174  virtual ~Process() ENTT_NOEXCEPT {
175  static_assert(std::is_base_of<Process, Derived>::value, "!");
176  }
177 
186  void abort(const bool immediately = false) ENTT_NOEXCEPT {
187  if(alive()) {
188  current = State::ABORTED;
189 
190  if(immediately) {
191  tick(0);
192  }
193  }
194  }
195 
200  bool alive() const ENTT_NOEXCEPT {
201  return current == State::RUNNING || current == State::PAUSED;
202  }
203 
208  bool dead() const ENTT_NOEXCEPT {
209  return current == State::FINISHED;
210  }
211 
216  bool paused() const ENTT_NOEXCEPT {
217  return current == State::PAUSED;
218  }
219 
224  bool rejected() const ENTT_NOEXCEPT {
225  return stopped;
226  }
227 
233  void tick(const Delta delta, void *data = nullptr) {
234  switch (current) {
235  case State::UNINITIALIZED:
236  tick(0, tag<State::UNINITIALIZED>{}, data);
237  current = State::RUNNING;
238  // no break on purpose, tasks are executed immediately
239  case State::RUNNING:
240  tick(0, tag<State::RUNNING>{}, delta, data);
241  default:
242  // suppress warnings
243  break;
244  }
245 
246  // if it's dead, it must be notified and removed immediately
247  switch(current) {
248  case State::SUCCEEDED:
249  tick(0, tag<State::SUCCEEDED>{});
250  current = State::FINISHED;
251  break;
252  case State::FAILED:
253  tick(0, tag<State::FAILED>{});
254  current = State::FINISHED;
255  stopped = true;
256  break;
257  case State::ABORTED:
258  tick(0, tag<State::ABORTED>{});
259  current = State::FINISHED;
260  stopped = true;
261  break;
262  default:
263  // suppress warnings
264  break;
265  }
266  }
267 
268 private:
269  State current{State::UNINITIALIZED};
270  bool stopped{false};
271 };
272 
273 
313 template<typename Func, typename Delta>
314 struct ProcessAdaptor: Process<ProcessAdaptor<Func, Delta>, Delta>, private Func {
320  template<typename... Args>
321  ProcessAdaptor(Args &&... args)
322  : Func{std::forward<Args>(args)...}
323  {}
324 
330  void update(const Delta delta, void *data) {
331  Func::operator()(delta, data, [this]() { this->succeed(); }, [this]() { this->fail(); });
332  }
333 };
334 
335 
336 }
337 
338 
339 #endif // ENTT_PROCESS_PROCESS_HPP
Base class for processes.
Definition: process.hpp:73
void unpause() ENTT_NOEXCEPT
Restarts a process if it&#39;s paused.
Definition: process.hpp:163
bool dead() const ENTT_NOEXCEPT
Returns true if a process is already terminated.
Definition: process.hpp:208
bool rejected() const ENTT_NOEXCEPT
Returns true if a process terminated with errors.
Definition: process.hpp:224
void abort(const bool immediately=false) ENTT_NOEXCEPT
Aborts a process if it&#39;s still alive.
Definition: process.hpp:186
EnTT default namespace.
Definition: algorithm.hpp:10
virtual ~Process() ENTT_NOEXCEPT
Default destructor.
Definition: process.hpp:174
ProcessAdaptor(Args &&... args)
Constructs a process adaptor from a lambda or a functor.
Definition: process.hpp:321
Adaptor for lambdas and functors to turn them into processes.
Definition: process.hpp:314
void fail() ENTT_NOEXCEPT
Terminates a process with errors if it&#39;s still alive.
Definition: process.hpp:139
bool alive() const ENTT_NOEXCEPT
Returns true if a process is either running or paused.
Definition: process.hpp:200
void succeed() ENTT_NOEXCEPT
Terminates a process with success if it&#39;s still alive.
Definition: process.hpp:127
Delta delta_type
Type used to provide elapsed time.
Definition: process.hpp:171
void update(const Delta delta, void *data)
Updates a process and its internal state if required.
Definition: process.hpp:330
void pause() ENTT_NOEXCEPT
Stops a process if it&#39;s in a running state.
Definition: process.hpp:151
void tick(const Delta delta, void *data=nullptr)
Updates a process and its internal state if required.
Definition: process.hpp:233
bool paused() const ENTT_NOEXCEPT
Returns true if a process is currently paused.
Definition: process.hpp:216