# 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: 27948 $
    00027  * $Author: rjongbloed $
    00028  * $Date: 2012-06-30 22:54:23 -0500 (Sat, 30 Jun 2012) $
    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
    00119 class PSafeObject : public PObject
    00120 {
    00121     PCLASSINFO(PSafeObject, PObject);
    00122   public:
    00127     PSafeObject(
    00128         PSafeObject * indirectLock = NULL
    00129     );
    00131
    00152     PBoolean SafeReference();
    00153
    00164     PBoolean SafeDereference();
    00165
    00183     PBoolean LockReadOnly() const;
    00184
    00195     void UnlockReadOnly() const;
    00196
    00214     PBoolean LockReadWrite();
    00215
    00226     void UnlockReadWrite();
    00227
    00237     void SafeRemove();
    00238
    00246     PBoolean SafelyCanBeDeleted() const;
    00247
    00259     virtual bool GarbageCollection();
    00261
    00262   private:
    00263     mutable PMutex    safetyMutex;
    00264     unsigned          safeReferenceCount;
    00265     bool              safelyBeingRemoved;
    00266     PReadWriteMutex   safeInUseMutex;
    00267     PReadWriteMutex * safeInUse;
    00268
    00269   friend class PSafeCollection;
    00270 };
    00271
    00272
    00275 class PSafeLockReadOnly
    00276 {
    00277   public:
    00278     PSafeLockReadOnly(const PSafeObject & object);
    00279     ~PSafeLockReadOnly();
    00280     PBoolean Lock();
    00281     void Unlock();
    00282     PBoolean IsLocked() const { return locked; }
    00283     bool operator!() const { return !locked; }
    00284
    00285   protected:
    00286     PSafeObject & safeObject;
    00287     PBoolean          locked;
    00288 };
    00289
    00290
    00291
    00294 class PSafeLockReadWrite
    00295 {
    00296   public:
    00297     PSafeLockReadWrite(const PSafeObject & object);
    00298     ~PSafeLockReadWrite();
    00299     PBoolean Lock();
    00300     void Unlock();
    00301     PBoolean IsLocked() const { return locked; }
    00302     bool operator!() const { return !locked; }
    00303
    00304   protected:
    00305     PSafeObject & safeObject;
    00306     PBoolean          locked;
    00307 };
    00308
    00309
    00310
    00323 class PSafeCollection : public PObject
    00324 {
    00325     PCLASSINFO(PSafeCollection, PObject);
    00326   public:
    00332     PSafeCollection(
    00333       PCollection * collection
    00334      );
    00335
    00339     ~PSafeCollection();
    00341
    00344   protected:
    00353     virtual PBoolean SafeRemove(
    00354       PSafeObject * obj
    00355     );
    00356
    00365     virtual PBoolean SafeRemoveAt(
    00366       PINDEX idx
    00367     );
    00368
    00369   public:
    00372     virtual void RemoveAll(
    00373       PBoolean synchronous = false
    00374     );
    00375
    00380     void AllowDeleteObjects(
    00381       PBoolean yes = true
    00382     ) { deleteObjects = yes; }
    00383
    00388     void DisallowDeleteObjects() { deleteObjects = false; }
    00389
    00394     virtual PBoolean DeleteObjectsToBeRemoved();
    00395
    00398     virtual void DeleteObject(PObject * object) const;
    00399
    00402     virtual void SetAutoDeleteObjects();
    00403
    00408     PINDEX GetSize() const;
    00409
    00414     PBoolean IsEmpty() const { return GetSize() == 0; }
    00415
    00418     const PMutex & GetMutex() const { return collectionMutex; }
    00420
    00421   protected:
    00422     void CopySafeCollection(PCollection * other);
    00423     void CopySafeDictionary(PAbstractDictionary * other);
    00424     void SafeRemoveObject(PSafeObject * obj);
    00425     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
    00426
    00427     PCollection      * collection;
    00428     mutable PMutex     collectionMutex;
    00429     bool               deleteObjects;
    00430     PList<PSafeObject> toBeRemoved;
    00431     PMutex             removalMutex;
    00432     PTimer             deleteObjectsTimer;
    00433
    00434   private:
    00435     PSafeCollection(const PSafeCollection & other) : PObject(other) { }
    00436     void operator=(const PSafeCollection &) { }
    00437
    00438   friend class PSafePtrBase;
    00439 };
    00440
    00441
    00442 enum PSafetyMode {
    00443   PSafeReference,
    00444   PSafeReadOnly,
    00445   PSafeReadWrite
    00446 };
    00447
    00460 class PSafePtrBase : public PObject
    00461 {
    00462     PCLASSINFO(PSafePtrBase, PObject);
    00463
    00466   protected:
    00474     PSafePtrBase(
    00475       PSafeObject * obj = NULL,
    00476       PSafetyMode mode = PSafeReference
    00477     );
    00478
    00486     PSafePtrBase(
    00487       const PSafeCollection & safeCollection,
    00488       PSafetyMode mode,
    00489       PINDEX idx
    00490     );
    00491
    00499     PSafePtrBase(
    00500       const PSafeCollection & safeCollection,
    00501       PSafetyMode mode,
    00502       PSafeObject * obj
    00503     );
    00504
    00510     PSafePtrBase(
    00511       const PSafePtrBase & enumerator
    00512     );
    00513
    00514   public:
    00517     ~PSafePtrBase();
    00519
    00526     virtual Comparison Compare(
    00527       const PObject & obj
    00528     ) const;
    00529
    00536     virtual void PrintOn(
    00537       ostream &strm   // Stream to print the object into.
    00538     ) const;
    00540
    00545     virtual void SetNULL();
    00546
    00549     bool operator!() const { return currentObject == NULL; }
    00550
    00553     PSafetyMode GetSafetyMode() const { return lockMode; }
    00554
    00561     virtual PBoolean SetSafetyMode(
    00562       PSafetyMode mode
    00563     );
    00564
    00567     const PSafeCollection * GetCollection() const { return collection; }
    00569
    00570     virtual void Assign(const PSafePtrBase & ptr);
    00571     virtual void Assign(const PSafeCollection & safeCollection);
    00572     virtual void Assign(PSafeObject * obj);
    00573     virtual void Assign(PINDEX idx);
    00574
    00575   protected:
    00576     virtual void Next();
    00577     virtual void Previous();
    00578     virtual void DeleteObject(PSafeObject * obj);
    00579
    00580     enum EnterSafetyModeOption {
    00581       WithReference,
    00582       AlreadyReferenced
    00583     };
    00584     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
    00585
    00586     enum ExitSafetyModeOption {
    00587       WithDereference,
    00588       NoDereference
    00589     };
    00590     void ExitSafetyMode(ExitSafetyModeOption ref);
    00591
    00592     virtual void LockPtr() { }
    00593     virtual void UnlockPtr() { }
    00594
    00595   protected:
    00596     const PSafeCollection * collection;
    00597     PSafeObject           * currentObject;
    00598     PSafetyMode             lockMode;
    00599 };
    00600
    00601
    00614 class PSafePtrMultiThreaded : public PSafePtrBase
    00615 {
    00616     PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
    00617
    00620   protected:
    00628     PSafePtrMultiThreaded(
    00629       PSafeObject * obj = NULL,
    00630       PSafetyMode mode = PSafeReference
    00631     );
    00632
    00640     PSafePtrMultiThreaded(
    00641       const PSafeCollection & safeCollection,
    00642       PSafetyMode mode,
    00643       PINDEX idx
    00644     );
    00645
    00653     PSafePtrMultiThreaded(
    00654       const PSafeCollection & safeCollection,
    00655       PSafetyMode mode,
    00656       PSafeObject * obj
    00657     );
    00658
    00664     PSafePtrMultiThreaded(
    00665       const PSafePtrMultiThreaded & enumerator
    00666     );
    00667
    00668   public:
    00671     ~PSafePtrMultiThreaded();
    00673
    00680     virtual Comparison Compare(
    00681       const PObject & obj
    00682     ) const;
    00684
    00689     virtual void SetNULL();
    00690
    00697     virtual PBoolean SetSafetyMode(
    00698       PSafetyMode mode
    00699     );
    00701
    00702     virtual void Assign(const PSafePtrMultiThreaded & ptr);
    00703     virtual void Assign(const PSafePtrBase & ptr);
    00704     virtual void Assign(const PSafeCollection & safeCollection);
    00705     virtual void Assign(PSafeObject * obj);
    00706     virtual void Assign(PINDEX idx);
    00707
    00708   protected:
    00709     virtual void Next();
    00710     virtual void Previous();
    00711     virtual void DeleteObject(PSafeObject * obj);
    00712
    00713     virtual void LockPtr() { m_mutex.Wait(); }
    00714     virtual void UnlockPtr();
    00715
    00716   protected:
    00717     mutable PMutex m_mutex;
    00718     PSafeObject  * m_objectToDelete;
    00719 };
    00720
    00721
    00742 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
    00743 {
    00744   public:
    00754     PSafePtr(
    00755       T * obj = NULL,
    00756       PSafetyMode mode = PSafeReference
    00757     ) : BaseClass(obj, mode) { }
    00758
    00766     PSafePtr(
    00767       const PSafeCollection & safeCollection,
    00768       PSafetyMode mode = PSafeReadWrite,
    00769       PINDEX idx = 0
    00770     ) : BaseClass(safeCollection, mode, idx) { }
    00771
    00779     PSafePtr(
    00780       const PSafeCollection & safeCollection,
    00781       PSafetyMode mode,
    00782       PSafeObject * obj
    00783     ) : BaseClass(safeCollection, mode, obj) { }
    00784
    00790     PSafePtr(
    00791       const PSafePtr & ptr
    00792     ) : BaseClass(ptr) { }
    00793
    00799     PSafePtr & operator=(const PSafePtr & ptr)
    00800       {
    00801         BaseClass::Assign(ptr);
    00802         return *this;
    00803       }
    00804
    00809     PSafePtr & operator=(const PSafeCollection & safeCollection)
    00810       {
    00811         BaseClass::Assign(safeCollection);
    00812         return *this;
    00813       }
    00814
    00830     PSafePtr & operator=(T * obj)
    00831       {
    00832         this->Assign(obj);
    00833         return *this;
    00834       }
    00835
    00845     PSafePtr & operator=(PINDEX idx)
    00846       {
    00847         BaseClass::Assign(idx);
    00848         return *this;
    00849       }
    00850
    00855     PSafePtr Set(T * obj)
    00856       {
    00857         this->LockPtr();
    00858         PSafePtr oldPtr = *this;
    00859         this->Assign(obj);
    00860         this->UnlockPtr();
    00861         return oldPtr;
    00862       }
    00864
    00869     operator T*()    const { return  (T *)BaseClass::currentObject; }
    00870
    00873     T & operator*()  const { return *(T *)PAssertNULL(BaseClass::currentObject); }
    00874
    00877     T * operator->() const { return  (T *)PAssertNULL(BaseClass::currentObject); }
    00878
    00883     T * operator++(int)
    00884       {
    00885         T * previous = (T *)BaseClass::currentObject;
    00886         BaseClass::Next();
    00887         return previous;
    00888       }
    00889
    00894     T * operator++()
    00895       {
    00896         BaseClass::Next();
    00897         return (T *)BaseClass::currentObject;
    00898       }
    00899
    00904     T * operator--(int)
    00905       {
    00906         T * previous = (T *)BaseClass::currentObject;
    00907         BaseClass::Previous();
    00908         return previous;
    00909       }
    00910
    00915     T * operator--()
    00916       {
    00917         BaseClass::Previous();
    00918         return (T *)BaseClass::currentObject;
    00919       }
    00921 };
    00922
    00923
    00927 template <class Base, class Derived>
    00928 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
    00929 {
    00930 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
    00931     PSafePtr<Derived> newPtr;
    00932     Base * realPtr = oldPtr;
    00933     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
    00934       newPtr.Assign(oldPtr);
    00935     return newPtr;
    00936 }
    00937
    00938
    00949 template <class Coll, class Base> class PSafeColl : public PSafeCollection
    00950 {
    00951     PCLASSINFO(PSafeColl, PSafeCollection);
    00952   public:
    00957     PSafeColl()
    00958       : PSafeCollection(new Coll)
    00959       { }
    00960
    00964     PSafeColl(const PSafeColl & other)
    00965       : PSafeCollection(new Coll)
    00966     {
    00967       PWaitAndSignal lock2(other.collectionMutex);
    00968       CopySafeCollection(dynamic_cast<Coll *>(other.collection));
    00969     }
    00970
    00974     PSafeColl & operator=(const PSafeColl & other)
    00975     {
    00976       if (&other != this) {
    00977         RemoveAll(true);
    00978         PWaitAndSignal lock1(collectionMutex);
    00979         PWaitAndSignal lock2(other.collectionMutex);
    00980         CopySafeCollection(dynamic_cast<Coll *>(other.collection));
    00981       }
    00982       return *this;
    00983     }
    00985
    00992     virtual PSafePtr<Base> Append(
    00993       Base * obj,
    00994       PSafetyMode mode = PSafeReference
    00995     ) {
    00996         PWaitAndSignal mutex(collectionMutex);
    00997         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
    00998             obj->SafeReference())
    00999           return PSafePtr<Base>(*this, mode, collection->Append(obj));
    01000         return NULL;
    01001       }
    01002
    01011     virtual PBoolean Remove(
    01012       Base * obj
    01013     ) {
    01014         return SafeRemove(obj);
    01015       }
    01016
    01025     virtual PBoolean RemoveAt(
    01026       PINDEX idx
    01027     ) {
    01028         return SafeRemoveAt(idx);
    01029       }
    01030
    01036     virtual PSafePtr<Base> GetAt(
    01037       PINDEX idx,
    01038       PSafetyMode mode = PSafeReadWrite
    01039     ) {
    01040         return PSafePtr<Base>(*this, mode, idx);
    01041       }
    01042
    01048     virtual PSafePtr<Base> FindWithLock(
    01049       const Base & value,
    01050       PSafetyMode mode = PSafeReadWrite
    01051     ) {
    01052         collectionMutex.Wait();
    01053         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
    01054         collectionMutex.Signal();
    01055         ptr.SetSafetyMode(mode);
    01056         return ptr;
    01057       }
    01059 };
    01060
    01061
    01066 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
    01067 {
    01068   public:
    01069     typedef PSafePtr<Base> value_type;
    01070 };
    01071
    01072
    01077 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
    01078 {
    01079   public:
    01080     typedef PSafePtr<Base> value_type;
    01081 };
    01082
    01083
    01088 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
    01089 {
    01090   public:
    01091     typedef PSafePtr<Base> value_type;
    01092 };
    01093
    01094
    01105 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
    01106 {
    01107     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
    01108   public:
    01113     PSafeDictionaryBase()
    01114       : PSafeCollection(new Coll) { }
    01115
    01119     PSafeDictionaryBase(const PSafeDictionaryBase & other)
    01120       : PSafeCollection(new Coll)
    01121     {
    01122       PWaitAndSignal lock2(other.collectionMutex);
    01123       CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
    01124     }
    01125
    01129     PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other)
    01130     {
    01131       if (&other != this) {
    01132         RemoveAll(true);
    01133         PWaitAndSignal lock1(collectionMutex);
    01134         PWaitAndSignal lock2(other.collectionMutex);
    01135         CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
    01136       }
    01137       return *this;
    01138     }
    01140
    01147     virtual void SetAt(const Key & key, Base * obj)
    01148       {
    01149         collectionMutex.Wait();
    01150         SafeRemove(((Coll *)collection)->GetAt(key));
    01151         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
    01152             obj->SafeReference())
    01153           ((Coll *)collection)->SetAt(key, obj);
    01154         collectionMutex.Signal();
    01155       }
    01156
    01165     virtual PBoolean RemoveAt(
    01166       const Key & key
    01167     ) {
    01168         PWaitAndSignal mutex(collectionMutex);
    01169         return SafeRemove(((Coll *)collection)->GetAt(key));
    01170       }
    01171
    01174     virtual PBoolean Contains(
    01175       const Key & key
    01176     ) {
    01177         PWaitAndSignal lock(collectionMutex);
    01178         return ((Coll *)collection)->Contains(key);
    01179       }
    01180
    01186     virtual PSafePtr<Base> GetAt(
    01187       PINDEX idx,
    01188       PSafetyMode mode = PSafeReadWrite
    01189     ) {
    01190         return PSafePtr<Base>(*this, mode, idx);
    01191       }
    01192
    01198     virtual PSafePtr<Base> FindWithLock(
    01199       const Key & key,
    01200       PSafetyMode mode = PSafeReadWrite
    01201     ) {
    01202         collectionMutex.Wait();
    01203         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
    01204         collectionMutex.Signal();
    01205         ptr.SetSafetyMode(mode);
    01206         return ptr;
    01207       }
    01208
    01211     PArray<Key> GetKeys() const
    01212     {
    01213       PArray<Key> keys;
    01214       collectionMutex.Wait();
    01215       ((Coll *)collection)->AbstractGetKeys(keys);
    01216       collectionMutex.Signal();
    01217       return keys;
    01218     }
    01220 };
    01221
    01222
    01227 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
    01228 {
    01229   public:
    01230     typedef PSafePtr<Base> value_type;
    01231 };
    01232
    01233
    01234 #endif // PTLIB_SAFE_COLLECTION_H
    01235
    01236
    01237 // End Of File ///////////////////////////////////////////////////////////////