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: 21363 $
00027  * $Author: rjongbloed $
00028  * $Date: 2008-10-16 05:28:45 +0000 (Thu, 16 Oct 2008) $
00029  */
00030  
00031 #ifndef _SAFE_COLLECTION_H
00032 #define _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 
00522     PBoolean SetSafetyMode(
00523       PSafetyMode mode  
00524     );
00525 
00528     const PSafeCollection * GetCollection() const { return collection; }
00530 
00531     void Assign(const PSafePtrBase & ptr);
00532     void Assign(const PSafeCollection & safeCollection);
00533     void Assign(PSafeObject * obj);
00534     void Assign(PINDEX idx);
00535 
00536   protected:
00537     void Next();
00538     void Previous();
00539 
00540     enum EnterSafetyModeOption {
00541       WithReference,
00542       AlreadyReferenced
00543     };
00544     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00545 
00546     enum ExitSafetyModeOption {
00547       WithDereference,
00548       NoDereference
00549     };
00550     void ExitSafetyMode(ExitSafetyModeOption ref);
00551 
00552   protected:
00553     const PSafeCollection * collection;
00554     PSafeObject           * currentObject;
00555     PSafetyMode             lockMode;
00556 };
00557 
00558 
00580 template <class T> class PSafePtr : public PSafePtrBase
00581 {
00582     PCLASSINFO(PSafePtr, PSafePtrBase);
00583   public:
00593     PSafePtr(
00594       T * obj = NULL,                   
00595       PSafetyMode mode = PSafeReference 
00596     ) : PSafePtrBase(obj, mode) { }
00597 
00605     PSafePtr(
00606       const PSafeCollection & safeCollection, 
00607       PSafetyMode mode = PSafeReadWrite,      
00608       PINDEX idx = 0                          
00609     ) : PSafePtrBase(safeCollection, mode, idx) { }
00610 
00618     PSafePtr(
00619       const PSafeCollection & safeCollection, 
00620       PSafetyMode mode,                       
00621       PSafeObject * obj                       
00622     ) : PSafePtrBase(safeCollection, mode, obj) { }
00623 
00629     PSafePtr(
00630       const PSafePtr & ptr   
00631     ) : PSafePtrBase(ptr) { }
00632 
00638     PSafePtr & operator=(const PSafePtr & ptr)
00639       {
00640         Assign(ptr);
00641         return *this;
00642       }
00643 
00648     PSafePtr & operator=(const PSafeCollection & safeCollection)
00649       {
00650         Assign(safeCollection);
00651         return *this;
00652       }
00653 
00669     PSafePtr & operator=(T * obj)
00670       {
00671         Assign(obj);
00672         return *this;
00673       }
00674 
00684     PSafePtr & operator=(PINDEX idx)
00685       {
00686         Assign(idx);
00687         return *this;
00688       }
00690 
00695     operator T*()    const { return  (T *)currentObject; }
00696 
00699     T & operator*()  const { return *(T *)PAssertNULL(currentObject); }
00700 
00703     T * operator->() const { return  (T *)PAssertNULL(currentObject); }
00704 
00709     T * operator++(int)
00710       {
00711         T * previous = (T *)currentObject;
00712         Next();
00713         return previous;
00714       }
00715 
00720     T * operator++()
00721       {
00722         Next();
00723         return (T *)currentObject;
00724       }
00725 
00730     T * operator--(int)
00731       {
00732         T * previous = (T *)currentObject;
00733         Previous();
00734         return previous;
00735       }
00736 
00741     T * operator--()
00742       {
00743         Previous();
00744         return (T *)currentObject;
00745       }
00747 
00751       /*
00752   template <class Base>
00753   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00754   {
00755     PSafePtr<T> newPtr;
00756     Base * realPtr = oldPtr;
00757     if (realPtr != NULL && PIsDescendant(realPtr, T))
00758       newPtr.Assign(oldPtr);
00759     return newPtr;
00760   }
00761   */
00762 };
00763 
00764 
00768 template <class Base, class Derived>
00769 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00770 {
00771 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00772     PSafePtr<Derived> newPtr;
00773     Base * realPtr = oldPtr;
00774     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00775       newPtr.Assign(oldPtr);
00776     return newPtr;
00777 }
00778 
00779 
00790 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00791 {
00792     PCLASSINFO(PSafeColl, PSafeCollection);
00793   public:
00798     PSafeColl()
00799       : PSafeCollection(new Coll)
00800       { }
00802 
00809     virtual PSafePtr<Base> Append(
00810       Base * obj,       
00811       PSafetyMode mode = PSafeReference
00812     ) {
00813         PWaitAndSignal mutex(collectionMutex);
00814         if (!obj->SafeReference())
00815           return NULL;
00816         return PSafePtr<Base>(*this, mode, collection->Append(obj));
00817       }
00818 
00827     virtual PBoolean Remove(
00828       Base * obj          
00829     ) {
00830         return SafeRemove(obj);
00831       }
00832 
00841     virtual PBoolean RemoveAt(
00842       PINDEX idx     
00843     ) {
00844         return SafeRemoveAt(idx);
00845       }
00846 
00852     virtual PSafePtr<Base> GetAt(
00853       PINDEX idx,
00854       PSafetyMode mode = PSafeReadWrite
00855     ) {
00856         return PSafePtr<Base>(*this, mode, idx);
00857       }
00858 
00864     virtual PSafePtr<Base> FindWithLock(
00865       const Base & value,
00866       PSafetyMode mode = PSafeReadWrite
00867     ) {
00868         collectionMutex.Wait();
00869         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00870         collectionMutex.Signal();
00871         ptr.SetSafetyMode(mode);
00872         return ptr;
00873       }
00875 };
00876 
00877 
00882 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00883 {
00884   public:
00885     typedef PSafePtr<Base> value_type;
00886 };
00887 
00888 
00893 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
00894 {
00895   public:
00896     typedef PSafePtr<Base> value_type;
00897 };
00898 
00899 
00904 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
00905 {
00906   public:
00907     typedef PSafePtr<Base> value_type;
00908 };
00909 
00910 
00921 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
00922 {
00923     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
00924   public:
00929     PSafeDictionaryBase()
00930       : PSafeCollection(new Coll) { }
00932 
00939     virtual void SetAt(const Key & key, Base * obj)
00940       {
00941         collectionMutex.Wait();
00942         SafeRemove(((Coll *)collection)->GetAt(key));
00943         if (obj->SafeReference())
00944           ((Coll *)collection)->SetAt(key, obj);
00945         collectionMutex.Signal();
00946       }
00947 
00956     virtual PBoolean RemoveAt(
00957       const Key & key   
00958     ) {
00959         PWaitAndSignal mutex(collectionMutex);
00960         return SafeRemove(((Coll *)collection)->GetAt(key));
00961       }
00962 
00965     virtual PBoolean Contains(
00966       const Key & key
00967     ) {
00968         PWaitAndSignal lock(collectionMutex);
00969         return ((Coll *)collection)->Contains(key);
00970       }
00971 
00977     virtual PSafePtr<Base> GetAt(
00978       PINDEX idx,
00979       PSafetyMode mode = PSafeReadWrite
00980     ) {
00981         return PSafePtr<Base>(*this, mode, idx);
00982       }
00983 
00989     virtual PSafePtr<Base> FindWithLock(
00990       const Key & key,
00991       PSafetyMode mode = PSafeReadWrite
00992     ) {
00993         collectionMutex.Wait();
00994         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
00995         collectionMutex.Signal();
00996         ptr.SetSafetyMode(mode);
00997         return ptr;
00998       }
01000 };
01001 
01002 
01007 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01008 {
01009   public:
01010     typedef PSafePtr<Base> value_type;
01011 };
01012 
01013 
01014 #endif // _SAFE_COLLECTION_H
01015 
01016 

Generated on Mon Feb 23 01:57:54 2009 for PTLib by  doxygen 1.5.1