Simulant  21.12-194
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 
72  T& value() const {
73  assert(state_->value);
74  return (state_->value.value());
75  }
76 
77  /* Starts another coroutine that waits until
78  * this one has been fulfilled */
79  template<typename Func>
81  /* Copy the smart pointer and pass to the callback */
82  auto state = state_;
83 
84  auto cb = [this, func, state]() -> typename promise_impl::func_traits<typename std::decay<Func>::type>::result_type {
85  while(!state->value) {
86  cr_yield();
87  }
88 
89  return func(state->value.value());
90  };
91 
92  return cr_async(cb);
93  }
94 
95  /* Default constructor does nothing */
96  Promise() = default;
97 
98  bool is_initialized() const {
99  return bool(state_);
100  }
101 
102 private:
103  template<typename Func>
104  friend Promise<typename std::result_of<Func()>::type> cr_async(Func func);
105 
106  Promise(typename promise_impl::PromiseState<T>::ptr state):
107  state_(state) {
108 
109  }
110 
111  typename promise_impl::PromiseState<T>::ptr state_;
112 };
113 
114 template<>
115 class Promise<void> {
116 private:
117  template<typename Func>
118  friend Promise<typename std::result_of<Func()>::type> cr_async(Func func);
119 
120  Promise(typename promise_impl::PromiseState<void>::ptr state):
121  state_(state) {
122 
123  }
124 
125  typename promise_impl::PromiseState<void>::ptr state_;
126 
127  /* Default constructor does nothing */
128  Promise() = default;
129 
130  bool is_initialized() const {
131  return bool(state_);
132  }
133 
134 public:
135  bool is_ready() const {
136  return state_ && state_->value;
137  }
138 
139  void value() const {}
140 
141  /* Starts another coroutine that waits until
142  * this one has been fulfilled */
143  template<typename Func>
144  auto then(Func&& func) -> Promise<typename promise_impl::func_traits<typename std::decay<Func>::type>::result_type> {
145  auto state = state_;
146 
147  auto cb = [this, func, state]() -> typename promise_impl::func_traits<typename std::decay<Func>::type>::result_type {
148  while(!state->value) {
149  cr_yield();
150  }
151 
152  return func();
153  };
154 
155  return cr_async(cb);
156  }
157 };
158 
159 void _trigger_coroutine(std::function<void ()> func);
160 void _trigger_idle_updates();
161 
162 template<typename Func>
163 Promise<typename std::result_of<Func()>::type> cr_async(Func func) {
164  typedef typename std::result_of<Func()>::type T;
165 
166  auto state = std::make_shared<typename promise_impl::PromiseState<T>>();
167  Promise<T> promise(state);
168 
169  _trigger_coroutine([state, func]() {
171  });
172 
173  return promise;
174 }
175 
176 /* Will wait for the promise returned by a coroutine
177  * to be fulfilled. Be careful when calling from the main
178  * thread, because in this case only idle tasks and
179  * coroutines will be updated (no rendering or scene
180  * updates will happen while you are waiting).
181  *
182  * In the main thread you may prefer to use
183  * start_coroutine(...).then(...)
184  */
185 template<typename T>
186 T cr_await(const Promise<T>& promise) {
187  while(!promise.is_ready()) {
188  if(cort::within_coroutine()){
189  cr_yield();
190  } else {
191  _trigger_idle_updates();
192  thread::sleep(0);
193  }
194  }
195 
196  return promise.value();
197 }
198 
199 }
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::optional
Definition: optional.h:13
smlt::Seconds
Definition: types.h:55
smlt::promise_impl::PromiseState
Definition: helpers.h:16