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: 19008 $
00027  * $Author: rjongbloed $
00028  * $Date: 2007-11-29 09:17:41 +0000 (Thu, 29 Nov 2007) $
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;
00226 
00227   private:
00228     mutable PMutex    safetyMutex;
00229     unsigned          safeReferenceCount;
00230     PBoolean              safelyBeingRemoved;
00231     PReadWriteMutex   safeInUseMutex;
00232     PReadWriteMutex * safeInUse;
00233 };
00234 
00235 
00238 class PSafeLockReadOnly
00239 {
00240   public:
00241     PSafeLockReadOnly(const PSafeObject & object);
00242     ~PSafeLockReadOnly();
00243     PBoolean Lock();
00244     void Unlock();
00245     PBoolean IsLocked() const { return locked; }
00246     bool operator!() const { return !locked; }
00247 
00248   protected:
00249     PSafeObject & safeObject;
00250     PBoolean          locked;
00251 };
00252 
00253 
00254 
00257 class PSafeLockReadWrite
00258 {
00259   public:
00260     PSafeLockReadWrite(const PSafeObject & object);
00261     ~PSafeLockReadWrite();
00262     PBoolean Lock();
00263     void Unlock();
00264     PBoolean IsLocked() const { return locked; }
00265     bool operator!() const { return !locked; }
00266 
00267   protected:
00268     PSafeObject & safeObject;
00269     PBoolean          locked;
00270 };
00271 
00272 
00273 
00286 class PSafeCollection : public PObject
00287 {
00288     PCLASSINFO(PSafeCollection, PObject);
00289   public:
00295     PSafeCollection(
00296       PCollection * collection    
00297      );
00298 
00302     ~PSafeCollection();
00304 
00307   protected:
00316     virtual PBoolean SafeRemove(
00317       PSafeObject * obj   
00318     );
00319 
00328     virtual PBoolean SafeRemoveAt(
00329       PINDEX idx    
00330     );
00331 
00332   public:
00335     virtual void RemoveAll(
00336       PBoolean synchronous = PFalse  
00337     );
00338 
00343     void AllowDeleteObjects(
00344       PBoolean yes = PTrue   
00345     ) { deleteObjects = yes; }
00346 
00351     void DisallowDeleteObjects() { deleteObjects = PFalse; }
00352 
00357     virtual PBoolean DeleteObjectsToBeRemoved();
00358 
00361     virtual void DeleteObject(PObject * object) const;
00362 
00365     virtual void SetAutoDeleteObjects();
00366 
00371     PINDEX GetSize() const;
00372 
00377     PBoolean IsEmpty() const { return GetSize() == 0; }
00378 
00381     const PMutex & GetMutex() const { return collectionMutex; }
00383 
00384   protected:
00385     void SafeRemoveObject(PSafeObject * obj);
00386     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00387 
00388     PCollection  *     collection;
00389     mutable PMutex     collectionMutex;
00390     PBoolean               deleteObjects;
00391     PList<PSafeObject> toBeRemoved;
00392     PMutex             removalMutex;
00393     PTimer             deleteObjectsTimer;
00394 
00395   friend class PSafePtrBase;
00396 };
00397 
00398 
00399 enum PSafetyMode {
00400   PSafeReference,
00401   PSafeReadOnly,
00402   PSafeReadWrite
00403 };
00404 
00420 class PSafePtrBase : public PObject
00421 {
00422     PCLASSINFO(PSafePtrBase, PObject);
00423 
00426   protected:
00434     PSafePtrBase(
00435       PSafeObject * obj = NULL,         
00436       PSafetyMode mode = PSafeReference 
00437     );
00438 
00446     PSafePtrBase(
00447       const PSafeCollection & safeCollection, 
00448       PSafetyMode mode,                       
00449       PINDEX idx                              
00450     );
00451 
00459     PSafePtrBase(
00460       const PSafeCollection & safeCollection, 
00461       PSafetyMode mode,                       
00462       PSafeObject * obj                       
00463     );
00464 
00470     PSafePtrBase(
00471       const PSafePtrBase & enumerator   
00472     );
00473 
00474   public:
00477     ~PSafePtrBase();
00479 
00486     Comparison Compare(
00487       const PObject & obj   
00488     ) const;
00490 
00495     bool operator!() const { return currentObject == NULL; }
00496 
00499     PSafetyMode GetSafetyMode() const { return lockMode; }
00500 
00503     PBoolean SetSafetyMode(
00504       PSafetyMode mode  
00505     );
00506 
00509     const PSafeCollection * GetCollection() const { return collection; }
00511 
00512     void Assign(const PSafePtrBase & ptr);
00513     void Assign(const PSafeCollection & safeCollection);
00514     void Assign(PSafeObject * obj);
00515     void Assign(PINDEX idx);
00516 
00517   protected:
00518     void Next();
00519     void Previous();
00520 
00521     enum EnterSafetyModeOption {
00522       WithReference,
00523       AlreadyReferenced
00524     };
00525     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00526 
00527     enum ExitSafetyModeOption {
00528       WithDereference,
00529       NoDereference
00530     };
00531     void ExitSafetyMode(ExitSafetyModeOption ref);
00532 
00533   protected:
00534     const PSafeCollection * collection;
00535     PSafeObject           * currentObject;
00536     PSafetyMode             lockMode;
00537 };
00538 
00539 
00561 template <class T> class PSafePtr : public PSafePtrBase
00562 {
00563     PCLASSINFO(PSafePtr, PSafePtrBase);
00564   public:
00574     PSafePtr(
00575       T * obj = NULL,                   
00576       PSafetyMode mode = PSafeReference 
00577     ) : PSafePtrBase(obj, mode) { }
00578 
00586     PSafePtr(
00587       const PSafeCollection & safeCollection, 
00588       PSafetyMode mode = PSafeReadWrite,      
00589       PINDEX idx = 0                          
00590     ) : PSafePtrBase(safeCollection, mode, idx) { }
00591 
00599     PSafePtr(
00600       const PSafeCollection & safeCollection, 
00601       PSafetyMode mode,                       
00602       PSafeObject * obj                       
00603     ) : PSafePtrBase(safeCollection, mode, obj) { }
00604 
00610     PSafePtr(
00611       const PSafePtr & ptr   
00612     ) : PSafePtrBase(ptr) { }
00613 
00619     PSafePtr & operator=(const PSafePtr & ptr)
00620       {
00621         Assign(ptr);
00622         return *this;
00623       }
00624 
00629     PSafePtr & operator=(const PSafeCollection & safeCollection)
00630       {
00631         Assign(safeCollection);
00632         return *this;
00633       }
00634 
00650     PSafePtr & operator=(T * obj)
00651       {
00652         Assign(obj);
00653         return *this;
00654       }
00655 
00665     PSafePtr & operator=(PINDEX idx)
00666       {
00667         Assign(idx);
00668         return *this;
00669       }
00671 
00676     operator T*()    const { return  (T *)currentObject; }
00677 
00680     T & operator*()  const { return *(T *)PAssertNULL(currentObject); }
00681 
00684     T * operator->() const { return  (T *)PAssertNULL(currentObject); }
00685 
00690     T * operator++(int)
00691       {
00692         T * previous = (T *)currentObject;
00693         Next();
00694         return previous;
00695       }
00696 
00701     T * operator++()
00702       {
00703         Next();
00704         return (T *)currentObject;
00705       }
00706 
00711     T * operator--(int)
00712       {
00713         T * previous = (T *)currentObject;
00714         Previous();
00715         return previous;
00716       }
00717 
00722     T * operator--()
00723       {
00724         Previous();
00725         return (T *)currentObject;
00726       }
00728 
00732       /*
00733   template <class Base>
00734   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00735   {
00736     PSafePtr<T> newPtr;
00737     Base * realPtr = oldPtr;
00738     if (realPtr != NULL && PIsDescendant(realPtr, T))
00739       newPtr.Assign(oldPtr);
00740     return newPtr;
00741   }
00742   */
00743 };
00744 
00745 
00749 template <class Base, class Derived>
00750 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00751 {
00752 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00753     PSafePtr<Derived> newPtr;
00754     Base * realPtr = oldPtr;
00755     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00756       newPtr.Assign(oldPtr);
00757     return newPtr;
00758 }
00759 
00760 
00771 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00772 {
00773     PCLASSINFO(PSafeColl, PSafeCollection);
00774   public:
00779     PSafeColl()
00780       : PSafeCollection(new Coll)
00781       { }
00783 
00790     virtual PSafePtr<Base> Append(
00791       Base * obj,       
00792       PSafetyMode mode = PSafeReference
00793     ) {
00794         PWaitAndSignal mutex(collectionMutex);
00795         if (!obj->SafeReference())
00796           return NULL;
00797         return PSafePtr<Base>(*this, mode, collection->Append(obj));
00798       }
00799 
00808     virtual PBoolean Remove(
00809       Base * obj          
00810     ) {
00811         return SafeRemove(obj);
00812       }
00813 
00822     virtual PBoolean RemoveAt(
00823       PINDEX idx     
00824     ) {
00825         return SafeRemoveAt(idx);
00826       }
00827 
00833     virtual PSafePtr<Base> GetAt(
00834       PINDEX idx,
00835       PSafetyMode mode = PSafeReadWrite
00836     ) {
00837         return PSafePtr<Base>(*this, mode, idx);
00838       }
00839 
00845     virtual PSafePtr<Base> FindWithLock(
00846       const Base & value,
00847       PSafetyMode mode = PSafeReadWrite
00848     ) {
00849         collectionMutex.Wait();
00850         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00851         collectionMutex.Signal();
00852         ptr.SetSafetyMode(mode);
00853         return ptr;
00854       }
00856 };
00857 
00858 
00863 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00864 {
00865 };
00866 
00867 
00872 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
00873 {
00874 };
00875 
00876 
00881 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
00882 {
00883 };
00884 
00885 
00896 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
00897 {
00898     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
00899   public:
00904     PSafeDictionaryBase()
00905       : PSafeCollection(new Coll) { }
00907 
00914     virtual void SetAt(const Key & key, Base * obj)
00915       {
00916         collectionMutex.Wait();
00917         SafeRemove(((Coll *)collection)->GetAt(key));
00918         if (obj->SafeReference())
00919           ((Coll *)collection)->SetAt(key, obj);
00920         collectionMutex.Signal();
00921       }
00922 
00931     virtual PBoolean RemoveAt(
00932       const Key & key   
00933     ) {
00934         PWaitAndSignal mutex(collectionMutex);
00935         return SafeRemove(((Coll *)collection)->GetAt(key));
00936       }
00937 
00940     virtual PBoolean Contains(
00941       const Key & key
00942     ) {
00943         PWaitAndSignal lock(collectionMutex);
00944         return ((Coll *)collection)->Contains(key);
00945       }
00946 
00952     virtual PSafePtr<Base> GetAt(
00953       PINDEX idx,
00954       PSafetyMode mode = PSafeReadWrite
00955     ) {
00956         return PSafePtr<Base>(*this, mode, idx);
00957       }
00958 
00964     virtual PSafePtr<Base> FindWithLock(
00965       const Key & key,
00966       PSafetyMode mode = PSafeReadWrite
00967     ) {
00968         collectionMutex.Wait();
00969         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
00970         collectionMutex.Signal();
00971         ptr.SetSafetyMode(mode);
00972         return ptr;
00973       }
00975 };
00976 
00977 
00982 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
00983 {
00984 };
00985 
00986 
00987 #endif // _SAFE_COLLECTION_H
00988 
00989 

Generated on Mon Dec 10 11:18:57 2007 for PTLib by  doxygen 1.5.1