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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2