RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
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