PTLib  Version 2.10.4
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: 25554 $
00027  * $Author: rjongbloed $
00028  * $Date: 2011-04-13 03:34:50 -0500 (Wed, 13 Apr 2011) $
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 
00119 class PSafeObject : public PObject
00120 {
00121     PCLASSINFO(PSafeObject, PObject);
00122   public:
00127     PSafeObject(
00128         PSafeObject * indirectLock = NULL 
00129     );
00131 
00152     PBoolean SafeReference();
00153 
00164     PBoolean SafeDereference();
00165 
00183     PBoolean LockReadOnly() const;
00184 
00195     void UnlockReadOnly() const;
00196 
00214     PBoolean LockReadWrite();
00215 
00226     void UnlockReadWrite();
00227 
00237     void SafeRemove();
00238 
00246     PBoolean SafelyCanBeDeleted() const;
00247 
00259     virtual bool GarbageCollection();
00261 
00262   private:
00263     mutable PMutex    safetyMutex;
00264     unsigned          safeReferenceCount;
00265     bool              safelyBeingRemoved;
00266     PReadWriteMutex   safeInUseMutex;
00267     PReadWriteMutex * safeInUse;
00268 
00269   friend class PSafeCollection;
00270 };
00271 
00272 
00275 class PSafeLockReadOnly
00276 {
00277   public:
00278     PSafeLockReadOnly(const PSafeObject & object);
00279     ~PSafeLockReadOnly();
00280     PBoolean Lock();
00281     void Unlock();
00282     PBoolean IsLocked() const { return locked; }
00283     bool operator!() const { return !locked; }
00284 
00285   protected:
00286     PSafeObject & safeObject;
00287     PBoolean          locked;
00288 };
00289 
00290 
00291 
00294 class PSafeLockReadWrite
00295 {
00296   public:
00297     PSafeLockReadWrite(const PSafeObject & object);
00298     ~PSafeLockReadWrite();
00299     PBoolean Lock();
00300     void Unlock();
00301     PBoolean IsLocked() const { return locked; }
00302     bool operator!() const { return !locked; }
00303 
00304   protected:
00305     PSafeObject & safeObject;
00306     PBoolean          locked;
00307 };
00308 
00309 
00310 
00323 class PSafeCollection : public PObject
00324 {
00325     PCLASSINFO(PSafeCollection, PObject);
00326   public:
00332     PSafeCollection(
00333       PCollection * collection    
00334      );
00335 
00339     ~PSafeCollection();
00341 
00344   protected:
00353     virtual PBoolean SafeRemove(
00354       PSafeObject * obj   
00355     );
00356 
00365     virtual PBoolean SafeRemoveAt(
00366       PINDEX idx    
00367     );
00368 
00369   public:
00372     virtual void RemoveAll(
00373       PBoolean synchronous = false  
00374     );
00375 
00380     void AllowDeleteObjects(
00381       PBoolean yes = true   
00382     ) { deleteObjects = yes; }
00383 
00388     void DisallowDeleteObjects() { deleteObjects = false; }
00389 
00394     virtual PBoolean DeleteObjectsToBeRemoved();
00395 
00398     virtual void DeleteObject(PObject * object) const;
00399 
00402     virtual void SetAutoDeleteObjects();
00403 
00408     PINDEX GetSize() const;
00409 
00414     PBoolean IsEmpty() const { return GetSize() == 0; }
00415 
00418     const PMutex & GetMutex() const { return collectionMutex; }
00420 
00421   protected:
00422     void CopySafeCollection(PCollection * other);
00423     void CopySafeDictionary(PAbstractDictionary * other);
00424     void SafeRemoveObject(PSafeObject * obj);
00425     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00426 
00427     PCollection      * collection;
00428     mutable PMutex     collectionMutex;
00429     bool               deleteObjects;
00430     PList<PSafeObject> toBeRemoved;
00431     PMutex             removalMutex;
00432     PTimer             deleteObjectsTimer;
00433 
00434   private:
00435     PSafeCollection(const PSafeCollection & other) : PObject(other) { }
00436     void operator=(const PSafeCollection &) { }
00437 
00438   friend class PSafePtrBase;
00439 };
00440 
00441 
00442 enum PSafetyMode {
00443   PSafeReference,
00444   PSafeReadOnly,
00445   PSafeReadWrite
00446 };
00447 
00460 class PSafePtrBase : public PObject
00461 {
00462     PCLASSINFO(PSafePtrBase, PObject);
00463 
00466   protected:
00474     PSafePtrBase(
00475       PSafeObject * obj = NULL,         
00476       PSafetyMode mode = PSafeReference 
00477     );
00478 
00486     PSafePtrBase(
00487       const PSafeCollection & safeCollection, 
00488       PSafetyMode mode,                       
00489       PINDEX idx                              
00490     );
00491 
00499     PSafePtrBase(
00500       const PSafeCollection & safeCollection, 
00501       PSafetyMode mode,                       
00502       PSafeObject * obj                       
00503     );
00504 
00510     PSafePtrBase(
00511       const PSafePtrBase & enumerator   
00512     );
00513 
00514   public:
00517     ~PSafePtrBase();
00519 
00526     virtual Comparison Compare(
00527       const PObject & obj   
00528     ) const;
00530 
00535     virtual void SetNULL();
00536 
00539     bool operator!() const { return currentObject == NULL; }
00540 
00543     PSafetyMode GetSafetyMode() const { return lockMode; }
00544 
00551     virtual PBoolean SetSafetyMode(
00552       PSafetyMode mode  
00553     );
00554 
00557     const PSafeCollection * GetCollection() const { return collection; }
00559 
00560     virtual void Assign(const PSafePtrBase & ptr);
00561     virtual void Assign(const PSafeCollection & safeCollection);
00562     virtual void Assign(PSafeObject * obj);
00563     virtual void Assign(PINDEX idx);
00564 
00565   protected:
00566     virtual void Next();
00567     virtual void Previous();
00568     virtual void DeleteObject(PSafeObject * obj);
00569 
00570     enum EnterSafetyModeOption {
00571       WithReference,
00572       AlreadyReferenced
00573     };
00574     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00575 
00576     enum ExitSafetyModeOption {
00577       WithDereference,
00578       NoDereference
00579     };
00580     void ExitSafetyMode(ExitSafetyModeOption ref);
00581 
00582   protected:
00583     const PSafeCollection * collection;
00584     PSafeObject           * currentObject;
00585     PSafetyMode             lockMode;
00586 };
00587 
00588 
00601 class PSafePtrMultiThreaded : public PSafePtrBase
00602 {
00603     PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
00604 
00607   protected:
00615     PSafePtrMultiThreaded(
00616       PSafeObject * obj = NULL,         
00617       PSafetyMode mode = PSafeReference 
00618     );
00619 
00627     PSafePtrMultiThreaded(
00628       const PSafeCollection & safeCollection, 
00629       PSafetyMode mode,                       
00630       PINDEX idx                              
00631     );
00632 
00640     PSafePtrMultiThreaded(
00641       const PSafeCollection & safeCollection, 
00642       PSafetyMode mode,                       
00643       PSafeObject * obj                       
00644     );
00645 
00651     PSafePtrMultiThreaded(
00652       const PSafePtrMultiThreaded & enumerator   
00653     );
00654 
00655   public:
00658     ~PSafePtrMultiThreaded();
00660 
00667     virtual Comparison Compare(
00668       const PObject & obj   
00669     ) const;
00671 
00676     virtual void SetNULL();
00677 
00684     virtual PBoolean SetSafetyMode(
00685       PSafetyMode mode  
00686     );
00688 
00689     virtual void Assign(const PSafePtrMultiThreaded & ptr);
00690     virtual void Assign(const PSafePtrBase & ptr);
00691     virtual void Assign(const PSafeCollection & safeCollection);
00692     virtual void Assign(PSafeObject * obj);
00693     virtual void Assign(PINDEX idx);
00694 
00695   protected:
00696     virtual void Next();
00697     virtual void Previous();
00698     virtual void DeleteObject(PSafeObject * obj);
00699 
00700     void Lock() { m_mutex.Wait(); }
00701     void Unlock();
00702 
00703   protected:
00704     mutable PMutex m_mutex;
00705     PSafeObject  * m_objectToDelete;
00706 };
00707 
00708 
00729 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
00730 {
00731   public:
00741     PSafePtr(
00742       T * obj = NULL,                   
00743       PSafetyMode mode = PSafeReference 
00744     ) : BaseClass(obj, mode) { }
00745 
00753     PSafePtr(
00754       const PSafeCollection & safeCollection, 
00755       PSafetyMode mode = PSafeReadWrite,      
00756       PINDEX idx = 0                          
00757     ) : BaseClass(safeCollection, mode, idx) { }
00758 
00766     PSafePtr(
00767       const PSafeCollection & safeCollection, 
00768       PSafetyMode mode,                       
00769       PSafeObject * obj                       
00770     ) : BaseClass(safeCollection, mode, obj) { }
00771 
00777     PSafePtr(
00778       const PSafePtr & ptr   
00779     ) : BaseClass(ptr) { }
00780 
00786     PSafePtr & operator=(const PSafePtr & ptr)
00787       {
00788         BaseClass::Assign(ptr);
00789         return *this;
00790       }
00791 
00796     PSafePtr & operator=(const PSafeCollection & safeCollection)
00797       {
00798         BaseClass::Assign(safeCollection);
00799         return *this;
00800       }
00801 
00817     PSafePtr & operator=(T * obj)
00818       {
00819         this->Assign(obj);
00820         return *this;
00821       }
00822 
00832     PSafePtr & operator=(PINDEX idx)
00833       {
00834         BaseClass::Assign(idx);
00835         return *this;
00836       }
00838 
00843     operator T*()    const { return  (T *)BaseClass::currentObject; }
00844 
00847     T & operator*()  const { return *(T *)PAssertNULL(BaseClass::currentObject); }
00848 
00851     T * operator->() const { return  (T *)PAssertNULL(BaseClass::currentObject); }
00852 
00857     T * operator++(int)
00858       {
00859         T * previous = (T *)BaseClass::currentObject;
00860         BaseClass::Next();
00861         return previous;
00862       }
00863 
00868     T * operator++()
00869       {
00870         BaseClass::Next();
00871         return (T *)BaseClass::currentObject;
00872       }
00873 
00878     T * operator--(int)
00879       {
00880         T * previous = (T *)BaseClass::currentObject;
00881         BaseClass::Previous();
00882         return previous;
00883       }
00884 
00889     T * operator--()
00890       {
00891         BaseClass::Previous();
00892         return (T *)BaseClass::currentObject;
00893       }
00895 
00899       /*
00900   template <class Base>
00901   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00902   {
00903     PSafePtr<T> newPtr;
00904     Base * realPtr = oldPtr;
00905     if (realPtr != NULL && PIsDescendant(realPtr, T))
00906       newPtr.Assign(oldPtr);
00907     return newPtr;
00908   }
00909   */
00910 };
00911 
00912 
00916 template <class Base, class Derived>
00917 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00918 {
00919 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00920     PSafePtr<Derived> newPtr;
00921     Base * realPtr = oldPtr;
00922     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00923       newPtr.Assign(oldPtr);
00924     return newPtr;
00925 }
00926 
00927 
00938 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00939 {
00940     PCLASSINFO(PSafeColl, PSafeCollection);
00941   public:
00946     PSafeColl()
00947       : PSafeCollection(new Coll)
00948       { }
00949 
00953     PSafeColl(const PSafeColl & other)
00954       : PSafeCollection(new Coll)
00955     {
00956       PWaitAndSignal lock2(other.collectionMutex);
00957       CopySafeCollection(dynamic_cast<Coll *>(other.collection));
00958     }
00959 
00963     PSafeColl & operator=(const PSafeColl & other)
00964     {
00965       if (&other != this) {
00966         RemoveAll(true);
00967         PWaitAndSignal lock1(collectionMutex);
00968         PWaitAndSignal lock2(other.collectionMutex);
00969         CopySafeCollection(dynamic_cast<Coll *>(other.collection));
00970       }
00971       return *this;
00972     }
00974 
00981     virtual PSafePtr<Base> Append(
00982       Base * obj,       
00983       PSafetyMode mode = PSafeReference   
00984     ) {
00985         PWaitAndSignal mutex(collectionMutex);
00986         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
00987             obj->SafeReference())
00988           return PSafePtr<Base>(*this, mode, collection->Append(obj));
00989         return NULL;
00990       }
00991 
01000     virtual PBoolean Remove(
01001       Base * obj          
01002     ) {
01003         return SafeRemove(obj);
01004       }
01005 
01014     virtual PBoolean RemoveAt(
01015       PINDEX idx     
01016     ) {
01017         return SafeRemoveAt(idx);
01018       }
01019 
01025     virtual PSafePtr<Base> GetAt(
01026       PINDEX idx,
01027       PSafetyMode mode = PSafeReadWrite
01028     ) {
01029         return PSafePtr<Base>(*this, mode, idx);
01030       }
01031 
01037     virtual PSafePtr<Base> FindWithLock(
01038       const Base & value,
01039       PSafetyMode mode = PSafeReadWrite
01040     ) {
01041         collectionMutex.Wait();
01042         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
01043         collectionMutex.Signal();
01044         ptr.SetSafetyMode(mode);
01045         return ptr;
01046       }
01048 };
01049 
01050 
01055 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
01056 {
01057   public:
01058     typedef PSafePtr<Base> value_type;
01059 };
01060 
01061 
01066 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
01067 {
01068   public:
01069     typedef PSafePtr<Base> value_type;
01070 };
01071 
01072 
01077 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
01078 {
01079   public:
01080     typedef PSafePtr<Base> value_type;
01081 };
01082 
01083 
01094 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
01095 {
01096     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
01097   public:
01102     PSafeDictionaryBase()
01103       : PSafeCollection(new Coll) { }
01104 
01108     PSafeDictionaryBase(const PSafeDictionaryBase & other)
01109       : PSafeCollection(new Coll)
01110     {
01111       PWaitAndSignal lock2(other.collectionMutex);
01112       CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
01113     }
01114 
01118     PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other)
01119     {
01120       if (&other != this) {
01121         RemoveAll(true);
01122         PWaitAndSignal lock1(collectionMutex);
01123         PWaitAndSignal lock2(other.collectionMutex);
01124         CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
01125       }
01126       return *this;
01127     }
01129 
01136     virtual void SetAt(const Key & key, Base * obj)
01137       {
01138         collectionMutex.Wait();
01139         SafeRemove(((Coll *)collection)->GetAt(key));
01140         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
01141             obj->SafeReference())
01142           ((Coll *)collection)->SetAt(key, obj);
01143         collectionMutex.Signal();
01144       }
01145 
01154     virtual PBoolean RemoveAt(
01155       const Key & key   
01156     ) {
01157         PWaitAndSignal mutex(collectionMutex);
01158         return SafeRemove(((Coll *)collection)->GetAt(key));
01159       }
01160 
01163     virtual PBoolean Contains(
01164       const Key & key
01165     ) {
01166         PWaitAndSignal lock(collectionMutex);
01167         return ((Coll *)collection)->Contains(key);
01168       }
01169 
01175     virtual PSafePtr<Base> GetAt(
01176       PINDEX idx,
01177       PSafetyMode mode = PSafeReadWrite
01178     ) {
01179         return PSafePtr<Base>(*this, mode, idx);
01180       }
01181 
01187     virtual PSafePtr<Base> FindWithLock(
01188       const Key & key,
01189       PSafetyMode mode = PSafeReadWrite
01190     ) {
01191         collectionMutex.Wait();
01192         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01193         collectionMutex.Signal();
01194         ptr.SetSafetyMode(mode);
01195         return ptr;
01196       }
01197 
01200     PArray<Key> GetKeys() const
01201     {
01202       PArray<Key> keys;
01203       collectionMutex.Wait();
01204       ((Coll *)collection)->AbstractGetKeys(keys);
01205       collectionMutex.Signal();
01206       return keys;
01207     }
01209 };
01210 
01211 
01216 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01217 {
01218   public:
01219     typedef PSafePtr<Base> value_type;
01220 };
01221 
01222 
01223 #endif // PTLIB_SAFE_COLLECTION_H
01224 
01225 
01226 // End Of File ///////////////////////////////////////////////////////////////
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines