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: 20385 $
00027  * $Author: rjongbloed $
00028  * $Date: 2008-06-04 10:40:38 +0000 (Wed, 04 Jun 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     PBoolean              safelyBeingRemoved;
00244     PReadWriteMutex   safeInUseMutex;
00245     PReadWriteMutex * safeInUse;
00246 };
00247 
00248 
00251 class PSafeLockReadOnly
00252 {
00253   public:
00254     PSafeLockReadOnly(const PSafeObject & object);
00255     ~PSafeLockReadOnly();
00256     PBoolean Lock();
00257     void Unlock();
00258     PBoolean IsLocked() const { return locked; }
00259     bool operator!() const { return !locked; }
00260 
00261   protected:
00262     PSafeObject & safeObject;
00263     PBoolean          locked;
00264 };
00265 
00266 
00267 
00270 class PSafeLockReadWrite
00271 {
00272   public:
00273     PSafeLockReadWrite(const PSafeObject & object);
00274     ~PSafeLockReadWrite();
00275     PBoolean Lock();
00276     void Unlock();
00277     PBoolean IsLocked() const { return locked; }
00278     bool operator!() const { return !locked; }
00279 
00280   protected:
00281     PSafeObject & safeObject;
00282     PBoolean          locked;
00283 };
00284 
00285 
00286 
00299 class PSafeCollection : public PObject
00300 {
00301     PCLASSINFO(PSafeCollection, PObject);
00302   public:
00308     PSafeCollection(
00309       PCollection * collection    
00310      );
00311 
00315     ~PSafeCollection();
00317 
00320   protected:
00329     virtual PBoolean SafeRemove(
00330       PSafeObject * obj   
00331     );
00332 
00341     virtual PBoolean SafeRemoveAt(
00342       PINDEX idx    
00343     );
00344 
00345   public:
00348     virtual void RemoveAll(
00349       PBoolean synchronous = PFalse  
00350     );
00351 
00356     void AllowDeleteObjects(
00357       PBoolean yes = PTrue   
00358     ) { deleteObjects = yes; }
00359 
00364     void DisallowDeleteObjects() { deleteObjects = PFalse; }
00365 
00370     virtual PBoolean DeleteObjectsToBeRemoved();
00371 
00374     virtual void DeleteObject(PObject * object) const;
00375 
00378     virtual void SetAutoDeleteObjects();
00379 
00384     PINDEX GetSize() const;
00385 
00390     PBoolean IsEmpty() const { return GetSize() == 0; }
00391 
00394     const PMutex & GetMutex() const { return collectionMutex; }
00396 
00397   protected:
00398     void SafeRemoveObject(PSafeObject * obj);
00399     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00400 
00401     PCollection  *     collection;
00402     mutable PMutex     collectionMutex;
00403     PBoolean               deleteObjects;
00404     PList<PSafeObject> toBeRemoved;
00405     PMutex             removalMutex;
00406     PTimer             deleteObjectsTimer;
00407 
00408   friend class PSafePtrBase;
00409 };
00410 
00411 
00412 enum PSafetyMode {
00413   PSafeReference,
00414   PSafeReadOnly,
00415   PSafeReadWrite
00416 };
00417 
00433 class PSafePtrBase : public PObject
00434 {
00435     PCLASSINFO(PSafePtrBase, PObject);
00436 
00439   protected:
00447     PSafePtrBase(
00448       PSafeObject * obj = NULL,         
00449       PSafetyMode mode = PSafeReference 
00450     );
00451 
00459     PSafePtrBase(
00460       const PSafeCollection & safeCollection, 
00461       PSafetyMode mode,                       
00462       PINDEX idx                              
00463     );
00464 
00472     PSafePtrBase(
00473       const PSafeCollection & safeCollection, 
00474       PSafetyMode mode,                       
00475       PSafeObject * obj                       
00476     );
00477 
00483     PSafePtrBase(
00484       const PSafePtrBase & enumerator   
00485     );
00486 
00487   public:
00490     ~PSafePtrBase();
00492 
00499     Comparison Compare(
00500       const PObject & obj   
00501     ) const;
00503 
00508     void SetNULL();
00509 
00512     bool operator!() const { return currentObject == NULL; }
00513 
00516     PSafetyMode GetSafetyMode() const { return lockMode; }
00517 
00520     PBoolean SetSafetyMode(
00521       PSafetyMode mode  
00522     );
00523 
00526     const PSafeCollection * GetCollection() const { return collection; }
00528 
00529     void Assign(const PSafePtrBase & ptr);
00530     void Assign(const PSafeCollection & safeCollection);
00531     void Assign(PSafeObject * obj);
00532     void Assign(PINDEX idx);
00533 
00534   protected:
00535     void Next();
00536     void Previous();
00537 
00538     enum EnterSafetyModeOption {
00539       WithReference,
00540       AlreadyReferenced
00541     };
00542     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00543 
00544     enum ExitSafetyModeOption {
00545       WithDereference,
00546       NoDereference
00547     };
00548     void ExitSafetyMode(ExitSafetyModeOption ref);
00549 
00550   protected:
00551     const PSafeCollection * collection;
00552     PSafeObject           * currentObject;
00553     PSafetyMode             lockMode;
00554 };
00555 
00556 
00578 template <class T> class PSafePtr : public PSafePtrBase
00579 {
00580     PCLASSINFO(PSafePtr, PSafePtrBase);
00581   public:
00591     PSafePtr(
00592       T * obj = NULL,                   
00593       PSafetyMode mode = PSafeReference 
00594     ) : PSafePtrBase(obj, mode) { }
00595 
00603     PSafePtr(
00604       const PSafeCollection & safeCollection, 
00605       PSafetyMode mode = PSafeReadWrite,      
00606       PINDEX idx = 0                          
00607     ) : PSafePtrBase(safeCollection, mode, idx) { }
00608 
00616     PSafePtr(
00617       const PSafeCollection & safeCollection, 
00618       PSafetyMode mode,                       
00619       PSafeObject * obj                       
00620     ) : PSafePtrBase(safeCollection, mode, obj) { }
00621 
00627     PSafePtr(
00628       const PSafePtr & ptr   
00629     ) : PSafePtrBase(ptr) { }
00630 
00636     PSafePtr & operator=(const PSafePtr & ptr)
00637       {
00638         Assign(ptr);
00639         return *this;
00640       }
00641 
00646     PSafePtr & operator=(const PSafeCollection & safeCollection)
00647       {
00648         Assign(safeCollection);
00649         return *this;
00650       }
00651 
00667     PSafePtr & operator=(T * obj)
00668       {
00669         Assign(obj);
00670         return *this;
00671       }
00672 
00682     PSafePtr & operator=(PINDEX idx)
00683       {
00684         Assign(idx);
00685         return *this;
00686       }
00688 
00693     operator T*()    const { return  (T *)currentObject; }
00694 
00697     T & operator*()  const { return *(T *)PAssertNULL(currentObject); }
00698 
00701     T * operator->() const { return  (T *)PAssertNULL(currentObject); }
00702 
00707     T * operator++(int)
00708       {
00709         T * previous = (T *)currentObject;
00710         Next();
00711         return previous;
00712       }
00713 
00718     T * operator++()
00719       {
00720         Next();
00721         return (T *)currentObject;
00722       }
00723 
00728     T * operator--(int)
00729       {
00730         T * previous = (T *)currentObject;
00731         Previous();
00732         return previous;
00733       }
00734 
00739     T * operator--()
00740       {
00741         Previous();
00742         return (T *)currentObject;
00743       }
00745 
00749       /*
00750   template <class Base>
00751   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00752   {
00753     PSafePtr<T> newPtr;
00754     Base * realPtr = oldPtr;
00755     if (realPtr != NULL && PIsDescendant(realPtr, T))
00756       newPtr.Assign(oldPtr);
00757     return newPtr;
00758   }
00759   */
00760 };
00761 
00762 
00766 template <class Base, class Derived>
00767 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00768 {
00769 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00770     PSafePtr<Derived> newPtr;
00771     Base * realPtr = oldPtr;
00772     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00773       newPtr.Assign(oldPtr);
00774     return newPtr;
00775 }
00776 
00777 
00788 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00789 {
00790     PCLASSINFO(PSafeColl, PSafeCollection);
00791   public:
00796     PSafeColl()
00797       : PSafeCollection(new Coll)
00798       { }
00800 
00807     virtual PSafePtr<Base> Append(
00808       Base * obj,       
00809       PSafetyMode mode = PSafeReference
00810     ) {
00811         PWaitAndSignal mutex(collectionMutex);
00812         if (!obj->SafeReference())
00813           return NULL;
00814         return PSafePtr<Base>(*this, mode, collection->Append(obj));
00815       }
00816 
00825     virtual PBoolean Remove(
00826       Base * obj          
00827     ) {
00828         return SafeRemove(obj);
00829       }
00830 
00839     virtual PBoolean RemoveAt(
00840       PINDEX idx     
00841     ) {
00842         return SafeRemoveAt(idx);
00843       }
00844 
00850     virtual PSafePtr<Base> GetAt(
00851       PINDEX idx,
00852       PSafetyMode mode = PSafeReadWrite
00853     ) {
00854         return PSafePtr<Base>(*this, mode, idx);
00855       }
00856 
00862     virtual PSafePtr<Base> FindWithLock(
00863       const Base & value,
00864       PSafetyMode mode = PSafeReadWrite
00865     ) {
00866         collectionMutex.Wait();
00867         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00868         collectionMutex.Signal();
00869         ptr.SetSafetyMode(mode);
00870         return ptr;
00871       }
00873 };
00874 
00875 
00880 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00881 {
00882   public:
00883     typedef PSafePtr<Base> value_type;
00884 };
00885 
00886 
00891 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
00892 {
00893   public:
00894     typedef PSafePtr<Base> value_type;
00895 };
00896 
00897 
00902 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
00903 {
00904   public:
00905     typedef PSafePtr<Base> value_type;
00906 };
00907 
00908 
00919 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
00920 {
00921     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
00922   public:
00927     PSafeDictionaryBase()
00928       : PSafeCollection(new Coll) { }
00930 
00937     virtual void SetAt(const Key & key, Base * obj)
00938       {
00939         collectionMutex.Wait();
00940         SafeRemove(((Coll *)collection)->GetAt(key));
00941         if (obj->SafeReference())
00942           ((Coll *)collection)->SetAt(key, obj);
00943         collectionMutex.Signal();
00944       }
00945 
00954     virtual PBoolean RemoveAt(
00955       const Key & key   
00956     ) {
00957         PWaitAndSignal mutex(collectionMutex);
00958         return SafeRemove(((Coll *)collection)->GetAt(key));
00959       }
00960 
00963     virtual PBoolean Contains(
00964       const Key & key
00965     ) {
00966         PWaitAndSignal lock(collectionMutex);
00967         return ((Coll *)collection)->Contains(key);
00968       }
00969 
00975     virtual PSafePtr<Base> GetAt(
00976       PINDEX idx,
00977       PSafetyMode mode = PSafeReadWrite
00978     ) {
00979         return PSafePtr<Base>(*this, mode, idx);
00980       }
00981 
00987     virtual PSafePtr<Base> FindWithLock(
00988       const Key & key,
00989       PSafetyMode mode = PSafeReadWrite
00990     ) {
00991         collectionMutex.Wait();
00992         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
00993         collectionMutex.Signal();
00994         ptr.SetSafetyMode(mode);
00995         return ptr;
00996       }
00998 };
00999 
01000 
01005 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01006 {
01007   public:
01008     typedef PSafePtr<Base> value_type;
01009 };
01010 
01011 
01012 #endif // _SAFE_COLLECTION_H
01013 
01014 

Generated on Mon Sep 15 01:21:35 2008 for PTLib by  doxygen 1.5.1