Empirical
Signal.h
Go to the documentation of this file.
1 
15 #ifndef EMP_CONTROL_SIGNAL
16 #define EMP_CONTROL_SIGNAL
17 
18 #include <map>
19 #include <string>
20 
21 #include "../meta/TypePack.h"
22 #include "../tools/FunctionSet.h"
23 #include "../tools/map_utils.h"
24 
25 #include "Action.h"
26 
27 namespace emp {
28 
30  class SignalKey {
31  private:
32  uint32_t signal_id;
33  uint32_t key_id;
34 
35  // Internal function to compare two signal kays.
36  int Compare(const SignalKey& in) const {
37  if (signal_id < in.signal_id) return -1;
38  if (signal_id > in.signal_id) return 1;
39  if (key_id < in.key_id) return -1;
40  if (key_id > in.key_id) return 1;
41  return 0;
42  }
43  public:
44  SignalKey(uint32_t _kid=0, uint32_t _sid=0) : signal_id(_sid), key_id(_kid) { ; }
45  SignalKey(const SignalKey &) = default;
46  SignalKey & operator=(const SignalKey &) = default;
47  ~SignalKey() { ; }
48 
50  bool operator==(const SignalKey& in) const { return Compare(in) == 0; }
51 
53  bool operator!=(const SignalKey& in) const { return Compare(in) != 0; }
54 
55  bool operator<(const SignalKey& in) const { return Compare(in) < 0; }
56  bool operator>(const SignalKey& in) const { return Compare(in) > 0; }
57  bool operator<=(const SignalKey& in) const { return Compare(in) <= 0; }
58  bool operator>=(const SignalKey& in) const { return Compare(in) >= 0; }
59 
61  uint32_t GetID() const { return key_id; }
62 
64  uint32_t GetSignalID() const { return signal_id; }
65 
67  bool IsActive() const { return key_id > 0; }
68 
70  void Set(uint32_t _kid=0, uint32_t _sid=0) { signal_id = _sid; key_id = _kid; }
71 
73  void Clear() { signal_id = 0; key_id = 0; }
74 
75  operator bool() { return key_id > 0; }
76  };
77 
78  // Forward declarations.
79  class SignalBase; // ...for pointers to signals.
80  class SignalManager; // ...for setting up as friend.
81 
82  // Mechanisms for Signals to report to a manager.
83  namespace internal {
85  virtual void NotifyConstruct(SignalBase * sig_ptr) = 0;
86  virtual void NotifyDestruct(SignalBase * sig_ptr) = 0;
87  virtual ~SignalManager_Base() { ; }
88  };
90  virtual SignalManager_Base & GetSignalManager() = 0;
91  virtual void NotifyConstruct(SignalBase * sig_ptr) = 0;
92  virtual ~SignalControl_Base() { ; }
93  };
94  }
95 
97  class SignalBase {
98  friend class SignalManager; // Allow SignalManager to alter internals of a signal.
99  protected:
101 
102  std::string name;
103  uint32_t signal_id;
104  uint32_t next_link_id;
105  std::map<SignalKey, size_t> link_key_map;
108 
109  // Helper Functions
110  SignalKey NextSignalKey() { return SignalKey(signal_id,++next_link_id); }
111 
112  // SignalBase should only be constructable from derrived classes.
113  SignalBase(const std::string & n, internal::SignalManager_Base * manager=nullptr)
114  : name(n), signal_id(0), next_link_id(0), link_key_map(), managers(), prime_manager(nullptr)
115  {
116  if (manager) manager->NotifyConstruct(this);
117  }
118  public:
119  SignalBase() = delete;
120  SignalBase(const SignalBase &) = delete;
121  SignalBase(SignalBase &&) = delete;
122  SignalBase & operator=(const SignalBase &) = delete;
123  SignalBase & operator=(SignalBase &&) = delete;
124  virtual ~SignalBase() {
125  // Let all managers other than prime know about destruction (prime must have triggered it.)
126  for (auto * m : managers) if (m != prime_manager) m->NotifyDestruct(this);
127  }
128  virtual SignalBase * Clone() const = 0;
129 
130  const std::string & GetName() const { return name; }
131  virtual size_t GetNumArgs() const = 0;
132  virtual size_t GetNumActions() const = 0;
133 
134  // NOTE: If a Trigger is called on a base class, convert the signal assuming that the args
135  // map to the correct types (defined below with a dynamic cast to ensure correctness)
136  template <typename... ARGS>
137  void BaseTrigger(ARGS... args);
138 
140  template <typename... ARGS>
141  SignalKey AddAction(const std::function<void(ARGS...)> & in_fun);
142 
144  virtual SignalKey AddAction(ActionBase &) = 0;
145 
147  virtual void Remove(SignalKey key) = 0;
148 
150  void Clear() {
151  // While we still have keys, remove them!
152  while (link_key_map.size()) Remove(link_key_map.begin()->first);
153  }
154 
155  bool Has(SignalKey key) const { return emp::Has(link_key_map, key); }
156  };
157 
159  template <typename... ARGS> class Signal;
160 
162  template <typename... ARGS>
163  class Signal<void(ARGS...)> : public SignalBase {
164  protected:
165  FunctionSet<void(ARGS...)> actions;
166  public:
167  using fun_t = void(ARGS...);
169 
170  Signal(const std::string & name="", internal::SignalManager_Base * manager=nullptr)
171  : SignalBase(name, manager), actions() { ; }
172  Signal(const std::string & name, internal::SignalControl_Base & control)
173  : this_t(name, &(control.GetSignalManager())) { ; }
174  virtual this_t * Clone() const {
175  this_t * new_copy = new this_t(name);
176  // @CAO: Make sure to copy over actions into new copy.
177  return new_copy;
178  }
179 
180  size_t GetNumArgs() const { return sizeof...(ARGS); }
181  size_t GetNumActions() const { return actions.GetSize(); }
182 
184  void Trigger(ARGS... args) { actions.Run(args...); }
185 
187  SignalKey AddAction(const std::function<void(ARGS...)> & in_fun) {
188  const SignalKey link_id = NextSignalKey();
189  link_key_map[link_id] = actions.size();
190  actions.Add(in_fun);
191  return link_id;
192  }
193 
196  Action<fun_t> * a = dynamic_cast< Action<fun_t>* >(&in_action);
197  emp_assert( a != nullptr && "action type must match signal type." );
198  return AddAction(a->GetFun());
199  }
200 
202  template <typename... FUN_ARGS, typename... EXTRA_ARGS>
203  SignalKey AddAction(const std::function<void(FUN_ARGS...)> & in_fun, TypePack<EXTRA_ARGS...>)
204  {
205  // If we made it here, we have isolated the extra arguments that we need to throw away to
206  // call this function correctly.
207  const SignalKey link_id = NextSignalKey();
208  link_key_map[link_id] = actions.size();
209  std::function<void(ARGS...)> expand_fun =
210  [in_fun](FUN_ARGS &&... args, EXTRA_ARGS...){ in_fun(std::forward<FUN_ARGS>(args)...); };
211  actions.Add(expand_fun);
212  return link_id;
213  }
214 
217  template <typename... FUN_ARGS>
218  SignalKey AddAction(const std::function<void(FUN_ARGS...)> & in_fun) {
219  // Identify the extra arguments by removing the ones that we know about.
220  using extra_type = typename TypePack<ARGS...>::template popN<sizeof...(FUN_ARGS)>;
221  return AddAction(in_fun, extra_type());
222  }
223 
226  template <typename... FUN_ARGS>
227  SignalKey AddAction(void in_fun(FUN_ARGS...)) {
228  // Identify the extra arguments by removing the ones that we know about.
229  using extra_type = typename TypePack<ARGS...>::template popN<sizeof...(FUN_ARGS)>;
230  return AddAction(std::function<void(FUN_ARGS...)>(in_fun), extra_type());
231  }
232 
234  void Remove(SignalKey key) {
235  // Find the action associate with this key.
236  emp_assert(emp::Has(link_key_map, key));
237  size_t pos = link_key_map[key];
238 
239  // Remove the action
240  actions.Remove(pos);
241  link_key_map.erase(key);
242 
243  // Adjust all of the positions of the actions that came after this one.
244  for (auto & x : link_key_map) {
245  if (x.second > pos) x.second = x.second - 1;
246  }
247  }
248 
250  size_t GetPriority(SignalKey key) {
251  emp_assert(emp::Has(link_key_map, key));
252  return link_key_map[key];
253  }
254 
255  };
256 
257  // Signals with NON-void return.
258  template <typename RETURN, typename... ARGS>
259  class Signal<RETURN(ARGS...)> : public SignalBase {
260  protected:
261  FunctionSet<RETURN(ARGS...)> actions;
262  public:
263  using fun_t = RETURN(ARGS...);
265 
266  Signal(const std::string & name="", internal::SignalManager_Base * manager=nullptr)
267  : SignalBase(name, manager) { ; }
268  Signal(const std::string & name, internal::SignalControl_Base & control)
269  : this_t(name, &(control.GetSignalManager())) { ; }
270  virtual this_t * Clone() const {
271  this_t * new_copy = new this_t(name);
272  // @CAO: Make sure to copy over actions into new copy.
273  return new_copy;
274  }
275 
276  size_t GetNumArgs() const { return sizeof...(ARGS); }
277  size_t GetNumActions() const { return actions.GetSize(); }
278 
279  const emp::vector<RETURN> & Trigger(ARGS... args) { return actions.Run(args...); }
280 
281  // Add an action that takes the proper arguments.
282  SignalKey AddAction(const std::function<fun_t> & in_fun) {
283  const SignalKey link_id = NextSignalKey();
284  link_key_map[link_id] = actions.size();
285  actions.Add(in_fun);
286  return link_id;
287  }
288 
290  Action<fun_t> * a = dynamic_cast< Action<fun_t>* >(&in_action);
291  emp_assert( a != nullptr && "action type must match signal type." );
292  return AddAction(a->GetFun());
293  }
294 
295  // Add an action that takes too few arguments... but provide specific padding info.
296  template <typename... FUN_ARGS, typename... EXTRA_ARGS>
297  SignalKey AddAction(const std::function<RETURN(FUN_ARGS...)> & in_fun, TypePack<EXTRA_ARGS...>)
298  {
299  // If we made it here, we have isolated the extra arguments that we need to throw away to
300  // call this function correctly.
301  const SignalKey link_id = NextSignalKey();
302  link_key_map[link_id] = actions.size();
303  std::function<fun_t> expand_fun =
304  [in_fun](FUN_ARGS &&... args, EXTRA_ARGS...){ in_fun(std::forward<FUN_ARGS>(args)...); };
305  actions.Add(expand_fun);
306  return link_id;
307  }
308 
309  // Add an std::function that takes the wrong number of arguments. For now, we will assume
310  // that there are too few and we need to figure out how to pad it out.
311  template <typename... FUN_ARGS>
312  SignalKey AddAction(const std::function<RETURN(FUN_ARGS...)> & in_fun) {
313  // Identify the extra arguments by removing the ones that we know about.
314  using extra_type = typename TypePack<ARGS...>::template popN<sizeof...(FUN_ARGS)>;
315  return AddAction(in_fun, extra_type());
316  }
317 
318  // Add a regular function that takes the wrong number of arguments. For now, we will assume
319  // that there are too few and we need to figure out how to pad it out.
320  template <typename... FUN_ARGS>
321  SignalKey AddAction(RETURN in_fun(FUN_ARGS...)) {
322  // Identify the extra arguments by removing the ones that we know about.
323  using extra_type = typename TypePack<ARGS...>::template popN<sizeof...(FUN_ARGS)>;
324  return AddAction(std::function<RETURN(FUN_ARGS...)>(in_fun), extra_type());
325  }
326 
327  void Remove(SignalKey key) {
328  // Find the action associate with this key.
329  emp_assert(emp::Has(link_key_map, key));
330  size_t pos = link_key_map[key];
331 
332  // Remove the action
333  actions.Remove(pos);
334  link_key_map.erase(key);
335 
336  // Adjust all of the positions of the actions that came after this one.
337  for (auto & x : link_key_map) {
338  if (x.second > pos) x.second = x.second - 1;
339  }
340  }
341 
342  size_t GetPriority(SignalKey key) {
343  emp_assert(emp::Has(link_key_map, key));
344  return link_key_map[key];
345  }
346 
347  };
348 
349  template<typename... ARGS>
350  inline void SignalBase::BaseTrigger(ARGS... args) {
351  // Make sure this base class is really of the correct derrived type (but do so in an
352  // assert since triggers may be called frequently and should be fast!)
353  emp_assert(dynamic_cast< Signal<void(ARGS...)> * >(this));
354  ((Signal<void(ARGS...)> *) this)->Trigger(args...);
355  }
356 
357  template <typename... ARGS>
358  inline SignalKey SignalBase::AddAction(const std::function<void(ARGS...)> & in_fun) {
359  // @CAO: Assert for now; ideally try to find solution with fewer args.
360  emp_assert(dynamic_cast< Signal<void(ARGS...)> * >(this));
361  return ((Signal<void(ARGS...)> *) this)->AddAction(in_fun);
362  }
363 
364 }
365 
366 #endif
const std::string & GetName() const
Definition: Signal.h:130
SignalKey tracks a specific function triggered by a signal. For now, its just a value pair...
Definition: Signal.h:30
SignalKey & operator=(const SignalKey &)=default
Definition: Action.h:28
uint32_t signal_id
What is the unique ID of this signal?
Definition: Signal.h:103
virtual this_t * Clone() const
Definition: Signal.h:270
Signal(const std::string &name="", internal::SignalManager_Base *manager=nullptr)
Definition: Signal.h:170
SignalKey AddAction(const std::function< void(ARGS...)> &in_fun)
Add an action that takes the proper arguments.
Definition: Signal.h:187
SignalKey AddAction(ActionBase &in_action)
Add an action using an Action object.
Definition: Signal.h:289
bool IsActive() const
Is this key currently pointing to a signal action?
Definition: Signal.h:67
SignalKey NextSignalKey()
Definition: Signal.h:110
Base class for all signals.
Definition: Signal.h:97
bool operator!=(const SignalKey &in) const
Are two signal keys different?
Definition: Signal.h:53
virtual void NotifyConstruct(SignalBase *sig_ptr)=0
Definition: Signal.h:84
bool operator<(const SignalKey &in) const
Definition: Signal.h:55
size_t GetNumActions() const
Definition: Signal.h:181
size_t GetNumArgs() const
Definition: Signal.h:180
A mechanism to abstract functions from their underlying type and provide run-time names...
void Trigger(ARGS...args)
Trigger this signal, providing all needed arguments.
Definition: Signal.h:184
uint32_t GetID() const
What is the KeyID associated with this signal key.
Definition: Signal.h:61
SignalKey AddAction(const std::function< fun_t > &in_fun)
Definition: Signal.h:282
void Remove(SignalKey key)
Remove an action from this signal by providing its key.
Definition: Signal.h:234
virtual ~SignalControl_Base()
Definition: Signal.h:92
size_t GetNumActions() const
Definition: Signal.h:277
std::map< SignalKey, size_t > link_key_map
Map unique link keys to link index for actions.
Definition: Signal.h:105
std::string name
What is the unique name of this signal?
Definition: Signal.h:102
RETURN(ARGS...) fun_t
Definition: Signal.h:263
SignalKey AddAction(RETURN in_fun(FUN_ARGS...))
Definition: Signal.h:321
size_t GetPriority(SignalKey key)
Retrieve the relative priority associated with a specific.
Definition: Signal.h:250
~SignalKey()
Definition: Signal.h:47
virtual ~SignalBase()
Definition: Signal.h:124
void Clear()
Remove all actions from this signal.
Definition: Signal.h:150
virtual ~SignalManager_Base()
Definition: Signal.h:87
SignalBase(const std::string &n, internal::SignalManager_Base *manager=nullptr)
Definition: Signal.h:113
void(ARGS...) fun_t
Definition: Signal.h:167
const emp::vector< RETURN > & Trigger(ARGS...args)
Definition: Signal.h:279
Generic version of Signals; needs specialization to a function type..
Definition: Signal.h:159
Definition: SignalManager.h:21
FunctionSet< void(ARGS...)> actions
Set of functions (actions) to be triggered with this signal.
Definition: Signal.h:165
Definition: Action.h:64
bool operator==(const SignalKey &in) const
Are two signal keys identical?
Definition: Signal.h:50
void BaseTrigger(ARGS...args)
Definition: Signal.h:350
bool operator<=(const SignalKey &in) const
Definition: Signal.h:57
SignalKey(uint32_t _kid=0, uint32_t _sid=0)
Definition: Signal.h:44
SignalKey AddAction(const std::function< RETURN(FUN_ARGS...)> &in_fun, TypePack< EXTRA_ARGS... >)
Definition: Signal.h:297
void Remove(SignalKey key)
Remove an action specified by its key.
Definition: Signal.h:327
size_t GetNumArgs() const
Definition: Signal.h:276
void Set(uint32_t _kid=0, uint32_t _sid=0)
Set this key to specified values.
Definition: Signal.h:70
bool Has(const MAP_T &in_map, const KEY_T &key)
Take any map type, and run find to determine if a key is present.
Definition: map_utils.h:21
Signal(const std::string &name="", internal::SignalManager_Base *manager=nullptr)
Definition: Signal.h:266
SignalKey AddAction(const std::function< void(FUN_ARGS...)> &in_fun)
Definition: Signal.h:218
emp::vector< man_t * > managers
What manager is handling this signal?
Definition: Signal.h:106
void Clear()
Clear this key.
Definition: Signal.h:73
uint32_t GetSignalID() const
What is the ID of the signal that this key is associated with.
Definition: Signal.h:64
size_t GetPriority(SignalKey key)
Definition: Signal.h:342
SignalKey AddAction(ActionBase &in_action)
Add a specified action to this signal.
Definition: Signal.h:195
If we are in emscripten, make sure to include the header.
Definition: array.h:37
Definition: Signal.h:89
SignalKey AddAction(const std::function< void(FUN_ARGS...)> &in_fun, TypePack< EXTRA_ARGS... >)
Add an action that takes too few arguments... but provide specific padding info.
Definition: Signal.h:203
virtual this_t * Clone() const
Definition: Signal.h:174
Definition: FunctionSet.h:19
Build a debug wrapper emp::vector around std::vector.
Definition: vector.h:42
#define emp_assert(...)
Definition: assert.h:199
Signal(const std::string &name, internal::SignalControl_Base &control)
Definition: Signal.h:268
SignalKey AddAction(void in_fun(FUN_ARGS...))
Definition: Signal.h:227
bool Has(SignalKey key) const
Definition: Signal.h:155
bool operator>(const SignalKey &in) const
Definition: Signal.h:56
uint32_t next_link_id
What ID shouild the next link have?
Definition: Signal.h:104
FunctionSet< RETURN(ARGS...)> actions
Definition: Signal.h:261
Signal(const std::string &name, internal::SignalControl_Base &control)
Definition: Signal.h:172
SignalKey AddAction(const std::function< RETURN(FUN_ARGS...)> &in_fun)
Definition: Signal.h:312
man_t * prime_manager
Which manager leads deletion? (nullptr for self)
Definition: Signal.h:107
Definition: TypePack.h:71
SignalKey AddAction(const std::function< void(ARGS...)> &in_fun)
Actions without arguments or a return type can be associated with any signal.
Definition: Signal.h:358
bool operator>=(const SignalKey &in) const
Definition: Signal.h:58