1 /**
2  *
3  *   Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU)
4  *   info_at_agrum_dot_org
5  *
6  *  This library is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU Lesser General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public License
17  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief Meta classes for signalers.
25  *
26  * @author Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU)
27  *
28  */
29 
30 #ifndef SIGNALER_PATRON_ACCEPTED
31 #  error "This file should not be included directly. Please use signaler{x}.h"
32 #endif   // SIGNALER_PATRON_ACCEPTED
33 
34 #include <agrum/tools/core/list.h>
35 
36 #ifndef DOXYGEN_SHOULD_SKIP_THIS
37 
38 namespace gum {
39 
40   namespace __sig__ {
41 
42     template < LIST_DECL_CLASSES >
MAKE_NAME(IConnector)43     class MAKE_NAME(IConnector) {
44       public:
45       virtual ~MAKE_NAME(IConnector)() {}
46 
47       virtual Listener* target() const                                           = 0;
48       virtual void      notify(const void*, LIST_DECL_ARGS)                      = 0;
49       virtual MAKE_NAME(IConnector)< LIST_CLASSES >* clone()                     = 0;
50       virtual MAKE_NAME(IConnector)< LIST_CLASSES >* duplicate(Listener* target) = 0;
51     };
52 
53     template < LIST_DECL_CLASSES >
MAKE_NAME(BasicSignaler)54     class MAKE_NAME(BasicSignaler) : public ISignaler {
55       protected:
56       typedef List< MAKE_NAME(IConnector) < LIST_CLASSES >* > ConnectorList;
57       typedef ListConstIteratorSafe< MAKE_NAME(IConnector) < LIST_CLASSES >* > ConnectorIterator;
58 
59       MAKE_NAME(BasicSignaler)() {
60         GUM_CONSTRUCTOR(MAKE_NAME(BasicSignaler));
61         ;
62       }
63 
64       MAKE_NAME(BasicSignaler)
65       (const MAKE_NAME(BasicSignaler) & s) : ISignaler(s) {
66         GUM_CONS_CPY(MAKE_NAME(BasicSignaler));
67 
68         for (const auto& connector: connectors_) {
69           connector->target()->_attachSignal_(this);
70           connectors_.pushBack(connector->clone());
71         }
72       }
73 
74       public:
75       virtual ~MAKE_NAME(BasicSignaler)() {
76         GUM_DESTRUCTOR(MAKE_NAME(BasicSignaler));
77 
78         for (const auto& connector: connectors_) {
79           connector->target()->_detachSignal_(this);
80           delete connector;
81         }
82 
83         connectors_.clear();
84       }
85 
86       bool hasListener() { return (!(connectors_.empty())); }
87 
88       void detach(Listener* target) {
89         for (ConnectorIterator it = connectors_.reginSafe();   // safe iterator needed here
90              it != connectors_.rendSafe();
91              --it) {
92           if ((*it)->target() == target) {
93             delete *it;
94             connectors_.erase(it);
95             target->_detachSignal_(this);
96             return;
97           }
98         }
99       }
100 
101       protected:
102       friend class Listener;
103 
104       void duplicateTarget(const Listener* oldtarget, Listener* newtarget) {
105         for (const auto& connector: connectors_)
106           if (connector->target() == oldtarget) {
107             connectors_.pushBack(connector->duplicate(newtarget));
108           }
109       }
110 
111       void detachFromTarget(Listener* target) {
112         ConnectorIterator itprev;
113 
114         for (ConnectorIterator it = connectors_.rbeginSafe();   // safe iterator needed here
115              it != connectors_.rendSafe();) {
116           itprev = it;
117           --it;
118 
119           if ((*itprev)->target() == target) {
120             delete *itprev;
121             connectors_.erase(itprev);
122           }
123         }
124       }
125 
126       ConnectorList connectors_;
127     };
128 
129     template < class TargetClass, LIST_DECL_CLASSES >
MAKE_NAME(Connector)130     class MAKE_NAME(Connector) : public MAKE_NAME(IConnector)< LIST_CLASSES > {
131       public:
132       MAKE_NAME(Connector)() {
133         GUM_CONSTRUCTOR(MAKE_NAME(Connector));
134         _target_ = NULL;
135         _action_ = NULL;
136       }
137 
138       MAKE_NAME(Connector)
139       (TargetClass* target, void (TargetClass::*action)(const void*, LIST_CLASSES)) {
140         GUM_CONSTRUCTOR(MAKE_NAME(Connector));
141         _target_ = target;
142         _action_ = action;
143       }
144 
145       MAKE_NAME(Connector)
146       (const MAKE_NAME(Connector) < TargetClass, LIST_CLASSES > *src) :
147           MAKE_NAME(IConnector)< LIST_CLASSES >(src) {
148         GUM_CONS_CPY(MAKE_NAME(Connector));
149       }
150 
151       virtual ~MAKE_NAME(Connector)() {
152         GUM_DESTRUCTOR(MAKE_NAME(Connector));
153         ;
154       }
155 
156       INLINE virtual MAKE_NAME(IConnector)< LIST_CLASSES >* clone() {
157         return new MAKE_NAME(Connector)< TargetClass, LIST_CLASSES >(*this);
158       }
159 
160       INLINE virtual MAKE_NAME(IConnector)< LIST_CLASSES >* duplicate(Listener* target) {
161         return new MAKE_NAME(Connector)< TargetClass, LIST_CLASSES >((TargetClass*)target,
162                                                                      _action_);
163       }
164 
165       INLINE virtual void notify(const void* src, LIST_DECL_ARGS) {
166         (_target_->*_action_)(src, LIST_ARGS);
167       }
168 
169       INLINE virtual Listener* target() const { return _target_; }
170 
171       private:
172       TargetClass* _target_;
173       void (TargetClass::*_action_)(const void*, LIST_CLASSES);
174     };
175 
176   }   // namespace  __sig__
177 
178   template < LIST_DECL_CLASSES >
MAKE_NAME(Signaler)179   class MAKE_NAME(Signaler) : public __sig__::MAKE_NAME(BasicSignaler)< LIST_CLASSES > {
180     typedef typename __sig__::MAKE_NAME(BasicSignaler)< LIST_CLASSES >::ConnectorIterator
181        ConnectorIterator;
182 
183     public:
184     using BasicSignaler = __sig__::MAKE_NAME(BasicSignaler)< LIST_CLASSES >;
185 
186     MAKE_NAME(Signaler)() {
187       GUM_CONSTRUCTOR(MAKE_NAME(Signaler));
188       ;
189     }
190 
191     MAKE_NAME(Signaler)
192     (const MAKE_NAME(Signaler) & s) : __sig__::MAKE_NAME(BasicSignaler)< LIST_CLASSES >(s) {
193       GUM_CONS_CPY(MAKE_NAME(Signaler));
194     }
195 
196     virtual ~MAKE_NAME(Signaler)() {
197       GUM_DESTRUCTOR(MAKE_NAME(Signaler));
198       ;
199     }
200 
201     template < class TargetClass >
202     void attach(TargetClass* target, void (TargetClass::*action)(const void*, LIST_CLASSES)) {
203       __sig__::MAKE_NAME(Connector)< TargetClass, LIST_CLASSES >* conn
204          = new __sig__::MAKE_NAME(Connector)< TargetClass, LIST_CLASSES >(target, action);
205       this->connectors_.pushBack(conn);
206       target->_attachSignal_(this);
207     }
208 
209     INLINE void operator()(const void* src, LIST_DECL_ARGS) {
210       for (const auto& connector: this->connectors_) {
211         connector->notify(src, LIST_ARGS);
212       }
213     }
214   };
215 
216 }   // namespace gum
217 
218 #endif   // DOXYGEN_SHOULD_SKIP_THIS
219 
220 #undef MAKE_NAME
221 #undef LIST_DECL_CLASSES
222 #undef LIST_CLASSES
223 #undef LIST_DECL_ARGS
224 #undef LIST_ARGS
225 #undef SIGNALER_PATRON_ACCEPTED
226