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  * $Revision: 22598 $
00027  * $Author: rjongbloed $
00028  * $Date: 2009-05-12 23:17:54 -0500 (Tue, 12 May 2009) $
00029  */
00030  
00031 #ifndef PTLIB_SAFE_COLLECTION_H
00032 #define PTLIB_SAFE_COLLECTION_H
00033 
00034 #ifdef P_USE_PRAGMA
00035 #pragma interface
00036 #endif
00037 
00038 
00097 class PSafeObject : public PObject
00098 {
00099     PCLASSINFO(PSafeObject, PObject);
00100   public:
00105     PSafeObject(
00106         PSafeObject * indirectLock = NULL 
00107     );
00109 
00130     PBoolean SafeReference();
00131 
00142     PBoolean SafeDereference();
00143 
00161     PBoolean LockReadOnly() const;
00162 
00173     void UnlockReadOnly() const;
00174 
00192     PBoolean LockReadWrite();
00193 
00204     void UnlockReadWrite();
00205 
00215     void SafeRemove();
00216 
00224     PBoolean SafelyCanBeDeleted() const;
00225 
00237     virtual bool GarbageCollection();
00239 
00240   private:
00241     mutable PMutex    safetyMutex;
00242     unsigned          safeReferenceCount;
00243     bool              safelyBeingRemoved;
00244     PReadWriteMutex   safeInUseMutex;
00245     PReadWriteMutex * safeInUse;
00246 
00247   friend class PSafeCollection;
00248 };
00249 
00250 
00253 class PSafeLockReadOnly
00254 {
00255   public:
00256     PSafeLockReadOnly(const PSafeObject & object);
00257     ~PSafeLockReadOnly();
00258     PBoolean Lock();
00259     void Unlock();
00260     PBoolean IsLocked() const { return locked; }
00261     bool operator!() const { return !locked; }
00262 
00263   protected:
00264     PSafeObject & safeObject;
00265     PBoolean          locked;
00266 };
00267 
00268 
00269 
00272 class PSafeLockReadWrite
00273 {
00274   public:
00275     PSafeLockReadWrite(const PSafeObject & object);
00276     ~PSafeLockReadWrite();
00277     PBoolean Lock();
00278     void Unlock();
00279     PBoolean IsLocked() const { return locked; }
00280     bool operator!() const { return !locked; }
00281 
00282   protected:
00283     PSafeObject & safeObject;
00284     PBoolean          locked;
00285 };
00286 
00287 
00288 
00301 class PSafeCollection : public PObject
00302 {
00303     PCLASSINFO(PSafeCollection, PObject);
00304   public:
00310     PSafeCollection(
00311       PCollection * collection    
00312      );
00313 
00317     ~PSafeCollection();
00319 
00322   protected:
00331     virtual PBoolean SafeRemove(
00332       PSafeObject * obj   
00333     );
00334 
00343     virtual PBoolean SafeRemoveAt(
00344       PINDEX idx    
00345     );
00346 
00347   public:
00350     virtual void RemoveAll(
00351       PBoolean synchronous = PFalse  
00352     );
00353 
00358     void AllowDeleteObjects(
00359       PBoolean yes = PTrue   
00360     ) { deleteObjects = yes; }
00361 
00366     void DisallowDeleteObjects() { deleteObjects = PFalse; }
00367 
00372     virtual PBoolean DeleteObjectsToBeRemoved();
00373 
00376     virtual void DeleteObject(PObject * object) const;
00377 
00380     virtual void SetAutoDeleteObjects();
00381 
00386     PINDEX GetSize() const;
00387 
00392     PBoolean IsEmpty() const { return GetSize() == 0; }
00393 
00396     const PMutex & GetMutex() const { return collectionMutex; }
00398 
00399   protected:
00400     void SafeRemoveObject(PSafeObject * obj);
00401     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00402 
00403     PCollection  *     collection;
00404     mutable PMutex     collectionMutex;
00405     PBoolean               deleteObjects;
00406     PList<PSafeObject> toBeRemoved;
00407     PMutex             removalMutex;
00408     PTimer             deleteObjectsTimer;
00409 
00410   friend class PSafePtrBase;
00411 };
00412 
00413 
00414 enum PSafetyMode {
00415   PSafeReference,
00416   PSafeReadOnly,
00417   PSafeReadWrite
00418 };
00419 
00432 class PSafePtrBase : public PObject
00433 {
00434     PCLASSINFO(PSafePtrBase, PObject);
00435 
00438   protected:
00446     PSafePtrBase(
00447       PSafeObject * obj = NULL,         
00448       PSafetyMode mode = PSafeReference 
00449     );
00450 
00458     PSafePtrBase(
00459       const PSafeCollection & safeCollection, 
00460       PSafetyMode mode,                       
00461       PINDEX idx                              
00462     );
00463 
00471     PSafePtrBase(
00472       const PSafeCollection & safeCollection, 
00473       PSafetyMode mode,                       
00474       PSafeObject * obj                       
00475     );
00476 
00482     PSafePtrBase(
00483       const PSafePtrBase & enumerator   
00484     );
00485 
00486   public:
00489     ~PSafePtrBase();
00491 
00498     virtual Comparison Compare(
00499       const PObject & obj   
00500     ) const;
00502 
00507     virtual void SetNULL();
00508 
00511     bool operator!() const { return currentObject == NULL; }
00512 
00515     PSafetyMode GetSafetyMode() const { return lockMode; }
00516 
00523     virtual PBoolean SetSafetyMode(
00524       PSafetyMode mode  
00525     );
00526 
00529     const PSafeCollection * GetCollection() const { return collection; }
00531 
00532     virtual void Assign(const PSafePtrBase & ptr);
00533     virtual void Assign(const PSafeCollection & safeCollection);
00534     virtual void Assign(PSafeObject * obj);
00535     virtual void Assign(PINDEX idx);
00536 
00537   protected:
00538     virtual void Next();
00539     virtual void Previous();
00540 
00541     enum EnterSafetyModeOption {
00542       WithReference,
00543       AlreadyReferenced
00544     };
00545     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00546 
00547     enum ExitSafetyModeOption {
00548       WithDereference,
00549       NoDereference
00550     };
00551     void ExitSafetyMode(ExitSafetyModeOption ref);
00552 
00553   protected:
00554     const PSafeCollection * collection;
00555     PSafeObject           * currentObject;
00556     PSafetyMode             lockMode;
00557 };
00558 
00559 
00572 class PSafePtrMultiThreaded : public PSafePtrBase
00573 {
00574     PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
00575 
00578   protected:
00586     PSafePtrMultiThreaded(
00587       PSafeObject * obj = NULL,         
00588       PSafetyMode mode = PSafeReference 
00589     );
00590 
00598     PSafePtrMultiThreaded(
00599       const PSafeCollection & safeCollection, 
00600       PSafetyMode mode,                       
00601       PINDEX idx                              
00602     );
00603 
00611     PSafePtrMultiThreaded(
00612       const PSafeCollection & safeCollection, 
00613       PSafetyMode mode,                       
00614       PSafeObject * obj                       
00615     );
00616 
00622     PSafePtrMultiThreaded(
00623       const PSafePtrMultiThreaded & enumerator   
00624     );
00625 
00626   public:
00629     ~PSafePtrMultiThreaded();
00631 
00638     virtual Comparison Compare(
00639       const PObject & obj   
00640     ) const;
00642 
00647     virtual void SetNULL();
00648 
00655     virtual PBoolean SetSafetyMode(
00656       PSafetyMode mode  
00657     );
00659 
00660     virtual void Assign(const PSafePtrMultiThreaded & ptr);
00661     virtual void Assign(const PSafePtrBase & ptr);
00662     virtual void Assign(const PSafeCollection & safeCollection);
00663     virtual void Assign(PSafeObject * obj);
00664     virtual void Assign(PINDEX idx);
00665 
00666   protected:
00667     virtual void Next();
00668     virtual void Previous();
00669 
00670   protected:
00671     mutable PMutex m_mutex;
00672 };
00673 
00674 
00695 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
00696 {
00697   public:
00707     PSafePtr(
00708       T * obj = NULL,                   
00709       PSafetyMode mode = PSafeReference 
00710     ) : BaseClass(obj, mode) { }
00711 
00719     PSafePtr(
00720       const PSafeCollection & safeCollection, 
00721       PSafetyMode mode = PSafeReadWrite,      
00722       PINDEX idx = 0                          
00723     ) : BaseClass(safeCollection, mode, idx) { }
00724 
00732     PSafePtr(
00733       const PSafeCollection & safeCollection, 
00734       PSafetyMode mode,                       
00735       PSafeObject * obj                       
00736     ) : BaseClass(safeCollection, mode, obj) { }
00737 
00743     PSafePtr(
00744       const PSafePtr & ptr   
00745     ) : BaseClass(ptr) { }
00746 
00752     PSafePtr & operator=(const PSafePtr & ptr)
00753       {
00754         BaseClass::Assign(ptr);
00755         return *this;
00756       }
00757 
00762     PSafePtr & operator=(const PSafeCollection & safeCollection)
00763       {
00764         BaseClass::Assign(safeCollection);
00765         return *this;
00766       }
00767 
00783     PSafePtr & operator=(T * obj)
00784       {
00785         Assign(obj);
00786         return *this;
00787       }
00788 
00798     PSafePtr & operator=(PINDEX idx)
00799       {
00800         BaseClass::Assign(idx);
00801         return *this;
00802       }
00804 
00809     operator T*()    const { return  (T *)BaseClass::currentObject; }
00810 
00813     T & operator*()  const { return *(T *)PAssertNULL(BaseClass::currentObject); }
00814 
00817     T * operator->() const { return  (T *)PAssertNULL(BaseClass::currentObject); }
00818 
00823     T * operator++(int)
00824       {
00825         T * previous = (T *)BaseClass::currentObject;
00826         BaseClass::Next();
00827         return previous;
00828       }
00829 
00834     T * operator++()
00835       {
00836         BaseClass::Next();
00837         return (T *)BaseClass::currentObject;
00838       }
00839 
00844     T * operator--(int)
00845       {
00846         T * previous = (T *)BaseClass::currentObject;
00847         BaseClass::Previous();
00848         return previous;
00849       }
00850 
00855     T * operator--()
00856       {
00857         BaseClass::Previous();
00858         return (T *)BaseClass::currentObject;
00859       }
00861 
00865       /*
00866   template <class Base>
00867   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00868   {
00869     PSafePtr<T> newPtr;
00870     Base * realPtr = oldPtr;
00871     if (realPtr != NULL && PIsDescendant(realPtr, T))
00872       newPtr.Assign(oldPtr);
00873     return newPtr;
00874   }
00875   */
00876 };
00877 
00878 
00882 template <class Base, class Derived>
00883 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00884 {
00885 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00886     PSafePtr<Derived> newPtr;
00887     Base * realPtr = oldPtr;
00888     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00889       newPtr.Assign(oldPtr);
00890     return newPtr;
00891 }
00892 
00893 
00904 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00905 {
00906     PCLASSINFO(PSafeColl, PSafeCollection);
00907   public:
00912     PSafeColl()
00913       : PSafeCollection(new Coll)
00914       { }
00916 
00923     virtual PSafePtr<Base> Append(
00924       Base * obj,       
00925       PSafetyMode mode = PSafeReference
00926     ) {
00927         PWaitAndSignal mutex(collectionMutex);
00928         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
00929             obj->SafeReference())
00930           return PSafePtr<Base>(*this, mode, collection->Append(obj));
00931         return NULL;
00932       }
00933 
00942     virtual PBoolean Remove(
00943       Base * obj          
00944     ) {
00945         return SafeRemove(obj);
00946       }
00947 
00956     virtual PBoolean RemoveAt(
00957       PINDEX idx     
00958     ) {
00959         return SafeRemoveAt(idx);
00960       }
00961 
00967     virtual PSafePtr<Base> GetAt(
00968       PINDEX idx,
00969       PSafetyMode mode = PSafeReadWrite
00970     ) {
00971         return PSafePtr<Base>(*this, mode, idx);
00972       }
00973 
00979     virtual PSafePtr<Base> FindWithLock(
00980       const Base & value,
00981       PSafetyMode mode = PSafeReadWrite
00982     ) {
00983         collectionMutex.Wait();
00984         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00985         collectionMutex.Signal();
00986         ptr.SetSafetyMode(mode);
00987         return ptr;
00988       }
00990 };
00991 
00992 
00997 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00998 {
00999   public:
01000     typedef PSafePtr<Base> value_type;
01001 };
01002 
01003 
01008 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
01009 {
01010   public:
01011     typedef PSafePtr<Base> value_type;
01012 };
01013 
01014 
01019 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
01020 {
01021   public:
01022     typedef PSafePtr<Base> value_type;
01023 };
01024 
01025 
01036 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
01037 {
01038     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
01039   public:
01044     PSafeDictionaryBase()
01045       : PSafeCollection(new Coll) { }
01047 
01054     virtual void SetAt(const Key & key, Base * obj)
01055       {
01056         collectionMutex.Wait();
01057         SafeRemove(((Coll *)collection)->GetAt(key));
01058         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
01059             obj->SafeReference())
01060           ((Coll *)collection)->SetAt(key, obj);
01061         collectionMutex.Signal();
01062       }
01063 
01072     virtual PBoolean RemoveAt(
01073       const Key & key   
01074     ) {
01075         PWaitAndSignal mutex(collectionMutex);
01076         return SafeRemove(((Coll *)collection)->GetAt(key));
01077       }
01078 
01081     virtual PBoolean Contains(
01082       const Key & key
01083     ) {
01084         PWaitAndSignal lock(collectionMutex);
01085         return ((Coll *)collection)->Contains(key);
01086       }
01087 
01093     virtual PSafePtr<Base> GetAt(
01094       PINDEX idx,
01095       PSafetyMode mode = PSafeReadWrite
01096     ) {
01097         return PSafePtr<Base>(*this, mode, idx);
01098       }
01099 
01105     virtual PSafePtr<Base> FindWithLock(
01106       const Key & key,
01107       PSafetyMode mode = PSafeReadWrite
01108     ) {
01109         collectionMutex.Wait();
01110         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01111         collectionMutex.Signal();
01112         ptr.SetSafetyMode(mode);
01113         return ptr;
01114       }
01116 };
01117 
01118 
01123 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01124 {
01125   public:
01126     typedef PSafePtr<Base> value_type;
01127 };
01128 
01129 
01130 #endif // PTLIB_SAFE_COLLECTION_H
01131 
01132 
01133 // End Of File ///////////////////////////////////////////////////////////////

Generated on Thu May 27 01:36:48 2010 for PTLib by  doxygen 1.4.7