1 // 2 // This file is part of the aMule Project. 3 // 4 // Copyright (c) 2005-2011 Mikkel Schubert ( xaignar@users.sourceforge.net ) 5 // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org ) 6 // 7 // Any parts of this program derived from the xMule, lMule or eMule project, 8 // or contributed by third-party developers are copyrighted by their 9 // respective authors. 10 // 11 // This program 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 2 of the License, or 14 // (at your option) any later version. 15 // 16 // This program is distributed in the hope that it will be useful, 17 // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 // GNU General Public License for more details. 20 // 21 // You should have received a copy of the GNU General Public License 22 // along with this program; if not, write to the Free Software 23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 24 // 25 26 #ifndef OBSERVABLEQUEUE_H 27 #define OBSERVABLEQUEUE_H 28 29 #include "Observable.h" 30 31 32 33 template <typename ValueType> 34 class CQueueObserver; 35 36 37 /** 38 * This class defines the protocol used by the CObservableQueue class. 39 * 40 * This specific protocol can be used by a class to make changes to its 41 * contents visible, assuming that said contents does not rely on being 42 * in a specific order, as insertions commands do not specify positions. 43 * 44 * The class CQueueObserver implements a queue that will always be kept 45 * in sync with the class observed, so that it is possible to handle all 46 * elements in a container object over a longer period of time, which 47 * would normally result in problems with changes accomulating in the list. 48 */ 49 template <typename ValueType> 50 class CQueueEvent 51 { 52 public: 53 //! The type of list used by this protocol to store values. 54 typedef std::vector<ValueType> ValueList; 55 56 //! The events used by this observable type. 57 //! Note: If more than one instance of a value has been added, removed or 58 //! updated, then the resulting events should reflect this fact by 59 //! including the same of instances as has been changed. 60 enum Type { 61 //! Signals a QueueObserver that it has been added to a queue. 62 STARTING, 63 //! Signals a QueueObserver that it has been removed from a queue. 64 STOPPING, 65 //! Signals that one or more values have been added. 66 INSERTED, 67 //! Signals that one or more values have been removed. 68 REMOVED, 69 //! Signals that the following values have been updated. 70 CHANGED, 71 //! Signals that all values have been removed. 72 CLEARED, 73 //! Contains the contents of the queue at subscription time. 74 INITIAL 75 }; 76 77 78 /** 79 * Constructor for misc events. 80 */ 81 CQueueEvent( Type event ); 82 83 84 /** 85 * Constructor for events regarding multiple values. 86 * 87 * Note: CQueueEvent does not take ownership of the specified list. 88 */ 89 CQueueEvent( Type event, const ValueList* list ); 90 91 92 /** 93 * Constructor for events regarding a single value 94 */ 95 CQueueEvent( Type event, const ValueType& value ); 96 97 98 /** 99 * Returns the event-type. 100 */ 101 Type GetEvent() const { 102 return m_type; 103 } 104 105 /** 106 * Returns the number of available values passed with the event. 107 */ 108 size_t GetCount() const; 109 110 /** 111 * Returns a copy of the ith value. 112 */ 113 ValueType GetValue( size_t i ) const; 114 115 116 private: 117 //! Pointer to a list of values. May be NULL. 118 const ValueList* m_list; 119 //! Pointer to a single value. May be NULL. 120 const ValueType* m_value; 121 //! The actual event-type. 122 Type m_type; 123 }; 124 125 126 127 /** 128 * This class forms the superclass for observable queues or lists. 129 * 130 * The protocol defined above is used (CQueueEvent). 131 * 132 * By subclassing this class, a container object can ensure that classes 133 * observing it are able to keep in sync with the changes made to the 134 * contents, with a few limits. 135 * 136 * For one thing, the value is assumed to be both key and value, so 137 * multimaps cannot be used with this class, since it will only pass 138 * the key. Nor can lists that rely on a specific order be used, since 139 * neither insertion nor deletion operations specify a specific 140 * object or position, instead just a "add/remove one of these" rule. 141 * 142 * The main purpose of this class is to allow another class to follow 143 * a list or queue, regardles of changes in actual order of the items 144 * and regardles of changes to the contents. 145 */ 146 template <typename ValueType> 147 class CObservableQueue : public CObservable< CQueueEvent<ValueType> > 148 { 149 public: 150 /** 151 * Destructor. 152 * 153 * Sends STOPPING to all observers. 154 */ ObserverAdded(ObserverType *)155 virtual ~CObservableQueue(); 156 157 protected: 158 typedef CQueueEvent< ValueType > EventType; 159 typedef CObserver< EventType > ObserverType; 160 typedef typename EventType::ValueList ValueList; 161 162 163 /** 164 * Sends a STARTING event to new observers. ObserverRemoved(ObserverType *)165 */ 166 virtual void ObserverAdded( ObserverType* ); 167 168 /** 169 * Sends a STOPPING event to removed observers. 170 */ 171 virtual void ObserverRemoved( ObserverType* ); 172 }; 173 174 175 176 /** 177 * This class is an automatically synchronized queue connected with an ObservableQueue. 178 * 179 * Note that this observer can only be assigned to ONE observable at a time! 180 * 181 * This class implements a queue (out-order not specified) that allows an 182 * ObservableQueue object to be object to be used as a queue without making 183 * by another object in a safe manner. Changes to the contents of the original 184 * queue are propagated to this queue, such that it will never contain values 185 * not found in the original queue and such that it will add new values added 186 * to the original queue. 187 * ~CObserver()188 * This allows the contents to be accessed safely, when for instance it is 189 * needed to iterate over the contents over a period of time, where one 190 * cannot be certain of the current state of the actual contents of the 191 * original lists. 192 * 193 * This class supersedes such broken solutions such as remembering the last 194 * used position in the original list, since no changes made to the original 195 * list will result in items being skipped or treated twice*. 196 * 197 * * With the exception of the same item being removed and then re-added, in 198 * which case the CQueueObserver class will consider it a new item. 199 */ 200 template <typename ValueType> 201 class CQueueObserver : public CObserver< CQueueEvent<ValueType> > 202 { 203 public: 204 typedef CQueueEvent<ValueType> EventType; 205 typedef typename CObserver< EventType >::ObservableType ObservableType; 206 typedef typename EventType::ValueList ValueList; 207 208 209 /** 210 * Constructor. 211 */ 212 CQueueObserver(); 213 214 215 /** 216 * Overloaded notification function. 217 */ 218 virtual void ReceiveNotification( const ObservableType*, const EventType& e ); 219 220 221 /** 222 * Returns the next element from the queue. 223 * 224 * Note: Objects will not be returned in the same order as 225 * they were found in the original observable. Also, note 226 * that calling GetNext() on an empty queue should only be 227 * done if the default contructed value does not match a 228 * valid object and can be used to check for End of Queue. 229 */ 230 ValueType GetNext(); 231 232 /** 233 * Returns the number of remaining elements in the queue. 234 */ 235 size_t GetRemaining() const; 236 237 /** 238 * Returns true if the observer is currently assigned to an observable-queue. 239 */ 240 bool IsActive() const; 241 242 /** 243 * Clears the queue and readds itself to the current object being observed. 244 */ 245 void Reset(); 246 247 private: 248 //! Lock used to ensure the threadsafety of the class 249 mutable wxMutex m_mutex; 250 251 typedef std::multiset<ValueType> Queue; 252 typedef typename Queue::iterator QueueIterator; 253 //! The remaining items. 254 Queue m_queue; 255 256 //! Used to check that we are only subscribed to one queue at a time 257 const ObservableType* m_owner; 258 }; 259 260 261 262 263 /////////////////////////////////////////////////// 264 265 266 267 268 template <typename ValueType> 269 CQueueEvent<ValueType>::CQueueEvent( Type event ) NotifyObservers(const EventType & e,ObserverType * o)270 : m_list( NULL ), 271 m_value( NULL ), 272 m_type( event ) 273 { 274 275 } 276 277 278 template <typename ValueType> 279 CQueueEvent<ValueType>::CQueueEvent( Type event, const ValueList* list ) 280 : m_list( list ), 281 m_value( NULL ), 282 m_type( event ) 283 { 284 wxASSERT( list ); 285 } 286 RemoveAllObservers()287 288 template <typename ValueType> 289 CQueueEvent<ValueType>::CQueueEvent( Type event, const ValueType& value ) 290 : m_list( NULL ), 291 m_value( &value ), 292 m_type( event ) 293 { 294 } 295 296 297 template <typename ValueType> 298 size_t CQueueEvent<ValueType>::GetCount() const { 299 if ( m_list ) { 300 return m_list->size(); 301 } else if ( m_value ) { 302 return 1; 303 } else { 304 return 0; 305 } 306 } 307 308 309 template <typename ValueType> 310 ValueType CQueueEvent<ValueType>::GetValue( size_t i ) const { 311 if ( m_list ) { 312 return (*m_list).at( i ); 313 } else if ( m_value && i == 0 ) { 314 return *m_value; 315 } else { 316 wxFAIL; 317 return ValueType(); 318 } 319 } 320 321 322 323 324 template <typename ValueType> 325 CObservableQueue<ValueType>::~CObservableQueue() 326 { 327 this->RemoveAllObservers(); 328 } 329 330 331 template <typename ValueType> 332 void CObservableQueue<ValueType>::ObserverAdded( ObserverType* o ) 333 { 334 this->NotifyObservers( EventType( EventType::STARTING ), o ); 335 } 336 337 338 template <typename ValueType> 339 void CObservableQueue<ValueType>::ObserverRemoved( ObserverType* o ) 340 { 341 this->NotifyObservers( EventType( EventType::STOPPING ), o ); 342 } 343 344 345 346 347 template <typename ValueType> 348 CQueueObserver<ValueType>::CQueueObserver() 349 { 350 m_owner = NULL; 351 } 352 353 354 template <typename ValueType> 355 void CQueueObserver<ValueType>::ReceiveNotification( const ObservableType* o, const EventType& e ) 356 { 357 wxMutexLocker lock( m_mutex ); 358 359 if ( e.GetEvent() == EventType::INSERTED || e.GetEvent() == EventType::INITIAL ) { 360 for ( size_t i = 0; i < e.GetCount(); i++ ) { 361 m_queue.insert( e.GetValue( i ) ); 362 } 363 } else if ( e.GetEvent() == EventType::REMOVED ) { 364 for ( size_t i = 0; i < e.GetCount(); i++ ) { 365 QueueIterator it = m_queue.find( e.GetValue( i ) ); 366 367 if ( it != m_queue.end() ) { 368 m_queue.erase( it ); 369 } 370 } 371 } else if ( e.GetEvent() == EventType::CLEARED ) { 372 m_queue.clear(); 373 } else if ( e.GetEvent() == EventType::STOPPING ) { 374 m_queue.clear(); 375 m_owner = NULL; 376 } else if ( e.GetEvent() == EventType::STARTING ) { 377 wxASSERT(m_owner == NULL); 378 m_owner = o; 379 } else { 380 wxFAIL; 381 } 382 } 383 384 385 template <typename ValueType> 386 ValueType CQueueObserver<ValueType>::GetNext() 387 { 388 wxMutexLocker lock( m_mutex ); 389 390 if (!m_queue.empty()) { 391 ValueType v = *m_queue.begin(); 392 m_queue.erase( m_queue.begin() ); 393 394 return v; 395 } 396 397 return ValueType(); 398 } 399 400 401 template <typename ValueType> 402 size_t CQueueObserver<ValueType>::GetRemaining() const 403 { 404 wxMutexLocker lock( m_mutex ); 405 406 return m_queue.size(); 407 } 408 409 410 template <typename ValueType> 411 bool CQueueObserver<ValueType>::IsActive() const 412 { 413 return (m_owner != NULL); 414 } 415 416 417 template <typename ValueType> 418 void CQueueObserver<ValueType>::Reset() 419 { 420 ObservableType* owner; 421 422 { 423 wxMutexLocker lock(m_mutex); 424 m_queue.clear(); 425 owner = const_cast<ObservableType*>( m_owner ); 426 } 427 428 owner->RemoveObserver( this ); 429 owner->AddObserver( this ); 430 } 431 432 433 434 #endif 435 // File_checked_for_headers 436