Rapicorn - Experimental UI Toolkit - Source Code
13.07.0
|
00001 // CC0 Public Domain: http://creativecommons.org/publicdomain/zero/1.0/ 00002 #ifndef __RAPICORN_AIDA_SIGNAL_HH__ 00003 #define __RAPICORN_AIDA_SIGNAL_HH__ 00004 00005 namespace Rapicorn { namespace Aida { 00006 00007 namespace Lib { 00008 00010 template<typename,typename> class ProtoSignal; // left undefined 00011 00013 template<typename> class AsyncSignal; // left undefined 00014 00016 template<typename,typename> class CollectorInvocation; 00017 00019 template<typename,typename> class PromiseInvocation; 00020 00022 template<typename Result> 00023 struct CollectorLast { 00024 typedef Result CollectorResult; 00025 explicit CollectorLast () : last_() {} 00026 inline bool operator() (Result r) { last_ = r; return true; } 00027 CollectorResult result () { return last_; } 00028 private: 00029 Result last_; 00030 }; 00031 00033 template<typename Result> 00034 struct CollectorDefault : CollectorLast<Result> 00035 {}; 00036 00038 template<> 00039 struct CollectorDefault<void> { 00040 typedef void CollectorResult; 00041 void result () {} 00042 inline bool operator() (void) { return true; } 00043 }; 00044 00046 template<class Collector, class R, class... Args> 00047 struct CollectorInvocation<Collector, R (Args...)> { 00048 static inline bool 00049 invoke (Collector &collector, const std::function<R (Args...)> &cbf, Args... args) 00050 { 00051 return collector (cbf (args...)); 00052 } 00053 }; 00054 00056 template<class Collector, class... Args> 00057 struct CollectorInvocation<Collector, void (Args...)> { 00058 static inline bool 00059 invoke (Collector &collector, const std::function<void (Args...)> &cbf, Args... args) 00060 { 00061 cbf (args...); return collector(); 00062 } 00063 }; 00064 00066 template<class Function> 00067 struct HandlerLink { 00068 HandlerLink *next, *prev; 00069 Function function; 00070 int ref_count; 00071 explicit HandlerLink (const Function &callback) : next (NULL), prev (NULL), function (callback), ref_count (1) {} 00072 /*dtor*/ ~HandlerLink () { AIDA_ASSERT (ref_count == 0); } 00073 void incref () { ref_count += 1; AIDA_ASSERT (ref_count > 0); } 00074 void decref () { ref_count -= 1; if (!ref_count) delete this; else AIDA_ASSERT (ref_count > 0); } 00075 void 00076 unlink () 00077 { 00078 function = NULL; 00079 if (next) 00080 next->prev = prev; 00081 if (prev) 00082 prev->next = next; 00083 next = prev = NULL; 00084 decref(); 00085 } 00086 size_t 00087 add_before (const Function &callback) 00088 { 00089 HandlerLink *link = new HandlerLink (callback); 00090 link->prev = prev; // link to last 00091 link->next = this; 00092 prev->next = link; // link from last 00093 prev = link; 00094 static_assert (sizeof (link) == sizeof (size_t), "sizeof size_t"); 00095 return size_t (link); 00096 } 00097 bool 00098 deactivate (const Function &callback) 00099 { 00100 if (callback == function) 00101 { 00102 function = NULL; // deactivate static head 00103 return true; 00104 } 00105 for (HandlerLink *link = this->next ? this->next : this; link != this; link = link->next) 00106 if (callback == link->function) 00107 { 00108 link->unlink(); // deactivate and unlink sibling 00109 return true; 00110 } 00111 return false; 00112 } 00113 bool 00114 remove_sibling (size_t id) 00115 { 00116 for (HandlerLink *link = this->next ? this->next : this; link != this; link = link->next) 00117 if (id == size_t (link)) 00118 { 00119 link->unlink(); // deactivate and unlink sibling 00120 return true; 00121 } 00122 return false; 00123 } 00124 }; 00125 00127 template<class Collector, class R, class... Args> 00128 class ProtoSignal<R (Args...), Collector> : private CollectorInvocation<Collector, R (Args...)> { 00129 protected: 00130 typedef std::function<R (Args...)> CbFunction; 00131 typedef typename CbFunction::result_type Result; 00132 typedef typename Collector::CollectorResult CollectorResult; 00133 typedef HandlerLink<CbFunction> SignalLink; 00134 private: 00135 SignalLink *callback_ring_; // linked ring of callback nodes 00136 /*copy-ctor*/ ProtoSignal (const ProtoSignal&) = delete; 00137 ProtoSignal& operator= (const ProtoSignal&) = delete; 00138 void 00139 ensure_ring () 00140 { 00141 if (!callback_ring_) 00142 { 00143 callback_ring_ = new SignalLink (CbFunction()); // ref_count = 1 00144 callback_ring_->incref(); // ref_count = 2, head of ring, can be deactivated but not removed 00145 callback_ring_->next = callback_ring_; // ring head initialization 00146 callback_ring_->prev = callback_ring_; // ring tail initialization 00147 } 00148 } 00149 protected: 00151 ProtoSignal (const CbFunction &method) : 00152 callback_ring_ (NULL) 00153 { 00154 if (method != NULL) 00155 { 00156 ensure_ring(); 00157 callback_ring_->function = method; 00158 } 00159 } 00161 ~ProtoSignal () 00162 { 00163 if (callback_ring_) 00164 { 00165 while (callback_ring_->next != callback_ring_) 00166 callback_ring_->next->unlink(); 00167 AIDA_ASSERT (callback_ring_->ref_count >= 2); 00168 callback_ring_->decref(); 00169 callback_ring_->decref(); 00170 } 00171 } 00172 public: 00174 size_t connect (const CbFunction &cb) { ensure_ring(); return callback_ring_->add_before (cb); } 00176 bool disconnect (size_t connection) { return callback_ring_ ? callback_ring_->remove_sibling (connection) : false; } 00178 CollectorResult 00179 emit (Args... args) 00180 { 00181 // check if an emission is needed 00182 Collector collector; 00183 if (!callback_ring_) 00184 return collector.result(); 00185 // capture and incref signal handler list 00186 const bool have_link0 = callback_ring_->function != NULL; 00187 size_t capacity = 1 * have_link0; 00188 SignalLink *link; 00189 for (link = callback_ring_->next; link != callback_ring_; link = link->next) 00190 capacity++; // capacity measuring is O(n), but we expect n to be small generally 00191 SignalLink *links[capacity]; 00192 size_t nlinks = 0; 00193 if (have_link0) 00194 { 00195 callback_ring_->incref(); 00196 links[nlinks++] = callback_ring_; 00197 } 00198 for (link = callback_ring_->next; link != callback_ring_; link = link->next) 00199 { 00200 link->incref(); 00201 links[nlinks++] = link; 00202 } 00203 AIDA_ASSERT (nlinks <= capacity); 00204 // walk signal handler list, invoke and decref 00205 size_t i; 00206 for (i = 0; i < nlinks; i++) 00207 { 00208 SignalLink *link = links[i]; 00209 if (link->function) 00210 { 00211 const bool continue_emission = this->invoke (collector, link->function, args...); 00212 if (!continue_emission) 00213 break; 00214 } 00215 link->decref(); 00216 } 00217 for (; i < nlinks; i++) 00218 links[i]->decref(); // continue decref after 'break' 00219 // done 00220 return collector.result(); 00221 } 00222 }; 00223 00225 template<class Promise, class R, class... Args> 00226 struct PromiseInvocation<Promise, R (Args...)> { 00227 static inline void 00228 invoke (Promise &promise, const std::function<R (Args...)> &callback, Args&&... args) 00229 { 00230 promise.set_value (callback (std::forward<Args> (args)...)); 00231 } 00232 }; 00233 00235 template<class Promise, class... Args> 00236 struct PromiseInvocation<Promise, void (Args...)> { 00237 static inline void 00238 invoke (Promise &promise, const std::function<void (Args...)> &callback, Args&&... args) 00239 { 00240 callback (std::forward<Args> (args)...); 00241 promise.set_value(); 00242 } 00243 }; 00244 00246 template<class R, class... Args> 00247 class AsyncSignal<R (Args...)> : private PromiseInvocation<std::promise<R>, R (Args...)> { 00248 protected: 00249 typedef std::function<std::future<R> (Args...)> FutureFunction; 00250 typedef std::function<R (Args...)> CbFunction; 00251 typedef HandlerLink<FutureFunction> SignalLink; 00252 private: 00253 SignalLink *callback_ring_; // linked ring of callback nodes 00254 /*copy-ctor*/ AsyncSignal (const AsyncSignal&) = delete; 00255 AsyncSignal& operator= (const AsyncSignal&) = delete; 00256 void 00257 ensure_ring () 00258 { 00259 if (!callback_ring_) 00260 { 00261 callback_ring_ = new SignalLink (FutureFunction()); // ref_count = 1 00262 callback_ring_->incref(); // ref_count = 2, head of ring, can be deactivated but not removed 00263 callback_ring_->next = callback_ring_; // ring head initialization 00264 callback_ring_->prev = callback_ring_; // ring tail initialization 00265 } 00266 } 00267 protected: 00269 AsyncSignal (const FutureFunction &method) : 00270 callback_ring_ (NULL) 00271 { 00272 if (method != NULL) 00273 { 00274 ensure_ring(); 00275 callback_ring_->function = method; 00276 } 00277 } 00279 ~AsyncSignal () 00280 { 00281 if (callback_ring_) 00282 { 00283 while (callback_ring_->next != callback_ring_) 00284 callback_ring_->next->unlink(); 00285 AIDA_ASSERT (callback_ring_->ref_count >= 2); 00286 callback_ring_->decref(); 00287 callback_ring_->decref(); 00288 } 00289 } 00290 public: 00291 class Emission { 00292 typedef std::function<std::future<R> (const FutureFunction&)> FunctionTrampoline; 00293 std::vector<SignalLink*> links_; 00294 size_t current_; 00295 std::future<R> future_; 00296 FunctionTrampoline trampoline_; 00297 public: 00298 Emission (SignalLink *start_link, Args&&... args) : 00299 current_ (0) 00300 { 00301 SignalLink *link = start_link; 00302 if (link) 00303 do 00304 { 00305 if (link->function != NULL) 00306 { 00307 link->incref(); 00308 links_.push_back (link); 00309 } 00310 link = link->next; 00311 } 00312 while (link != start_link); 00313 // wrap args into lambda for deferred execution 00314 auto lambda = 00315 [link] (const FutureFunction &ff, Args... args) // -> std::future<R> 00316 { 00317 return std::move (ff (args...)); 00318 }; 00319 // FIXME: instead of std::bind, use lambda capture: [args...](){return ff(args...);}, but see gcc bug #41933 00320 trampoline_ = std::bind (lambda, std::placeholders::_1, std::forward<Args> (args)...); 00321 } 00322 ~Emission() 00323 { 00324 for (size_t i = 0; i < links_.size(); i++) 00325 links_[i]->decref(); 00326 } 00327 bool has_value () { return future_.valid() && future_ready(); } 00328 R get_value () { future_.wait(); return future_.get(); } 00329 bool done () { return current_ >= links_.size() && !future_.valid(); } 00330 bool pending () { return has_value() || (!future_.valid() && current_ < links_.size()); } 00331 bool dispatch () { emit_stepwise(); return !done(); } 00332 private: 00333 bool 00334 future_ready () 00335 { 00336 #if __GNUC__ == 4 && __GNUC_MINOR__ == 6 00337 return future_.wait_for (std::chrono::nanoseconds (0)) != false; // g++-4.6.2: work around experimental code 00338 #else 00339 return future_.wait_for (std::chrono::nanoseconds (0)) == std::future_status::ready; 00340 #endif 00341 } 00342 inline void 00343 emit_stepwise() 00344 { 00345 if (future_.valid()) 00346 return; // processing handler, use has_value 00347 if (current_ >= links_.size()) 00348 return; // done 00349 const FutureFunction &function = links_[current_]->function; 00350 current_++; 00351 if (AIDA_ISLIKELY (function != NULL)) 00352 future_ = std::move (trampoline_ (function)); // valid() == true 00353 } 00354 RAPICORN_CLASS_NON_COPYABLE (Emission); 00355 }; 00357 size_t connect_future (const FutureFunction &fcb) { ensure_ring(); return callback_ring_->add_before (fcb); } 00358 size_t connect (const CbFunction &callback) 00359 { 00360 auto lambda = 00361 [this, callback] (Args&&... args) // -> std::future<R> 00362 { 00363 std::promise<R> promise; 00364 this->invoke (promise, callback, std::forward<Args> (args)...); 00365 return std::move (promise.get_future()); 00366 }; 00367 return connect_future (lambda); 00368 } 00370 bool disconnect (size_t connection) { return callback_ring_ ? callback_ring_->remove_sibling (connection) : false; } 00372 Emission* 00373 emission (Args&&... args) 00374 { 00375 return new Emission (callback_ring_, std::forward<Args> (args)...); 00376 } 00377 }; 00378 00379 } // Lib 00380 // namespace Rapicorn::Aida 00381 00397 template <typename SignalSignature, class Collector = Lib::CollectorDefault<typename std::function<SignalSignature>::result_type> > 00398 class Signal /*final*/ : 00399 protected Lib::ProtoSignal<SignalSignature, Collector> 00400 { 00401 typedef Lib::ProtoSignal<SignalSignature, Collector> ProtoSignal; 00402 typedef typename ProtoSignal::CbFunction CbFunction; 00403 class Connector { 00404 Signal &signal_; 00405 friend class Signal; 00406 Connector& operator= (const Connector&) = delete; 00407 explicit Connector (Signal &signal) : signal_ (signal) {} 00408 public: 00410 size_t operator+= (const CbFunction &cb) { return signal_.connect (cb); } 00412 bool operator-= (size_t connection_id) { return signal_.disconnect (connection_id); } 00413 }; 00414 public: 00415 using ProtoSignal::emit; 00417 Signal (const CbFunction &method = CbFunction()) : ProtoSignal (method) {} 00419 Connector operator() () { return Connector (*this); } 00420 }; 00421 00423 template<class Instance, class Class, class R, class... Args> std::function<R (Args...)> 00424 slot (Instance &object, R (Class::*method) (Args...)) 00425 { 00426 return [&object, method] (Args... args) { return (object .* method) (args...); }; 00427 } 00428 00430 template<class Class, class R, class... Args> std::function<R (Args...)> 00431 slot (Class *object, R (Class::*method) (Args...)) 00432 { 00433 return [object, method] (Args... args) { return (object ->* method) (args...); }; 00434 } 00435 00437 template<typename Result> 00438 struct CollectorUntil0 { 00439 typedef Result CollectorResult; 00440 explicit CollectorUntil0 () : result_() {} 00441 const CollectorResult& result () { return result_; } 00442 inline bool 00443 operator() (Result r) 00444 { 00445 result_ = r; 00446 return result_ ? true : false; 00447 } 00448 private: 00449 CollectorResult result_; 00450 }; 00451 00453 template<typename Result> 00454 struct CollectorWhile0 { 00455 typedef Result CollectorResult; 00456 explicit CollectorWhile0 () : result_() {} 00457 const CollectorResult& result () { return result_; } 00458 inline bool 00459 operator() (Result r) 00460 { 00461 result_ = r; 00462 return result_ ? false : true; 00463 } 00464 private: 00465 CollectorResult result_; 00466 }; 00467 00469 template<typename Result> 00470 struct CollectorVector { 00471 typedef std::vector<Result> CollectorResult; 00472 const CollectorResult& result () { return result_; } 00473 inline bool 00474 operator() (Result r) 00475 { 00476 result_.push_back (r); 00477 return true; 00478 } 00479 private: 00480 CollectorResult result_; 00481 }; 00482 00484 template<class Object, class SignalSignature> 00485 class Connector { 00486 typedef std::function<SignalSignature> CbFunction; 00487 typedef size_t (Object::*PMF) (size_t, const CbFunction&); 00488 Object &instance_; 00489 PMF method_; 00490 public: 00491 Connector (Object &instance, PMF method) : instance_ (instance), method_ (method) {} 00493 size_t operator+= (const CbFunction &cb) { return (instance_.*method_) (0, cb); } 00495 bool operator-= (size_t connection_id) { return connection_id ? (instance_.*method_) (connection_id, *(CbFunction*) NULL) : false; } 00496 }; 00497 00521 template <typename SignalSignature> 00522 class AsyncSignal /*final*/ : protected Lib::AsyncSignal<SignalSignature> 00523 { 00524 typedef Lib::AsyncSignal<SignalSignature> BaseSignal; 00525 typedef typename BaseSignal::CbFunction CbFunction; 00526 typedef typename BaseSignal::FutureFunction FutureFunction; 00527 class Connector { 00528 AsyncSignal &signal_; 00529 friend class AsyncSignal; 00530 Connector& operator= (const Connector&) = delete; 00531 explicit Connector (AsyncSignal &signal) : signal_ (signal) {} 00532 public: 00534 size_t connect_future (const FutureFunction &ff) { return signal_.connect_future (ff); } 00536 size_t operator+= (const CbFunction &cb) { return signal_.connect (cb); } 00538 bool operator-= (size_t connection_id) { return signal_.disconnect (connection_id); } 00539 }; 00540 public: 00541 using BaseSignal::Emission; 00542 using BaseSignal::emission; 00544 AsyncSignal (const FutureFunction &method = FutureFunction()) : BaseSignal (method) {} 00546 Connector operator() () { return Connector (*this); } 00547 }; 00548 00549 } } // Rapicorn::Aida 00550 00551 #endif // __RAPICORN_AIDA_SIGNAL_HH__