PTLib  Version 2.10.4
 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: 25554 $
27  * $Author: rjongbloed $
28  * $Date: 2011-04-13 03:34:50 -0500 (Wed, 13 Apr 2011) $
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;
530 
535  virtual void SetNULL();
536 
539  bool operator!() const { return currentObject == NULL; }
540 
543  PSafetyMode GetSafetyMode() const { return lockMode; }
544 
551  virtual PBoolean SetSafetyMode(
552  PSafetyMode mode
553  );
554 
557  const PSafeCollection * GetCollection() const { return collection; }
559 
560  virtual void Assign(const PSafePtrBase & ptr);
561  virtual void Assign(const PSafeCollection & safeCollection);
562  virtual void Assign(PSafeObject * obj);
563  virtual void Assign(PINDEX idx);
564 
565  protected:
566  virtual void Next();
567  virtual void Previous();
568  virtual void DeleteObject(PSafeObject * obj);
569 
573  };
575 
579  };
581 
582  protected:
586 };
587 
588 
602 {
603  PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
604 
607  protected:
616  PSafeObject * obj = NULL,
618  );
619 
628  const PSafeCollection & safeCollection,
629  PSafetyMode mode,
630  PINDEX idx
631  );
632 
641  const PSafeCollection & safeCollection,
642  PSafetyMode mode,
643  PSafeObject * obj
644  );
645 
652  const PSafePtrMultiThreaded & enumerator
653  );
654 
655  public:
660 
667  virtual Comparison Compare(
668  const PObject & obj
669  ) const;
671 
676  virtual void SetNULL();
677 
684  virtual PBoolean SetSafetyMode(
685  PSafetyMode mode
686  );
688 
689  virtual void Assign(const PSafePtrMultiThreaded & ptr);
690  virtual void Assign(const PSafePtrBase & ptr);
691  virtual void Assign(const PSafeCollection & safeCollection);
692  virtual void Assign(PSafeObject * obj);
693  virtual void Assign(PINDEX idx);
694 
695  protected:
696  virtual void Next();
697  virtual void Previous();
698  virtual void DeleteObject(PSafeObject * obj);
699 
700  void Lock() { m_mutex.Wait(); }
701  void Unlock();
702 
703  protected:
704  mutable PMutex m_mutex;
706 };
707 
708 
729 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
730 {
731  public:
742  T * obj = NULL,
744  ) : BaseClass(obj, mode) { }
745 
754  const PSafeCollection & safeCollection,
755  PSafetyMode mode = PSafeReadWrite,
756  PINDEX idx = 0
757  ) : BaseClass(safeCollection, mode, idx) { }
758 
767  const PSafeCollection & safeCollection,
768  PSafetyMode mode,
769  PSafeObject * obj
770  ) : BaseClass(safeCollection, mode, obj) { }
771 
778  const PSafePtr & ptr
779  ) : BaseClass(ptr) { }
780 
786  PSafePtr & operator=(const PSafePtr & ptr)
787  {
788  BaseClass::Assign(ptr);
789  return *this;
790  }
791 
796  PSafePtr & operator=(const PSafeCollection & safeCollection)
797  {
798  BaseClass::Assign(safeCollection);
799  return *this;
800  }
801 
817  PSafePtr & operator=(T * obj)
818  {
819  this->Assign(obj);
820  return *this;
821  }
822 
832  PSafePtr & operator=(PINDEX idx)
833  {
834  BaseClass::Assign(idx);
835  return *this;
836  }
838 
843  operator T*() const { return (T *)BaseClass::currentObject; }
844 
847  T & operator*() const { return *(T *)PAssertNULL(BaseClass::currentObject); }
848 
851  T * operator->() const { return (T *)PAssertNULL(BaseClass::currentObject); }
852 
857  T * operator++(int)
858  {
859  T * previous = (T *)BaseClass::currentObject;
860  BaseClass::Next();
861  return previous;
862  }
863 
869  {
870  BaseClass::Next();
871  return (T *)BaseClass::currentObject;
872  }
873 
878  T * operator--(int)
879  {
880  T * previous = (T *)BaseClass::currentObject;
881  BaseClass::Previous();
882  return previous;
883  }
884 
890  {
891  BaseClass::Previous();
892  return (T *)BaseClass::currentObject;
893  }
895 
899  /*
900  template <class Base>
901  static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
902  {
903  PSafePtr<T> newPtr;
904  Base * realPtr = oldPtr;
905  if (realPtr != NULL && PIsDescendant(realPtr, T))
906  newPtr.Assign(oldPtr);
907  return newPtr;
908  }
909  */
910 };
911 
912 
916 template <class Base, class Derived>
918 {
919 // return PSafePtr<Derived>::DownCast<Base>(oldPtr);
920  PSafePtr<Derived> newPtr;
921  Base * realPtr = oldPtr;
922  if (realPtr != NULL && PIsDescendant(realPtr, Derived))
923  newPtr.Assign(oldPtr);
924  return newPtr;
925 }
926 
927 
938 template <class Coll, class Base> class PSafeColl : public PSafeCollection
939 {
940  PCLASSINFO(PSafeColl, PSafeCollection);
941  public:
947  : PSafeCollection(new Coll)
948  { }
949 
953  PSafeColl(const PSafeColl & other)
954  : PSafeCollection(new Coll)
955  {
956  PWaitAndSignal lock2(other.collectionMutex);
957  CopySafeCollection(dynamic_cast<Coll *>(other.collection));
958  }
959 
963  PSafeColl & operator=(const PSafeColl & other)
964  {
965  if (&other != this) {
966  RemoveAll(true);
968  PWaitAndSignal lock2(other.collectionMutex);
969  CopySafeCollection(dynamic_cast<Coll *>(other.collection));
970  }
971  return *this;
972  }
974 
982  Base * obj,
984  ) {
986  if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
987  obj->SafeReference())
988  return PSafePtr<Base>(*this, mode, collection->Append(obj));
989  return NULL;
990  }
991 
1000  virtual PBoolean Remove(
1001  Base * obj
1002  ) {
1003  return SafeRemove(obj);
1004  }
1005 
1015  PINDEX idx
1016  ) {
1017  return SafeRemoveAt(idx);
1018  }
1019 
1026  PINDEX idx,
1028  ) {
1029  return PSafePtr<Base>(*this, mode, idx);
1030  }
1031 
1038  const Base & value,
1040  ) {
1041  collectionMutex.Wait();
1043  collectionMutex.Signal();
1044  ptr.SetSafetyMode(mode);
1045  return ptr;
1046  }
1048 };
1049 
1050 
1055 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
1056 {
1057  public:
1059 };
1060 
1061 
1066 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
1067 {
1068  public:
1070 };
1071 
1072 
1077 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
1078 {
1079  public:
1081 };
1082 
1083 
1094 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
1095 {
1096  PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
1097  public:
1103  : PSafeCollection(new Coll) { }
1104 
1109  : PSafeCollection(new Coll)
1110  {
1111  PWaitAndSignal lock2(other.collectionMutex);
1112  CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1113  }
1114 
1119  {
1120  if (&other != this) {
1121  RemoveAll(true);
1123  PWaitAndSignal lock2(other.collectionMutex);
1124  CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1125  }
1126  return *this;
1127  }
1129 
1136  virtual void SetAt(const Key & key, Base * obj)
1137  {
1138  collectionMutex.Wait();
1139  SafeRemove(((Coll *)collection)->GetAt(key));
1140  if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
1141  obj->SafeReference())
1142  ((Coll *)collection)->SetAt(key, obj);
1143  collectionMutex.Signal();
1144  }
1145 
1155  const Key & key
1156  ) {
1158  return SafeRemove(((Coll *)collection)->GetAt(key));
1159  }
1160 
1164  const Key & key
1165  ) {
1167  return ((Coll *)collection)->Contains(key);
1168  }
1169 
1176  PINDEX idx,
1178  ) {
1179  return PSafePtr<Base>(*this, mode, idx);
1180  }
1181 
1188  const Key & key,
1190  ) {
1191  collectionMutex.Wait();
1192  PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
1193  collectionMutex.Signal();
1194  ptr.SetSafetyMode(mode);
1195  return ptr;
1196  }
1197 
1201  {
1202  PArray<Key> keys;
1203  collectionMutex.Wait();
1204  ((Coll *)collection)->AbstractGetKeys(keys);
1205  collectionMutex.Signal();
1206  return keys;
1207  }
1209 };
1210 
1211 
1216 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
1217 {
1218  public:
1220 };
1221 
1222 
1223 #endif // PTLIB_SAFE_COLLECTION_H
1224 
1225 
1226 // End Of File ///////////////////////////////////////////////////////////////