PTLib
Version 2.10.4
|
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: 25554 $ 00027 * $Author: rjongbloed $ 00028 * $Date: 2011-04-13 03:34:50 -0500 (Wed, 13 Apr 2011) $ 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; 00530 00535 virtual void SetNULL(); 00536 00539 bool operator!() const { return currentObject == NULL; } 00540 00543 PSafetyMode GetSafetyMode() const { return lockMode; } 00544 00551 virtual PBoolean SetSafetyMode( 00552 PSafetyMode mode 00553 ); 00554 00557 const PSafeCollection * GetCollection() const { return collection; } 00559 00560 virtual void Assign(const PSafePtrBase & ptr); 00561 virtual void Assign(const PSafeCollection & safeCollection); 00562 virtual void Assign(PSafeObject * obj); 00563 virtual void Assign(PINDEX idx); 00564 00565 protected: 00566 virtual void Next(); 00567 virtual void Previous(); 00568 virtual void DeleteObject(PSafeObject * obj); 00569 00570 enum EnterSafetyModeOption { 00571 WithReference, 00572 AlreadyReferenced 00573 }; 00574 PBoolean EnterSafetyMode(EnterSafetyModeOption ref); 00575 00576 enum ExitSafetyModeOption { 00577 WithDereference, 00578 NoDereference 00579 }; 00580 void ExitSafetyMode(ExitSafetyModeOption ref); 00581 00582 protected: 00583 const PSafeCollection * collection; 00584 PSafeObject * currentObject; 00585 PSafetyMode lockMode; 00586 }; 00587 00588 00601 class PSafePtrMultiThreaded : public PSafePtrBase 00602 { 00603 PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase); 00604 00607 protected: 00615 PSafePtrMultiThreaded( 00616 PSafeObject * obj = NULL, 00617 PSafetyMode mode = PSafeReference 00618 ); 00619 00627 PSafePtrMultiThreaded( 00628 const PSafeCollection & safeCollection, 00629 PSafetyMode mode, 00630 PINDEX idx 00631 ); 00632 00640 PSafePtrMultiThreaded( 00641 const PSafeCollection & safeCollection, 00642 PSafetyMode mode, 00643 PSafeObject * obj 00644 ); 00645 00651 PSafePtrMultiThreaded( 00652 const PSafePtrMultiThreaded & enumerator 00653 ); 00654 00655 public: 00658 ~PSafePtrMultiThreaded(); 00660 00667 virtual Comparison Compare( 00668 const PObject & obj 00669 ) const; 00671 00676 virtual void SetNULL(); 00677 00684 virtual PBoolean SetSafetyMode( 00685 PSafetyMode mode 00686 ); 00688 00689 virtual void Assign(const PSafePtrMultiThreaded & ptr); 00690 virtual void Assign(const PSafePtrBase & ptr); 00691 virtual void Assign(const PSafeCollection & safeCollection); 00692 virtual void Assign(PSafeObject * obj); 00693 virtual void Assign(PINDEX idx); 00694 00695 protected: 00696 virtual void Next(); 00697 virtual void Previous(); 00698 virtual void DeleteObject(PSafeObject * obj); 00699 00700 void Lock() { m_mutex.Wait(); } 00701 void Unlock(); 00702 00703 protected: 00704 mutable PMutex m_mutex; 00705 PSafeObject * m_objectToDelete; 00706 }; 00707 00708 00729 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass 00730 { 00731 public: 00741 PSafePtr( 00742 T * obj = NULL, 00743 PSafetyMode mode = PSafeReference 00744 ) : BaseClass(obj, mode) { } 00745 00753 PSafePtr( 00754 const PSafeCollection & safeCollection, 00755 PSafetyMode mode = PSafeReadWrite, 00756 PINDEX idx = 0 00757 ) : BaseClass(safeCollection, mode, idx) { } 00758 00766 PSafePtr( 00767 const PSafeCollection & safeCollection, 00768 PSafetyMode mode, 00769 PSafeObject * obj 00770 ) : BaseClass(safeCollection, mode, obj) { } 00771 00777 PSafePtr( 00778 const PSafePtr & ptr 00779 ) : BaseClass(ptr) { } 00780 00786 PSafePtr & operator=(const PSafePtr & ptr) 00787 { 00788 BaseClass::Assign(ptr); 00789 return *this; 00790 } 00791 00796 PSafePtr & operator=(const PSafeCollection & safeCollection) 00797 { 00798 BaseClass::Assign(safeCollection); 00799 return *this; 00800 } 00801 00817 PSafePtr & operator=(T * obj) 00818 { 00819 this->Assign(obj); 00820 return *this; 00821 } 00822 00832 PSafePtr & operator=(PINDEX idx) 00833 { 00834 BaseClass::Assign(idx); 00835 return *this; 00836 } 00838 00843 operator T*() const { return (T *)BaseClass::currentObject; } 00844 00847 T & operator*() const { return *(T *)PAssertNULL(BaseClass::currentObject); } 00848 00851 T * operator->() const { return (T *)PAssertNULL(BaseClass::currentObject); } 00852 00857 T * operator++(int) 00858 { 00859 T * previous = (T *)BaseClass::currentObject; 00860 BaseClass::Next(); 00861 return previous; 00862 } 00863 00868 T * operator++() 00869 { 00870 BaseClass::Next(); 00871 return (T *)BaseClass::currentObject; 00872 } 00873 00878 T * operator--(int) 00879 { 00880 T * previous = (T *)BaseClass::currentObject; 00881 BaseClass::Previous(); 00882 return previous; 00883 } 00884 00889 T * operator--() 00890 { 00891 BaseClass::Previous(); 00892 return (T *)BaseClass::currentObject; 00893 } 00895 00899 /* 00900 template <class Base> 00901 static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr) 00902 { 00903 PSafePtr<T> newPtr; 00904 Base * realPtr = oldPtr; 00905 if (realPtr != NULL && PIsDescendant(realPtr, T)) 00906 newPtr.Assign(oldPtr); 00907 return newPtr; 00908 } 00909 */ 00910 }; 00911 00912 00916 template <class Base, class Derived> 00917 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr) 00918 { 00919 // return PSafePtr<Derived>::DownCast<Base>(oldPtr); 00920 PSafePtr<Derived> newPtr; 00921 Base * realPtr = oldPtr; 00922 if (realPtr != NULL && PIsDescendant(realPtr, Derived)) 00923 newPtr.Assign(oldPtr); 00924 return newPtr; 00925 } 00926 00927 00938 template <class Coll, class Base> class PSafeColl : public PSafeCollection 00939 { 00940 PCLASSINFO(PSafeColl, PSafeCollection); 00941 public: 00946 PSafeColl() 00947 : PSafeCollection(new Coll) 00948 { } 00949 00953 PSafeColl(const PSafeColl & other) 00954 : PSafeCollection(new Coll) 00955 { 00956 PWaitAndSignal lock2(other.collectionMutex); 00957 CopySafeCollection(dynamic_cast<Coll *>(other.collection)); 00958 } 00959 00963 PSafeColl & operator=(const PSafeColl & other) 00964 { 00965 if (&other != this) { 00966 RemoveAll(true); 00967 PWaitAndSignal lock1(collectionMutex); 00968 PWaitAndSignal lock2(other.collectionMutex); 00969 CopySafeCollection(dynamic_cast<Coll *>(other.collection)); 00970 } 00971 return *this; 00972 } 00974 00981 virtual PSafePtr<Base> Append( 00982 Base * obj, 00983 PSafetyMode mode = PSafeReference 00984 ) { 00985 PWaitAndSignal mutex(collectionMutex); 00986 if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") && 00987 obj->SafeReference()) 00988 return PSafePtr<Base>(*this, mode, collection->Append(obj)); 00989 return NULL; 00990 } 00991 01000 virtual PBoolean Remove( 01001 Base * obj 01002 ) { 01003 return SafeRemove(obj); 01004 } 01005 01014 virtual PBoolean RemoveAt( 01015 PINDEX idx 01016 ) { 01017 return SafeRemoveAt(idx); 01018 } 01019 01025 virtual PSafePtr<Base> GetAt( 01026 PINDEX idx, 01027 PSafetyMode mode = PSafeReadWrite 01028 ) { 01029 return PSafePtr<Base>(*this, mode, idx); 01030 } 01031 01037 virtual PSafePtr<Base> FindWithLock( 01038 const Base & value, 01039 PSafetyMode mode = PSafeReadWrite 01040 ) { 01041 collectionMutex.Wait(); 01042 PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value)); 01043 collectionMutex.Signal(); 01044 ptr.SetSafetyMode(mode); 01045 return ptr; 01046 } 01048 }; 01049 01050 01055 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base> 01056 { 01057 public: 01058 typedef PSafePtr<Base> value_type; 01059 }; 01060 01061 01066 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base> 01067 { 01068 public: 01069 typedef PSafePtr<Base> value_type; 01070 }; 01071 01072 01077 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base> 01078 { 01079 public: 01080 typedef PSafePtr<Base> value_type; 01081 }; 01082 01083 01094 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection 01095 { 01096 PCLASSINFO(PSafeDictionaryBase, PSafeCollection); 01097 public: 01102 PSafeDictionaryBase() 01103 : PSafeCollection(new Coll) { } 01104 01108 PSafeDictionaryBase(const PSafeDictionaryBase & other) 01109 : PSafeCollection(new Coll) 01110 { 01111 PWaitAndSignal lock2(other.collectionMutex); 01112 CopySafeDictionary(dynamic_cast<Coll *>(other.collection)); 01113 } 01114 01118 PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other) 01119 { 01120 if (&other != this) { 01121 RemoveAll(true); 01122 PWaitAndSignal lock1(collectionMutex); 01123 PWaitAndSignal lock2(other.collectionMutex); 01124 CopySafeDictionary(dynamic_cast<Coll *>(other.collection)); 01125 } 01126 return *this; 01127 } 01129 01136 virtual void SetAt(const Key & key, Base * obj) 01137 { 01138 collectionMutex.Wait(); 01139 SafeRemove(((Coll *)collection)->GetAt(key)); 01140 if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") && 01141 obj->SafeReference()) 01142 ((Coll *)collection)->SetAt(key, obj); 01143 collectionMutex.Signal(); 01144 } 01145 01154 virtual PBoolean RemoveAt( 01155 const Key & key 01156 ) { 01157 PWaitAndSignal mutex(collectionMutex); 01158 return SafeRemove(((Coll *)collection)->GetAt(key)); 01159 } 01160 01163 virtual PBoolean Contains( 01164 const Key & key 01165 ) { 01166 PWaitAndSignal lock(collectionMutex); 01167 return ((Coll *)collection)->Contains(key); 01168 } 01169 01175 virtual PSafePtr<Base> GetAt( 01176 PINDEX idx, 01177 PSafetyMode mode = PSafeReadWrite 01178 ) { 01179 return PSafePtr<Base>(*this, mode, idx); 01180 } 01181 01187 virtual PSafePtr<Base> FindWithLock( 01188 const Key & key, 01189 PSafetyMode mode = PSafeReadWrite 01190 ) { 01191 collectionMutex.Wait(); 01192 PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key)); 01193 collectionMutex.Signal(); 01194 ptr.SetSafetyMode(mode); 01195 return ptr; 01196 } 01197 01200 PArray<Key> GetKeys() const 01201 { 01202 PArray<Key> keys; 01203 collectionMutex.Wait(); 01204 ((Coll *)collection)->AbstractGetKeys(keys); 01205 collectionMutex.Signal(); 01206 return keys; 01207 } 01209 }; 01210 01211 01216 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base> 01217 { 01218 public: 01219 typedef PSafePtr<Base> value_type; 01220 }; 01221 01222 01223 #endif // PTLIB_SAFE_COLLECTION_H 01224 01225 01226 // End Of File ///////////////////////////////////////////////////////////////