EnTT  3.8.1
process.hpp
1 #ifndef ENTT_PROCESS_PROCESS_HPP
2 #define ENTT_PROCESS_PROCESS_HPP
3 
4 
5 #include <utility>
6 #include <type_traits>
7 #include "../config/config.h"
8 
9 
10 namespace entt {
11 
12 
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  REJECTED
83  };
84 
85  template<typename Target = Derived>
86  auto next(std::integral_constant<state, state::UNINITIALIZED>)
87  -> decltype(std::declval<Target>().init(), void()) {
88  static_cast<Target *>(this)->init();
89  }
90 
91  template<typename Target = Derived>
92  auto next(std::integral_constant<state, state::RUNNING>, Delta delta, void *data)
93  -> decltype(std::declval<Target>().update(delta, data), void()) {
94  static_cast<Target *>(this)->update(delta, data);
95  }
96 
97  template<typename Target = Derived>
98  auto next(std::integral_constant<state, state::SUCCEEDED>)
99  -> decltype(std::declval<Target>().succeeded(), void()) {
100  static_cast<Target *>(this)->succeeded();
101  }
102 
103  template<typename Target = Derived>
104  auto next(std::integral_constant<state, state::FAILED>)
105  -> decltype(std::declval<Target>().failed(), void()) {
106  static_cast<Target *>(this)->failed();
107  }
108 
109  template<typename Target = Derived>
110  auto next(std::integral_constant<state, state::ABORTED>)
111  -> decltype(std::declval<Target>().aborted(), void()) {
112  static_cast<Target *>(this)->aborted();
113  }
114 
115  void next(...) const ENTT_NOEXCEPT {}
116 
117 protected:
124  void succeed() ENTT_NOEXCEPT {
125  if(alive()) {
126  current = state::SUCCEEDED;
127  }
128  }
129 
136  void fail() ENTT_NOEXCEPT {
137  if(alive()) {
138  current = state::FAILED;
139  }
140  }
141 
148  void pause() ENTT_NOEXCEPT {
149  if(current == state::RUNNING) {
150  current = state::PAUSED;
151  }
152  }
153 
160  void unpause() ENTT_NOEXCEPT {
161  if(current == state::PAUSED) {
162  current = state::RUNNING;
163  }
164  }
165 
166 public:
168  using delta_type = Delta;
169 
171  virtual ~process() {
172  static_assert(std::is_base_of_v<process, Derived>, "Incorrect use of the class template");
173  }
174 
183  void abort(const bool immediately = false) {
184  if(alive()) {
185  current = state::ABORTED;
186 
187  if(immediately) {
188  tick({});
189  }
190  }
191  }
192 
197  [[nodiscard]] bool alive() const ENTT_NOEXCEPT {
198  return current == state::RUNNING || current == state::PAUSED;
199  }
200 
205  [[nodiscard]] bool finished() const ENTT_NOEXCEPT {
206  return current == state::FINISHED;
207  }
208 
213  [[nodiscard]] bool paused() const ENTT_NOEXCEPT {
214  return current == state::PAUSED;
215  }
216 
221  [[nodiscard]] bool rejected() const ENTT_NOEXCEPT {
222  return current == state::REJECTED;
223  }
224 
230  void tick(const Delta delta, void *data = nullptr) {
231  switch (current) {
232  case state::UNINITIALIZED:
233  next(std::integral_constant<state, state::UNINITIALIZED>{});
234  current = state::RUNNING;
235  break;
236  case state::RUNNING:
237  next(std::integral_constant<state, state::RUNNING>{}, delta, data);
238  break;
239  default:
240  // suppress warnings
241  break;
242  }
243 
244  // if it's dead, it must be notified and removed immediately
245  switch(current) {
246  case state::SUCCEEDED:
247  next(std::integral_constant<state, state::SUCCEEDED>{});
248  current = state::FINISHED;
249  break;
250  case state::FAILED:
251  next(std::integral_constant<state, state::FAILED>{});
252  current = state::REJECTED;
253  break;
254  case state::ABORTED:
255  next(std::integral_constant<state, state::ABORTED>{});
256  current = state::REJECTED;
257  break;
258  default:
259  // suppress warnings
260  break;
261  }
262  }
263 
264 private:
265  state current{state::UNINITIALIZED};
266 };
267 
268 
308 template<typename Func, typename Delta>
309 struct process_adaptor: process<process_adaptor<Func, Delta>, Delta>, private Func {
315  template<typename... Args>
316  process_adaptor(Args &&... args)
317  : Func{std::forward<Args>(args)...}
318  {}
319 
325  void update(const Delta delta, void *data) {
326  Func::operator()(delta, data, [this]() { this->succeed(); }, [this]() { this->fail(); });
327  }
328 };
329 
330 
331 }
332 
333 
334 #endif
Base class for processes.
Definition: process.hpp:73
bool alive() const
Returns true if a process is either running or paused.
Definition: process.hpp:197
virtual ~process()
Default destructor.
Definition: process.hpp:171
void succeed()
Terminates a process with success if it's still alive.
Definition: process.hpp:124
void fail()
Terminates a process with errors if it's still alive.
Definition: process.hpp:136
void pause()
Stops a process if it's in a running state.
Definition: process.hpp:148
bool finished() const
Returns true if a process is already terminated.
Definition: process.hpp:205
Delta delta_type
Type used to provide elapsed time.
Definition: process.hpp:168
bool paused() const
Returns true if a process is currently paused.
Definition: process.hpp:213
void unpause()
Restarts a process if it's paused.
Definition: process.hpp:160
bool rejected() const
Returns true if a process terminated with errors.
Definition: process.hpp:221
void tick(const Delta delta, void *data=nullptr)
Updates a process and its internal state if required.
Definition: process.hpp:230
void abort(const bool immediately=false)
Aborts a process if it's still alive.
Definition: process.hpp:183
EnTT default namespace.
Definition: algorithm.hpp:13
Adaptor for lambdas and functors to turn them into processes.
Definition: process.hpp:309
void update(const Delta delta, void *data)
Updates a process and its internal state if required.
Definition: process.hpp:325
process_adaptor(Args &&... args)
Constructs a process adaptor from a lambda or a functor.
Definition: process.hpp:316