(file) Return to List.h CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  1 mike  1.2 //%2006////////////////////////////////////////////////////////////////////////
  2           //
  3           // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
  4           // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
  5           // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
  6           // IBM Corp.; EMC Corporation, The Open Group.
  7           // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
  8           // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
  9           // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10           // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11           // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 12           // EMC Corporation; Symantec Corporation; The Open Group.
 13           //
 14           // Permission is hereby granted, free of charge, to any person obtaining a copy
 15           // of this software and associated documentation files (the "Software"), to
 16           // deal in the Software without restriction, including without limitation the
 17           // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 18           // sell copies of the Software, and to permit persons to whom the Software is
 19           // furnished to do so, subject to the following conditions:
 20           // 
 21           // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 22 mike  1.2 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 23           // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 24           // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 25           // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 26           // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 27           // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 28           // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 29           //
 30           //==============================================================================
 31           //
 32           // Author: Mike Brasher (m.brasher@inovadevelopment.com)
 33           //
 34           //%/////////////////////////////////////////////////////////////////////////////
 35           
 36           #ifndef _Pegasus_Common_List_h
 37           #define _Pegasus_Common_List_h
 38           
 39           #include <Pegasus/Common/Config.h>
 40           #include <Pegasus/Common/Linkage.h>
 41           #include <Pegasus/Common/Linkable.h>
 42           #include <Pegasus/Common/Magic.h>
 43 mike  1.2 
 44           PEGASUS_NAMESPACE_BEGIN
 45           
 46           /** The NullLock class can be passed as the LockType template parameter to the
 47               List template class. The NullLock implements no-ops for the lock(), 
 48               try_lock() and unlock() operations.
 49           */
 50           class NullLock
 51           {
 52           public:
 53           
 54               /** no-op lock().
 55               */
 56               void lock() { }
 57           
 58               /** no-op try_lock().
 59               */
 60               void try_lock() { }
 61           
 62               /** no-op unlock().
 63               */
 64 mike  1.2     void unlock() { }
 65           };
 66           
 67           // Intrusive list implementation class (internal to List class).
 68           class PEGASUS_COMMON_LINKAGE ListRep
 69           {
 70           public:
 71           
 72               typedef bool (*Equal)(const Linkable* elem, const void* client_data);
 73           
 74               typedef void (*Apply)(const Linkable* elem, const void* client_data);
 75           
 76               ListRep(void (*destructor)(Linkable*));
 77           
 78               ~ListRep();
 79           
 80               void clear();
 81           
 82               size_t size() const { return _size; }
 83           
 84               size_t empty() const { return _size == 0; }
 85 mike  1.2 
 86               Linkable* front() { return _front; }
 87           
 88               const Linkable* front() const { return _front; }
 89           
 90               Linkable* back() { return _back; }
 91           
 92               const Linkable* back() const { return _back; }
 93           
 94               void next(Linkable*& elem) { elem = elem->next; };
 95           
 96               void prev(Linkable*& elem) { elem = elem->prev; };
 97           
 98               void insert_front(Linkable* elem);
 99           
100               void insert_back(Linkable* elem);
101           
102               void insert_after(Linkable* pos, Linkable* elem);
103           
104               void insert_before(Linkable* pos, Linkable* elem);
105           
106 mike  1.2     void remove(Linkable* pos);
107           
108               bool contains(const Linkable* elem);
109           
110               Linkable* remove_front();
111           
112               Linkable* remove_back();
113           
114               Linkable* find(Equal equal, const void* client_data);
115           
116               Linkable* remove(Equal equal, const void* client_data);
117           
118               void apply(Apply apply, const void* client_data);
119           
120           private:
121           
122               ListRep(const ListRep& x) { }
123               ListRep& operator=(const ListRep& x) { return *this; }
124           
125               Magic<0x6456FD0A> _magic;
126               Linkable* _front;
127 mike  1.2     Linkable* _back;
128               size_t _size;
129               void (*_destructor)(Linkable*);
130           };
131           
132           /** The List class implements an intrusive linked list. We say it is intrusive
133               because the element class must derive from Linkable, which provides the 
134               link fields used by this implementation. An intrusive implementation has 
135               two main benefits: it is more efficient and uses less memory. Recall that
136               a non-intrusive linked list must allocate an additional "node" object that
137               contains the links fields as well as a pointer to the element. This implies
138               that removal is O(N) since an element must be located before it can be
139               removed. Also, the extra memory object compromises space and efficiency.
140           
141               The List template takes two arguments: the element type and the lock type.
142               Again, the element type must derive from Linkable. The lock type is used
143               to synchronize access to the list operations and can be any class that 
144               implements these methods: lock(), try_lock(), unlock(). Here are three
145               classes that can be used as the lock type.
146           
147                   - NullLock - no locking at all.
148 mike  1.2         - Mutex - non-recursive mutex.
149 mike  1.3         - Mutex - recursive mutex.
150 mike  1.2 
151               Now we consider an example. So you want to create a list of Person 
152               elements. First you must derive from the Linkable class as shown below.
153           
154           	\code
155           	class Person : public Linkable
156           	{
157           	    Person(const String& name);
158           	    .
159           	    .
160           	    .
161           	}
162           	\endcode
163           
164               Linkable is a non-virtual base class and contains the link fields this
165               implementation will use to place Person elements onto the list. Second,
166               you must instantiate the List template. Here are three possibilities.
167           
168           	\code
169           	List<Person, NullLink>; // Do no synchronization.
170           	List<Person, Mutex>; // Use Mutex class to synchronize.
171 mike  1.3 	List<Person, Mutex>; // Use Mutex class to synchronize.
172 mike  1.2 	\endcode
173           
174               Finally, use the list. The following example adds three Person objects
175               to the back of the list and removes one from the front.
176           
177           	\code
178 mike  1.3 	typedef List<Person, Mutex> PersonList;
179 mike  1.2 	PersonList list;
180           
181           	list.insert_back(new Person("John"));
182           	list.insert_back(new Person("Mary"));
183           	list.insert_back(new Person("Jane"));
184           
185           	Person* person = list.remove_front();
186           	\endcode
187           
188               One recurring usage pattern is exhausting the elements of a list. For 
189               example (this is thread-safe).
190           
191           	\code
192           	Person* person;
193           
194           	while ((person = list.remove_front())
195           	{
196           	    // Do something with person here.
197           	}
198           	\endcode
199           
200 mike  1.2     Another pattern is to iterate the elements of the list, which requires a
201               lock for the duration of the iteration. For example:
202           
203           	\code
204           	list.lock();
205           
206           	for (Person* p = list.front(); p; p = list.next_of(p))
207           	{
208           	    // Use p here!
209           	}
210           
211           	list.unlock();
212           	\endcode
213           
214               Beware that this pattern fails for non-recursive mutexes since the mutex
215               is locked once by our example and again by front(). You may have noticed
216               that if an exception is thrown before unlock(), that the mutex will
217               remain locked. For this reason, the List class contains an AutoLock class
218               that will automatically release the mutex. We now rework the previous 
219               example to use an AutoLock object.
220           
221 mike  1.2 	\code
222           	{
223           	    PersonList::AutoLock autoLock(list);
224           
225           	    for (Person* p = list.front(); p; p = list.next_of(p))
226           	    {
227           		// Use p here!
228           	    }
229           	}
230           	\endcode
231           
232               The List class provides a special find function to simplify recurring 
233               lookups of an element by some specific criteria. For example, lets add an
234               equal function to our Person class as follows:
235           
236           	\code
237           	class Person : public Linkable
238           	{
239           	    Person(const String& name);
240           	    const String& name();
241           
242 mike  1.2 	    static bool equal(const Person* person, const char* client_data)
243           	    {
244           		const String& name = *((const String*)client_data);
245           		return person->name() == name;
246           	    }
247           	}
248           	\endcode
249           
250               This equal function may now be passed to the find() function to lookup
251               a specific person in a thread-safe way. For example:
252           
253           	\code
254           	const String name = "John";
255           	Person* person = list.find(Person::equal, &name);
256           
257           	if (person)
258           	{
259           	    // Found John!
260           	}
261           	\endcode
262           
263 mike  1.2     Similary, we can delete "John" by using the equal-form of remove().
264           
265           	\code
266           	const String name = "John";
267           	Person* person = list.remove(Person::equal, &name);
268           	\endcode
269           
270               Finally, we can "apply" a function to every element of the list using
271               the apply method. For example:
272           
273           	\code
274           	static void _print(Person* person, const void* client_data)
275           	{
276           	    printf("%s\n", (const char*)client_data);
277           	    person->print();
278           	}
279           
280           	list.apply(_print, "My List");
281           	\endcode
282           */
283           template<class ElemType, class LockType>
284 mike  1.2 class List
285           {
286           public:
287           
288               typedef List<ElemType, LockType> This;
289           
290               typedef bool (*Equal)(const ElemType* elem, const void* client_data);
291           
292               typedef void (*Apply)(const ElemType* elem, const void* client_data);
293           
294               /** Default constructor.
295               */
296               List() : _rep(_destructor) 
297               {
298               }
299           
300               /** Destructor.
301               */
302               ~List()
303               {
304           	AutoLock al(*this);
305 mike  1.2 	_rep.clear();
306               }
307           
308               /** Remove and delete all elements in this list. size() returns zero
309           	after this is called.
310               */
311               void clear()
312               {
313           	AutoLock al(*this);
314           	_rep.clear();
315               }
316           
317               /** Returns the number of elements in the list.
318               */
319               size_t size() const 
320               {
321           	AutoLock al(*this);
322           	return _rep.size(); 
323               }
324           
325               /** Returns true if the list is empty (i.e., has zero elements).
326 mike  1.2     */
327               size_t is_empty() const 
328               { 
329           	AutoLock al(*this);
330           	return _rep.empty(); 
331               }
332           
333               /** Obtains a pointer to the element at the front of the list.
334               */
335               ElemType* front() 
336               { 
337           	AutoLock al(*this);
338           	return static_cast<ElemType*>(_rep.front()); 
339               }
340           
341               /** Obtains a const-pointer to the element at the front of the list.
342               */
343               const ElemType* front() const
344               { 
345           	AutoLock al(*this);
346           	return static_cast<const ElemType*>(_rep.front()); 
347 mike  1.2     }
348           
349               /** Obtains a pointer to the element at the back of the list.
350               */
351               ElemType* back() 
352               { 
353           	AutoLock al(*this);
354           	return static_cast<ElemType*>(_rep.back()); 
355               }
356           
357               /** Obtains a const-pointer to the element at the back of the list.
358               */
359               const ElemType* back() const
360               { 
361           	AutoLock al(*this);
362           	return static_cast<const ElemType*>(_rep.back()); 
363               }
364           
365               /** Returns the element after elem (used to iterate list).
366               */
367               ElemType* next_of(ElemType* elem) 
368 mike  1.2     {
369           	return static_cast<ElemType*>(elem->next);
370               }
371           
372               /** Returns the element before elem (used to iterate list).
373               */
374               ElemType* prev_of(ElemType* elem) 
375               {
376           	return static_cast<ElemType*>(elem->prev);
377               }
378           
379               /** Insert elem at the front of the list.
380               */
381               void insert_front(ElemType* elem)
382               {
383           	AutoLock al(*this);
384           	_rep.insert_front(elem);
385               }
386           
387               /** Insert elem at the back of the list.
388               */
389 mike  1.2     void insert_back(ElemType* elem)
390               {
391           	AutoLock al(*this);
392           	_rep.insert_back(elem);
393               }
394           
395               /** Insert elem after pos.
396               */
397               void insert_after(ElemType* pos, ElemType* elem)
398               {
399           	AutoLock al(*this);
400           	_rep.insert_after(pos, elem);
401               }
402           
403               /** Insert elem before pos.
404               */
405               void insert_before(ElemType* pos, ElemType* elem)
406               {
407           	AutoLock al(*this);
408           	_rep.insert_before(pos, elem);
409               }
410 mike  1.2 
411               /** Remove the given element.
412               */
413               void remove(ElemType* pos)
414               {
415           	AutoLock al(*this);
416           	_rep.remove(pos);
417               }
418           
419               /** Returns true if the list contains the given element.
420               */
421               bool contains(const ElemType* elem)
422               {
423           	AutoLock al(*this);
424           	return _rep.contains(elem);
425               }
426           
427               /** Removes and returns the element at the front of the list.
428               */
429               ElemType* remove_front()
430               {
431 mike  1.2 	AutoLock al(*this);
432           	return static_cast<ElemType*>(_rep.remove_front());
433               }
434           
435               /** Removes and returns the element at the back of the list.
436               */
437               ElemType* remove_back()
438               {
439           	AutoLock al(*this);
440           	return static_cast<ElemType*>(_rep.remove_back());
441               }
442           
443               /** Attempts to find an element in the list that satisfies the equal()
444                   predicate. Returns first element satisfying equal() or null if none.
445               */
446               ElemType* find(Equal equal, const void* client_data)
447               {
448           	AutoLock al(*this);
449           	return static_cast<ElemType*>(
450           	    _rep.find(ListRep::Equal(equal), client_data));
451               }
452 mike  1.2 
453               /** Attempts to remove the element in the list that satisfies the equal()
454                   predicate. Removes and returns the first element satisfying equal() or
455           	null if none.
456               */
457               ElemType* remove(Equal equal, const void* client_data)
458               {
459           	AutoLock al(*this);
460           	return static_cast<ElemType*>(
461           	    _rep.remove(ListRep::Equal(equal), client_data));
462               }
463           
464               /** Apply the given function to every element of the list.
465               */
466               void apply(Apply apply, const void* client_data)
467               {
468           	AutoLock al(*this);
469           	_rep.apply(ListRep::Apply(apply), client_data);
470               }
471           
472               /** Lock the list.
473 mike  1.2     */
474               void lock() { _lock.lock(); }
475           
476               /** Try to lock the list.
477               */
478               void try_lock() { _lock.try_lock(); }
479           
480               /** Unlock the list.
481               */
482               void unlock() { _lock.unlock(); }
483           
484               /** Get reference to lock type.
485               */
486               LockType& getLock() const { return ((This*)this)->_lock; }
487           
488               /** An instance of this class is used to lock this list on construction
489           	and later unlock it on destruction.
490               */
491               class AutoLock
492               {
493               public:
494 mike  1.2 
495           	/**
496           	*/
497           	AutoLock(const This& list) : _lock(list.getLock())
498           	{
499           	    _lock.lock();
500           	}
501           
502           	/**
503           	*/
504           	~AutoLock() 
505           	{
506           	    _lock.unlock();
507           	}
508           
509               private:
510           	LockType& _lock;
511               };
512           
513           private:
514           
515 mike  1.2     static void _destructor(Linkable* ptr)
516               {
517           	delete static_cast<ElemType*>(ptr);
518               }
519           
520               ListRep _rep;
521               LockType _lock;
522           };
523           
524           PEGASUS_NAMESPACE_END
525           
526           #endif /* _Pegasus_Common_List_h */

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2