00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
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 = false
00352 );
00353
00358 void AllowDeleteObjects(
00359 PBoolean yes = true
00360 ) { deleteObjects = yes; }
00361
00366 void DisallowDeleteObjects() { deleteObjects = false; }
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 CopySafeCollection(PCollection * other);
00401 void CopySafeDictionary(PAbstractDictionary * other);
00402 void SafeRemoveObject(PSafeObject * obj);
00403 PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00404
00405 PCollection * collection;
00406 mutable PMutex collectionMutex;
00407 bool deleteObjects;
00408 PList<PSafeObject> toBeRemoved;
00409 PMutex removalMutex;
00410 PTimer deleteObjectsTimer;
00411
00412 private:
00413 PSafeCollection(const PSafeCollection & other) : PObject(other) { }
00414 void operator=(const PSafeCollection &) { }
00415
00416 friend class PSafePtrBase;
00417 };
00418
00419
00420 enum PSafetyMode {
00421 PSafeReference,
00422 PSafeReadOnly,
00423 PSafeReadWrite
00424 };
00425
00438 class PSafePtrBase : public PObject
00439 {
00440 PCLASSINFO(PSafePtrBase, PObject);
00441
00444 protected:
00452 PSafePtrBase(
00453 PSafeObject * obj = NULL,
00454 PSafetyMode mode = PSafeReference
00455 );
00456
00464 PSafePtrBase(
00465 const PSafeCollection & safeCollection,
00466 PSafetyMode mode,
00467 PINDEX idx
00468 );
00469
00477 PSafePtrBase(
00478 const PSafeCollection & safeCollection,
00479 PSafetyMode mode,
00480 PSafeObject * obj
00481 );
00482
00488 PSafePtrBase(
00489 const PSafePtrBase & enumerator
00490 );
00491
00492 public:
00495 ~PSafePtrBase();
00497
00504 virtual Comparison Compare(
00505 const PObject & obj
00506 ) const;
00508
00513 virtual void SetNULL();
00514
00517 bool operator!() const { return currentObject == NULL; }
00518
00521 PSafetyMode GetSafetyMode() const { return lockMode; }
00522
00529 virtual PBoolean SetSafetyMode(
00530 PSafetyMode mode
00531 );
00532
00535 const PSafeCollection * GetCollection() const { return collection; }
00537
00538 virtual void Assign(const PSafePtrBase & ptr);
00539 virtual void Assign(const PSafeCollection & safeCollection);
00540 virtual void Assign(PSafeObject * obj);
00541 virtual void Assign(PINDEX idx);
00542
00543 protected:
00544 virtual void Next();
00545 virtual void Previous();
00546 virtual void DeleteObject(PSafeObject * obj);
00547
00548 enum EnterSafetyModeOption {
00549 WithReference,
00550 AlreadyReferenced
00551 };
00552 PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
00553
00554 enum ExitSafetyModeOption {
00555 WithDereference,
00556 NoDereference
00557 };
00558 void ExitSafetyMode(ExitSafetyModeOption ref);
00559
00560 protected:
00561 const PSafeCollection * collection;
00562 PSafeObject * currentObject;
00563 PSafetyMode lockMode;
00564 };
00565
00566
00579 class PSafePtrMultiThreaded : public PSafePtrBase
00580 {
00581 PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
00582
00585 protected:
00593 PSafePtrMultiThreaded(
00594 PSafeObject * obj = NULL,
00595 PSafetyMode mode = PSafeReference
00596 );
00597
00605 PSafePtrMultiThreaded(
00606 const PSafeCollection & safeCollection,
00607 PSafetyMode mode,
00608 PINDEX idx
00609 );
00610
00618 PSafePtrMultiThreaded(
00619 const PSafeCollection & safeCollection,
00620 PSafetyMode mode,
00621 PSafeObject * obj
00622 );
00623
00629 PSafePtrMultiThreaded(
00630 const PSafePtrMultiThreaded & enumerator
00631 );
00632
00633 public:
00636 ~PSafePtrMultiThreaded();
00638
00645 virtual Comparison Compare(
00646 const PObject & obj
00647 ) const;
00649
00654 virtual void SetNULL();
00655
00662 virtual PBoolean SetSafetyMode(
00663 PSafetyMode mode
00664 );
00666
00667 virtual void Assign(const PSafePtrMultiThreaded & ptr);
00668 virtual void Assign(const PSafePtrBase & ptr);
00669 virtual void Assign(const PSafeCollection & safeCollection);
00670 virtual void Assign(PSafeObject * obj);
00671 virtual void Assign(PINDEX idx);
00672
00673 protected:
00674 virtual void Next();
00675 virtual void Previous();
00676 virtual void DeleteObject(PSafeObject * obj);
00677
00678 void Lock() { m_mutex.Wait(); }
00679 void Unlock();
00680
00681 protected:
00682 mutable PMutex m_mutex;
00683 PSafeObject * m_objectToDelete;
00684 };
00685
00686
00707 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
00708 {
00709 public:
00719 PSafePtr(
00720 T * obj = NULL,
00721 PSafetyMode mode = PSafeReference
00722 ) : BaseClass(obj, mode) { }
00723
00731 PSafePtr(
00732 const PSafeCollection & safeCollection,
00733 PSafetyMode mode = PSafeReadWrite,
00734 PINDEX idx = 0
00735 ) : BaseClass(safeCollection, mode, idx) { }
00736
00744 PSafePtr(
00745 const PSafeCollection & safeCollection,
00746 PSafetyMode mode,
00747 PSafeObject * obj
00748 ) : BaseClass(safeCollection, mode, obj) { }
00749
00755 PSafePtr(
00756 const PSafePtr & ptr
00757 ) : BaseClass(ptr) { }
00758
00764 PSafePtr & operator=(const PSafePtr & ptr)
00765 {
00766 BaseClass::Assign(ptr);
00767 return *this;
00768 }
00769
00774 PSafePtr & operator=(const PSafeCollection & safeCollection)
00775 {
00776 BaseClass::Assign(safeCollection);
00777 return *this;
00778 }
00779
00795 PSafePtr & operator=(T * obj)
00796 {
00797 Assign(obj);
00798 return *this;
00799 }
00800
00810 PSafePtr & operator=(PINDEX idx)
00811 {
00812 BaseClass::Assign(idx);
00813 return *this;
00814 }
00816
00821 operator T*() const { return (T *)BaseClass::currentObject; }
00822
00825 T & operator*() const { return *(T *)PAssertNULL(BaseClass::currentObject); }
00826
00829 T * operator->() const { return (T *)PAssertNULL(BaseClass::currentObject); }
00830
00835 T * operator++(int)
00836 {
00837 T * previous = (T *)BaseClass::currentObject;
00838 BaseClass::Next();
00839 return previous;
00840 }
00841
00846 T * operator++()
00847 {
00848 BaseClass::Next();
00849 return (T *)BaseClass::currentObject;
00850 }
00851
00856 T * operator--(int)
00857 {
00858 T * previous = (T *)BaseClass::currentObject;
00859 BaseClass::Previous();
00860 return previous;
00861 }
00862
00867 T * operator--()
00868 {
00869 BaseClass::Previous();
00870 return (T *)BaseClass::currentObject;
00871 }
00873
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888 };
00889
00890
00894 template <class Base, class Derived>
00895 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00896 {
00897
00898 PSafePtr<Derived> newPtr;
00899 Base * realPtr = oldPtr;
00900 if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00901 newPtr.Assign(oldPtr);
00902 return newPtr;
00903 }
00904
00905
00916 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00917 {
00918 PCLASSINFO(PSafeColl, PSafeCollection);
00919 public:
00924 PSafeColl()
00925 : PSafeCollection(new Coll)
00926 { }
00927
00931 PSafeColl(const PSafeColl & other)
00932 : PSafeCollection(new Coll)
00933 {
00934 PWaitAndSignal lock2(other.collectionMutex);
00935 CopySafeCollection(dynamic_cast<Coll *>(other.collection));
00936 }
00937
00941 PSafeColl & operator=(const PSafeColl & other)
00942 {
00943 if (&other != this) {
00944 RemoveAll(true);
00945 PWaitAndSignal lock1(collectionMutex);
00946 PWaitAndSignal lock2(other.collectionMutex);
00947 CopySafeCollection(dynamic_cast<Coll *>(other.collection));
00948 }
00949 return *this;
00950 }
00952
00959 virtual PSafePtr<Base> Append(
00960 Base * obj,
00961 PSafetyMode mode = PSafeReference
00962 ) {
00963 PWaitAndSignal mutex(collectionMutex);
00964 if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
00965 obj->SafeReference())
00966 return PSafePtr<Base>(*this, mode, collection->Append(obj));
00967 return NULL;
00968 }
00969
00978 virtual PBoolean Remove(
00979 Base * obj
00980 ) {
00981 return SafeRemove(obj);
00982 }
00983
00992 virtual PBoolean RemoveAt(
00993 PINDEX idx
00994 ) {
00995 return SafeRemoveAt(idx);
00996 }
00997
01003 virtual PSafePtr<Base> GetAt(
01004 PINDEX idx,
01005 PSafetyMode mode = PSafeReadWrite
01006 ) {
01007 return PSafePtr<Base>(*this, mode, idx);
01008 }
01009
01015 virtual PSafePtr<Base> FindWithLock(
01016 const Base & value,
01017 PSafetyMode mode = PSafeReadWrite
01018 ) {
01019 collectionMutex.Wait();
01020 PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
01021 collectionMutex.Signal();
01022 ptr.SetSafetyMode(mode);
01023 return ptr;
01024 }
01026 };
01027
01028
01033 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
01034 {
01035 public:
01036 typedef PSafePtr<Base> value_type;
01037 };
01038
01039
01044 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
01045 {
01046 public:
01047 typedef PSafePtr<Base> value_type;
01048 };
01049
01050
01055 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
01056 {
01057 public:
01058 typedef PSafePtr<Base> value_type;
01059 };
01060
01061
01072 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
01073 {
01074 PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
01075 public:
01080 PSafeDictionaryBase()
01081 : PSafeCollection(new Coll) { }
01082
01086 PSafeDictionaryBase(const PSafeDictionaryBase & other)
01087 : PSafeCollection(new Coll)
01088 {
01089 PWaitAndSignal lock2(other.collectionMutex);
01090 CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
01091 }
01092
01096 PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other)
01097 {
01098 if (&other != this) {
01099 RemoveAll(true);
01100 PWaitAndSignal lock1(collectionMutex);
01101 PWaitAndSignal lock2(other.collectionMutex);
01102 CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
01103 }
01104 return *this;
01105 }
01107
01114 virtual void SetAt(const Key & key, Base * obj)
01115 {
01116 collectionMutex.Wait();
01117 SafeRemove(((Coll *)collection)->GetAt(key));
01118 if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
01119 obj->SafeReference())
01120 ((Coll *)collection)->SetAt(key, obj);
01121 collectionMutex.Signal();
01122 }
01123
01132 virtual PBoolean RemoveAt(
01133 const Key & key
01134 ) {
01135 PWaitAndSignal mutex(collectionMutex);
01136 return SafeRemove(((Coll *)collection)->GetAt(key));
01137 }
01138
01141 virtual PBoolean Contains(
01142 const Key & key
01143 ) {
01144 PWaitAndSignal lock(collectionMutex);
01145 return ((Coll *)collection)->Contains(key);
01146 }
01147
01153 virtual PSafePtr<Base> GetAt(
01154 PINDEX idx,
01155 PSafetyMode mode = PSafeReadWrite
01156 ) {
01157 return PSafePtr<Base>(*this, mode, idx);
01158 }
01159
01165 virtual PSafePtr<Base> FindWithLock(
01166 const Key & key,
01167 PSafetyMode mode = PSafeReadWrite
01168 ) {
01169 collectionMutex.Wait();
01170 PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01171 collectionMutex.Signal();
01172 ptr.SetSafetyMode(mode);
01173 return ptr;
01174 }
01176 };
01177
01178
01183 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01184 {
01185 public:
01186 typedef PSafePtr<Base> value_type;
01187 };
01188
01189
01190 #endif // PTLIB_SAFE_COLLECTION_H
01191
01192
01193