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.14  2004/11/08 02:34:18  csoutheren
00028  * Refactored code to (hopefully) compile on Linux
00029  *
00030  * Revision 1.13  2004/11/07 12:55:38  rjongbloed
00031  * Fixed safe ptr casting so keeps associated collection for use in for loops.
00032  *
00033  * Revision 1.12  2004/10/28 12:19:44  rjongbloed
00034  * Added oeprator! to assure test for NULL that some people use is correct for PSafePtr
00035  *
00036  * Revision 1.11  2004/10/14 12:31:45  rjongbloed
00037  * Added synchronous mode for safe collection RemoveAll() to wait until all objects
00038  *   have actually been deleted before returning.
00039  *
00040  * Revision 1.10  2004/10/04 12:54:33  rjongbloed
00041  * Added functions for locking an unlocking to "auto-unlock" classes.
00042  *
00043  * Revision 1.9  2004/08/12 12:37:40  rjongbloed
00044  * Fixed bug recently introduced so removes deleted object from deletion list.
00045  * Also changed removal list to be correct type.
00046  *
00047  * Revision 1.8  2004/08/05 12:15:56  rjongbloed
00048  * Added classes for auto unlocking read only and read write mutex on
00049  *   PSafeObject - similar to PWaitAndSIgnal.
00050  * Utilised mutable keyword for mutex and improved the constness of functions.
00051  * Added DisallowDeleteObjects to safe collections so can have a PSafeObject in
00052  *   multiple collections.
00053  * Added a tempalte function to do casting of PSafePtr to a PSafePtr of a derived
00054  *   class.
00055  * Assured that a PSafeObject present on a collection always increments its
00056  *   reference count so while in collection it is not deleted.
00057  *
00058  * Revision 1.7  2002/12/10 07:36:57  robertj
00059  * Fixed possible deadlock in PSafeCollection find functions.
00060  *
00061  * Revision 1.6  2002/10/29 00:06:14  robertj
00062  * Changed template classes so things like PSafeList actually creates the
00063  *   base collection class as well.
00064  * Allowed for the PSafeList::Append() to return a locked pointer to the
00065  *   object just appended.
00066  *
00067  * Revision 1.5  2002/10/04 08:22:40  robertj
00068  * Changed read/write mutex so can be called by same thread without deadlock
00069  *   removing the need to a lock count in safe pointer.
00070  * Added asserts if try and dereference a NULL safe pointer.
00071  * Added more documentation on behaviour.
00072  *
00073  * Revision 1.4  2002/09/16 01:08:59  robertj
00074  * Added #define so can select if #pragma interface/implementation is used on
00075  *   platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan.
00076  *
00077  * Revision 1.3  2002/08/29 06:51:11  robertj
00078  * Added optimisiation, separate mutex for toBeRemoved list.
00079  *
00080  * Revision 1.2  2002/05/06 00:44:45  robertj
00081  * Made the lock/unlock read only const so can be used in const functions.
00082  *
00083  * Revision 1.1  2002/05/01 04:16:43  robertj
00084  * Added thread safe collection classes.
00085  *
00086  */
00087  
00088 #ifndef _SAFE_COLLECTION_H
00089 #define _SAFE_COLLECTION_H
00090 
00091 #ifdef P_USE_PRAGMA
00092 #pragma interface
00093 #endif
00094 
00095 
00154 class PSafeObject : public PObject
00155 {
00156     PCLASSINFO(PSafeObject, PObject);
00157   public:
00162     PSafeObject();
00164 
00185     BOOL SafeReference();
00186 
00194     void SafeDereference();
00195 
00213     BOOL LockReadOnly() const;
00214 
00225     void UnlockReadOnly() const;
00226 
00244     BOOL LockReadWrite();
00245 
00256     void UnlockReadWrite();
00257 
00267     void SafeRemove();
00268 
00276     BOOL SafelyCanBeDeleted() const;
00278 
00279   protected:
00280     mutable PMutex          safetyMutex;
00281             unsigned        safeReferenceCount;
00282             BOOL            safelyBeingRemoved;
00283     mutable PReadWriteMutex safeInUseFlag;
00284 };
00285 
00286 
00289 class PSafeLockReadOnly
00290 {
00291   public:
00292     PSafeLockReadOnly(const PSafeObject & object);
00293     ~PSafeLockReadOnly();
00294     BOOL Lock();
00295     void Unlock();
00296     BOOL IsLocked() const { return locked; }
00297     bool operator!() const { return !locked; }
00298 
00299   protected:
00300     PSafeObject & safeObject;
00301     BOOL          locked;
00302 };
00303 
00304 
00305 
00308 class PSafeLockReadWrite
00309 {
00310   public:
00311     PSafeLockReadWrite(const PSafeObject & object);
00312     ~PSafeLockReadWrite();
00313     BOOL Lock();
00314     void Unlock();
00315     BOOL IsLocked() const { return locked; }
00316     bool operator!() const { return !locked; }
00317 
00318   protected:
00319     PSafeObject & safeObject;
00320     BOOL          locked;
00321 };
00322 
00323 
00324 
00337 class PSafeCollection : public PObject
00338 {
00339     PCLASSINFO(PSafeCollection, PObject);
00340   public:
00346     PSafeCollection(
00347       PCollection * collection    
00348      );
00349 
00353     ~PSafeCollection();
00355 
00358   protected:
00367     virtual BOOL SafeRemove(
00368       PSafeObject * obj   
00369     );
00370 
00379     virtual BOOL SafeRemoveAt(
00380       PINDEX idx    
00381     );
00382 
00383   public:
00386     virtual void RemoveAll(
00387       BOOL synchronous = FALSE  
00388     );
00389 
00394     void AllowDeleteObjects(
00395       BOOL yes = TRUE   
00396     ) { deleteObjects = yes; }
00397 
00402     void DisallowDeleteObjects() { deleteObjects = FALSE; }
00403 
00408     virtual BOOL DeleteObjectsToBeRemoved();
00409 
00412     virtual void DeleteObject(PObject * object) const;
00413 
00416     virtual void SetAutoDeleteObjects();
00417 
00422     PINDEX GetSize() const;
00423 
00428     BOOL IsEmpty() const { return GetSize() == 0; }
00429 
00432     const PMutex & GetMutex() const { return collectionMutex; }
00434 
00435   protected:
00436     void SafeRemoveObject(PSafeObject * obj);
00437     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00438 
00439     PCollection  *     collection;
00440     mutable PMutex     collectionMutex;
00441     BOOL               deleteObjects;
00442     PList<PSafeObject> toBeRemoved;
00443     PMutex             removalMutex;
00444     PTimer             deleteObjectsTimer;
00445 
00446   friend class PSafePtrBase;
00447 };
00448 
00449 
00450 enum PSafetyMode {
00451   PSafeReference,
00452   PSafeReadOnly,
00453   PSafeReadWrite
00454 };
00455 
00471 class PSafePtrBase : public PObject
00472 {
00473     PCLASSINFO(PSafePtrBase, PObject);
00474 
00477   protected:
00485     PSafePtrBase(
00486       PSafeObject * obj = NULL,         
00487       PSafetyMode mode = PSafeReference 
00488     );
00489 
00497     PSafePtrBase(
00498       const PSafeCollection & safeCollection, 
00499       PSafetyMode mode,                       
00500       PINDEX idx                              
00501     );
00502 
00510     PSafePtrBase(
00511       const PSafeCollection & safeCollection, 
00512       PSafetyMode mode,                       
00513       PSafeObject * obj                       
00514     );
00515 
00521     PSafePtrBase(
00522       const PSafePtrBase & enumerator   
00523     );
00524 
00525   public:
00528     ~PSafePtrBase();
00530 
00537     Comparison Compare(
00538       const PObject & obj   
00539     ) const;
00541 
00546     bool operator!() const { return currentObject == NULL; }
00547 
00550     PSafetyMode GetSafetyMode() const { return lockMode; }
00551 
00554     BOOL SetSafetyMode(
00555       PSafetyMode mode  
00556     );
00557 
00560     const PSafeCollection * GetCollection() const { return collection; }
00562 
00563     void Assign(const PSafePtrBase & ptr);
00564     void Assign(const PSafeCollection & safeCollection);
00565     void Assign(PSafeObject * obj);
00566     void Assign(PINDEX idx);
00567 
00568   protected:
00569     void Next();
00570     void Previous();
00571 
00572     enum EnterSafetyModeOption {
00573       WithReference,
00574       AlreadyReferenced
00575     };
00576     BOOL EnterSafetyMode(EnterSafetyModeOption ref);
00577 
00578     enum ExitSafetyModeOption {
00579       WithDereference,
00580       NoDereference
00581     };
00582     void ExitSafetyMode(ExitSafetyModeOption ref);
00583 
00584   protected:
00585     const PSafeCollection * collection;
00586     PSafeObject           * currentObject;
00587     PSafetyMode             lockMode;
00588 };
00589 
00590 
00612 template <class T> class PSafePtr : public PSafePtrBase
00613 {
00614     PCLASSINFO(PSafePtr, PSafePtrBase);
00615   public:
00625     PSafePtr(
00626       T * obj = NULL,                   
00627       PSafetyMode mode = PSafeReference 
00628     ) : PSafePtrBase(obj, mode) { }
00629 
00637     PSafePtr(
00638       const PSafeCollection & safeCollection, 
00639       PSafetyMode mode = PSafeReadWrite,      
00640       PINDEX idx = 0                          
00641     ) : PSafePtrBase(safeCollection, mode, idx) { }
00642 
00650     PSafePtr(
00651       const PSafeCollection & safeCollection, 
00652       PSafetyMode mode,                       
00653       PSafeObject * obj                       
00654     ) : PSafePtrBase(safeCollection, mode, obj) { }
00655 
00661     PSafePtr(
00662       const PSafePtr & ptr   
00663     ) : PSafePtrBase(ptr) { }
00664 
00670     PSafePtr & operator=(const PSafePtr & ptr)
00671       {
00672         Assign(ptr);
00673         return *this;
00674       }
00675 
00680     PSafePtr & operator=(const PSafeCollection & safeCollection)
00681       {
00682         Assign(safeCollection);
00683         return *this;
00684       }
00685 
00701     PSafePtr & operator=(T * obj)
00702       {
00703         Assign(obj);
00704         return *this;
00705       }
00706 
00716     PSafePtr & operator=(PINDEX idx)
00717       {
00718         Assign(idx);
00719         return *this;
00720       }
00722 
00727     operator T*()    const { return  (T *)currentObject; }
00728 
00731     T & operator*()  const { return *(T *)PAssertNULL(currentObject); }
00732 
00735     T * operator->() const { return  (T *)PAssertNULL(currentObject); }
00736 
00741     T * operator++(int)
00742       {
00743         T * previous = (T *)currentObject;
00744         Next();
00745         return previous;
00746       }
00747 
00752     T * operator++()
00753       {
00754         Next();
00755         return (T *)currentObject;
00756       }
00757 
00762     T * operator--(int)
00763       {
00764         T * previous = (T *)currentObject;
00765         Previous();
00766         return previous;
00767       }
00768 
00773     T * operator--()
00774       {
00775         Previous();
00776         return (T *)currentObject;
00777       }
00779 
00783       /*
00784   template <class Base>
00785   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00786   {
00787     PSafePtr<T> newPtr;
00788     Base * realPtr = oldPtr;
00789     if (realPtr != NULL && PIsDescendant(realPtr, T))
00790       newPtr.Assign(oldPtr);
00791     return newPtr;
00792   }
00793   */
00794 };
00795 
00796 
00800 template <class Base, class Derived>
00801 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00802 {
00803 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00804     PSafePtr<Derived> newPtr;
00805     Base * realPtr = oldPtr;
00806     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00807       newPtr.Assign(oldPtr);
00808     return newPtr;
00809 }
00810 
00811 
00822 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00823 {
00824     PCLASSINFO(PSafeColl, PSafeCollection);
00825   public:
00830     PSafeColl()
00831       : PSafeCollection(new Coll)
00832       { }
00834 
00841     virtual PSafePtr<Base> Append(
00842       Base * obj,       
00843       PSafetyMode mode = PSafeReference
00844     ) {
00845         PWaitAndSignal mutex(collectionMutex);
00846         if (!obj->SafeReference())
00847           return NULL;
00848         return PSafePtr<Base>(*this, mode, collection->Append(obj));
00849       }
00850 
00859     virtual BOOL Remove(
00860       Base * obj          
00861     ) {
00862         return SafeRemove(obj);
00863       }
00864 
00873     virtual BOOL RemoveAt(
00874       PINDEX idx     
00875     ) {
00876         return SafeRemoveAt(idx);
00877       }
00878 
00884     virtual PSafePtr<Base> GetAt(
00885       PINDEX idx,
00886       PSafetyMode mode = PSafeReadWrite
00887     ) {
00888         return PSafePtr<Base>(*this, mode, idx);
00889       }
00890 
00896     virtual PSafePtr<Base> FindWithLock(
00897       const Base & value,
00898       PSafetyMode mode = PSafeReadWrite
00899     ) {
00900         collectionMutex.Wait();
00901         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00902         collectionMutex.Signal();
00903         ptr.SetSafetyMode(mode);
00904         return ptr;
00905       }
00907 };
00908 
00909 
00914 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00915 {
00916 };
00917 
00918 
00923 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
00924 {
00925 };
00926 
00927 
00932 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
00933 {
00934 };
00935 
00936 
00947 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
00948 {
00949     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
00950   public:
00955     PSafeDictionaryBase()
00956       : PSafeCollection(new Coll) { }
00958 
00965     virtual void SetAt(const Key & key, Base * obj)
00966       {
00967         collectionMutex.Wait();
00968         SafeRemove(((Coll *)collection)->GetAt(key));
00969         if (obj->SafeReference())
00970           ((Coll *)collection)->SetAt(key, obj);
00971         collectionMutex.Signal();
00972       }
00973 
00982     virtual BOOL RemoveAt(
00983       const Key & key   
00984     ) {
00985         PWaitAndSignal mutex(collectionMutex);
00986         return SafeRemove(((Coll *)collection)->GetAt(key));
00987       }
00988 
00991     virtual BOOL Contains(
00992       const Key & key
00993     ) {
00994         PWaitAndSignal lock(collectionMutex);
00995         return ((Coll *)collection)->Contains(key);
00996       }
00997 
01003     virtual PSafePtr<Base> GetAt(
01004       PINDEX idx,
01005       PSafetyMode mode = PSafeReadWrite
01006     ) {
01007         return PSafePtr<Base>(*this, mode, idx);
01008       }
01009 
01015     virtual PSafePtr<Base> FindWithLock(
01016       const Key & key,
01017       PSafetyMode mode = PSafeReadWrite
01018     ) {
01019         collectionMutex.Wait();
01020         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01021         collectionMutex.Signal();
01022         ptr.SetSafetyMode(mode);
01023         return ptr;
01024       }
01026 };
01027 
01028 
01033 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01034 {
01035 };
01036 
01037 
01038 #endif // _SAFE_COLLECTION_H
01039 
01040 

Generated on Mon Feb 21 20:43:09 2005 for PWLib by  doxygen 1.4.1