Caffa  1.1.0
C++ Application Framework for Embedded Systems with introspection
cafSignal.h
1 //##################################################################################################
2 //
3 // Custom Visualization Core library
4 // Copyright (C) 2020- Ceetron Solutions AS
5 //
6 // This library may be used under the terms of either the GNU General Public License or
7 // the GNU Lesser General Public License as follows:
8 //
9 // GNU General Public License Usage
10 // This library is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful, but WITHOUT ANY
16 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 // FITNESS FOR A PARTICULAR PURPOSE.
18 //
19 // See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
20 // for more details.
21 //
22 // GNU Lesser General Public License Usage
23 // This library is free software; you can redistribute it and/or modify
24 // it under the terms of the GNU Lesser General Public License as published by
25 // the Free Software Foundation; either version 2.1 of the License, or
26 // (at your option) any later version.
27 //
28 // This library is distributed in the hope that it will be useful, but WITHOUT ANY
29 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
30 // FITNESS FOR A PARTICULAR PURPOSE.
31 //
32 // See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
33 // for more details.
34 //
35 //##################################################################################################
36 #pragma once
37 
38 #include "cafAssert.h"
39 
40 #include <functional>
41 #include <list>
42 #include <map>
43 #include <string>
44 #include <type_traits>
45 
46 namespace caffa
47 {
48 class SignalEmitter;
49 class SignalObserver;
50 
52 {
53 public:
54  virtual ~AbstractSignal() noexcept = default;
55  virtual void disconnect( SignalObserver* observer ) = 0;
56 };
57 
58 //==================================================================================================
61 //==================================================================================================
63 {
64 public:
65  SignalEmitter();
66  virtual ~SignalEmitter() noexcept;
67 
68  void addEmittedSignal( AbstractSignal* signalToAdd ) const;
69  std::list<AbstractSignal*> emittedSignals() const;
70 
71 private:
72  mutable std::list<AbstractSignal*> m_signals;
73 };
74 
75 //==================================================================================================
78 //==================================================================================================
80 {
81 public:
83  virtual ~SignalObserver() noexcept;
84  std::list<AbstractSignal*> observedSignals() const;
85  void addObservedSignal( AbstractSignal* signalToAdd ) const;
86  void removeObservedSignal( AbstractSignal* signalToRemove ) const noexcept;
87 
88 private:
89  void disconnectAllSignals() noexcept;
90 
91 private:
92  mutable std::list<AbstractSignal*> m_signals;
93 };
94 
95 //==================================================================================================
100 //==================================================================================================
101 template <typename... Args>
102 class Signal : public AbstractSignal
103 {
104 public:
105  using MemberCallback = std::function<void( const SignalEmitter*, Args... args )>;
106  using MemberCallbackAndActiveFlag = std::pair<MemberCallback, bool>;
107 
108 public:
109  Signal( const SignalEmitter* emitter )
110  : m_emitter( emitter )
111  {
112  m_emitter->addEmittedSignal( this );
113  }
114 
115  virtual ~Signal()
116  {
117  for ( auto observerCallbackPair : m_observerCallbacks )
118  {
119  observerCallbackPair.first->removeObservedSignal( this );
120  }
121  }
122 
123  template <typename ClassType>
124  void connect( ClassType* observer, void ( ClassType::*method )( const SignalEmitter*, Args... args ) )
125  {
126  MemberCallback lambda = [=]( const SignalEmitter* emitter, Args... args )
127  {
128  // Call method
129  ( observer->*method )( emitter, args... );
130  };
131  connect( observer, lambda );
132  }
133 
134  template <typename ClassType>
135  void connect( ClassType* observer, const MemberCallback& callback )
136  {
137  static_assert( std::is_convertible<ClassType*, SignalObserver*>::value,
138  "Only classes that inherit SignalObserver can connect as an observer of a Signal." );
139  m_observerCallbacks[observer] = std::make_pair( callback, true );
140  observer->addObservedSignal( this );
141  }
142 
143  // Disconnect an observer from the signal. Do this only when the relationship between the
144  // observer and emitter is severed but the object kept alive.
145  // There's no need to do this when deleting the observer.
146  void disconnect( SignalObserver* observer ) noexcept override
147  {
148  // This does not throw, since std::map::erase only throws if the comparison operator throws
149  // and we're just comparing pointers.
150  m_observerCallbacks.erase( observer );
151  observer->removeObservedSignal( this );
152  }
153 
154  void send( Args... args ) const
155  {
156  auto observerCallBacksCopy = m_observerCallbacks;
157  for ( auto observerCallbackPair : observerCallBacksCopy )
158  {
159  if ( observerCallbackPair.second.second )
160  {
161  observerCallbackPair.second.first( m_emitter, args... );
162  }
163  }
164  }
165 
166  void block( SignalObserver* observer )
167  {
168  auto it = m_observerCallbacks.find( observer );
169  CAFFA_ASSERT( it != m_observerCallbacks.end() );
170  it->second.second = false;
171  }
172 
173  void unblock( SignalObserver* observer )
174  {
175  auto it = m_observerCallbacks.find( observer );
176  CAFFA_ASSERT( it != m_observerCallbacks.end() );
177  it->second.second = true;
178  }
179  size_t observerCount() const { return m_observerCallbacks.size(); }
180 
181  bool connected( const SignalObserver* observer ) const
182  {
183  for ( const auto& observerPair : m_observerCallbacks )
184  {
185  if ( observerPair.first == observer ) return true;
186  }
187  return false;
188  }
189 
190 private:
191  Signal( const Signal& rhs ) = delete;
192  Signal& operator=( const Signal& rhs ) = delete;
193 
194 private:
195  std::map<SignalObserver*, MemberCallbackAndActiveFlag> m_observerCallbacks;
196  const SignalEmitter* m_emitter;
197 };
198 } // namespace caffa
Definition: cafSignal.h:52
Definition: cafSignal.h:63
Definition: cafSignal.h:80
Definition: cafSignal.h:103
Main Caffa namespace.
Definition: __init__.py:1