Rapicorn - Experimental UI Toolkit - Source Code  13.07.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
aidasignal.hh
Go to the documentation of this file.
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__
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines