AMFuture  201909
String localization library
AMFuture.h
Go to the documentation of this file.
1 
9 #ifndef SAW_ALL_AMFUTURE_H
10 #define SAW_ALL_AMFUTURE_H
11 
12 #include <functional>
13 #include <chrono>
14 #include <type_traits>
15 #include <cassert>
16 
17 #if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__)
18 
19 namespace AMCore {
20 
21  enum class AMFutureStatus
22  {
23  ready,
24  timeout
25  };
26 
27  enum class AMLaunch
28  {
29  async = 0
30  };
31 
32  template<class T>
33  class AMFuture;
34  template<class Callback, class AvailCallback, class Function, class TCF, class... Args>
35  AMFuture<std::invoke_result_t<std::decay_t<Callback>, TCF, void *>>
36  AMAsync(AMLaunch policy, Callback &&callback, AvailCallback &&a, Function &&f, TCF &&tcf, Args &&... args);
37 
38  template<class Result>
39  class _AMLaunchFnHolderBase
40  {
41  public:
42  _AMLaunchFnHolderBase(Result (*_sget)(void*, void*), bool (*_savail)(void*, void*), void* _holder)
43  :sget(_sget),
44  savail(_savail),
45  holder(_holder)
46  {
47  }
48  Result SGet(void* mem)
49  {
50  return sget(holder, mem);
51  }
52  bool SIsAvail(void* mem)
53  {
54  return savail(holder, mem);
55  }
56  virtual ~_AMLaunchFnHolderBase()
57  {
58 
59  }
60  protected:
61  Result (*sget)(void* holder, void* mem);
62  bool (*savail)(void* holder, void* mem);
63  void* holder;
64  };
65 
66  template<class AvailCallback, class Callback, class TObject>
67  class _AMLaunchFnHolder: public _AMLaunchFnHolderBase<std::invoke_result_t<std::decay_t<Callback>, TObject, void*>> {
68  public:
69  _AMLaunchFnHolder(TObject& _obj, AvailCallback&& _ac, Callback&& _c)
70  : _AMLaunchFnHolderBase<std::invoke_result_t<std::decay_t<Callback>, TObject, void*>>(_AMLaunchFnHolder::SGetS, _AMLaunchFnHolder::SIsAvailS,(void*)this), obj(_obj), ac(std::move(_ac)), c(std::move(_c))
71  {
72  }
73  ~_AMLaunchFnHolder()
74  {
75  }
76  protected:
77  static bool SIsAvailS(void* _holder, void* mem)
78  {
79  _AMLaunchFnHolder* holder = (_AMLaunchFnHolder*)_holder;
80  return std::invoke(holder->ac, holder->obj, mem);
81  }
82  static std::invoke_result_t<std::decay_t<Callback>, TObject, void*> SGetS(void* _holder, void* mem)
83  {
84  _AMLaunchFnHolder* holder = (_AMLaunchFnHolder*)_holder;
85  return std::invoke(holder->c, holder->obj, mem);
86  }
87  TObject &obj;
88  AvailCallback ac;
89  Callback c;
90  };
91 
92  template<class T> class AMFuture
93  {
94  public:
95 
96  AMFuture() noexcept;
97  AMFuture(AMFuture&& other) noexcept;
98  AMFuture(const AMFuture& other) = delete;
99 
100  AMFuture& operator=(AMFuture&& other) noexcept;
101  AMFuture& operator=(const AMFuture& other) = delete;
102 
103  bool valid() const noexcept;
104 
105  T get();
106  //T& get();
107  //void get();
108 
109  ~AMFuture();
110 
111  template< class Rep, class Period >
112  AMFutureStatus wait_for( const std::chrono::duration<Rep,Period>& timeout_duration ) const;
113  void wait() const;
114 
115  template<class Callback, class AvailCallback, class Function, class TCF, class... Args>
116  friend
117  AMFuture<std::invoke_result_t<std::decay_t<Callback>, TCF, void *>>
118  AMAsync(AMLaunch policy, Callback &&callback, AvailCallback &&a, Function &&f, TCF &&tcf, Args &&... args);
119 
120  protected:
121  template< class Callback, class AvailCallback, class Function, class TCF, class... Args > friend
122  AMFuture<std::invoke_result_t<std::decay_t<Callback>, TCF, void*>>
123  AMAsync( AMLaunch policy, Callback&& callback, AvailCallback&& a, Function&& f, TCF&& tcf, Args&&... args );
124 
125  void destroy();
126  bool validFlag;
127  void *mem;
128  _AMLaunchFnHolderBase<T>* holder;
129  AMFuture(void*, _AMLaunchFnHolderBase<T>* holder) noexcept;
130  };
131 
132  template<class T> AMFuture<T>::AMFuture() noexcept:
133  validFlag(false), mem(), holder(nullptr)
134  {
135  }
136 
137  template<class T> AMFuture<T>::AMFuture(AMFuture&& other) noexcept
138  {
139  validFlag = other.validFlag;
140  other.validFlag = false;
141  mem = other.mem;
142  other.mem = nullptr;
143  holder = other.holder;
144  other.holder = nullptr;
145  }
146 
147  template<class T> AMFuture<T>& AMFuture<T>::operator=(AMFuture&& other) noexcept
148  {
149  validFlag = other.validFlag;
150  other.validFlag = false;
151  mem = other.mem;
152  other.mem = nullptr;
153  holder = other.holder;
154  other.holder = nullptr;
155  return *this;
156  }
157 
158  template<class T> AMFuture<T>::AMFuture(void* _mem, _AMLaunchFnHolderBase<T>* _holder) noexcept:
159  validFlag(false), mem(_mem), holder(_holder)
160  {
161  }
162 
163  template<class T> AMFuture<T>::~AMFuture()
164  {
165  destroy();
166  }
167 
168  template<class T> bool AMFuture<T>::valid() const noexcept
169  {
170  if (validFlag || (holder && holder->SIsAvail(mem))) {
171  return true;
172  }
173  return false;
174  }
175  template<class T> T AMFuture<T>::get()
176  {
177  wait();
178  validFlag = false;
179  T rv = holder->SGet(mem);
180  if (holder) {
181  delete holder;
182  holder = nullptr;
183  }
184  return rv;
185  }
186  /*
187  template<class T> T& AMFuture<T>::get()
188  {
189  wait();
190  return AMFuture<T>::data.find(futureId);
191  }
192  */
193  /*
194  template<class T> void AMFuture<T>::get()
195  {
196  wait();
197  }
198  */
199  template<class T> void AMFuture<T>::destroy()
200  {
201  wait();
202  if (holder) {
203  delete holder;
204  holder = nullptr;
205  }
206  }
207 
208  template<class T> void AMFuture<T>::wait() const
209  {
210  if (!validFlag) {
211  if (holder) {
212  assert(holder->SIsAvail(mem));
213  }
214  }
215  }
216 
217  template<class T>
218  template< class Rep, class Period >
219  AMFutureStatus AMFuture<T>::wait_for( const std::chrono::duration<Rep,Period>& timeout_duration ) const
220  {
221  if (validFlag || (holder && holder->SIsAvail(mem))) {
222  return AMFutureStatus::ready;
223  }
224  return AMFutureStatus::timeout;
225  }
226 
227  template< class Function, class... Args >
228  AMFuture<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>>
229  AMAsync( Function&& f, Args&&... args )
230  {
231  return AMAsync(AMLaunch::async, f, args...);
232  }
233 
234  template< class Callback, class AvailCallback, class Function, class TCF, class... Args >
235  AMFuture<std::invoke_result_t<std::decay_t<Callback>, TCF, void*>>
236  AMAsync( AMLaunch policy, Callback&& callback, AvailCallback&& a, Function&& f, TCF&& tcf, Args&&... args )
237  {
238  (void)policy;
239  auto h = new _AMLaunchFnHolder(tcf, std::move(a), std::move(callback));
240  void* mem = std::invoke(f, tcf, args...);
241  return AMFuture<std::invoke_result_t<std::decay_t<Callback>, std::decay_t<TCF>, void*>>(mem, h);
242  }
243 
244 
245 
246  class _AMFutureZombieBase
247  {
248  public:
249  static bool checkZombies() {return true;};
250  };
251 
252  inline bool checkZombies()
253  {
254  return _AMFutureZombieBase::checkZombies();
255  }
256 
257 }
258 #else
259 
260 #include <future>
261 #include <set>
262 
263 namespace AMCore {
264 
268  typedef std::future_status AMFutureStatus;
269 
273  typedef std::launch AMLaunch;
274 
275 
276  template<class T>
277  class AMFuture;
278  template<class Callback, class AvailCallback, class Function, class TCF, class... Args>
280  AMAsync(AMLaunch policy, Callback &&callback, AvailCallback &&a, Function &&f, TCF &&tcf, Args &&... args);
281 
285  template<class T>
286  class AMFuture : public std::future<T> {
287  public:
288 
292  AMFuture() noexcept;
293 
298  AMFuture(AMFuture<T> &&other) noexcept;
299 
304  AMFuture(const AMFuture &other) = delete;
305 
310  AMFuture &operator=(AMFuture &&other) noexcept;
311 
316  AMFuture &operator=(const AMFuture &other) = delete;
317 
323  ~AMFuture();
324 
325  template<class Callback, class AvailCallback, class Function, class TCF, class... Args>
326  friend
327  AMFuture<std::invoke_result_t<std::decay_t<Callback>, TCF, void *>>
328  AMAsync(AMLaunch policy, Callback &&callback, AvailCallback &&a, Function &&f, TCF &&tcf, Args &&... args);
329  protected:
330  template<class Callback, class AvailCallback, class Function, class TCF, class... Args>
331  friend
332  AMFuture<std::invoke_result_t<std::decay_t<Callback>, TCF, void *>>
333  AMAsync(AMLaunch policy, Callback &&callback, AvailCallback &&a, Function &&f, TCF &&tcf, Args &&... args);
334 
335  template<class Function, class Callback, class TCF, class... Args>
336  static T perform(Function &&f, Callback &&c, TCF &&tcf, Args &&... args);
337 
338  AMFuture(std::future<T> &&other) noexcept;
339  };
340 
341  template<class T>
342  AMFuture<T>::AMFuture() noexcept
343  :std::future<T>() {
344  }
345 
346  template<class T>
348  :std::future<T>(std::move(other)) {
349  }
350 
351  template<class T>
352  AMFuture<T>::AMFuture(std::future<T> &&other) noexcept
353  :std::future<T>(std::move(other)) {
354  }
355 
356  template<class T>
358  std::future<T>::operator=(std::move(other));
359  return *this;
360  }
361 
362  template<class T>
363  template<class Function, class Callback, class TCF, class... Args>
364  T AMFuture<T>::perform(Function &&f, Callback &&c, TCF &&tcf, Args &&... args) {
365  void *mem = std::invoke(f, tcf, args...);
366  return std::invoke(c, tcf, mem);
367  }
368 
387  template<class Callback, class AvailCallback, class Function, class TCF, class... Args>
388  AMFuture<std::invoke_result_t<std::decay_t<Callback>, TCF, void *>>
389  AMAsync(AMLaunch policy, Callback &&callback, AvailCallback &&a, Function &&f, TCF &&tcf, Args &&... args) {
390  (void) policy;
391  auto newCallback = &AMFuture<std::invoke_result_t<std::decay_t<Callback>, std::decay_t<TCF>, void *>>::template perform<std::decay_t<Function>, std::decay_t<Callback>, std::decay_t<TCF>, std::decay_t<Args>...>;
392  std::future<std::invoke_result_t<std::decay_t<Callback>, TCF, void *>> base =
393  std::async(
394  policy,
395  newCallback,
396  std::forward<Function>(f),
397  std::forward<Callback>(callback),
398  std::forward<TCF>(tcf),
399  std::forward<Args>(args)...
400  );
401  return std::move(
402  AMFuture<std::invoke_result_t<std::decay_t<Callback>, std::decay_t<TCF>, void *>>(std::move(base)));
403  }
404 
405  class _AMFutureZombieBase {
406  public:
407  static void add(_AMFutureZombieBase *p);
408 
409  static bool checkZombies();
410 
411  virtual ~_AMFutureZombieBase();
412 
413  protected:
414  virtual bool valid() = 0;
415 
416  virtual bool ready() = 0;
417 
418  virtual void get() = 0;
419 
420  static std::set<_AMFutureZombieBase *> m_zombies;
421  };
422 
423  template<class T>
424  class _AMFutureZombie : public _AMFutureZombieBase, public AMFuture<T> {
425  public:
426  _AMFutureZombie(AMFuture<T> &&other) noexcept;
427 
428  ~_AMFutureZombie() {/*printf("zombie destruct\n");*/}
429 
430  protected:
431  bool valid() override;
432  bool ready() override;
433  void get() override;
434  };
435 
436  template<class T>
438  if (AMFuture<T>::valid()) {
439  _AMFutureZombieBase::add(new _AMFutureZombie<T>(std::move(*this)));
440  }
441  }
442 
443  template<class T>
444  bool _AMFutureZombie<T>::valid() {
445  return AMFuture<T>::valid();
446  }
447 
448  template<class T>
449  bool _AMFutureZombie<T>::ready() {
450  return AMFuture<T>::wait_for(std::chrono::seconds(0)) == AMCore::AMFutureStatus::ready;
451  }
452 
453  template<class T>
454  void _AMFutureZombie<T>::get() {
455  AMFuture<T>::get();
456  }
457 
458  template<class T>
459  _AMFutureZombie<T>::_AMFutureZombie(AMFuture<T> &&other) noexcept
460  :AMFuture<T>(std::move(other)) {
461  }
462 
463 
468  inline bool checkZombies()
469  {
470  return _AMFutureZombieBase::checkZombies();
471  }
472 }
473 
474 
475 #endif
476 #endif //SAW_ALL_AMFUTURE_H
AMCore::AMFuture::AMFuture
AMFuture() noexcept
default contructor
Definition: AMFuture.h:342
AMCore::AMAsync
AMFuture< std::invoke_result_t< std::decay_t< Callback >, TCF, void * > > AMAsync(AMLaunch policy, Callback &&callback, AvailCallback &&a, Function &&f, TCF &&tcf, Args &&... args)
asynchronous call
Definition: AMFuture.h:389
AMCore::AMLaunch
std::launch AMLaunch
Launch mode is exactly the same as std::launch.
Definition: AMFuture.h:273
AMCore::AMFuture::~AMFuture
~AMFuture()
destructor.
Definition: AMFuture.h:437
AMCore::checkZombies
bool checkZombies()
Check for active AMFuture.
Definition: AMFuture.h:468
AMCore::AMFutureStatus
std::future_status AMFutureStatus
Status of future is exacly the same as std::future_status.
Definition: AMFuture.h:268
AMCore::AMFuture::operator=
AMFuture & operator=(AMFuture &&other) noexcept
move assignment
Definition: AMFuture.h:357
AMCore::AMFuture::AMAsync
friend AMFuture< std::invoke_result_t< std::decay_t< Callback >, TCF, void * > > AMAsync(AMLaunch policy, Callback &&callback, AvailCallback &&a, Function &&f, TCF &&tcf, Args &&... args)
asynchronous call
Definition: AMFuture.h:389
AMCore::AMFuture
Result of type T of asynchronous call.
Definition: AMFuture.h:277