Honeycomb  0.1
Component-Model Framework
Promise.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
4 #include "Honey/Misc/Exception.h"
6 
7 namespace honey
8 {
9 
11 namespace future
12 {
18 
20  namespace priv
21  {
22  struct StateBase : SharedObj<StateBase>
23  {
24  template<class Alloc>
25  StateBase(Alloc&& a) : SharedObj(forward<Alloc>(a)), ready(false), futureRetrieved(false) {}
26 
27  virtual ~StateBase()
28  {
29  // onReady functors must delete themselves
30  if (!ready) for (auto& e : onReady) e(*this);
31  }
32 
33  void setException(const Exception::ConstPtr& e, bool setReady = true)
34  {
35  ConditionLock::Scoped _(waiters);
36  if (ready) throw_ AlreadySatisfied();
37  ex = e;
38  if (setReady) setReady_();
39  }
40 
41  void setReady() { ConditionLock::Scoped _(waiters); setReady_(); }
42 
43  template<class Func>
44  void addOnReady(Func&& f)
45  {
46  SharedPtr<StateBase> this_;
47  ConditionLock::Scoped _(waiters);
48  if (ready)
49  {
50  this_ = this; //functor may own this state and delete itself, delay deletion until lock is released
51  f(*this);
52  }
53  else
54  onReady.push_back(mt::FuncptrCreate(forward<Func>(f)));
55  }
56 
57  Exception::ConstPtr ex;
58  bool ready;
59  bool futureRetrieved;
60  ConditionLock waiters;
61  //std::function is not used here to avoid the operator() virtual call.
62  //Functors must delete themselves after running. If src.ready is false then src is being destructed.
63  vector<mt::Funcptr<void (StateBase& src)>> onReady;
64 
65  protected:
66  void setReady_()
67  {
68  assert(!ready);
69  ready = true;
70  waiters.broadcast();
71  for (auto& e : onReady) e(*this);
72  }
73  };
74 
76  template<class R>
77  struct State : StateBase
78  {
79  template<class Alloc>
80  State(Alloc&& a) : StateBase(forward<Alloc>(a)) debug_if(, _result(&result())) {}
81 
82  ~State()
83  {
84  //Result uses generic storage, must destroy manually
85  if (ready && !ex) result().~R();
86  }
87 
88  template<class T>
89  void setValue(T&& val, bool setReady = true)
90  {
91  ConditionLock::Scoped _(waiters);
92  if (ready) throw_ AlreadySatisfied();
93  new (&_storage) R(forward<T>(val));
94  if (setReady) setReady_();
95  }
96 
97  R& result() { return reinterpret_cast<R&>(_storage); }
98  const R& result() const { return reinterpret_cast<const R&>(_storage); }
99 
101  typedef typename std::aligned_storage<sizeof(R), alignof(R)>::type Storage;
102  Storage _storage;
103  debug_if(R* _result;) //make result visible in debugger
104  };
105 
107  template<class R>
108  struct State<R&> : StateBase
109  {
110  template<class Alloc>
111  State(Alloc&& a) : StateBase(forward<Alloc>(a)), _result(nullptr) {}
112 
113  template<class T>
114  void setValue(T& val, bool setReady = true)
115  {
116  ConditionLock::Scoped _(waiters);
117  if (ready) throw_ AlreadySatisfied();
118  _result = &val;
119  if (setReady) setReady_();
120  }
121 
122  R& result() { assert(_result); return *_result; }
123  const R& result() const { assert(_result); return *_result; }
124 
125  R* _result;
126  };
127 
129  template<>
130  struct State<void> : StateBase
131  {
132  template<class Alloc>
133  State(Alloc&& a) : StateBase(forward<Alloc>(a)) {}
134 
135  void setValue(bool setReady = true)
136  {
137  ConditionLock::Scoped _(waiters);
138  if (ready) throw_ AlreadySatisfied();
139  if (setReady) setReady_();
140  }
141  };
142 
144  template<class R>
145  struct invoke
146  {
147  typedef State<R> State;
148 
149  template<class F, class... Args>
150  void operator()(State& state, bool setReady, F&& f, Args&&... args)
151  {
152  try { state.setValue(f(forward<Args>(args)...), setReady); }
153  catch (...) { state.setException(Exception::current(), setReady); }
154  }
155  };
156 
158  template<>
159  struct invoke<void>
160  {
161  typedef State<void> State;
162 
163  template<class F, class... Args>
164  void operator()(State& state, bool setReady, F&& f, Args&&... args)
165  {
166  try { f(forward<Args>(args)...); state.setValue(setReady); }
167  catch (...) { state.setException(Exception::current(), setReady); }
168  }
169  };
170  }
172 }
173 
174 template<class R> class Future;
175 
177 
180 template<class R>
182 {
183  template<class R_> friend class Future;
184  template<class Sig> friend class PackagedTask;
185 public:
186  typedef future::priv::State<R> State;
187 
189  template<class Alloc = std::allocator<State>>
190  Promise(Alloc&& a = Alloc())
191  {
192  typedef typename mt::removeRef<Alloc>::type::template rebind<State>::other Alloc_;
193  Alloc_ a_ = forward<Alloc>(a);
194  _state.set(new (a_.allocate(1)) State(a_));
195  }
196 
197  Promise(Promise&& rhs) noexcept : _state(nullptr) { operator=(move(rhs)); }
199 
200  Promise& operator=(Promise&& rhs) { finalize(); _state = move(rhs._state); return *this; }
201 
203 
208  {
209  if (!valid()) throw_ future::NoState();
210  ConditionLock::Scoped _(_state->waiters);
211  if (_state->futureRetrieved) throw_ future::FutureAlreadyRetrieved();
212  _state->futureRetrieved = true;
213  return Future<R>(_state);
214  }
215 
217 
221  template<class T>
222  typename mt::disable_if<mt::True<T>::value && (mt::isRef<R>::value || std::is_void<R>::value)>::type
223  setValue(T&& val) { if (!valid()) throw_ future::NoState(); _state->setValue(forward<T>(val)); }
225  template<class T>
226  typename std::enable_if<mt::True<T>::value && mt::isRef<R>::value>::type
227  setValue(T& val) { if (!valid()) throw_ future::NoState(); _state->setValue(val); }
229  void setValue() { static_assert(!mt::True<R>::value, "Only for use with void type"); }
230 
232 
236  void setException(const Exception::ConstPtr& e) { if (!valid()) throw_ future::NoState(); _state->setException(e); }
237 
239  bool valid() const { return _state; }
240 
242  State& __state() const { assert(_state); return *_state; }
243 
244 private:
245  explicit Promise(const SharedPtr<State>& state) : _state(state) {}
246 
247  void finalize() { if (valid() && !_state->ready) setException(new future::Broken()); }
248 
249  SharedPtr<State> _state;
250 };
251 
252 template<> inline void Promise<void>::setValue() { if (!valid()) throw_ future::NoState(); _state->setValue(); }
253 
254 }
A scoped lock that references any lockable. Locks on construction and unlocks on destruction.
Definition: Mutex.h:10
Promise(Alloc &&a=Alloc())
Construct with allocator for shared state.
Definition: Promise.h:190
Unique future, guarantees sole access to a future function result.
Definition: Future.h:53
Definition: Promise.h:16
Inherit to declare that class is not copyable.
Definition: Meta.h:286
std::enable_if<!b, T > disable_if
Opposite of std::enable_if.
Definition: Meta.h:62
the future result is ready
Future< R > future()
Get future from which delayed result can be retrieved.
Definition: Promise.h:207
Promise(Promise &&rhs) noexcept
Definition: Promise.h:197
Reference-counted object for intrusive shared pointers.
Definition: SharedPtr.h:93
Container to hold a delayed function result.
Definition: Promise.h:181
std::remove_reference< T > removeRef
Remove reference from type.
Definition: Meta.h:44
State & __state() const
Get the shared state.
Definition: Promise.h:242
static auto _
Definition: Module.cpp:8
mt::disable_if< mt::True< T >::value &&(mt::isRef< R >::value||std::is_void< R >::value)>::type setValue(T &&val)
Set stored result. Result is copy/move constructed from value.
Definition: Promise.h:223
Promise & operator=(Promise &&rhs)
Definition: Promise.h:200
void setException(const Exception::ConstPtr &e)
Set stored exception.
Definition: Promise.h:236
#define EXCEPTION(Class)
Declares methods required for every subclass of honey::Exception.
Definition: Exception.h:17
std::enable_if< mt::True< T >::value &&mt::isRef< R >::value >::type setValue(T &val)
Set stored result for ref result type.
Definition: Promise.h:227
#define assert(...)
Forwards to assert_#args. See assert_1(), assert_2().
Definition: Debug.h:24
Value< bool, std::is_reference< T >::value > isRef
Check if type is a reference.
Definition: Meta.h:57
void setValue()
Set stored result for void result type.
Definition: Promise.h:229
Always returns true. Can be used to force a clause to be type dependent.
Definition: Meta.h:31
A container that wraps a function so that its result is stored in a future when invoked.
Definition: PackagedTask.h:10
~Promise()
Definition: Promise.h:198
Base exception class. Exceptions inherited from this class provide debug info and can be thrown polym...
Definition: Exception.h:45
#define throw_
Use in place of throw keyword to throw a honey::Exception object polymorphically and provide debug in...
Definition: Exception.h:11
Functor to delete a pointer.
Definition: Allocator.h:161
Exceptions.
Definition: Promise.h:14
#define debug_if(...)
Evaluate expression in debug mode only, does nothing in final mode.
Definition: Debug.h:30
Funcptr< Sig > FuncptrCreate(F &&f)
Convenient method to create a Funcptr from a functor that inherits from FuncptrBase.
Definition: Meta.h:279
bool valid() const
Check if this instance has state and can be used. State can be transferred out to another instance th...
Definition: Promise.h:239
UniqueLock< ConditionLock > Scoped
Definition: Lock.h:36
Definition: Promise.h:17
static Ptr current()
Create a clone of the current exception caught with (...)
Definition: Exception.h:154
future::priv::State< R > State
Definition: Promise.h:186
Global Honeycomb namespace.