aGrUM 3.0.0
a C++ library for (probabilistic) graphical models
signaler_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41
42#pragma once
43
45
46namespace gum::__sig__ {
47
48 // =========================================================================
49 // Connector<TargetClass, Args...>
50 // =========================================================================
51
52 template < class TargetClass, typename... Args >
54 _target_(target), _action_(action) {
55 GUM_CONSTRUCTOR(Connector);
56 }
57
58 template < class TargetClass, typename... Args >
60 IConnector< Args... >(), _target_(src._target_), _action_(src._action_) {
61 GUM_CONS_CPY(Connector);
62 }
63
64 template < class TargetClass, typename... Args >
68
69 template < class TargetClass, typename... Args >
70 void Connector< TargetClass, Args... >::notify(const void* src, Args... args) {
71 (_target_->*_action_)(src, args...);
72 }
73
74 template < class TargetClass, typename... Args >
76 return new Connector< TargetClass, Args... >(*this);
77 }
78
79 template < class TargetClass, typename... Args >
81 return new Connector< TargetClass, Args... >(static_cast< TargetClass* >(newTarget), _action_);
82 }
83
84 // =========================================================================
85 // BasicSignaler<Args...>
86 // =========================================================================
87
88 template < typename... Args >
90 GUM_CONS_CPY(BasicSignaler);
91 for (const auto* connector: other._connectors_) {
92 auto* cloned = connector->clone();
93 _connectors_.push_back(cloned);
94 cloned->target()->_attachSignal_(this);
95 }
96 }
97
98 template < typename... Args >
100 GUM_DESTRUCTOR(BasicSignaler);
101 for (auto* connector: _connectors_) {
102 connector->target()->_detachSignal_(this);
103 delete connector;
104 }
105 _connectors_.clear();
106 }
107
108 template < typename... Args >
110 return !_connectors_.empty();
111 }
112
113 template < typename... Args >
115 for (auto it = _connectors_.rbegin(); it != _connectors_.rend(); ++it) {
116 if ((*it)->target() == target) {
117 auto* conn = *it;
118 _connectors_.erase(std::next(it).base());
119 target->_detachSignal_(this);
120 delete conn;
121 return;
122 }
123 }
124 }
125
126 template < typename... Args >
128 for (auto it = _connectors_.begin(); it != _connectors_.end();) {
129 if ((*it)->target() == target) {
130 delete *it;
131 it = _connectors_.erase(it);
132 } else {
133 ++it;
134 }
135 }
136 }
137
138 template < typename... Args >
140 ConnectorList toAdd;
141 for (auto* connector: _connectors_) {
142 if (connector->target() == oldTarget) { toAdd.push_back(connector->duplicate(newTarget)); }
143 }
144 for (auto* newConn: toAdd) {
145 _connectors_.push_back(newConn);
146 }
147 }
148
149} // namespace gum::__sig__
150
151namespace gum {
152
153 // =========================================================================
154 // Signaler<Args...>
155 // =========================================================================
156
157 template < typename... Args >
158 Signaler< Args... >::Signaler(const Signaler& other) : __sig__::BasicSignaler< Args... >(other) {
159 GUM_CONS_CPY(Signaler);
160 }
161
162 template < typename... Args >
163 template < class TargetClass >
164 void Signaler< Args... >::attach(TargetClass* target,
165 void (TargetClass::*action)(const void*, Args...)) {
166 auto* conn = new __sig__::Connector< TargetClass, Args... >(target, action);
167 this->_connectors_.push_back(conn);
168 target->_attachSignal_(this);
169 }
170
171 template < typename... Args >
172 void Signaler< Args... >::operator()(const void* src, Args... args) {
173 if (this->_connectors_.empty()) { return; }
174 for (const auto connectors = this->_connectors_; auto* connector: connectors) {
175 connector->notify(src, args...);
176 }
177 }
179} // namespace gum
Every class who would catch signal from signaler should derive from Listener.
Definition listener.h:93
void _detachSignal_(__sig__::ISignaler *sender)
Signaler()
Default constructor.
Definition signaler.h:239
void attach(TargetClass *target, void(TargetClass::*action)(const void *, Args...))
Attach a listener with a member function callback.
void operator()(const void *src, Args... args)
Emit the signal, notifying all attached listeners.
std::vector< IConnector< Args... > * > ConnectorList
Definition signaler.h:165
void duplicateTarget(const Listener *oldTarget, Listener *newTarget) override
Called by Listener copy constructor to duplicate connections.
BasicSignaler()
Default constructor.
Definition signaler.h:168
friend class gum::Listener
Definition signaler.h:184
~BasicSignaler() override
Destructor: detaches from all targets and deletes connectors.
void detachFromTarget(Listener *target) override
Called by Listener to detach when the listener is destroyed.
ConnectorList _connectors_
Definition signaler.h:192
void detach(Listener *target)
Detach a specific listener from this signaler.
Concrete connector binding a target object and its member function.
Definition signaler.h:120
void(TargetClass::*)(const void *, Args...) ActionType
Type alias for the member function pointer.
Definition signaler.h:123
Listener * target() const override
IConnector< Args... > * duplicate(Listener *newTarget) const override
Create a duplicate connector pointing to a new target.
void notify(const void *src, Args... args) override
Notify the target with the given source and arguments.
Connector()
Default constructor.
Definition signaler.h:126
TargetClass * _target_
Definition signaler.h:150
IConnector< Args... > * clone() const override
Create a deep copy of this connector.
Abstract interface for signal connectors with variadic arguments.
Definition signaler.h:93
Internal namespace for aGrUM signaler/listener components.
Definition agrum.h:49
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
C++20 variadic template implementation of the Signaler/Listener pattern.