RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/sigslot/signal.h
00001 /* signal.h                                                      -*- C++ -*-
00002    Jeremy Barnes, 4 November 2010
00003    Copyright (c) 2010 Datacratic.  All rights reserved.
00004 
00005    A signal framework that allows for signals to be set up.
00006 */
00007 
00008 #pragma once
00009 
00010 #include "slot.h"
00011 #include "jml/arch/rtti_utils.h"
00012 #include <boost/function.hpp>
00013 #include <unordered_map>
00014 #include <boost/signals2.hpp>
00015 #include "jml/utils/string_functions.h"
00016 
00017 namespace Datacratic {
00018 
00019 
00020 /*****************************************************************************/
00021 /* SIGNAL INFO                                                               */
00022 /*****************************************************************************/
00023 
00027 struct SignalInfo {
00028 
00029     SignalInfo()
00030         : callbackType(0), objectType(0), inherited(false)
00031     {
00032     }
00033 
00035     Json::Value toJson() const;
00036 
00037     std::string eventName;  
00038     const std::type_info * callbackType;  
00039     const std::type_info * objectType;    
00040     bool inherited;         
00041 };
00042 
00043 
00044 /*****************************************************************************/
00045 /* SIGNAL REGISTRY BASE                                                      */
00046 /*****************************************************************************/
00047 
00052 struct SignalRegistryBase {
00053 
00057     SignalRegistryBase();
00058 
00062     SignalRegistryBase(SignalRegistryBase & inheritFrom);
00063 
00064     ~SignalRegistryBase();
00065 
00067     size_t size() const { return signals.size(); }
00068 
00076     template<typename Class>
00077     SlotDisconnector on(const std::string & name,
00078                         Class * object,
00079                         const Slot & slot,
00080                         int priority = 0) const
00081     {
00082         return doOn(name, object, typeid(Class), slot, priority);
00083     }
00084 
00086     std::vector<std::string> names() const;
00087 
00089     SignalInfo info(const std::string & name) const;
00090 
00094     void inheritSignals(SignalRegistryBase & inheritFrom);
00095 
00096 protected:
00110     typedef SlotDisconnector (* RegisterFn) (void * thisPtr,
00111                                              const std::type_info & thisType,
00112                                              const std::string & name,
00113                                              const Slot & slotToRegister,
00114                                              int priority,
00115                                              void * data);
00116     
00120     struct Info : public SignalInfo {
00121         Info()
00122             : registerFn(0), data(0)
00123         {
00124         }
00125 
00126         RegisterFn registerFn;  
00127         void * data;            
00128     };
00129 
00130     typedef std::unordered_map<std::string, Info> Signals;
00131 
00133     Signals signals;
00134 
00136     SlotDisconnector doOn(const std::string & name,
00137                           void * object,
00138                           const std::type_info & objectType,
00139                           const Slot & slot,
00140                           int priority) const;
00141 
00143     void add(const std::string & eventName,
00144              //const std::string & description, // TODO: would be nice...
00145              const std::type_info & callbackType,
00146              const std::type_info & objectType,
00147              RegisterFn registerFn, void * data = 0);
00148 
00153     typedef void (NewEvent) (const SignalRegistryBase &, const Info &);
00154     
00156     boost::signals2::signal<NewEvent> newEvent;
00157 
00159     std::vector<boost::signals2::connection> parentRegistrations;
00160 
00167     void addSignal(const Info & signal, bool inherited);
00168 };
00169 
00170 
00171 /*****************************************************************************/
00172 /* SIGNAL REGISTRY                                                           */
00173 /*****************************************************************************/
00174 
00177 template<typename Class>
00178 struct SignalRegistry : public SignalRegistryBase {
00179 
00180     SignalRegistry()
00181     {
00182     }
00183 
00184     template<typename Fn,
00185              SlotDisconnector (Class::* AddFn) (const std::string & name,
00186                                                 const Slot & slot,
00187                                                 int priority,
00188                                                 void * data)>
00189     static SlotDisconnector doRegister(void * thisPtr,
00190                                        const std::type_info & thisType,
00191                                        const std::string & name,
00192                                        const Slot & slotToRegister,
00193                                        int priority,
00194                                        void * data)
00195     {
00196         Class * cl = (Class *)ML::is_convertible(thisType, typeid(Class),
00197                                                  thisPtr);
00198         if (!cl)
00199             throw ML::Exception("object of type " + ML::demangle(thisType)
00200                                 + " at "
00201                                 + ML::format("%p", thisPtr)
00202                                 + " is not convertible to "
00203                                 + ML::type_name<Class>()
00204                                 + " trying to register for notification "
00205                                 + name);
00206         return (cl ->* AddFn) (name, slotToRegister, priority);
00207     }
00208 
00209     template<typename Fn,
00210              SlotDisconnector (Class::* AddFn) (const boost::function<Fn> &,
00211                                                 int priority)>
00212     struct Helper {
00213         static SlotDisconnector doRegister(void * thisPtr,
00214                                            const std::type_info & thisType,
00215                                            const std::string & name,
00216                                            const Slot & slotToRegister,
00217                                            int priority,
00218                                            void * data)
00219         {
00220             Class * cl = (Class *)ML::is_convertible(thisType, typeid(Class),
00221                                                      thisPtr);
00222             if (!cl)
00223                 throw ML::Exception("object of type " + ML::demangle(thisType)
00224                                     + " at "
00225                                     + ML::format("%p", thisPtr)
00226                                     + " is not convertible to "
00227                                     + ML::type_name<Class>()
00228                                     + " trying to register for notification "
00229                                     + name);
00230             return (cl ->* AddFn) (slotToRegister.as<Fn>(), priority);
00231         }
00232     };
00233 
00234     template<typename Fn,
00235              SlotDisconnector (Class::* AddFn) (const Slot & slot,
00236                                                 int priority)>
00237     void add(const std::string & name,
00238              void (Class::* addFn) (const Slot & slot, int priority))
00239     {
00240         SignalRegistryBase::
00241             add(name, typeid(Fn), typeid(Class), &doRegister<Fn, AddFn>, 0);
00242     }
00243 
00244     template<typename Fn,
00245              SlotDisconnector (Class::* AddFn) (const boost::function<Fn> & slot, int priority)>
00246     void add(const std::string & name)
00247     {
00248         RegisterFn fn = &Helper<Fn, AddFn>::doRegister;
00249         SignalRegistryBase::add(name, typeid(Fn), typeid(Class), fn, 0);
00250     }
00251 };
00252 
00253 struct DoRegisterSignals {
00254     template<typename Fn>
00255     DoRegisterSignals(Fn fn)
00256     {
00257         fn();
00258     }
00259 };
00260 
00261 } // namespace Datacratic
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator