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: 22165 $
00027  * $Author: rjongbloed $
00028  * $Date: 2009-03-06 00:24:25 +0000 (Fri, 06 Mar 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 
00435 class PSafePtrBase : public PObject
00436 {
00437     PCLASSINFO(PSafePtrBase, PObject);
00438 
00441   protected:
00449     PSafePtrBase(
00450       PSafeObject * obj = NULL,         
00451       PSafetyMode mode = PSafeReference 
00452     );
00453 
00461     PSafePtrBase(
00462       const PSafeCollection & safeCollection, 
00463       PSafetyMode mode,                       
00464       PINDEX idx                              
00465     );
00466 
00474     PSafePtrBase(
00475       const PSafeCollection & safeCollection, 
00476       PSafetyMode mode,                       
00477       PSafeObject * obj                       
00478     );
00479 
00485     PSafePtrBase(
00486       const PSafePtrBase & enumerator   
00487     );
00488 
00489   public:
00492     ~PSafePtrBase();
00494 
00501     Comparison Compare(
00502       const PObject & obj   
00503     ) const;
00505 
00510     void SetNULL();
00511 
00514     bool operator!() const { return currentObject == NULL; }
00515 
00518     PSafetyMode GetSafetyMode() const { return lockMode; }
00519 
00526     PBoolean SetSafetyMode(
00527       PSafetyMode mode  
00528     );
00529 
00532     const PSafeCollection * GetCollection() const { return collection; }
00534 
00535     void Assign(const PSafePtrBase & ptr);
00536     void Assign(const PSafeCollection & safeCollection);
00537     void Assign(PSafeObject * obj);
00538     void Assign(PINDEX idx);
00539 
00540   protected:
00541     void Next();
00542     void Previous();
00543 
00544     enum EnterSafetyModeOption {
00545       WithReference,
00546       AlreadyReferenced
00547     };
00548     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00549 
00550     enum ExitSafetyModeOption {
00551       WithDereference,
00552       NoDereference
00553     };
00554     void ExitSafetyMode(ExitSafetyModeOption ref);
00555 
00556   protected:
00557     const PSafeCollection * collection;
00558     PSafeObject           * currentObject;
00559     PSafetyMode             lockMode;
00560 };
00561 
00562 
00584 template <class T> class PSafePtr : public PSafePtrBase
00585 {
00586     PCLASSINFO(PSafePtr, PSafePtrBase);
00587   public:
00597     PSafePtr(
00598       T * obj = NULL,                   
00599       PSafetyMode mode = PSafeReference 
00600     ) : PSafePtrBase(obj, mode) { }
00601 
00609     PSafePtr(
00610       const PSafeCollection & safeCollection, 
00611       PSafetyMode mode = PSafeReadWrite,      
00612       PINDEX idx = 0                          
00613     ) : PSafePtrBase(safeCollection, mode, idx) { }
00614 
00622     PSafePtr(
00623       const PSafeCollection & safeCollection, 
00624       PSafetyMode mode,                       
00625       PSafeObject * obj                       
00626     ) : PSafePtrBase(safeCollection, mode, obj) { }
00627 
00633     PSafePtr(
00634       const PSafePtr & ptr   
00635     ) : PSafePtrBase(ptr) { }
00636 
00642     PSafePtr & operator=(const PSafePtr & ptr)
00643       {
00644         Assign(ptr);
00645         return *this;
00646       }
00647 
00652     PSafePtr & operator=(const PSafeCollection & safeCollection)
00653       {
00654         Assign(safeCollection);
00655         return *this;
00656       }
00657 
00673     PSafePtr & operator=(T * obj)
00674       {
00675         Assign(obj);
00676         return *this;
00677       }
00678 
00688     PSafePtr & operator=(PINDEX idx)
00689       {
00690         Assign(idx);
00691         return *this;
00692       }
00694 
00699     operator T*()    const { return  (T *)currentObject; }
00700 
00703     T & operator*()  const { return *(T *)PAssertNULL(currentObject); }
00704 
00707     T * operator->() const { return  (T *)PAssertNULL(currentObject); }
00708 
00713     T * operator++(int)
00714       {
00715         T * previous = (T *)currentObject;
00716         Next();
00717         return previous;
00718       }
00719 
00724     T * operator++()
00725       {
00726         Next();
00727         return (T *)currentObject;
00728       }
00729 
00734     T * operator--(int)
00735       {
00736         T * previous = (T *)currentObject;
00737         Previous();
00738         return previous;
00739       }
00740 
00745     T * operator--()
00746       {
00747         Previous();
00748         return (T *)currentObject;
00749       }
00751 
00755       /*
00756   template <class Base>
00757   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00758   {
00759     PSafePtr<T> newPtr;
00760     Base * realPtr = oldPtr;
00761     if (realPtr != NULL && PIsDescendant(realPtr, T))
00762       newPtr.Assign(oldPtr);
00763     return newPtr;
00764   }
00765   */
00766 };
00767 
00768 
00772 template <class Base, class Derived>
00773 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00774 {
00775 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00776     PSafePtr<Derived> newPtr;
00777     Base * realPtr = oldPtr;
00778     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00779       newPtr.Assign(oldPtr);
00780     return newPtr;
00781 }
00782 
00783 
00794 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00795 {
00796     PCLASSINFO(PSafeColl, PSafeCollection);
00797   public:
00802     PSafeColl()
00803       : PSafeCollection(new Coll)
00804       { }
00806 
00813     virtual PSafePtr<Base> Append(
00814       Base * obj,       
00815       PSafetyMode mode = PSafeReference
00816     ) {
00817         PWaitAndSignal mutex(collectionMutex);
00818         if (!obj->SafeReference())
00819           return NULL;
00820         return PSafePtr<Base>(*this, mode, collection->Append(obj));
00821       }
00822 
00831     virtual PBoolean Remove(
00832       Base * obj          
00833     ) {
00834         return SafeRemove(obj);
00835       }
00836 
00845     virtual PBoolean RemoveAt(
00846       PINDEX idx     
00847     ) {
00848         return SafeRemoveAt(idx);
00849       }
00850 
00856     virtual PSafePtr<Base> GetAt(
00857       PINDEX idx,
00858       PSafetyMode mode = PSafeReadWrite
00859     ) {
00860         return PSafePtr<Base>(*this, mode, idx);
00861       }
00862 
00868     virtual PSafePtr<Base> FindWithLock(
00869       const Base & value,
00870       PSafetyMode mode = PSafeReadWrite
00871     ) {
00872         collectionMutex.Wait();
00873         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00874         collectionMutex.Signal();
00875         ptr.SetSafetyMode(mode);
00876         return ptr;
00877       }
00879 };
00880 
00881 
00886 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00887 {
00888   public:
00889     typedef PSafePtr<Base> value_type;
00890 };
00891 
00892 
00897 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
00898 {
00899   public:
00900     typedef PSafePtr<Base> value_type;
00901 };
00902 
00903 
00908 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
00909 {
00910   public:
00911     typedef PSafePtr<Base> value_type;
00912 };
00913 
00914 
00925 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
00926 {
00927     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
00928   public:
00933     PSafeDictionaryBase()
00934       : PSafeCollection(new Coll) { }
00936 
00943     virtual void SetAt(const Key & key, Base * obj)
00944       {
00945         collectionMutex.Wait();
00946         SafeRemove(((Coll *)collection)->GetAt(key));
00947         if (obj->SafeReference())
00948           ((Coll *)collection)->SetAt(key, obj);
00949         collectionMutex.Signal();
00950       }
00951 
00960     virtual PBoolean RemoveAt(
00961       const Key & key   
00962     ) {
00963         PWaitAndSignal mutex(collectionMutex);
00964         return SafeRemove(((Coll *)collection)->GetAt(key));
00965       }
00966 
00969     virtual PBoolean Contains(
00970       const Key & key
00971     ) {
00972         PWaitAndSignal lock(collectionMutex);
00973         return ((Coll *)collection)->Contains(key);
00974       }
00975 
00981     virtual PSafePtr<Base> GetAt(
00982       PINDEX idx,
00983       PSafetyMode mode = PSafeReadWrite
00984     ) {
00985         return PSafePtr<Base>(*this, mode, idx);
00986       }
00987 
00993     virtual PSafePtr<Base> FindWithLock(
00994       const Key & key,
00995       PSafetyMode mode = PSafeReadWrite
00996     ) {
00997         collectionMutex.Wait();
00998         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
00999         collectionMutex.Signal();
01000         ptr.SetSafetyMode(mode);
01001         return ptr;
01002       }
01004 };
01005 
01006 
01011 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01012 {
01013   public:
01014     typedef PSafePtr<Base> value_type;
01015 };
01016 
01017 
01018 #endif // PTLIB_SAFE_COLLECTION_H
01019 
01020 
01021 // End Of File ///////////////////////////////////////////////////////////////

Generated on Fri Apr 10 22:33:49 2009 for PTLib by  doxygen 1.5.8