PTLib  Version 2.12.9
 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: 30263 $
27  * $Author: rjongbloed $
28  * $Date: 2013-08-07 16:37:36 +1000 (Wed, 07 Aug 2013) $
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 
39 #include <ptlib/syncthrd.h>
40 
41 
42 class PTimer;
43 
44 
125 class PSafeObject : public PObject
126 {
127  PCLASSINFO(PSafeObject, PObject);
128  public:
133  PSafeObject(
134  PSafeObject * indirectLock = NULL
135  );
137 
159 
171 
189  PBoolean LockReadOnly() const;
190 
201  void UnlockReadOnly() const;
202 
221 
232  void UnlockReadWrite();
233 
243  void SafeRemove();
244 
253 
265  virtual bool GarbageCollection();
266 
271  unsigned GetSafeReferenceCount() const { return safeReferenceCount; }
273 
274  private:
275  mutable PMutex safetyMutex;
276  unsigned safeReferenceCount;
277  bool safelyBeingRemoved;
278  PReadWriteMutex safeInUseMutex;
279  PReadWriteMutex * safeInUse;
280 
281  friend class PSafeCollection;
282 };
283 
284 
288 {
289  public:
290  PSafeLockReadOnly(const PSafeObject & object);
292  PBoolean Lock();
293  void Unlock();
294  PBoolean IsLocked() const { return locked; }
295  bool operator!() const { return !locked; }
296 
297  protected:
300 };
301 
302 
303 
307 {
308  public:
309  PSafeLockReadWrite(const PSafeObject & object);
311  PBoolean Lock();
312  void Unlock();
313  PBoolean IsLocked() const { return locked; }
314  bool operator!() const { return !locked; }
315 
316  protected:
319 };
320 
321 
322 
335 class PSafeCollection : public PObject
336 {
337  PCLASSINFO(PSafeCollection, PObject);
338  public:
346  );
347 
353 
356  protected:
365  virtual PBoolean SafeRemove(
366  PSafeObject * obj
367  );
368 
377  virtual PBoolean SafeRemoveAt(
378  PINDEX idx
379  );
380 
381  public:
388  virtual void PrintOn(
389  ostream &strm // Stream to print the object into.
390  ) const;
391 
394  virtual void RemoveAll(
395  PBoolean synchronous = false
396  );
397 
403  PBoolean yes = true
404  ) { deleteObjects = yes; }
405 
411 
417 
420  virtual void DeleteObject(PObject * object) const;
421 
424  virtual void SetAutoDeleteObjects();
425 
430  PINDEX GetSize() const;
431 
436  PBoolean IsEmpty() const { return GetSize() == 0; }
437 
440  const PMutex & GetMutex() const { return collectionMutex; }
442 
443  protected:
444  void CopySafeCollection(PCollection * other);
446  bool SafeAddObject(PSafeObject * obj, PSafeObject * old);
447  void SafeRemoveObject(PSafeObject * obj);
448  PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
449 
456 
457  private:
458  PSafeCollection(const PSafeCollection & other) : PObject(other) { }
459  void operator=(const PSafeCollection &) { }
460 
461  friend class PSafePtrBase;
462 };
463 
464 
469 };
470 
483 class PSafePtrBase : public PObject
484 {
485  PCLASSINFO(PSafePtrBase, PObject);
486 
489  protected:
497  PSafePtrBase(
498  PSafeObject * obj = NULL,
500  );
501 
509  PSafePtrBase(
510  const PSafeCollection & safeCollection,
511  PSafetyMode mode,
512  PINDEX idx
513  );
514 
522  PSafePtrBase(
523  const PSafeCollection & safeCollection,
524  PSafetyMode mode,
525  PSafeObject * obj
526  );
527 
533  PSafePtrBase(
534  const PSafePtrBase & enumerator
535  );
536 
537  public:
540  ~PSafePtrBase();
542 
549  virtual Comparison Compare(
550  const PObject & obj
551  ) const;
552 
559  virtual void PrintOn(
560  ostream &strm // Stream to print the object into.
561  ) const;
563 
568  virtual void SetNULL();
569 
572  bool operator!() const { return currentObject == NULL; }
573 
576  PSafeObject * GetObject() const { return currentObject; }
577 
580  template <class T>
581  T * GetObjectAs() const { return dynamic_cast<T *>(currentObject); }
582 
585  PSafetyMode GetSafetyMode() const { return lockMode; }
586 
593  virtual PBoolean SetSafetyMode(
594  PSafetyMode mode
595  );
597 
598  virtual void Assign(const PSafePtrBase & ptr);
599  virtual void Assign(const PSafeCollection & safeCollection);
600  virtual void Assign(PSafeObject * obj);
601  virtual void Assign(PINDEX idx);
602 
603  protected:
604  virtual void Next();
605  virtual void Previous();
606  virtual void DeleteObject(PSafeObject * obj);
607 
611  };
613 
617  };
619 
620  virtual void LockPtr() { }
621  virtual void UnlockPtr() { }
622 
623  protected:
627 };
628 
629 
643 {
644  PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
645 
648  protected:
657  PSafeObject * obj = NULL,
659  );
660 
669  const PSafeCollection & safeCollection,
670  PSafetyMode mode,
671  PINDEX idx
672  );
673 
682  const PSafeCollection & safeCollection,
683  PSafetyMode mode,
684  PSafeObject * obj
685  );
686 
693  const PSafePtrMultiThreaded & enumerator
694  );
695 
696  public:
701 
708  virtual Comparison Compare(
709  const PObject & obj
710  ) const;
712 
717  virtual void SetNULL();
718 
725  virtual PBoolean SetSafetyMode(
726  PSafetyMode mode
727  );
729 
730  virtual void Assign(const PSafePtrMultiThreaded & ptr);
731  virtual void Assign(const PSafePtrBase & ptr);
732  virtual void Assign(const PSafeCollection & safeCollection);
733  virtual void Assign(PSafeObject * obj);
734  virtual void Assign(PINDEX idx);
735 
736  protected:
737  virtual void Next();
738  virtual void Previous();
739  virtual void DeleteObject(PSafeObject * obj);
740 
741  virtual void LockPtr() { m_mutex.Wait(); }
742  virtual void UnlockPtr();
743 
744  protected:
745  mutable PMutex m_mutex;
747 };
748 
749 
770 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
771 {
772  public:
783  T * obj = NULL,
785  ) : BaseClass(obj, mode) { }
786 
795  const PSafeCollection & safeCollection,
796  PSafetyMode mode = PSafeReadWrite,
797  PINDEX idx = 0
798  ) : BaseClass(safeCollection, mode, idx) { }
799 
808  const PSafeCollection & safeCollection,
809  PSafetyMode mode,
810  PSafeObject * obj
811  ) : BaseClass(safeCollection, mode, obj) { }
812 
819  const PSafePtr & ptr
820  ) : BaseClass(ptr) { }
821 
827  PSafePtr & operator=(const PSafePtr & ptr)
828  {
829  BaseClass::Assign(ptr);
830  return *this;
831  }
832 
837  PSafePtr & operator=(const PSafeCollection & safeCollection)
838  {
839  BaseClass::Assign(safeCollection);
840  return *this;
841  }
842 
858  PSafePtr & operator=(T * obj)
859  {
860  this->Assign(obj);
861  return *this;
862  }
863 
873  PSafePtr & operator=(PINDEX idx)
874  {
875  BaseClass::Assign(idx);
876  return *this;
877  }
878 
883  PSafePtr Set(T * obj)
884  {
885  this->LockPtr();
886  PSafePtr oldPtr = *this;
887  this->Assign(obj);
888  this->UnlockPtr();
889  return oldPtr;
890  }
892 
897  operator T*() const { return dynamic_cast<T *>(BaseClass::currentObject); }
898 
901  T & operator*() const { return *dynamic_cast<T *>(PAssertNULL(BaseClass::currentObject)); }
902 
905  T * operator->() const { return dynamic_cast<T *>(PAssertNULL(BaseClass::currentObject)); }
906 
911  T * operator++(int)
912  {
913  T * previous = dynamic_cast<T *>(BaseClass::currentObject);
914  BaseClass::Next();
915  return previous;
916  }
917 
923  {
924  BaseClass::Next();
925  return dynamic_cast<T *>(BaseClass::currentObject);
926  }
927 
932  T * operator--(int)
933  {
934  T * previous = dynamic_cast<T *>(BaseClass::currentObject);
935  BaseClass::Previous();
936  return previous;
937  }
938 
944  {
945  BaseClass::Previous();
946  return dynamic_cast<T *>(BaseClass::currentObject);
947  }
949 };
950 
951 
955 template <class Base, class Derived>
957 {
958  PSafePtr<Derived> newPtr;
959  if (dynamic_cast<Derived *>(oldPtr.GetObject()) != NULL)
960  newPtr.Assign(oldPtr);
961  return newPtr;
962 }
963 
964 
975 template <class Coll, class Base> class PSafeColl : public PSafeCollection
976 {
977  PCLASSINFO_WITH_CLONE(PSafeColl, PSafeCollection);
978  public:
984  : PSafeCollection(new Coll)
985  { }
986 
990  PSafeColl(const PSafeColl & other)
991  : PSafeCollection(new Coll)
992  {
993  PWaitAndSignal lock2(other.collectionMutex);
994  CopySafeCollection(dynamic_cast<Coll *>(other.collection));
995  }
996 
1000  PSafeColl & operator=(const PSafeColl & other)
1001  {
1002  if (&other != this) {
1003  RemoveAll(true);
1005  PWaitAndSignal lock2(other.collectionMutex);
1006  CopySafeCollection(dynamic_cast<Coll *>(other.collection));
1007  }
1008  return *this;
1009  }
1011 
1019  Base * obj,
1020  PSafetyMode mode = PSafeReference
1021  ) {
1023  if (SafeAddObject(obj, NULL))
1024  return PSafePtr<Base>(*this, mode, collection->Append(obj));
1025  return NULL;
1026  }
1027 
1036  virtual PBoolean Remove(
1037  Base * obj
1038  ) {
1039  return SafeRemove(obj);
1040  }
1041 
1051  PINDEX idx
1052  ) {
1053  return SafeRemoveAt(idx);
1054  }
1055 
1062  PINDEX idx,
1064  ) {
1065  return PSafePtr<Base>(*this, mode, idx);
1066  }
1067 
1074  const Base & value,
1076  ) {
1077  collectionMutex.Wait();
1079  collectionMutex.Signal();
1080  ptr.SetSafetyMode(mode);
1081  return ptr;
1082  }
1084 };
1085 
1086 
1091 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
1092 {
1093  public:
1095 };
1096 
1097 
1102 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
1103 {
1104  public:
1106 };
1107 
1108 
1113 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
1114 {
1115  public:
1117 };
1118 
1119 
1130 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
1131 {
1132  PCLASSINFO_WITH_CLONE(PSafeDictionaryBase, PSafeCollection);
1133  public:
1139  : PSafeCollection(new Coll) { }
1140 
1145  : PSafeCollection(new Coll)
1146  {
1147  PWaitAndSignal lock2(other.collectionMutex);
1148  CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1149  }
1150 
1155  {
1156  if (&other != this) {
1157  RemoveAll(true);
1159  PWaitAndSignal lock2(other.collectionMutex);
1160  CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1161  }
1162  return *this;
1163  }
1165 
1172  virtual void SetAt(const Key & key, Base * obj)
1173  {
1174  collectionMutex.Wait();
1175  if (SafeAddObject(obj, dynamic_cast<Coll &>(*collection).GetAt(key)))
1176  dynamic_cast<Coll &>(*collection).SetAt(key, obj);
1177  collectionMutex.Signal();
1178  }
1179 
1189  const Key & key
1190  ) {
1192  return SafeRemove(dynamic_cast<Coll &>(*collection).GetAt(key));
1193  }
1194 
1198  const Key & key
1199  ) {
1201  return dynamic_cast<Coll &>(*collection).Contains(key);
1202  }
1203 
1210  PINDEX idx,
1212  ) {
1213  return PSafePtr<Base>(*this, mode, idx);
1214  }
1215 
1222  const Key & key,
1224  ) const {
1225  collectionMutex.Wait();
1226  PSafePtr<Base> ptr(*this, PSafeReference, dynamic_cast<Coll &>(*collection).GetAt(key));
1227  collectionMutex.Signal();
1228  ptr.SetSafetyMode(mode);
1229  return ptr;
1230  }
1231 
1235  {
1236  PArray<Key> keys;
1237  collectionMutex.Wait();
1238  dynamic_cast<Coll &>(*collection).AbstractGetKeys(keys);
1239  collectionMutex.Signal();
1240  return keys;
1241  }
1243 };
1244 
1245 
1250 template <class K, class D>
1251  class PSafeDictionary : public PSafeDictionaryBase<PDictionary<K, D>, K, D>
1252 {
1253  public:
1254  typedef K key_type;
1255  typedef D data_type;
1258 
1261  class iterator;
1262  class const_iterator;
1264  protected:
1265  K * m_internal_first; // Must be first two members
1267 
1270  PINDEX m_position;
1271 
1273  : m_internal_first(NULL)
1274  , m_internal_second(NULL)
1275  , m_dictionary(NULL)
1276  , m_position(P_MAX_INDEX)
1277  {
1278  }
1279 
1280  iterator_base(const dict_type * dict)
1281  : m_dictionary(dict)
1282  , m_keys(dict->GetKeys())
1283  {
1284  this->SetPosition(0);
1285  }
1286 
1287  iterator_base(const dict_type * dict, const K & key)
1288  : m_dictionary(dict)
1289  , m_keys(dict->GetKeys())
1290  {
1291  this->SetPosition(m_keys.GetValuesIndex(key));
1292  }
1293 
1294  bool SetPosition(PINDEX position)
1295  {
1296  if (position >= this->m_keys.GetSize()) {
1297  this->m_position = P_MAX_INDEX;
1298  this->m_internal_first = NULL;
1299  this->m_internal_second.SetNULL();
1300  return false;
1301  }
1302 
1303  this->m_position = position;
1304  this->m_internal_first = &this->m_keys[position];
1306  return this->m_internal_second == NULL;
1307  }
1308 
1309  void Next() { while (this->SetPosition(this->m_position+1)) { } }
1310  void Prev() { while (this->SetPosition(this->m_position > 0 ? this->m_position+1 : P_MAX_INDEX)) { } }
1311 
1312  public:
1313  bool operator==(const iterator_base & it) const { return this->m_position == it.m_position; }
1314  bool operator!=(const iterator_base & it) const { return this->m_position != it.m_position; }
1315  };
1316 
1318  public:
1319  const K & first;
1321 
1322  private:
1323  iterator_pair() : first(reinterpret_cast<const K &>(0)) { }
1324  };
1325 
1326  class iterator : public iterator_base, public std::iterator<std::forward_iterator_tag, iterator_pair> {
1327  protected:
1328  iterator(dict_type * dict) : iterator_base(dict) { }
1329  iterator(dict_type * dict, const K & key) : iterator_base(dict, key) { }
1330 
1331  public:
1332  iterator() { }
1333 
1334  iterator operator++() { this->Next(); return *this; }
1335  iterator operator--() { this->Prev(); return *this; }
1336  iterator operator++(int) { iterator it = *this; this->Next(); return it; }
1337  iterator operator--(int) { iterator it = *this; this->Prev(); return it; }
1338 
1339  const iterator_pair * operator->() const { return reinterpret_cast<const iterator_pair *>(this); }
1340  const iterator_pair & operator* () const { return *reinterpret_cast<const iterator_pair *>(this); }
1341 
1342  friend class PSafeDictionary<K, D>;
1343  };
1344 
1345  iterator begin() { return iterator(this); }
1346  iterator end() { return iterator(); }
1347  iterator find(const K & key) { return iterator(this, key); }
1348 
1349 
1350  class const_iterator : public iterator_base, public std::iterator<std::forward_iterator_tag, iterator_pair> {
1351  protected:
1352  const_iterator(const dict_type * dict) : iterator_base(dict) { }
1353  const_iterator(const dict_type * dict, const K & key) : iterator_base(dict, key) { }
1354 
1355  public:
1357  const_iterator(const typename dict_type::iterator & it) : iterator_base(it) { }
1358 
1359  const_iterator operator++() { this->Next(); return *this; }
1360  const_iterator operator--() { this->Prev(); return *this; }
1361  const_iterator operator++(int) { const_iterator it = *this; this->Next(); return it; }
1362  const_iterator operator--(int) { const_iterator it = *this; this->Prev(); return it; }
1363 
1364  const iterator_pair * operator->() const { return reinterpret_cast<const iterator_pair *>(this); }
1365  const iterator_pair & operator* () const { return *reinterpret_cast<const iterator_pair *>(this); }
1366 
1367  friend class PSafeDictionary<K, D>;
1368  };
1369 
1370  const_iterator begin() const { return const_iterator(this); }
1371  const_iterator end() const { return const_iterator(); }
1372  const_iterator find(const K & key) const { return const_iterator(this, key); }
1373 
1374  void erase(const iterator & it) { this->RemoveAt(it->first); }
1375  void erase(const const_iterator & it) { this->RemoveAt(it->first); }
1377 };
1378 
1379 
1380 #endif // PTLIB_SAFE_COLLECTION_H
1381 
1382 
1383 // End Of File ///////////////////////////////////////////////////////////////