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-2023 Ceetron Solutions AS
5 // Copyright (C) 2024- Kontur AS
6 //
7 // This library may be used under the terms of either the GNU General Public License or
8 // the GNU Lesser General Public License as follows:
9 //
10 // GNU General Public License Usage
11 // This library is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE.
19 //
20 // See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
21 // for more details.
22 //
23 // GNU Lesser General Public License Usage
24 // This library is free software; you can redistribute it and/or modify
25 // it under the terms of the GNU Lesser General Public License as published by
26 // the Free Software Foundation; either version 2.1 of the License, or
27 // (at your option) any later version.
28 //
29 // This library is distributed in the hope that it will be useful, but WITHOUT ANY
30 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
31 // FITNESS FOR A PARTICULAR PURPOSE.
32 //
33 // See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
34 // for more details.
35 //
36 // ##################################################################################################
37 #pragma once
38 
39 #include "cafAssert.h"
40 
41 #include <functional>
42 #include <map>
43 #include <set>
44 #include <string>
45 #include <type_traits>
46 
47 namespace caffa
48 {
49 class SignalEmitter;
50 class SignalObserver;
51 
53 {
54 public:
55  virtual ~AbstractSignal() noexcept = default;
56  virtual void disconnect( SignalObserver* observer ) = 0;
57 };
58 
59 //==================================================================================================
62 //==================================================================================================
64 {
65 public:
66  SignalEmitter();
67  virtual ~SignalEmitter() noexcept;
68 
69  void addEmittedSignal( AbstractSignal* signalToAdd ) const;
70  std::set<AbstractSignal*> emittedSignals() const;
71 
72 private:
73  mutable std::set<AbstractSignal*> m_signals;
74 };
75 
76 //==================================================================================================
79 //==================================================================================================
81 {
82 public:
84  virtual ~SignalObserver() noexcept;
85  std::set<AbstractSignal*> observedSignals() const;
86  void addObservedSignal( AbstractSignal* signalToAdd ) const;
87  void removeObservedSignal( AbstractSignal* signalToRemove ) const noexcept;
88 
89 private:
90  void disconnectAllSignals() noexcept;
91 
92 private:
93  mutable std::set<AbstractSignal*> m_signals;
94 };
95 
96 //==================================================================================================
101 //==================================================================================================
102 template <typename... Args>
103 class Signal : public AbstractSignal
104 {
105 public:
106  using MemberCallback = std::function<void( const SignalEmitter*, Args... args )>;
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& [observer, callback] : m_observerCallbacks )
118  {
119  observer->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] = callback;
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 ( const auto& [observer, callback] : observerCallBacksCopy )
158  {
159  callback( m_emitter, args... );
160  }
161  }
162 
163  size_t observerCount() const { return m_observerCallbacks.size(); }
164 
165  bool connected( const SignalObserver* observer ) const
166  {
167  // Possible to search for const-pointer due to transparent comparator
168  auto it = m_observerCallbacks.find( observer );
169  return it != m_observerCallbacks.end();
170  }
171 
172 private:
173  Signal( const Signal& rhs ) = delete;
174  Signal& operator=( const Signal& rhs ) = delete;
175 
176 private:
177  using TransparentComparator = std::less<>;
178  std::map<SignalObserver*, MemberCallback, TransparentComparator> m_observerCallbacks;
179  const SignalEmitter* m_emitter;
180 };
181 } // namespace caffa
Definition: cafSignal.h:52
Definition: cafSignal.h:80
Definition: cafSignal.h:63
Definition: cafSignal.h:103
Main Caffa namespace.
Definition: cafApplication.h:30