Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

safecoll.h

Go to the documentation of this file.
00001 /*
00002  * safecoll.h
00003  *
00004  * Thread safe collection classes.
00005  *
00006  * Portable Windows Library
00007  *
00008  * Copyright (c) 2002 Equivalence Pty. Ltd.
00009  *
00010  * The contents of this file are subject to the Mozilla Public License
00011  * Version 1.0 (the "License"); you may not use this file except in
00012  * compliance with the License. You may obtain a copy of the License at
00013  * http://www.mozilla.org/MPL/
00014  *
00015  * Software distributed under the License is distributed on an "AS IS"
00016  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00017  * the License for the specific language governing rights and limitations
00018  * under the License.
00019  *
00020  * The Original Code is Portable Windows Library.
00021  *
00022  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
00023  *
00024  * Contributor(s): ______________________________________.
00025  *
00026  * $Log: safecoll.h,v $
00027  * Revision 1.15  2005/11/25 03:43:47  csoutheren
00028  * Fixed function argument comments to be compatible with Doxygen
00029  *
00030  * Revision 1.14  2004/11/08 02:34:18  csoutheren
00031  * Refactored code to (hopefully) compile on Linux
00032  *
00033  * Revision 1.13  2004/11/07 12:55:38  rjongbloed
00034  * Fixed safe ptr casting so keeps associated collection for use in for loops.
00035  *
00036  * Revision 1.12  2004/10/28 12:19:44  rjongbloed
00037  * Added oeprator! to assure test for NULL that some people use is correct for PSafePtr
00038  *
00039  * Revision 1.11  2004/10/14 12:31:45  rjongbloed
00040  * Added synchronous mode for safe collection RemoveAll() to wait until all objects
00041  *   have actually been deleted before returning.
00042  *
00043  * Revision 1.10  2004/10/04 12:54:33  rjongbloed
00044  * Added functions for locking an unlocking to "auto-unlock" classes.
00045  *
00046  * Revision 1.9  2004/08/12 12:37:40  rjongbloed
00047  * Fixed bug recently introduced so removes deleted object from deletion list.
00048  * Also changed removal list to be correct type.
00049  *
00050  * Revision 1.8  2004/08/05 12:15:56  rjongbloed
00051  * Added classes for auto unlocking read only and read write mutex on
00052  *   PSafeObject - similar to PWaitAndSIgnal.
00053  * Utilised mutable keyword for mutex and improved the constness of functions.
00054  * Added DisallowDeleteObjects to safe collections so can have a PSafeObject in
00055  *   multiple collections.
00056  * Added a tempalte function to do casting of PSafePtr to a PSafePtr of a derived
00057  *   class.
00058  * Assured that a PSafeObject present on a collection always increments its
00059  *   reference count so while in collection it is not deleted.
00060  *
00061  * Revision 1.7  2002/12/10 07:36:57  robertj
00062  * Fixed possible deadlock in PSafeCollection find functions.
00063  *
00064  * Revision 1.6  2002/10/29 00:06:14  robertj
00065  * Changed template classes so things like PSafeList actually creates the
00066  *   base collection class as well.
00067  * Allowed for the PSafeList::Append() to return a locked pointer to the
00068  *   object just appended.
00069  *
00070  * Revision 1.5  2002/10/04 08:22:40  robertj
00071  * Changed read/write mutex so can be called by same thread without deadlock
00072  *   removing the need to a lock count in safe pointer.
00073  * Added asserts if try and dereference a NULL safe pointer.
00074  * Added more documentation on behaviour.
00075  *
00076  * Revision 1.4  2002/09/16 01:08:59  robertj
00077  * Added #define so can select if #pragma interface/implementation is used on
00078  *   platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan.
00079  *
00080  * Revision 1.3  2002/08/29 06:51:11  robertj
00081  * Added optimisiation, separate mutex for toBeRemoved list.
00082  *
00083  * Revision 1.2  2002/05/06 00:44:45  robertj
00084  * Made the lock/unlock read only const so can be used in const functions.
00085  *
00086  * Revision 1.1  2002/05/01 04:16:43  robertj
00087  * Added thread safe collection classes.
00088  *
00089  */
00090  
00091 #ifndef _SAFE_COLLECTION_H
00092 #define _SAFE_COLLECTION_H
00093 
00094 #ifdef P_USE_PRAGMA
00095 #pragma interface
00096 #endif
00097 
00098 
00157 class PSafeObject : public PObject
00158 {
00159     PCLASSINFO(PSafeObject, PObject);
00160   public:
00165     PSafeObject();
00167 
00188     BOOL SafeReference();
00189 
00197     void SafeDereference();
00198 
00216     BOOL LockReadOnly() const;
00217 
00228     void UnlockReadOnly() const;
00229 
00247     BOOL LockReadWrite();
00248 
00259     void UnlockReadWrite();
00260 
00270     void SafeRemove();
00271 
00279     BOOL SafelyCanBeDeleted() const;
00281 
00282   protected:
00283     mutable PMutex          safetyMutex;
00284             unsigned        safeReferenceCount;
00285             BOOL            safelyBeingRemoved;
00286     mutable PReadWriteMutex safeInUseFlag;
00287 };
00288 
00289 
00292 class PSafeLockReadOnly
00293 {
00294   public:
00295     PSafeLockReadOnly(const PSafeObject & object);
00296     ~PSafeLockReadOnly();
00297     BOOL Lock();
00298     void Unlock();
00299     BOOL IsLocked() const { return locked; }
00300     bool operator!() const { return !locked; }
00301 
00302   protected:
00303     PSafeObject & safeObject;
00304     BOOL          locked;
00305 };
00306 
00307 
00308 
00311 class PSafeLockReadWrite
00312 {
00313   public:
00314     PSafeLockReadWrite(const PSafeObject & object);
00315     ~PSafeLockReadWrite();
00316     BOOL Lock();
00317     void Unlock();
00318     BOOL IsLocked() const { return locked; }
00319     bool operator!() const { return !locked; }
00320 
00321   protected:
00322     PSafeObject & safeObject;
00323     BOOL          locked;
00324 };
00325 
00326 
00327 
00340 class PSafeCollection : public PObject
00341 {
00342     PCLASSINFO(PSafeCollection, PObject);
00343   public:
00349     PSafeCollection(
00350       PCollection * collection    
00351      );
00352 
00356     ~PSafeCollection();
00358 
00361   protected:
00370     virtual BOOL SafeRemove(
00371       PSafeObject * obj   
00372     );
00373 
00382     virtual BOOL SafeRemoveAt(
00383       PINDEX idx    
00384     );
00385 
00386   public:
00389     virtual void RemoveAll(
00390       BOOL synchronous = FALSE  
00391     );
00392 
00397     void AllowDeleteObjects(
00398       BOOL yes = TRUE   
00399     ) { deleteObjects = yes; }
00400 
00405     void DisallowDeleteObjects() { deleteObjects = FALSE; }
00406 
00411     virtual BOOL DeleteObjectsToBeRemoved();
00412 
00415     virtual void DeleteObject(PObject * object) const;
00416 
00419     virtual void SetAutoDeleteObjects();
00420 
00425     PINDEX GetSize() const;
00426 
00431     BOOL IsEmpty() const { return GetSize() == 0; }
00432 
00435     const PMutex & GetMutex() const { return collectionMutex; }
00437 
00438   protected:
00439     void SafeRemoveObject(PSafeObject * obj);
00440     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00441 
00442     PCollection  *     collection;
00443     mutable PMutex     collectionMutex;
00444     BOOL               deleteObjects;
00445     PList<PSafeObject> toBeRemoved;
00446     PMutex             removalMutex;
00447     PTimer             deleteObjectsTimer;
00448 
00449   friend class PSafePtrBase;
00450 };
00451 
00452 
00453 enum PSafetyMode {
00454   PSafeReference,
00455   PSafeReadOnly,
00456   PSafeReadWrite
00457 };
00458 
00474 class PSafePtrBase : public PObject
00475 {
00476     PCLASSINFO(PSafePtrBase, PObject);
00477 
00480   protected:
00488     PSafePtrBase(
00489       PSafeObject * obj = NULL,         
00490       PSafetyMode mode = PSafeReference 
00491     );
00492 
00500     PSafePtrBase(
00501       const PSafeCollection & safeCollection, 
00502       PSafetyMode mode,                       
00503       PINDEX idx                              
00504     );
00505 
00513     PSafePtrBase(
00514       const PSafeCollection & safeCollection, 
00515       PSafetyMode mode,                       
00516       PSafeObject * obj                       
00517     );
00518 
00524     PSafePtrBase(
00525       const PSafePtrBase & enumerator   
00526     );
00527 
00528   public:
00531     ~PSafePtrBase();
00533 
00540     Comparison Compare(
00541       const PObject & obj   
00542     ) const;
00544 
00549     bool operator!() const { return currentObject == NULL; }
00550 
00553     PSafetyMode GetSafetyMode() const { return lockMode; }
00554 
00557     BOOL SetSafetyMode(
00558       PSafetyMode mode  
00559     );
00560 
00563     const PSafeCollection * GetCollection() const { return collection; }
00565 
00566     void Assign(const PSafePtrBase & ptr);
00567     void Assign(const PSafeCollection & safeCollection);
00568     void Assign(PSafeObject * obj);
00569     void Assign(PINDEX idx);
00570 
00571   protected:
00572     void Next();
00573     void Previous();
00574 
00575     enum EnterSafetyModeOption {
00576       WithReference,
00577       AlreadyReferenced
00578     };
00579     BOOL EnterSafetyMode(EnterSafetyModeOption ref);
00580 
00581     enum ExitSafetyModeOption {
00582       WithDereference,
00583       NoDereference
00584     };
00585     void ExitSafetyMode(ExitSafetyModeOption ref);
00586 
00587   protected:
00588     const PSafeCollection * collection;
00589     PSafeObject           * currentObject;
00590     PSafetyMode             lockMode;
00591 };
00592 
00593 
00615 template <class T> class PSafePtr : public PSafePtrBase
00616 {
00617     PCLASSINFO(PSafePtr, PSafePtrBase);
00618   public:
00628     PSafePtr(
00629       T * obj = NULL,                   
00630       PSafetyMode mode = PSafeReference 
00631     ) : PSafePtrBase(obj, mode) { }
00632 
00640     PSafePtr(
00641       const PSafeCollection & safeCollection, 
00642       PSafetyMode mode = PSafeReadWrite,      
00643       PINDEX idx = 0                          
00644     ) : PSafePtrBase(safeCollection, mode, idx) { }
00645 
00653     PSafePtr(
00654       const PSafeCollection & safeCollection, 
00655       PSafetyMode mode,                       
00656       PSafeObject * obj                       
00657     ) : PSafePtrBase(safeCollection, mode, obj) { }
00658 
00664     PSafePtr(
00665       const PSafePtr & ptr   
00666     ) : PSafePtrBase(ptr) { }
00667 
00673     PSafePtr & operator=(const PSafePtr & ptr)
00674       {
00675         Assign(ptr);
00676         return *this;
00677       }
00678 
00683     PSafePtr & operator=(const PSafeCollection & safeCollection)
00684       {
00685         Assign(safeCollection);
00686         return *this;
00687       }
00688 
00704     PSafePtr & operator=(T * obj)
00705       {
00706         Assign(obj);
00707         return *this;
00708       }
00709 
00719     PSafePtr & operator=(PINDEX idx)
00720       {
00721         Assign(idx);
00722         return *this;
00723       }
00725 
00730     operator T*()    const { return  (T *)currentObject; }
00731 
00734     T & operator*()  const { return *(T *)PAssertNULL(currentObject); }
00735 
00738     T * operator->() const { return  (T *)PAssertNULL(currentObject); }
00739 
00744     T * operator++(int)
00745       {
00746         T * previous = (T *)currentObject;
00747         Next();
00748         return previous;
00749       }
00750 
00755     T * operator++()
00756       {
00757         Next();
00758         return (T *)currentObject;
00759       }
00760 
00765     T * operator--(int)
00766       {
00767         T * previous = (T *)currentObject;
00768         Previous();
00769         return previous;
00770       }
00771 
00776     T * operator--()
00777       {
00778         Previous();
00779         return (T *)currentObject;
00780       }
00782 
00786       /*
00787   template <class Base>
00788   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00789   {
00790     PSafePtr<T> newPtr;
00791     Base * realPtr = oldPtr;
00792     if (realPtr != NULL && PIsDescendant(realPtr, T))
00793       newPtr.Assign(oldPtr);
00794     return newPtr;
00795   }
00796   */
00797 };
00798 
00799 
00803 template <class Base, class Derived>
00804 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00805 {
00806 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00807     PSafePtr<Derived> newPtr;
00808     Base * realPtr = oldPtr;
00809     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00810       newPtr.Assign(oldPtr);
00811     return newPtr;
00812 }
00813 
00814 
00825 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00826 {
00827     PCLASSINFO(PSafeColl, PSafeCollection);
00828   public:
00833     PSafeColl()
00834       : PSafeCollection(new Coll)
00835       { }
00837 
00844     virtual PSafePtr<Base> Append(
00845       Base * obj,       
00846       PSafetyMode mode = PSafeReference
00847     ) {
00848         PWaitAndSignal mutex(collectionMutex);
00849         if (!obj->SafeReference())
00850           return NULL;
00851         return PSafePtr<Base>(*this, mode, collection->Append(obj));
00852       }
00853 
00862     virtual BOOL Remove(
00863       Base * obj          
00864     ) {
00865         return SafeRemove(obj);
00866       }
00867 
00876     virtual BOOL RemoveAt(
00877       PINDEX idx     
00878     ) {
00879         return SafeRemoveAt(idx);
00880       }
00881 
00887     virtual PSafePtr<Base> GetAt(
00888       PINDEX idx,
00889       PSafetyMode mode = PSafeReadWrite
00890     ) {
00891         return PSafePtr<Base>(*this, mode, idx);
00892       }
00893 
00899     virtual PSafePtr<Base> FindWithLock(
00900       const Base & value,
00901       PSafetyMode mode = PSafeReadWrite
00902     ) {
00903         collectionMutex.Wait();
00904         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00905         collectionMutex.Signal();
00906         ptr.SetSafetyMode(mode);
00907         return ptr;
00908       }
00910 };
00911 
00912 
00917 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00918 {
00919 };
00920 
00921 
00926 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
00927 {
00928 };
00929 
00930 
00935 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
00936 {
00937 };
00938 
00939 
00950 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
00951 {
00952     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
00953   public:
00958     PSafeDictionaryBase()
00959       : PSafeCollection(new Coll) { }
00961 
00968     virtual void SetAt(const Key & key, Base * obj)
00969       {
00970         collectionMutex.Wait();
00971         SafeRemove(((Coll *)collection)->GetAt(key));
00972         if (obj->SafeReference())
00973           ((Coll *)collection)->SetAt(key, obj);
00974         collectionMutex.Signal();
00975       }
00976 
00985     virtual BOOL RemoveAt(
00986       const Key & key   
00987     ) {
00988         PWaitAndSignal mutex(collectionMutex);
00989         return SafeRemove(((Coll *)collection)->GetAt(key));
00990       }
00991 
00994     virtual BOOL Contains(
00995       const Key & key
00996     ) {
00997         PWaitAndSignal lock(collectionMutex);
00998         return ((Coll *)collection)->Contains(key);
00999       }
01000 
01006     virtual PSafePtr<Base> GetAt(
01007       PINDEX idx,
01008       PSafetyMode mode = PSafeReadWrite
01009     ) {
01010         return PSafePtr<Base>(*this, mode, idx);
01011       }
01012 
01018     virtual PSafePtr<Base> FindWithLock(
01019       const Key & key,
01020       PSafetyMode mode = PSafeReadWrite
01021     ) {
01022         collectionMutex.Wait();
01023         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01024         collectionMutex.Signal();
01025         ptr.SetSafetyMode(mode);
01026         return ptr;
01027       }
01029 };
01030 
01031 
01036 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01037 {
01038 };
01039 
01040 
01041 #endif // _SAFE_COLLECTION_H
01042 
01043 

Generated on Thu Jun 15 15:24:29 2006 for PWLib by  doxygen 1.4.2