Upstream tarball 20080414
[amule.git] / src / ObservableQueue.h
blobcd99c0e6f1bd278e8e31c2577512e5b5e95aeaef
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (C) 2005-2008 Mikkel Schubert ( xaignar@users.sourceforge.net )
5 // Copyright (C) 2005-2008 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.
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.
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
26 #ifndef OBSERVABLEQUEUE_H
27 #define OBSERVABLEQUEUE_H
29 #include "Observable.h"
33 template <typename ValueType>
34 class CQueueObserver;
37 /**
38 * This class defines the protocol used by the CObservableQueue class.
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.
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.
49 template <typename ValueType>
50 class CQueueEvent
52 public:
53 //! The type of list used by this protocol to store values.
54 typedef std::vector<ValueType> ValueList;
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
78 /**
79 * Constructor for misc events.
81 CQueueEvent( Type event );
84 /**
85 * Constructor for events regarding multiple values.
87 * Note: CQueueEvent does not take ownership of the specified list.
89 CQueueEvent( Type event, const ValueList* list );
92 /**
93 * Constructor for events regarding a single value
95 CQueueEvent( Type event, const ValueType& value );
98 /**
99 * Returns the event-type.
101 Type GetEvent() const {
102 return m_type;
106 * Returns the number of available values passed with the event.
108 size_t GetCount() const;
111 * Returns a copy of the ith value.
113 ValueType GetValue( size_t i ) const;
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;
128 * This class forms the superclass for observable queues or lists.
130 * The protocol defined above is used (CQueueEvent).
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.
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.
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.
146 template <typename ValueType>
147 class CObservableQueue : public CObservable< CQueueEvent<ValueType> >
149 public:
151 * Destructor.
153 * Sends STOPPING to all observers.
155 virtual ~CObservableQueue();
157 protected:
158 typedef CQueueEvent< ValueType > EventType;
159 typedef CObserver< EventType > ObserverType;
160 typedef typename EventType::ValueList ValueList;
164 * Sends a STARTING event to new observers.
166 virtual void ObserverAdded( ObserverType* );
169 * Sends a STOPPING event to removed observers.
171 virtual void ObserverRemoved( ObserverType* );
177 * This class is an automatically synchronized queue connected with an ObservableQueue.
179 * Note that this observer can only be assigned to ONE observable at a time!
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.
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.
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*.
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.
200 template <typename ValueType>
201 class CQueueObserver : public CObserver< CQueueEvent<ValueType> >
203 public:
204 typedef CQueueEvent<ValueType> EventType;
205 typedef typename CObserver< EventType >::ObservableType ObservableType;
206 typedef typename EventType::ValueList ValueList;
210 * Constructor.
212 CQueueObserver();
216 * Overloaded notification function.
218 virtual void ReceiveNotification( const ObservableType*, const EventType& e );
222 * Returns the next element from the queue.
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.
230 ValueType GetNext();
233 * Returns the number of remaining elements in the queue.
235 size_t GetRemaining() const;
238 * Returns true if the observer is currently assigned to an observable-queue.
240 bool IsActive() const;
243 * Clears the queue and readds itself to the current object being observed.
245 void Reset();
247 private:
248 //! Lock used to ensure the threadsafety of the class
249 mutable wxMutex m_mutex;
251 typedef std::multiset<ValueType> Queue;
252 typedef typename Queue::iterator QueueIterator;
253 //! The remaining items.
254 Queue m_queue;
256 //! Used to check that we are only subscribed to one queue at a time
257 const ObservableType* m_owner;
263 ///////////////////////////////////////////////////
268 template <typename ValueType>
269 CQueueEvent<ValueType>::CQueueEvent( Type event )
270 : m_list( NULL ),
271 m_value( NULL ),
272 m_type( event )
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 )
284 wxASSERT( list );
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 )
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;
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 wxASSERT( false );
317 return ValueType();
324 template <typename ValueType>
325 CObservableQueue<ValueType>::~CObservableQueue()
327 this->RemoveAllObservers();
331 template <typename ValueType>
332 void CObservableQueue<ValueType>::ObserverAdded( ObserverType* o )
334 NotifyObservers( EventType( EventType::STARTING ), o );
338 template <typename ValueType>
339 void CObservableQueue<ValueType>::ObserverRemoved( ObserverType* o )
341 NotifyObservers( EventType( EventType::STOPPING ), o );
347 template <typename ValueType>
348 CQueueObserver<ValueType>::CQueueObserver()
350 m_owner = NULL;
354 template <typename ValueType>
355 void CQueueObserver<ValueType>::ReceiveNotification( const ObservableType* o, const EventType& e )
357 wxMutexLocker lock( m_mutex );
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 ) );
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 ) );
367 if ( it != m_queue.end() ) {
368 m_queue.erase( it );
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 wxASSERT( false );
385 template <typename ValueType>
386 ValueType CQueueObserver<ValueType>::GetNext()
388 wxMutexLocker lock( m_mutex );
390 if ( m_queue.size() ) {
391 ValueType v = *m_queue.begin();
392 m_queue.erase( m_queue.begin() );
394 return v;
397 return ValueType();
401 template <typename ValueType>
402 size_t CQueueObserver<ValueType>::GetRemaining() const
404 wxMutexLocker lock( m_mutex );
406 return m_queue.size();
410 template <typename ValueType>
411 bool CQueueObserver<ValueType>::IsActive() const
413 return (m_owner != NULL);
417 template <typename ValueType>
418 void CQueueObserver<ValueType>::Reset()
420 ObservableType* owner;
423 wxMutexLocker lock(m_mutex);
424 m_queue.clear();
425 owner = const_cast<ObservableType*>( m_owner );
428 owner->RemoveObserver( this );
429 owner->AddObserver( this );
434 #endif
435 // File_checked_for_headers