PTLib  Version 2.10.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
safecoll.h
Go to the documentation of this file.
1 /*
2  * safecoll.h
3  *
4  * Thread safe collection classes.
5  *
6  * Portable Windows Library
7  *
8  * Copyright (c) 2002 Equivalence Pty. Ltd.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23  *
24  * Contributor(s): ______________________________________.
25  *
26  * $Revision: 27948 $
27  * $Author: rjongbloed $
28  * $Date: 2012-06-30 22:54:23 -0500 (Sat, 30 Jun 2012) $
29  */
30 
31 #ifndef PTLIB_SAFE_COLLECTION_H
32 #define PTLIB_SAFE_COLLECTION_H
33 
34 #ifdef P_USE_PRAGMA
35 #pragma interface
36 #endif
37 
38 
119 class PSafeObject : public PObject
120 {
121  PCLASSINFO(PSafeObject, PObject);
122  public:
127  PSafeObject(
128  PSafeObject * indirectLock = NULL
129  );
131 
153 
165 
183  PBoolean LockReadOnly() const;
184 
195  void UnlockReadOnly() const;
196 
215 
226  void UnlockReadWrite();
227 
237  void SafeRemove();
238 
247 
259  virtual bool GarbageCollection();
261 
262  private:
263  mutable PMutex safetyMutex;
264  unsigned safeReferenceCount;
265  bool safelyBeingRemoved;
266  PReadWriteMutex safeInUseMutex;
267  PReadWriteMutex * safeInUse;
268 
269  friend class PSafeCollection;
270 };
271 
272 
276 {
277  public:
278  PSafeLockReadOnly(const PSafeObject & object);
280  PBoolean Lock();
281  void Unlock();
282  PBoolean IsLocked() const { return locked; }
283  bool operator!() const { return !locked; }
284 
285  protected:
288 };
289 
290 
291 
295 {
296  public:
297  PSafeLockReadWrite(const PSafeObject & object);
299  PBoolean Lock();
300  void Unlock();
301  PBoolean IsLocked() const { return locked; }
302  bool operator!() const { return !locked; }
303 
304  protected:
307 };
308 
309 
310 
323 class PSafeCollection : public PObject
324 {
325  PCLASSINFO(PSafeCollection, PObject);
326  public:
334  );
335 
341 
344  protected:
353  virtual PBoolean SafeRemove(
354  PSafeObject * obj
355  );
356 
365  virtual PBoolean SafeRemoveAt(
366  PINDEX idx
367  );
368 
369  public:
372  virtual void RemoveAll(
373  PBoolean synchronous = false
374  );
375 
381  PBoolean yes = true
382  ) { deleteObjects = yes; }
383 
389 
395 
398  virtual void DeleteObject(PObject * object) const;
399 
402  virtual void SetAutoDeleteObjects();
403 
408  PINDEX GetSize() const;
409 
414  PBoolean IsEmpty() const { return GetSize() == 0; }
415 
418  const PMutex & GetMutex() const { return collectionMutex; }
420 
421  protected:
422  void CopySafeCollection(PCollection * other);
424  void SafeRemoveObject(PSafeObject * obj);
425  PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
426 
433 
434  private:
435  PSafeCollection(const PSafeCollection & other) : PObject(other) { }
436  void operator=(const PSafeCollection &) { }
437 
438  friend class PSafePtrBase;
439 };
440 
441 
446 };
447 
460 class PSafePtrBase : public PObject
461 {
462  PCLASSINFO(PSafePtrBase, PObject);
463 
466  protected:
474  PSafePtrBase(
475  PSafeObject * obj = NULL,
477  );
478 
486  PSafePtrBase(
487  const PSafeCollection & safeCollection,
488  PSafetyMode mode,
489  PINDEX idx
490  );
491 
499  PSafePtrBase(
500  const PSafeCollection & safeCollection,
501  PSafetyMode mode,
502  PSafeObject * obj
503  );
504 
510  PSafePtrBase(
511  const PSafePtrBase & enumerator
512  );
513 
514  public:
517  ~PSafePtrBase();
519 
526  virtual Comparison Compare(
527  const PObject & obj
528  ) const;
529 
536  virtual void PrintOn(
537  ostream &strm // Stream to print the object into.
538  ) const;
540 
545  virtual void SetNULL();
546 
549  bool operator!() const { return currentObject == NULL; }
550 
553  PSafetyMode GetSafetyMode() const { return lockMode; }
554 
561  virtual PBoolean SetSafetyMode(
562  PSafetyMode mode
563  );
564 
567  const PSafeCollection * GetCollection() const { return collection; }
569 
570  virtual void Assign(const PSafePtrBase & ptr);
571  virtual void Assign(const PSafeCollection & safeCollection);
572  virtual void Assign(PSafeObject * obj);
573  virtual void Assign(PINDEX idx);
574 
575  protected:
576  virtual void Next();
577  virtual void Previous();
578  virtual void DeleteObject(PSafeObject * obj);
579 
583  };
585 
589  };
591 
592  virtual void LockPtr() { }
593  virtual void UnlockPtr() { }
594 
595  protected:
599 };
600 
601 
615 {
616  PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
617 
620  protected:
629  PSafeObject * obj = NULL,
631  );
632 
641  const PSafeCollection & safeCollection,
642  PSafetyMode mode,
643  PINDEX idx
644  );
645 
654  const PSafeCollection & safeCollection,
655  PSafetyMode mode,
656  PSafeObject * obj
657  );
658 
665  const PSafePtrMultiThreaded & enumerator
666  );
667 
668  public:
673 
680  virtual Comparison Compare(
681  const PObject & obj
682  ) const;
684 
689  virtual void SetNULL();
690 
697  virtual PBoolean SetSafetyMode(
698  PSafetyMode mode
699  );
701 
702  virtual void Assign(const PSafePtrMultiThreaded & ptr);
703  virtual void Assign(const PSafePtrBase & ptr);
704  virtual void Assign(const PSafeCollection & safeCollection);
705  virtual void Assign(PSafeObject * obj);
706  virtual void Assign(PINDEX idx);
707 
708  protected:
709  virtual void Next();
710  virtual void Previous();
711  virtual void DeleteObject(PSafeObject * obj);
712 
713  virtual void LockPtr() { m_mutex.Wait(); }
714  virtual void UnlockPtr();
715 
716  protected:
717  mutable PMutex m_mutex;
719 };
720 
721 
742 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
743 {
744  public:
755  T * obj = NULL,
757  ) : BaseClass(obj, mode) { }
758 
767  const PSafeCollection & safeCollection,
768  PSafetyMode mode = PSafeReadWrite,
769  PINDEX idx = 0
770  ) : BaseClass(safeCollection, mode, idx) { }
771 
780  const PSafeCollection & safeCollection,
781  PSafetyMode mode,
782  PSafeObject * obj
783  ) : BaseClass(safeCollection, mode, obj) { }
784 
791  const PSafePtr & ptr
792  ) : BaseClass(ptr) { }
793 
799  PSafePtr & operator=(const PSafePtr & ptr)
800  {
801  BaseClass::Assign(ptr);
802  return *this;
803  }
804 
809  PSafePtr & operator=(const PSafeCollection & safeCollection)
810  {
811  BaseClass::Assign(safeCollection);
812  return *this;
813  }
814 
830  PSafePtr & operator=(T * obj)
831  {
832  this->Assign(obj);
833  return *this;
834  }
835 
845  PSafePtr & operator=(PINDEX idx)
846  {
847  BaseClass::Assign(idx);
848  return *this;
849  }
850 
855  PSafePtr Set(T * obj)
856  {
857  this->LockPtr();
858  PSafePtr oldPtr = *this;
859  this->Assign(obj);
860  this->UnlockPtr();
861  return oldPtr;
862  }
864 
869  operator T*() const { return (T *)BaseClass::currentObject; }
870 
873  T & operator*() const { return *(T *)PAssertNULL(BaseClass::currentObject); }
874 
877  T * operator->() const { return (T *)PAssertNULL(BaseClass::currentObject); }
878 
883  T * operator++(int)
884  {
885  T * previous = (T *)BaseClass::currentObject;
886  BaseClass::Next();
887  return previous;
888  }
889 
895  {
896  BaseClass::Next();
897  return (T *)BaseClass::currentObject;
898  }
899 
904  T * operator--(int)
905  {
906  T * previous = (T *)BaseClass::currentObject;
907  BaseClass::Previous();
908  return previous;
909  }
910 
916  {
917  BaseClass::Previous();
918  return (T *)BaseClass::currentObject;
919  }
921 };
922 
923 
927 template <class Base, class Derived>
929 {
930 // return PSafePtr<Derived>::DownCast<Base>(oldPtr);
931  PSafePtr<Derived> newPtr;
932  Base * realPtr = oldPtr;
933  if (realPtr != NULL && PIsDescendant(realPtr, Derived))
934  newPtr.Assign(oldPtr);
935  return newPtr;
936 }
937 
938 
949 template <class Coll, class Base> class PSafeColl : public PSafeCollection
950 {
951  PCLASSINFO(PSafeColl, PSafeCollection);
952  public:
958  : PSafeCollection(new Coll)
959  { }
960 
964  PSafeColl(const PSafeColl & other)
965  : PSafeCollection(new Coll)
966  {
967  PWaitAndSignal lock2(other.collectionMutex);
968  CopySafeCollection(dynamic_cast<Coll *>(other.collection));
969  }
970 
974  PSafeColl & operator=(const PSafeColl & other)
975  {
976  if (&other != this) {
977  RemoveAll(true);
979  PWaitAndSignal lock2(other.collectionMutex);
980  CopySafeCollection(dynamic_cast<Coll *>(other.collection));
981  }
982  return *this;
983  }
985 
993  Base * obj,
995  ) {
997  if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
998  obj->SafeReference())
999  return PSafePtr<Base>(*this, mode, collection->Append(obj));
1000  return NULL;
1001  }
1002 
1011  virtual PBoolean Remove(
1012  Base * obj
1013  ) {
1014  return SafeRemove(obj);
1015  }
1016 
1026  PINDEX idx
1027  ) {
1028  return SafeRemoveAt(idx);
1029  }
1030 
1037  PINDEX idx,
1039  ) {
1040  return PSafePtr<Base>(*this, mode, idx);
1041  }
1042 
1049  const Base & value,
1051  ) {
1052  collectionMutex.Wait();
1054  collectionMutex.Signal();
1055  ptr.SetSafetyMode(mode);
1056  return ptr;
1057  }
1059 };
1060 
1061 
1066 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
1067 {
1068  public:
1070 };
1071 
1072 
1077 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
1078 {
1079  public:
1081 };
1082 
1083 
1088 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
1089 {
1090  public:
1092 };
1093 
1094 
1105 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
1106 {
1107  PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
1108  public:
1114  : PSafeCollection(new Coll) { }
1115 
1120  : PSafeCollection(new Coll)
1121  {
1122  PWaitAndSignal lock2(other.collectionMutex);
1123  CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1124  }
1125 
1130  {
1131  if (&other != this) {
1132  RemoveAll(true);
1134  PWaitAndSignal lock2(other.collectionMutex);
1135  CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1136  }
1137  return *this;
1138  }
1140 
1147  virtual void SetAt(const Key & key, Base * obj)
1148  {
1149  collectionMutex.Wait();
1150  SafeRemove(((Coll *)collection)->GetAt(key));
1151  if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
1152  obj->SafeReference())
1153  ((Coll *)collection)->SetAt(key, obj);
1154  collectionMutex.Signal();
1155  }
1156 
1166  const Key & key
1167  ) {
1169  return SafeRemove(((Coll *)collection)->GetAt(key));
1170  }
1171 
1175  const Key & key
1176  ) {
1178  return ((Coll *)collection)->Contains(key);
1179  }
1180 
1187  PINDEX idx,
1189  ) {
1190  return PSafePtr<Base>(*this, mode, idx);
1191  }
1192 
1199  const Key & key,
1201  ) {
1202  collectionMutex.Wait();
1203  PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
1204  collectionMutex.Signal();
1205  ptr.SetSafetyMode(mode);
1206  return ptr;
1207  }
1208 
1212  {
1213  PArray<Key> keys;
1214  collectionMutex.Wait();
1215  ((Coll *)collection)->AbstractGetKeys(keys);
1216  collectionMutex.Signal();
1217  return keys;
1218  }
1220 };
1221 
1222 
1227 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
1228 {
1229  public:
1231 };
1232 
1233 
1234 #endif // PTLIB_SAFE_COLLECTION_H
1235 
1236 
1237 // End Of File ///////////////////////////////////////////////////////////////