Simulant  21.12-574
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
helpers.h
1 #pragma once
2 
3 #include <functional>
4 #include <memory>
5 #include <type_traits>
6 
7 #include "../generic/static_if.h"
8 #include "coroutine.h"
9 #include "../threads/thread.h"
10 
11 namespace smlt {
12 
13 namespace promise_impl {
14 
15 template<typename T>
16 struct PromiseState {
17  typedef std::shared_ptr<PromiseState<T>> ptr;
18 
19  optional<T> value;
20 };
21 
22 template<>
23 struct PromiseState<void> {
24  typedef std::shared_ptr<PromiseState<void>> ptr;
25  bool value;
26 };
27 
28 
29 template<typename Func, typename T>
31 public:
32  void operator()(Func f, typename PromiseState<T>::ptr state) {
33  state->value = f();
34  }
35 };
36 
37 template<typename Func>
38 struct CallAndSetState<Func, void> {
39 public:
40  void operator()(Func f, typename PromiseState<void>::ptr state) {
41  f();
42  state->value = true;
43  }
44 };
45 
46 template <typename T>
47 struct func_traits : public func_traits<decltype(&T::operator())> {};
48 
49 template <typename C, typename Ret, typename... Args>
50 struct func_traits<Ret(C::*)(Args...) const> {
51  using result_type = Ret;
52 
53  template <std::size_t i>
54  struct arg {
55  using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
56  };
57 };
58 
59 }
60 
61 void cr_yield();
62 void cr_yield_for(const Seconds& seconds);
63 void cr_run_main(std::function<void ()> func);
64 
65 template<typename T>
66 class Promise {
67 public:
68  bool is_ready() const {
69  return state_ && state_->value;
70  }
71 
78  bool fulfill(T&& value) {
79  if(!state_) {
80  S_WARN("Tried to fulfill a Promise without state");
81  return false;
82  }
83 
84  if(is_ready()) {
85  return false;
86  }
87 
88  state_->value = std::move(value);
89  return true;
90  }
91 
92  T& value() const {
93  assert(state_->value);
94  return (state_->value.value());
95  }
96 
97  /* Starts another coroutine that waits until
98  * this one has been fulfilled */
99  template<typename Func>
100  auto then(Func&& func) -> Promise<typename promise_impl::func_traits<typename std::decay<Func>::type>::result_type> {
101  /* Copy the smart pointer and pass to the callback */
102  auto state = state_;
103 
104  auto cb = [func, state]() -> typename promise_impl::func_traits<typename std::decay<Func>::type>::result_type {
105  while(!state->value) {
106  cr_yield();
107  }
108 
109  return func(state->value.value());
110  };
111 
112  return cr_async(cb);
113  }
114 
115  /* Default constructor does nothing */
116  Promise() = default;
117 
118  bool is_initialized() const {
119  return bool(state_);
120  }
121 
122  static Promise<T> create() {
123  return Promise<T>(
124  std::make_shared<promise_impl::PromiseState<T>>()
125  );
126  }
127 
128 private:
129  template<typename Func>
130  friend Promise<typename std::result_of<Func()>::type> cr_async(Func func);
131 
132  Promise(typename promise_impl::PromiseState<T>::ptr state):
133  state_(state) {
134 
135  }
136 
137  typename promise_impl::PromiseState<T>::ptr state_;
138 };
139 
140 template<>
141 class Promise<void> {
142 private:
143  template<typename Func>
144  friend Promise<typename std::result_of<Func()>::type> cr_async(Func func);
145 
146  Promise(typename promise_impl::PromiseState<void>::ptr state):
147  state_(state) {
148 
149  }
150 
151  typename promise_impl::PromiseState<void>::ptr state_;
152 
153 public:
154  /* Default constructor does nothing */
155  Promise() = default;
156 
157  static Promise<void> create() {
158  return Promise<void>(
159  std::make_shared<promise_impl::PromiseState<void>>()
160  );
161  }
162 
163  bool is_initialized() const {
164  return bool(state_);
165  }
166 
167  bool is_ready() const {
168  return state_ && state_->value;
169  }
170 
171  bool fulfill() {
172  if(!state_) {
173  S_WARN("Tried to fulfill a Promise without state");
174  return false;
175  }
176 
177  if(is_ready()) {
178  return false;
179  }
180 
181  state_->value = true;
182  return true;
183  }
184 
185  void value() const {}
186 
187  /* Starts another coroutine that waits until
188  * this one has been fulfilled */
189  template<typename Func>
190  auto then(Func&& func) -> Promise<typename promise_impl::func_traits<typename std::decay<Func>::type>::result_type> {
191  auto state = state_;
192 
193  auto cb = [this, func, state]() -> typename promise_impl::func_traits<typename std::decay<Func>::type>::result_type {
194  while(!state->value) {
195  cr_yield();
196  }
197 
198  return func();
199  };
200 
201  return cr_async(cb);
202  }
203 };
204 
205 void _trigger_coroutine(std::function<void ()> func);
206 void _trigger_idle_updates();
207 
208 template<typename Func>
209 Promise<typename std::result_of<Func()>::type> cr_async(Func func) {
210  typedef typename std::result_of<Func()>::type T;
211 
212  auto state = std::make_shared<typename promise_impl::PromiseState<T>>();
213  Promise<T> promise(state);
214 
215  _trigger_coroutine([state, func]() {
217  });
218 
219  return promise;
220 }
221 
222 /* Will wait for the promise returned by a coroutine
223  * to be fulfilled. Be careful when calling from the main
224  * thread, because in this case only idle tasks and
225  * coroutines will be updated (no rendering or scene
226  * updates will happen while you are waiting).
227  *
228  * In the main thread you may prefer to use
229  * start_coroutine(...).then(...)
230  */
231 template<typename T>
232 T cr_await(const Promise<T>& promise) {
233  while(!promise.is_ready()) {
234  if(cort::within_coroutine()){
235  cr_yield();
236  } else {
237  _trigger_idle_updates();
238  thread::sleep(0);
239  }
240  }
241 
242  return promise.value();
243 }
244 
245 }
smlt::Promise
Definition: helpers.h:66
smlt::promise_impl::func_traits
Definition: helpers.h:47
smlt::promise_impl::CallAndSetState
Definition: helpers.h:30
smlt
Definition: animation.cpp:25
smlt::Promise::fulfill
bool fulfill(T &&value)
fulfill
Definition: helpers.h:78
smlt::optional
Definition: optional.h:13
smlt::promise_impl::PromiseState< void >
Definition: helpers.h:23
smlt::Seconds
Definition: types.h:55
smlt::Promise< void >
Definition: helpers.h:141
smlt::promise_impl::PromiseState
Definition: helpers.h:16