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 	 */
GetEvent()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 	 */
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.
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  *
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>
CQueueEvent(Type event)269 CQueueEvent<ValueType>::CQueueEvent( Type event )
270 	: m_list( NULL  ),
271 	  m_value( NULL ),
272 	  m_type( event )
273 {
274 
275 }
276 
277 
278 template <typename ValueType>
CQueueEvent(Type event,const ValueList * list)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 
287 
288 template <typename ValueType>
CQueueEvent(Type event,const ValueType & value)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>
GetCount()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>
GetValue(size_t i)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>
~CObservableQueue()325 CObservableQueue<ValueType>::~CObservableQueue()
326 {
327 	this->RemoveAllObservers();
328 }
329 
330 
331 template <typename ValueType>
ObserverAdded(ObserverType * o)332 void CObservableQueue<ValueType>::ObserverAdded( ObserverType* o )
333 {
334 	this->NotifyObservers( EventType( EventType::STARTING ), o );
335 }
336 
337 
338 template <typename ValueType>
ObserverRemoved(ObserverType * o)339 void CObservableQueue<ValueType>::ObserverRemoved( ObserverType* o )
340 {
341 	this->NotifyObservers( EventType( EventType::STOPPING ), o );
342 }
343 
344 
345 
346 
347 template <typename ValueType>
CQueueObserver()348 CQueueObserver<ValueType>::CQueueObserver()
349 {
350 	m_owner = NULL;
351 }
352 
353 
354 template <typename ValueType>
ReceiveNotification(const ObservableType * o,const EventType & e)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>
GetNext()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>
GetRemaining()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>
IsActive()411 bool CQueueObserver<ValueType>::IsActive() const
412 {
413 	return (m_owner != NULL);
414 }
415 
416 
417 template <typename ValueType>
Reset()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