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: 27948 $
00027  * $Author: rjongbloed $
00028  * $Date: 2012-06-30 22:54:23 -0500 (Sat, 30 Jun 2012) $
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;
00529 
00536     virtual void PrintOn(
00537       ostream &strm   // Stream to print the object into.
00538     ) const;
00540 
00545     virtual void SetNULL();
00546 
00549     bool operator!() const { return currentObject == NULL; }
00550 
00553     PSafetyMode GetSafetyMode() const { return lockMode; }
00554 
00561     virtual PBoolean SetSafetyMode(
00562       PSafetyMode mode  
00563     );
00564 
00567     const PSafeCollection * GetCollection() const { return collection; }
00569 
00570     virtual void Assign(const PSafePtrBase & ptr);
00571     virtual void Assign(const PSafeCollection & safeCollection);
00572     virtual void Assign(PSafeObject * obj);
00573     virtual void Assign(PINDEX idx);
00574 
00575   protected:
00576     virtual void Next();
00577     virtual void Previous();
00578     virtual void DeleteObject(PSafeObject * obj);
00579 
00580     enum EnterSafetyModeOption {
00581       WithReference,
00582       AlreadyReferenced
00583     };
00584     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00585 
00586     enum ExitSafetyModeOption {
00587       WithDereference,
00588       NoDereference
00589     };
00590     void ExitSafetyMode(ExitSafetyModeOption ref);
00591 
00592     virtual void LockPtr() { }
00593     virtual void UnlockPtr() { }
00594 
00595   protected:
00596     const PSafeCollection * collection;
00597     PSafeObject           * currentObject;
00598     PSafetyMode             lockMode;
00599 };
00600 
00601 
00614 class PSafePtrMultiThreaded : public PSafePtrBase
00615 {
00616     PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
00617 
00620   protected:
00628     PSafePtrMultiThreaded(
00629       PSafeObject * obj = NULL,         
00630       PSafetyMode mode = PSafeReference 
00631     );
00632 
00640     PSafePtrMultiThreaded(
00641       const PSafeCollection & safeCollection, 
00642       PSafetyMode mode,                       
00643       PINDEX idx                              
00644     );
00645 
00653     PSafePtrMultiThreaded(
00654       const PSafeCollection & safeCollection, 
00655       PSafetyMode mode,                       
00656       PSafeObject * obj                       
00657     );
00658 
00664     PSafePtrMultiThreaded(
00665       const PSafePtrMultiThreaded & enumerator   
00666     );
00667 
00668   public:
00671     ~PSafePtrMultiThreaded();
00673 
00680     virtual Comparison Compare(
00681       const PObject & obj   
00682     ) const;
00684 
00689     virtual void SetNULL();
00690 
00697     virtual PBoolean SetSafetyMode(
00698       PSafetyMode mode  
00699     );
00701 
00702     virtual void Assign(const PSafePtrMultiThreaded & ptr);
00703     virtual void Assign(const PSafePtrBase & ptr);
00704     virtual void Assign(const PSafeCollection & safeCollection);
00705     virtual void Assign(PSafeObject * obj);
00706     virtual void Assign(PINDEX idx);
00707 
00708   protected:
00709     virtual void Next();
00710     virtual void Previous();
00711     virtual void DeleteObject(PSafeObject * obj);
00712 
00713     virtual void LockPtr() { m_mutex.Wait(); }
00714     virtual void UnlockPtr();
00715 
00716   protected:
00717     mutable PMutex m_mutex;
00718     PSafeObject  * m_objectToDelete;
00719 };
00720 
00721 
00742 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
00743 {
00744   public:
00754     PSafePtr(
00755       T * obj = NULL,                   
00756       PSafetyMode mode = PSafeReference 
00757     ) : BaseClass(obj, mode) { }
00758 
00766     PSafePtr(
00767       const PSafeCollection & safeCollection, 
00768       PSafetyMode mode = PSafeReadWrite,      
00769       PINDEX idx = 0                          
00770     ) : BaseClass(safeCollection, mode, idx) { }
00771 
00779     PSafePtr(
00780       const PSafeCollection & safeCollection, 
00781       PSafetyMode mode,                       
00782       PSafeObject * obj                       
00783     ) : BaseClass(safeCollection, mode, obj) { }
00784 
00790     PSafePtr(
00791       const PSafePtr & ptr   
00792     ) : BaseClass(ptr) { }
00793 
00799     PSafePtr & operator=(const PSafePtr & ptr)
00800       {
00801         BaseClass::Assign(ptr);
00802         return *this;
00803       }
00804 
00809     PSafePtr & operator=(const PSafeCollection & safeCollection)
00810       {
00811         BaseClass::Assign(safeCollection);
00812         return *this;
00813       }
00814 
00830     PSafePtr & operator=(T * obj)
00831       {
00832         this->Assign(obj);
00833         return *this;
00834       }
00835 
00845     PSafePtr & operator=(PINDEX idx)
00846       {
00847         BaseClass::Assign(idx);
00848         return *this;
00849       }
00850 
00855     PSafePtr Set(T * obj)
00856       {
00857         this->LockPtr();
00858         PSafePtr oldPtr = *this;
00859         this->Assign(obj);
00860         this->UnlockPtr();
00861         return oldPtr;
00862       }
00864 
00869     operator T*()    const { return  (T *)BaseClass::currentObject; }
00870 
00873     T & operator*()  const { return *(T *)PAssertNULL(BaseClass::currentObject); }
00874 
00877     T * operator->() const { return  (T *)PAssertNULL(BaseClass::currentObject); }
00878 
00883     T * operator++(int)
00884       {
00885         T * previous = (T *)BaseClass::currentObject;
00886         BaseClass::Next();
00887         return previous;
00888       }
00889 
00894     T * operator++()
00895       {
00896         BaseClass::Next();
00897         return (T *)BaseClass::currentObject;
00898       }
00899 
00904     T * operator--(int)
00905       {
00906         T * previous = (T *)BaseClass::currentObject;
00907         BaseClass::Previous();
00908         return previous;
00909       }
00910 
00915     T * operator--()
00916       {
00917         BaseClass::Previous();
00918         return (T *)BaseClass::currentObject;
00919       }
00921 };
00922 
00923 
00927 template <class Base, class Derived>
00928 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00929 {
00930 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00931     PSafePtr<Derived> newPtr;
00932     Base * realPtr = oldPtr;
00933     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00934       newPtr.Assign(oldPtr);
00935     return newPtr;
00936 }
00937 
00938 
00949 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00950 {
00951     PCLASSINFO(PSafeColl, PSafeCollection);
00952   public:
00957     PSafeColl()
00958       : PSafeCollection(new Coll)
00959       { }
00960 
00964     PSafeColl(const PSafeColl & other)
00965       : PSafeCollection(new Coll)
00966     {
00967       PWaitAndSignal lock2(other.collectionMutex);
00968       CopySafeCollection(dynamic_cast<Coll *>(other.collection));
00969     }
00970 
00974     PSafeColl & operator=(const PSafeColl & other)
00975     {
00976       if (&other != this) {
00977         RemoveAll(true);
00978         PWaitAndSignal lock1(collectionMutex);
00979         PWaitAndSignal lock2(other.collectionMutex);
00980         CopySafeCollection(dynamic_cast<Coll *>(other.collection));
00981       }
00982       return *this;
00983     }
00985 
00992     virtual PSafePtr<Base> Append(
00993       Base * obj,       
00994       PSafetyMode mode = PSafeReference   
00995     ) {
00996         PWaitAndSignal mutex(collectionMutex);
00997         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
00998             obj->SafeReference())
00999           return PSafePtr<Base>(*this, mode, collection->Append(obj));
01000         return NULL;
01001       }
01002 
01011     virtual PBoolean Remove(
01012       Base * obj          
01013     ) {
01014         return SafeRemove(obj);
01015       }
01016 
01025     virtual PBoolean RemoveAt(
01026       PINDEX idx     
01027     ) {
01028         return SafeRemoveAt(idx);
01029       }
01030 
01036     virtual PSafePtr<Base> GetAt(
01037       PINDEX idx,
01038       PSafetyMode mode = PSafeReadWrite
01039     ) {
01040         return PSafePtr<Base>(*this, mode, idx);
01041       }
01042 
01048     virtual PSafePtr<Base> FindWithLock(
01049       const Base & value,
01050       PSafetyMode mode = PSafeReadWrite
01051     ) {
01052         collectionMutex.Wait();
01053         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
01054         collectionMutex.Signal();
01055         ptr.SetSafetyMode(mode);
01056         return ptr;
01057       }
01059 };
01060 
01061 
01066 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
01067 {
01068   public:
01069     typedef PSafePtr<Base> value_type;
01070 };
01071 
01072 
01077 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
01078 {
01079   public:
01080     typedef PSafePtr<Base> value_type;
01081 };
01082 
01083 
01088 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
01089 {
01090   public:
01091     typedef PSafePtr<Base> value_type;
01092 };
01093 
01094 
01105 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
01106 {
01107     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
01108   public:
01113     PSafeDictionaryBase()
01114       : PSafeCollection(new Coll) { }
01115 
01119     PSafeDictionaryBase(const PSafeDictionaryBase & other)
01120       : PSafeCollection(new Coll)
01121     {
01122       PWaitAndSignal lock2(other.collectionMutex);
01123       CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
01124     }
01125 
01129     PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other)
01130     {
01131       if (&other != this) {
01132         RemoveAll(true);
01133         PWaitAndSignal lock1(collectionMutex);
01134         PWaitAndSignal lock2(other.collectionMutex);
01135         CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
01136       }
01137       return *this;
01138     }
01140 
01147     virtual void SetAt(const Key & key, Base * obj)
01148       {
01149         collectionMutex.Wait();
01150         SafeRemove(((Coll *)collection)->GetAt(key));
01151         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
01152             obj->SafeReference())
01153           ((Coll *)collection)->SetAt(key, obj);
01154         collectionMutex.Signal();
01155       }
01156 
01165     virtual PBoolean RemoveAt(
01166       const Key & key   
01167     ) {
01168         PWaitAndSignal mutex(collectionMutex);
01169         return SafeRemove(((Coll *)collection)->GetAt(key));
01170       }
01171 
01174     virtual PBoolean Contains(
01175       const Key & key
01176     ) {
01177         PWaitAndSignal lock(collectionMutex);
01178         return ((Coll *)collection)->Contains(key);
01179       }
01180 
01186     virtual PSafePtr<Base> GetAt(
01187       PINDEX idx,
01188       PSafetyMode mode = PSafeReadWrite
01189     ) {
01190         return PSafePtr<Base>(*this, mode, idx);
01191       }
01192 
01198     virtual PSafePtr<Base> FindWithLock(
01199       const Key & key,
01200       PSafetyMode mode = PSafeReadWrite
01201     ) {
01202         collectionMutex.Wait();
01203         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01204         collectionMutex.Signal();
01205         ptr.SetSafetyMode(mode);
01206         return ptr;
01207       }
01208 
01211     PArray<Key> GetKeys() const
01212     {
01213       PArray<Key> keys;
01214       collectionMutex.Wait();
01215       ((Coll *)collection)->AbstractGetKeys(keys);
01216       collectionMutex.Signal();
01217       return keys;
01218     }
01220 };
01221 
01222 
01227 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01228 {
01229   public:
01230     typedef PSafePtr<Base> value_type;
01231 };
01232 
01233 
01234 #endif // PTLIB_SAFE_COLLECTION_H
01235 
01236 
01237 // End Of File ///////////////////////////////////////////////////////////////

Generated on Fri Feb 15 20:58:31 2013 for PTLib by  doxygen 1.4.7