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