1 /* 2 * The Doomsday Engine Project -- libcore 3 * 4 * Copyright © 2004-2017 Jaakko Keränen <jaakko.keranen@iki.fi> 5 * 6 * @par License 7 * LGPL: http://www.gnu.org/licenses/lgpl.html 8 * 9 * <small>This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as published by 11 * the Free Software Foundation; either version 3 of the License, or (at your 12 * option) any later version. This program is distributed in the hope that it 13 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15 * General Public License for more details. You should have received a copy of 16 * the GNU Lesser General Public License along with this program; if not, see: 17 * http://www.gnu.org/licenses</small> 18 */ 19 20 #ifndef LIBDENG2_OBSERVERS_H 21 #define LIBDENG2_OBSERVERS_H 22 23 #include "../libcore.h" 24 #include "../Lockable" 25 #include "../Guard" 26 #include "../PointerSet" 27 28 #include <QSet> 29 30 /** 31 * Macro that forms the name of an observer interface. 32 */ 33 #define DENG2_AUDIENCE_INTERFACE(Name) \ 34 I##Name##Observer 35 36 /** 37 * Macro for declaring an observer interface containing one method. 38 * 39 * @param Name Name of the audience. E.g., "Deletion" produces @c DeletionAudience. 40 * @param Method The pure virtual method that the observer has to implement. 41 * The @c virtual keyword and <code>=0</code> are automatically included. 42 */ 43 #define DENG2_DECLARE_AUDIENCE(Name, Method) \ 44 class DENG2_AUDIENCE_INTERFACE(Name) : public de::ObserverBase { \ 45 public: \ 46 virtual ~DENG2_AUDIENCE_INTERFACE(Name)() {} \ 47 virtual Method = 0; \ 48 }; 49 50 /** 51 * Defines an audience. Typically used inside a class to define the observers 52 * as a public member variable (used by DENG_DEFINE_AUDIENCE). Produces a 53 * member variable called "audienceFor{Name}". 54 * 55 * @param Name Name of the audience. 56 */ 57 #define DENG2_AUDIENCE(Name) \ 58 typedef de::Observers<DENG2_AUDIENCE_INTERFACE(Name)> Name##Audience; \ 59 Name##Audience audienceFor##Name; 60 61 #define DENG2_EXTERN_AUDIENCE(Name) \ 62 typedef de::Observers<DENG2_AUDIENCE_INTERFACE(Name)> Name##Audience; \ 63 DENG2_PUBLIC extern Name##Audience audienceFor##Name; 64 65 #define DENG2_DECLARE_AUDIENCE_METHOD(Name) \ 66 typedef de::Observers<DENG2_AUDIENCE_INTERFACE(Name)> Name##Audience; \ 67 Name##Audience &audienceFor##Name(); \ 68 Name##Audience const &audienceFor##Name() const; 69 70 #define DENG2_AUDIENCE_METHOD(ClassName, Name) \ 71 ClassName::Name##Audience &ClassName::audienceFor##Name() { return d->audienceFor##Name; } \ 72 ClassName::Name##Audience const &ClassName::audienceFor##Name() const { return d->audienceFor##Name; } 73 74 #define DENG2_AUDIENCE_METHOD_INLINE(Name) \ 75 typedef de::Observers<DENG2_AUDIENCE_INTERFACE(Name)> Name##Audience; \ 76 Name##Audience _audienceFor##Name; \ 77 Name##Audience &audienceFor##Name() { return _audienceFor##Name; } \ 78 Name##Audience const &audienceFor##Name() const { return _audienceFor##Name; } 79 80 #define DENG2_PIMPL_AUDIENCE(Name) \ 81 Name##Audience audienceFor##Name; 82 83 /** 84 * Macro for defining an observer interface containing a single method. 85 * 86 * @param Name Name of the audience. E.g., "Deletion" produces @c DeletionAudience 87 * and @c audienceForDeletion. 88 * @param Method The pure virtual method that the observer has to implement. 89 * The @c virtual keyword and <code>=0</code> are automatically included. 90 */ 91 #define DENG2_DEFINE_AUDIENCE(Name, Method) \ 92 DENG2_DECLARE_AUDIENCE(Name, Method) \ 93 DENG2_AUDIENCE(Name) 94 95 #define DENG2_DEFINE_AUDIENCE2(Name, Method) \ 96 DENG2_DECLARE_AUDIENCE(Name, Method) \ 97 DENG2_DECLARE_AUDIENCE_METHOD(Name) 98 99 #define DENG2_DEFINE_AUDIENCE_INLINE(Name, Method) \ 100 DENG2_DECLARE_AUDIENCE(Name, Method) \ 101 DENG2_AUDIENCE_METHOD_INLINE(Name) 102 103 /** 104 * Macro that can be used in class declarations to specify which audiences the class 105 * can belong to. 106 * 107 * @param Type Name of the type where the audience is defined. 108 * @param Audience Audience name. 109 */ 110 #define DENG2_OBSERVES(Type, Audience) public Type::I##Audience##Observer 111 112 /** 113 * Macro for looping through all observers. @note The @a Audience type needs to be defined 114 * in the scope. 115 * 116 * @param SetName Name of the observer set class. 117 * @param Var Variable used in the loop. 118 * @param Name Name of the observer set. 119 */ 120 #define DENG2_FOR_EACH_OBSERVER(SetName, Var, Name) for (SetName::Loop Var(Name); !Var.done(); ++Var) 121 122 /** 123 * Macro for looping through the audience members. 124 * 125 * @param Name Name of the audience. 126 * @param Var Variable used in the loop. 127 */ 128 #define DENG2_FOR_AUDIENCE(Name, Var) \ 129 DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, audienceFor##Name) 130 131 #define DENG2_FOR_AUDIENCE2(Name, Var) \ 132 DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, audienceFor##Name()) 133 134 /** 135 * Macro for looping through the public audience members from inside a private 136 * implementation. 137 * 138 * @param Name Name of the audience. 139 * @param Var Variable used in the loop. 140 */ 141 #define DENG2_FOR_PUBLIC_AUDIENCE(Name, Var) \ 142 DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, self().audienceFor##Name) 143 144 #define DENG2_FOR_PUBLIC_AUDIENCE2(Name, Var) \ 145 DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, self().audienceFor##Name()) 146 147 namespace de { 148 149 class ObserverBase; 150 151 /** 152 * Interface for a group of observers. 153 */ 154 class DENG2_PUBLIC IAudience 155 { 156 public: 157 virtual ~IAudience(); 158 virtual void addMember (ObserverBase *member) = 0; 159 virtual void removeMember(ObserverBase *member) = 0; 160 }; 161 162 class DENG2_PUBLIC ObserverBase 163 { 164 public: 165 ObserverBase(); 166 ObserverBase(ObserverBase const &) = delete; // copying denied 167 virtual ~ObserverBase(); 168 169 void addMemberOf (IAudience &observers); 170 void removeMemberOf(IAudience &observers); 171 172 private: 173 LockableT<PointerSetT<IAudience>> _memberOf; 174 }; 175 176 /** 177 * Template for observer sets. The template type should be an interface 178 * implemented by all the observers. The observer type must implement ObserverBase. 179 * @ingroup data 180 * 181 * @par How to use the non-pimpl audience macros 182 * 183 * These examples explain how to create an audience called "Deletion". In 184 * general, audience names should be nouns like this so they can be used in the 185 * form "audience for (something)". 186 * 187 * In a class declaration, define the audience in the @c public section of the 188 * class: <pre>DENG2_DEFINE_AUDIENCE(Deletion, ...interface-function...)</pre> 189 * 190 * This will generate a public member variable called @c audienceForDeletion 191 * that can be directly manipulated by other objects. 192 * 193 * Note that because the audience is created as a public member variable, this 194 * can easily lead to ABI backwards compatibility issues down the road if there 195 * is need to make changes to the class. 196 * 197 * @par How to use the pimpl audience macros 198 * 199 * Another set of macros is provided for declaring and defining a 200 * pimpl-friendly audience. The caveat is that you'll need to separately 201 * declare accessor methods and define the audience inside the private 202 * implementation of the class. 203 * 204 * First, define the audience in the @c public section of the class: 205 * <pre>DENG2_DEFINE_AUDIENCE2(Deletion, ...interface-function...)</pre> 206 * 207 * This works like DENG2_DEFINE_AUDIENCE, but without a public member variable. 208 * Instead, accessor methods are declared for accessing the audience. 209 * 210 * Then, inside the private implementation (@c Instance struct), define the 211 * audience: <pre>DENG2_PIMPL_AUDIENCE(Deletion)</pre> 212 * 213 * Finally, define the accessor methods (for instance, just before the 214 * constructor of the class): 215 * <pre>DENG2_AUDIENCE_METHOD(ClassName, Deletion)</pre> 216 * 217 * It is recommended to keep the DENG2_PIMPL_AUDIENCE and DENG2_AUDIENCE_METHOD 218 * macros close together in the source file for easier maintenance. The former 219 * could be at the end of the @c Instance struct while the latter is immediately 220 * following the struct. 221 * 222 * @par Thread-safety 223 * 224 * Observers and Observers::Loop lock the observer set separately for reading 225 * and writing as appropriate. 226 */ 227 template <typename Type> 228 class Observers : public Lockable, public IAudience 229 { 230 public: 231 typedef PointerSetT<Type> Members; // note: ordered, array-based 232 typedef typename Members::const_iterator const_iterator; 233 typedef int size_type; 234 235 /** 236 * Iteration utility for observers. This should be used when 237 * notifying observers, because it is safe against the observer removing 238 * itself from the observer set, or the set itself being destroyed. 239 */ 240 class Loop : public PointerSet::IIterationObserver { 241 public: Loop(Observers const & observers)242 Loop(Observers const &observers) : _audience(&observers) 243 , _prevObserver(nullptr) { 244 DENG2_GUARD(_audience); 245 if (members().flags() & PointerSet::AllowInsertionDuringIteration) { 246 _prevObserver = members().iterationObserver(); 247 members().setIterationObserver(this); 248 } 249 members().setBeingIterated(true); 250 _next = members().begin(); 251 next(); 252 } ~Loop()253 virtual ~Loop() { 254 DENG2_GUARD(_audience); 255 members().setBeingIterated(false); 256 if (members().flags() & PointerSet::AllowInsertionDuringIteration) { 257 members().setIterationObserver(_prevObserver); 258 } 259 } done()260 bool done() const { 261 return _current >= members().end(); 262 } next()263 void next() { 264 _current = _next; 265 if (_current < members().begin()) { 266 _current = members().begin(); 267 if (_next < _current) _next = _current; 268 } 269 if (_next < members().end()) { 270 ++_next; 271 } 272 } get()273 const_iterator const &get() const { 274 return _current; 275 } 276 Type *operator -> () const { 277 return *get(); 278 } 279 Loop &operator ++ () { 280 next(); 281 return *this; 282 } pointerSetIteratorsWereInvalidated(PointerSet::Pointer const * oldBase,PointerSet::Pointer const * newBase)283 void pointerSetIteratorsWereInvalidated(PointerSet::Pointer const *oldBase, 284 PointerSet::Pointer const *newBase) override { 285 if (_prevObserver) { 286 _prevObserver->pointerSetIteratorsWereInvalidated(oldBase, newBase); 287 } 288 _current = reinterpret_cast<const_iterator>(newBase) + 289 (_current - reinterpret_cast<const_iterator>(oldBase)); 290 _next = reinterpret_cast<const_iterator>(newBase) + 291 (_next - reinterpret_cast<const_iterator>(oldBase)); 292 } 293 private: members()294 inline Members const &members() const { 295 return _audience->_members; 296 } 297 Observers const *_audience; 298 PointerSet::IIterationObserver *_prevObserver; 299 const_iterator _current; 300 const_iterator _next; 301 }; 302 303 friend class Loop; 304 305 public: Observers()306 Observers() {} 307 Observers(Observers<Type> const & other)308 Observers(Observers<Type> const &other) { 309 *this = other; 310 } 311 ~Observers()312 virtual ~Observers() { 313 _disassociateAllMembers(); 314 DENG2_GUARD(this); 315 } 316 clear()317 void clear() { 318 DENG2_GUARD(this); 319 _disassociateAllMembers(); 320 _members.clear(); 321 } 322 323 Observers<Type> &operator = (Observers<Type> const &other) { 324 if (this == &other) return *this; 325 DENG2_GUARD(other); 326 DENG2_GUARD(this); 327 _members = other._members; 328 for (Type *observer : _members) { 329 observer->addMemberOf(*this); 330 } 331 return *this; 332 } 333 334 /// Add an observer into the set. The set does not receive 335 /// ownership of the observer instance. add(Type * observer)336 void add(Type *observer) { 337 _add(observer); 338 observer->addMemberOf(*this); 339 } 340 341 Observers<Type> &operator += (Type *observer) { 342 add(observer); 343 return *this; 344 } 345 346 Observers<Type> &operator += (Type &observer) { 347 add(&observer); 348 return *this; 349 } 350 351 Observers<Type> const &operator += (Type const *observer) const { 352 const_cast<Observers<Type> *>(this)->add(const_cast<Type *>(observer)); 353 return *this; 354 } 355 356 Observers<Type> const &operator += (Type const &observer) const { 357 const_cast<Observers<Type> *>(this)->add(const_cast<Type *>(&observer)); 358 return *this; 359 } 360 remove(Type * observer)361 void remove(Type *observer) { 362 _remove(observer); 363 observer->removeMemberOf(*this); 364 } 365 366 Observers<Type> &operator -= (Type *observer) { 367 remove(observer); 368 return *this; 369 } 370 371 Observers<Type> &operator -= (Type &observer) { 372 remove(&observer); 373 return *this; 374 } 375 376 Observers<Type> const &operator -= (Type *observer) const { 377 const_cast<Observers<Type> *>(this)->remove(observer); 378 return *this; 379 } 380 381 Observers<Type> const &operator -= (Type &observer) const { 382 const_cast<Observers<Type> *>(this)->remove(&observer); 383 return *this; 384 } 385 size()386 size_type size() const { 387 DENG2_GUARD(this); 388 return _members.size(); 389 } 390 isEmpty()391 inline bool isEmpty() const { 392 return size() == 0; 393 } 394 contains(Type const * observer)395 bool contains(Type const *observer) const { 396 DENG2_GUARD(this); 397 return _members.contains(const_cast<Type *>(observer)); 398 } 399 contains(Type const & observer)400 bool contains(Type const &observer) const { 401 DENG2_GUARD(this); 402 return _members.contains(const_cast<Type *>(&observer)); 403 } 404 405 /** 406 * Allows or denies addition of audience members while the audience is being 407 * iterated. By default, addition is not allowed. If additions are allowed, only one 408 * Loop can be iterating the audience at a time. 409 * 410 * @param yes @c true to allow additions, @c false to deny. 411 */ setAdditionAllowedDuringIteration(bool yes)412 void setAdditionAllowedDuringIteration(bool yes) { 413 DENG2_GUARD(this); 414 _members.setFlags(Members::AllowInsertionDuringIteration, yes); 415 } 416 417 // Implements IAudience. addMember(ObserverBase * member)418 void addMember (ObserverBase *member) { _add (static_cast<Type *>(member)); } removeMember(ObserverBase * member)419 void removeMember(ObserverBase *member) { _remove(static_cast<Type *>(member)); } 420 421 private: _disassociateAllMembers()422 void _disassociateAllMembers() { 423 for (Type *observer : _members) { 424 observer->removeMemberOf(*this); 425 } 426 } 427 _add(Type * observer)428 void _add(Type *observer) { 429 DENG2_GUARD(this); 430 DENG2_ASSERT(observer != 0); 431 _members.insert(observer); 432 } 433 _remove(Type * observer)434 void _remove(Type *observer) { 435 DENG2_GUARD(this); 436 _members.remove(observer); 437 } 438 439 Members _members; 440 }; 441 442 } // namespace de 443 444 #endif /* LIBDENG2_OBSERVERS_H */ 445