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: 24846 $
00027  * $Author: rjongbloed $
00028  * $Date: 2010-10-30 00:09:31 -0500 (Sat, 30 Oct 2010) $
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 = false  
00352     );
00353 
00358     void AllowDeleteObjects(
00359       PBoolean yes = true   
00360     ) { deleteObjects = yes; }
00361 
00366     void DisallowDeleteObjects() { deleteObjects = false; }
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 CopySafeCollection(PCollection * other);
00401     void CopySafeDictionary(PAbstractDictionary * other);
00402     void SafeRemoveObject(PSafeObject * obj);
00403     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00404 
00405     PCollection      * collection;
00406     mutable PMutex     collectionMutex;
00407     bool               deleteObjects;
00408     PList<PSafeObject> toBeRemoved;
00409     PMutex             removalMutex;
00410     PTimer             deleteObjectsTimer;
00411 
00412   private:
00413     PSafeCollection(const PSafeCollection & other) : PObject(other) { }
00414     void operator=(const PSafeCollection &) { }
00415 
00416   friend class PSafePtrBase;
00417 };
00418 
00419 
00420 enum PSafetyMode {
00421   PSafeReference,
00422   PSafeReadOnly,
00423   PSafeReadWrite
00424 };
00425 
00438 class PSafePtrBase : public PObject
00439 {
00440     PCLASSINFO(PSafePtrBase, PObject);
00441 
00444   protected:
00452     PSafePtrBase(
00453       PSafeObject * obj = NULL,         
00454       PSafetyMode mode = PSafeReference 
00455     );
00456 
00464     PSafePtrBase(
00465       const PSafeCollection & safeCollection, 
00466       PSafetyMode mode,                       
00467       PINDEX idx                              
00468     );
00469 
00477     PSafePtrBase(
00478       const PSafeCollection & safeCollection, 
00479       PSafetyMode mode,                       
00480       PSafeObject * obj                       
00481     );
00482 
00488     PSafePtrBase(
00489       const PSafePtrBase & enumerator   
00490     );
00491 
00492   public:
00495     ~PSafePtrBase();
00497 
00504     virtual Comparison Compare(
00505       const PObject & obj   
00506     ) const;
00508 
00513     virtual void SetNULL();
00514 
00517     bool operator!() const { return currentObject == NULL; }
00518 
00521     PSafetyMode GetSafetyMode() const { return lockMode; }
00522 
00529     virtual PBoolean SetSafetyMode(
00530       PSafetyMode mode  
00531     );
00532 
00535     const PSafeCollection * GetCollection() const { return collection; }
00537 
00538     virtual void Assign(const PSafePtrBase & ptr);
00539     virtual void Assign(const PSafeCollection & safeCollection);
00540     virtual void Assign(PSafeObject * obj);
00541     virtual void Assign(PINDEX idx);
00542 
00543   protected:
00544     virtual void Next();
00545     virtual void Previous();
00546     virtual void DeleteObject(PSafeObject * obj);
00547 
00548     enum EnterSafetyModeOption {
00549       WithReference,
00550       AlreadyReferenced
00551     };
00552     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00553 
00554     enum ExitSafetyModeOption {
00555       WithDereference,
00556       NoDereference
00557     };
00558     void ExitSafetyMode(ExitSafetyModeOption ref);
00559 
00560   protected:
00561     const PSafeCollection * collection;
00562     PSafeObject           * currentObject;
00563     PSafetyMode             lockMode;
00564 };
00565 
00566 
00579 class PSafePtrMultiThreaded : public PSafePtrBase
00580 {
00581     PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
00582 
00585   protected:
00593     PSafePtrMultiThreaded(
00594       PSafeObject * obj = NULL,         
00595       PSafetyMode mode = PSafeReference 
00596     );
00597 
00605     PSafePtrMultiThreaded(
00606       const PSafeCollection & safeCollection, 
00607       PSafetyMode mode,                       
00608       PINDEX idx                              
00609     );
00610 
00618     PSafePtrMultiThreaded(
00619       const PSafeCollection & safeCollection, 
00620       PSafetyMode mode,                       
00621       PSafeObject * obj                       
00622     );
00623 
00629     PSafePtrMultiThreaded(
00630       const PSafePtrMultiThreaded & enumerator   
00631     );
00632 
00633   public:
00636     ~PSafePtrMultiThreaded();
00638 
00645     virtual Comparison Compare(
00646       const PObject & obj   
00647     ) const;
00649 
00654     virtual void SetNULL();
00655 
00662     virtual PBoolean SetSafetyMode(
00663       PSafetyMode mode  
00664     );
00666 
00667     virtual void Assign(const PSafePtrMultiThreaded & ptr);
00668     virtual void Assign(const PSafePtrBase & ptr);
00669     virtual void Assign(const PSafeCollection & safeCollection);
00670     virtual void Assign(PSafeObject * obj);
00671     virtual void Assign(PINDEX idx);
00672 
00673   protected:
00674     virtual void Next();
00675     virtual void Previous();
00676     virtual void DeleteObject(PSafeObject * obj);
00677 
00678     void Lock() { m_mutex.Wait(); }
00679     void Unlock();
00680 
00681   protected:
00682     mutable PMutex m_mutex;
00683     PSafeObject  * m_objectToDelete;
00684 };
00685 
00686 
00707 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
00708 {
00709   public:
00719     PSafePtr(
00720       T * obj = NULL,                   
00721       PSafetyMode mode = PSafeReference 
00722     ) : BaseClass(obj, mode) { }
00723 
00731     PSafePtr(
00732       const PSafeCollection & safeCollection, 
00733       PSafetyMode mode = PSafeReadWrite,      
00734       PINDEX idx = 0                          
00735     ) : BaseClass(safeCollection, mode, idx) { }
00736 
00744     PSafePtr(
00745       const PSafeCollection & safeCollection, 
00746       PSafetyMode mode,                       
00747       PSafeObject * obj                       
00748     ) : BaseClass(safeCollection, mode, obj) { }
00749 
00755     PSafePtr(
00756       const PSafePtr & ptr   
00757     ) : BaseClass(ptr) { }
00758 
00764     PSafePtr & operator=(const PSafePtr & ptr)
00765       {
00766         BaseClass::Assign(ptr);
00767         return *this;
00768       }
00769 
00774     PSafePtr & operator=(const PSafeCollection & safeCollection)
00775       {
00776         BaseClass::Assign(safeCollection);
00777         return *this;
00778       }
00779 
00795     PSafePtr & operator=(T * obj)
00796       {
00797         Assign(obj);
00798         return *this;
00799       }
00800 
00810     PSafePtr & operator=(PINDEX idx)
00811       {
00812         BaseClass::Assign(idx);
00813         return *this;
00814       }
00816 
00821     operator T*()    const { return  (T *)BaseClass::currentObject; }
00822 
00825     T & operator*()  const { return *(T *)PAssertNULL(BaseClass::currentObject); }
00826 
00829     T * operator->() const { return  (T *)PAssertNULL(BaseClass::currentObject); }
00830 
00835     T * operator++(int)
00836       {
00837         T * previous = (T *)BaseClass::currentObject;
00838         BaseClass::Next();
00839         return previous;
00840       }
00841 
00846     T * operator++()
00847       {
00848         BaseClass::Next();
00849         return (T *)BaseClass::currentObject;
00850       }
00851 
00856     T * operator--(int)
00857       {
00858         T * previous = (T *)BaseClass::currentObject;
00859         BaseClass::Previous();
00860         return previous;
00861       }
00862 
00867     T * operator--()
00868       {
00869         BaseClass::Previous();
00870         return (T *)BaseClass::currentObject;
00871       }
00873 
00877       /*
00878   template <class Base>
00879   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00880   {
00881     PSafePtr<T> newPtr;
00882     Base * realPtr = oldPtr;
00883     if (realPtr != NULL && PIsDescendant(realPtr, T))
00884       newPtr.Assign(oldPtr);
00885     return newPtr;
00886   }
00887   */
00888 };
00889 
00890 
00894 template <class Base, class Derived>
00895 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00896 {
00897 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00898     PSafePtr<Derived> newPtr;
00899     Base * realPtr = oldPtr;
00900     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00901       newPtr.Assign(oldPtr);
00902     return newPtr;
00903 }
00904 
00905 
00916 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00917 {
00918     PCLASSINFO(PSafeColl, PSafeCollection);
00919   public:
00924     PSafeColl()
00925       : PSafeCollection(new Coll)
00926       { }
00927 
00931     PSafeColl(const PSafeColl & other)
00932       : PSafeCollection(new Coll)
00933     {
00934       PWaitAndSignal lock2(other.collectionMutex);
00935       CopySafeCollection(dynamic_cast<Coll *>(other.collection));
00936     }
00937 
00941     PSafeColl & operator=(const PSafeColl & other)
00942     {
00943       if (&other != this) {
00944         RemoveAll(true);
00945         PWaitAndSignal lock1(collectionMutex);
00946         PWaitAndSignal lock2(other.collectionMutex);
00947         CopySafeCollection(dynamic_cast<Coll *>(other.collection));
00948       }
00949       return *this;
00950     }
00952 
00959     virtual PSafePtr<Base> Append(
00960       Base * obj,       
00961       PSafetyMode mode = PSafeReference   
00962     ) {
00963         PWaitAndSignal mutex(collectionMutex);
00964         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
00965             obj->SafeReference())
00966           return PSafePtr<Base>(*this, mode, collection->Append(obj));
00967         return NULL;
00968       }
00969 
00978     virtual PBoolean Remove(
00979       Base * obj          
00980     ) {
00981         return SafeRemove(obj);
00982       }
00983 
00992     virtual PBoolean RemoveAt(
00993       PINDEX idx     
00994     ) {
00995         return SafeRemoveAt(idx);
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 Base & value,
01017       PSafetyMode mode = PSafeReadWrite
01018     ) {
01019         collectionMutex.Wait();
01020         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
01021         collectionMutex.Signal();
01022         ptr.SetSafetyMode(mode);
01023         return ptr;
01024       }
01026 };
01027 
01028 
01033 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
01034 {
01035   public:
01036     typedef PSafePtr<Base> value_type;
01037 };
01038 
01039 
01044 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
01045 {
01046   public:
01047     typedef PSafePtr<Base> value_type;
01048 };
01049 
01050 
01055 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
01056 {
01057   public:
01058     typedef PSafePtr<Base> value_type;
01059 };
01060 
01061 
01072 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
01073 {
01074     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
01075   public:
01080     PSafeDictionaryBase()
01081       : PSafeCollection(new Coll) { }
01082 
01086     PSafeDictionaryBase(const PSafeDictionaryBase & other)
01087       : PSafeCollection(new Coll)
01088     {
01089       PWaitAndSignal lock2(other.collectionMutex);
01090       CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
01091     }
01092 
01096     PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other)
01097     {
01098       if (&other != this) {
01099         RemoveAll(true);
01100         PWaitAndSignal lock1(collectionMutex);
01101         PWaitAndSignal lock2(other.collectionMutex);
01102         CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
01103       }
01104       return *this;
01105     }
01107 
01114     virtual void SetAt(const Key & key, Base * obj)
01115       {
01116         collectionMutex.Wait();
01117         SafeRemove(((Coll *)collection)->GetAt(key));
01118         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
01119             obj->SafeReference())
01120           ((Coll *)collection)->SetAt(key, obj);
01121         collectionMutex.Signal();
01122       }
01123 
01132     virtual PBoolean RemoveAt(
01133       const Key & key   
01134     ) {
01135         PWaitAndSignal mutex(collectionMutex);
01136         return SafeRemove(((Coll *)collection)->GetAt(key));
01137       }
01138 
01141     virtual PBoolean Contains(
01142       const Key & key
01143     ) {
01144         PWaitAndSignal lock(collectionMutex);
01145         return ((Coll *)collection)->Contains(key);
01146       }
01147 
01153     virtual PSafePtr<Base> GetAt(
01154       PINDEX idx,
01155       PSafetyMode mode = PSafeReadWrite
01156     ) {
01157         return PSafePtr<Base>(*this, mode, idx);
01158       }
01159 
01165     virtual PSafePtr<Base> FindWithLock(
01166       const Key & key,
01167       PSafetyMode mode = PSafeReadWrite
01168     ) {
01169         collectionMutex.Wait();
01170         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01171         collectionMutex.Signal();
01172         ptr.SetSafetyMode(mode);
01173         return ptr;
01174       }
01176 };
01177 
01178 
01183 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01184 {
01185   public:
01186     typedef PSafePtr<Base> value_type;
01187 };
01188 
01189 
01190 #endif // PTLIB_SAFE_COLLECTION_H
01191 
01192 
01193 // End Of File ///////////////////////////////////////////////////////////////

Generated on Fri Oct 14 01:44:10 2011 for PTLib by  doxygen 1.4.7