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: 24177 $
00027  * $Author: rjongbloed $
00028  * $Date: 2010-04-05 06:52:04 -0500 (Mon, 05 Apr 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 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     virtual void DeleteObject(PSafeObject * obj);
00541 
00542     enum EnterSafetyModeOption {
00543       WithReference,
00544       AlreadyReferenced
00545     };
00546     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00547 
00548     enum ExitSafetyModeOption {
00549       WithDereference,
00550       NoDereference
00551     };
00552     void ExitSafetyMode(ExitSafetyModeOption ref);
00553 
00554   protected:
00555     const PSafeCollection * collection;
00556     PSafeObject           * currentObject;
00557     PSafetyMode             lockMode;
00558 };
00559 
00560 
00573 class PSafePtrMultiThreaded : public PSafePtrBase
00574 {
00575     PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
00576 
00579   protected:
00587     PSafePtrMultiThreaded(
00588       PSafeObject * obj = NULL,         
00589       PSafetyMode mode = PSafeReference 
00590     );
00591 
00599     PSafePtrMultiThreaded(
00600       const PSafeCollection & safeCollection, 
00601       PSafetyMode mode,                       
00602       PINDEX idx                              
00603     );
00604 
00612     PSafePtrMultiThreaded(
00613       const PSafeCollection & safeCollection, 
00614       PSafetyMode mode,                       
00615       PSafeObject * obj                       
00616     );
00617 
00623     PSafePtrMultiThreaded(
00624       const PSafePtrMultiThreaded & enumerator   
00625     );
00626 
00627   public:
00630     ~PSafePtrMultiThreaded();
00632 
00639     virtual Comparison Compare(
00640       const PObject & obj   
00641     ) const;
00643 
00648     virtual void SetNULL();
00649 
00656     virtual PBoolean SetSafetyMode(
00657       PSafetyMode mode  
00658     );
00660 
00661     virtual void Assign(const PSafePtrMultiThreaded & ptr);
00662     virtual void Assign(const PSafePtrBase & ptr);
00663     virtual void Assign(const PSafeCollection & safeCollection);
00664     virtual void Assign(PSafeObject * obj);
00665     virtual void Assign(PINDEX idx);
00666 
00667   protected:
00668     virtual void Next();
00669     virtual void Previous();
00670     virtual void DeleteObject(PSafeObject * obj);
00671 
00672     void Lock() { m_mutex.Wait(); }
00673     void Unlock();
00674 
00675   protected:
00676     mutable PMutex m_mutex;
00677     PSafeObject  * m_objectToDelete;
00678 };
00679 
00680 
00701 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
00702 {
00703   public:
00713     PSafePtr(
00714       T * obj = NULL,                   
00715       PSafetyMode mode = PSafeReference 
00716     ) : BaseClass(obj, mode) { }
00717 
00725     PSafePtr(
00726       const PSafeCollection & safeCollection, 
00727       PSafetyMode mode = PSafeReadWrite,      
00728       PINDEX idx = 0                          
00729     ) : BaseClass(safeCollection, mode, idx) { }
00730 
00738     PSafePtr(
00739       const PSafeCollection & safeCollection, 
00740       PSafetyMode mode,                       
00741       PSafeObject * obj                       
00742     ) : BaseClass(safeCollection, mode, obj) { }
00743 
00749     PSafePtr(
00750       const PSafePtr & ptr   
00751     ) : BaseClass(ptr) { }
00752 
00758     PSafePtr & operator=(const PSafePtr & ptr)
00759       {
00760         BaseClass::Assign(ptr);
00761         return *this;
00762       }
00763 
00768     PSafePtr & operator=(const PSafeCollection & safeCollection)
00769       {
00770         BaseClass::Assign(safeCollection);
00771         return *this;
00772       }
00773 
00789     PSafePtr & operator=(T * obj)
00790       {
00791         Assign(obj);
00792         return *this;
00793       }
00794 
00804     PSafePtr & operator=(PINDEX idx)
00805       {
00806         BaseClass::Assign(idx);
00807         return *this;
00808       }
00810 
00815     operator T*()    const { return  (T *)BaseClass::currentObject; }
00816 
00819     T & operator*()  const { return *(T *)PAssertNULL(BaseClass::currentObject); }
00820 
00823     T * operator->() const { return  (T *)PAssertNULL(BaseClass::currentObject); }
00824 
00829     T * operator++(int)
00830       {
00831         T * previous = (T *)BaseClass::currentObject;
00832         BaseClass::Next();
00833         return previous;
00834       }
00835 
00840     T * operator++()
00841       {
00842         BaseClass::Next();
00843         return (T *)BaseClass::currentObject;
00844       }
00845 
00850     T * operator--(int)
00851       {
00852         T * previous = (T *)BaseClass::currentObject;
00853         BaseClass::Previous();
00854         return previous;
00855       }
00856 
00861     T * operator--()
00862       {
00863         BaseClass::Previous();
00864         return (T *)BaseClass::currentObject;
00865       }
00867 
00871       /*
00872   template <class Base>
00873   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00874   {
00875     PSafePtr<T> newPtr;
00876     Base * realPtr = oldPtr;
00877     if (realPtr != NULL && PIsDescendant(realPtr, T))
00878       newPtr.Assign(oldPtr);
00879     return newPtr;
00880   }
00881   */
00882 };
00883 
00884 
00888 template <class Base, class Derived>
00889 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00890 {
00891 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00892     PSafePtr<Derived> newPtr;
00893     Base * realPtr = oldPtr;
00894     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00895       newPtr.Assign(oldPtr);
00896     return newPtr;
00897 }
00898 
00899 
00910 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00911 {
00912     PCLASSINFO(PSafeColl, PSafeCollection);
00913   public:
00918     PSafeColl()
00919       : PSafeCollection(new Coll)
00920       { }
00922 
00929     virtual PSafePtr<Base> Append(
00930       Base * obj,       
00931       PSafetyMode mode = PSafeReference   
00932     ) {
00933         PWaitAndSignal mutex(collectionMutex);
00934         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
00935             obj->SafeReference())
00936           return PSafePtr<Base>(*this, mode, collection->Append(obj));
00937         return NULL;
00938       }
00939 
00948     virtual PBoolean Remove(
00949       Base * obj          
00950     ) {
00951         return SafeRemove(obj);
00952       }
00953 
00962     virtual PBoolean RemoveAt(
00963       PINDEX idx     
00964     ) {
00965         return SafeRemoveAt(idx);
00966       }
00967 
00973     virtual PSafePtr<Base> GetAt(
00974       PINDEX idx,
00975       PSafetyMode mode = PSafeReadWrite
00976     ) {
00977         return PSafePtr<Base>(*this, mode, idx);
00978       }
00979 
00985     virtual PSafePtr<Base> FindWithLock(
00986       const Base & value,
00987       PSafetyMode mode = PSafeReadWrite
00988     ) {
00989         collectionMutex.Wait();
00990         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00991         collectionMutex.Signal();
00992         ptr.SetSafetyMode(mode);
00993         return ptr;
00994       }
00996 };
00997 
00998 
01003 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
01004 {
01005   public:
01006     typedef PSafePtr<Base> value_type;
01007 };
01008 
01009 
01014 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
01015 {
01016   public:
01017     typedef PSafePtr<Base> value_type;
01018 };
01019 
01020 
01025 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
01026 {
01027   public:
01028     typedef PSafePtr<Base> value_type;
01029 };
01030 
01031 
01042 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
01043 {
01044     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
01045   public:
01050     PSafeDictionaryBase()
01051       : PSafeCollection(new Coll) { }
01053 
01060     virtual void SetAt(const Key & key, Base * obj)
01061       {
01062         collectionMutex.Wait();
01063         SafeRemove(((Coll *)collection)->GetAt(key));
01064         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
01065             obj->SafeReference())
01066           ((Coll *)collection)->SetAt(key, obj);
01067         collectionMutex.Signal();
01068       }
01069 
01078     virtual PBoolean RemoveAt(
01079       const Key & key   
01080     ) {
01081         PWaitAndSignal mutex(collectionMutex);
01082         return SafeRemove(((Coll *)collection)->GetAt(key));
01083       }
01084 
01087     virtual PBoolean Contains(
01088       const Key & key
01089     ) {
01090         PWaitAndSignal lock(collectionMutex);
01091         return ((Coll *)collection)->Contains(key);
01092       }
01093 
01099     virtual PSafePtr<Base> GetAt(
01100       PINDEX idx,
01101       PSafetyMode mode = PSafeReadWrite
01102     ) {
01103         return PSafePtr<Base>(*this, mode, idx);
01104       }
01105 
01111     virtual PSafePtr<Base> FindWithLock(
01112       const Key & key,
01113       PSafetyMode mode = PSafeReadWrite
01114     ) {
01115         collectionMutex.Wait();
01116         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01117         collectionMutex.Signal();
01118         ptr.SetSafetyMode(mode);
01119         return ptr;
01120       }
01122 };
01123 
01124 
01129 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01130 {
01131   public:
01132     typedef PSafePtr<Base> value_type;
01133 };
01134 
01135 
01136 #endif // PTLIB_SAFE_COLLECTION_H
01137 
01138 
01139 // End Of File ///////////////////////////////////////////////////////////////

Generated on Thu May 27 01:49:40 2010 for PTLib by  doxygen 1.4.7