PTLib  Version 2.14.3
 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: 32649 $
27  * $Author: rjongbloed $
28  * $Date: 2014-09-01 17:26:08 +1000 (Mon, 01 Sep 2014) $
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; }
443 
444  protected:
445  void CopySafeCollection(PCollection * other);
447  bool SafeAddObject(PSafeObject * obj, PSafeObject * old);
448  void SafeRemoveObject(PSafeObject * obj);
449  PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
450 
457 
458  private:
459  PSafeCollection(const PSafeCollection & other) : PObject(other) { }
460  void operator=(const PSafeCollection &) { }
461 
462  friend class PSafePtrBase;
463 };
464 
465 
470 };
471 
484 class PSafePtrBase : public PObject
485 {
486  PCLASSINFO(PSafePtrBase, PObject);
487 
490  protected:
498  PSafePtrBase(
499  PSafeObject * obj = NULL,
501  );
502 
510  PSafePtrBase(
511  const PSafeCollection & safeCollection,
512  PSafetyMode mode,
513  PINDEX idx
514  );
515 
523  PSafePtrBase(
524  const PSafeCollection & safeCollection,
525  PSafetyMode mode,
526  PSafeObject * obj
527  );
528 
534  PSafePtrBase(
535  const PSafePtrBase & enumerator
536  );
537 
538  public:
541  ~PSafePtrBase();
543 
550  virtual Comparison Compare(
551  const PObject & obj
552  ) const;
553 
560  virtual void PrintOn(
561  ostream &strm // Stream to print the object into.
562  ) const;
564 
569  virtual void SetNULL();
570 
573  bool operator!() const { return currentObject == NULL; }
574 
577  PSafeObject * GetObject() const { return currentObject; }
578 
581  template <class T>
582  T * GetObjectAs() const { return dynamic_cast<T *>(currentObject); }
583 
586  PSafetyMode GetSafetyMode() const { return lockMode; }
587 
594  virtual PBoolean SetSafetyMode(
595  PSafetyMode mode
596  );
598 
599  virtual void Assign(const PSafePtrBase & ptr);
600  virtual void Assign(const PSafeCollection & safeCollection);
601  virtual void Assign(PSafeObject * obj);
602  virtual void Assign(PINDEX idx);
603 
604  protected:
605  virtual void Next();
606  virtual void Previous();
607  virtual void DeleteObject(PSafeObject * obj);
608 
612  };
614 
618  };
620 
621  virtual void LockPtr() { }
622  virtual void UnlockPtr() { }
623 
624  protected:
628 };
629 
630 
644 {
645  PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
646 
649  protected:
658  PSafeObject * obj = NULL,
660  );
661 
670  const PSafeCollection & safeCollection,
671  PSafetyMode mode,
672  PINDEX idx
673  );
674 
683  const PSafeCollection & safeCollection,
684  PSafetyMode mode,
685  PSafeObject * obj
686  );
687 
694  const PSafePtrMultiThreaded & enumerator
695  );
696 
697  public:
702 
709  virtual Comparison Compare(
710  const PObject & obj
711  ) const;
713 
718  virtual void SetNULL();
719 
726  virtual PBoolean SetSafetyMode(
727  PSafetyMode mode
728  );
730 
731  virtual void Assign(const PSafePtrMultiThreaded & ptr);
732  virtual void Assign(const PSafePtrBase & ptr);
733  virtual void Assign(const PSafeCollection & safeCollection);
734  virtual void Assign(PSafeObject * obj);
735  virtual void Assign(PINDEX idx);
736 
737  protected:
738  virtual void Next();
739  virtual void Previous();
740  virtual void DeleteObject(PSafeObject * obj);
741 
742  virtual void LockPtr() { m_mutex.Wait(); }
743  virtual void UnlockPtr();
744 
745  protected:
746  mutable PMutex m_mutex;
748 };
749 
750 
771 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
772 {
773  public:
784  T * obj = NULL,
786  ) : BaseClass(obj, mode) { }
787 
796  const PSafeCollection & safeCollection,
797  PSafetyMode mode = PSafeReadWrite,
798  PINDEX idx = 0
799  ) : BaseClass(safeCollection, mode, idx) { }
800 
809  const PSafeCollection & safeCollection,
810  PSafetyMode mode,
811  PSafeObject * obj
812  ) : BaseClass(safeCollection, mode, obj) { }
813 
820  const PSafePtr & ptr
821  ) : BaseClass(ptr) { }
822 
828  PSafePtr & operator=(const PSafePtr & ptr)
829  {
830  BaseClass::Assign(ptr);
831  return *this;
832  }
833 
838  PSafePtr & operator=(const PSafeCollection & safeCollection)
839  {
840  BaseClass::Assign(safeCollection);
841  return *this;
842  }
843 
859  PSafePtr & operator=(T * obj)
860  {
861  this->Assign(obj);
862  return *this;
863  }
864 
874  PSafePtr & operator=(PINDEX idx)
875  {
876  BaseClass::Assign(idx);
877  return *this;
878  }
879 
884  PSafePtr Set(T * obj)
885  {
886  this->LockPtr();
887  PSafePtr oldPtr = *this;
888  this->Assign(obj);
889  this->UnlockPtr();
890  return oldPtr;
891  }
893 
898  operator T*() const { return dynamic_cast<T *>(BaseClass::currentObject); }
899 
902  T & operator*() const { return *dynamic_cast<T *>(PAssertNULL(BaseClass::currentObject)); }
903 
906  T * operator->() const { return dynamic_cast<T *>(PAssertNULL(BaseClass::currentObject)); }
907 
912  T * operator++(int)
913  {
914  T * previous = dynamic_cast<T *>(BaseClass::currentObject);
915  BaseClass::Next();
916  return previous;
917  }
918 
924  {
925  BaseClass::Next();
926  return dynamic_cast<T *>(BaseClass::currentObject);
927  }
928 
933  T * operator--(int)
934  {
935  T * previous = dynamic_cast<T *>(BaseClass::currentObject);
936  BaseClass::Previous();
937  return previous;
938  }
939 
945  {
946  BaseClass::Previous();
947  return dynamic_cast<T *>(BaseClass::currentObject);
948  }
950 };
951 
952 
956 template <class Base, class Derived>
958 {
959  PSafePtr<Derived> newPtr;
960  if (dynamic_cast<Derived *>(oldPtr.GetObject()) != NULL)
961  newPtr.Assign(oldPtr);
962  return newPtr;
963 }
964 
965 
976 template <class Coll, class Base> class PSafeColl : public PSafeCollection
977 {
978  PCLASSINFO_WITH_CLONE(PSafeColl, PSafeCollection);
979  public:
985  : PSafeCollection(new Coll)
986  { }
987 
991  PSafeColl(const PSafeColl & other)
992  : PSafeCollection(new Coll)
993  {
994  PWaitAndSignal lock2(other.collectionMutex);
995  CopySafeCollection(dynamic_cast<Coll *>(other.collection));
996  }
997 
1001  PSafeColl & operator=(const PSafeColl & other)
1002  {
1003  if (&other != this) {
1004  RemoveAll(true);
1006  PWaitAndSignal lock2(other.collectionMutex);
1007  CopySafeCollection(dynamic_cast<Coll *>(other.collection));
1008  }
1009  return *this;
1010  }
1012 
1020  Base * obj,
1021  PSafetyMode mode = PSafeReference
1022  ) {
1024  if (SafeAddObject(obj, NULL))
1025  return PSafePtr<Base>(*this, mode, collection->Append(obj));
1026  return NULL;
1027  }
1028 
1037  virtual PBoolean Remove(
1038  Base * obj
1039  ) {
1040  return SafeRemove(obj);
1041  }
1042 
1052  PINDEX idx
1053  ) {
1054  return SafeRemoveAt(idx);
1055  }
1056 
1063  PINDEX idx,
1065  ) {
1066  return PSafePtr<Base>(*this, mode, idx);
1067  }
1068 
1075  const Base & value,
1077  ) {
1078  collectionMutex.Wait();
1080  collectionMutex.Signal();
1081  ptr.SetSafetyMode(mode);
1082  return ptr;
1083  }
1085 };
1086 
1087 
1092 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
1093 {
1094  public:
1096 };
1097 
1098 
1103 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
1104 {
1105  public:
1107 };
1108 
1109 
1114 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
1115 {
1116  public:
1118 };
1119 
1120 
1131 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
1132 {
1133  PCLASSINFO_WITH_CLONE(PSafeDictionaryBase, PSafeCollection);
1134  public:
1140  : PSafeCollection(new Coll) { }
1141 
1146  : PSafeCollection(new Coll)
1147  {
1148  PWaitAndSignal lock2(other.collectionMutex);
1149  CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1150  }
1151 
1156  {
1157  if (&other != this) {
1158  RemoveAll(true);
1160  PWaitAndSignal lock2(other.collectionMutex);
1161  CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1162  }
1163  return *this;
1164  }
1166 
1173  virtual void SetAt(const Key & key, Base * obj)
1174  {
1175  collectionMutex.Wait();
1176  if (SafeAddObject(obj, dynamic_cast<Coll &>(*collection).GetAt(key)))
1177  dynamic_cast<Coll &>(*collection).SetAt(key, obj);
1178  collectionMutex.Signal();
1179  }
1180 
1190  const Key & key
1191  ) {
1193  return SafeRemove(dynamic_cast<Coll &>(*collection).GetAt(key));
1194  }
1195 
1199  const Key & key
1200  ) {
1202  return dynamic_cast<Coll &>(*collection).Contains(key);
1203  }
1204 
1211  PINDEX idx,
1213  ) {
1214  return PSafePtr<Base>(*this, mode, idx);
1215  }
1216 
1223  const Key & key,
1225  ) const {
1226  collectionMutex.Wait();
1227  PSafePtr<Base> ptr(*this, PSafeReference, dynamic_cast<Coll &>(*collection).GetAt(key));
1228  collectionMutex.Signal();
1229  ptr.SetSafetyMode(mode);
1230  return ptr;
1231  }
1232 
1235  virtual bool Move(
1236  const Key & from,
1237  const Key & to
1238  ) {
1240  if (dynamic_cast<Coll &>(*collection).GetAt(to) != NULL)
1241  return false;
1242  dynamic_cast<Coll &>(*collection).SetAt(to, dynamic_cast<Coll &>(*collection).GetAt(from));
1243  return true;
1244  }
1245 
1249  {
1250  PArray<Key> keys;
1251  collectionMutex.Wait();
1252  dynamic_cast<Coll &>(*collection).AbstractGetKeys(keys);
1253  collectionMutex.Signal();
1254  return keys;
1255  }
1257 };
1258 
1259 
1264 template <class K, class D>
1265  class PSafeDictionary : public PSafeDictionaryBase<PDictionary<K, D>, K, D>
1266 {
1267  public:
1268  typedef K key_type;
1269  typedef D data_type;
1272 
1275  class iterator;
1276  class const_iterator;
1278  protected:
1279  K * m_internal_first; // Must be first two members
1281 
1284  PINDEX m_position;
1285 
1287  : m_internal_first(NULL)
1288  , m_internal_second(NULL)
1289  , m_dictionary(NULL)
1290  , m_position(P_MAX_INDEX)
1291  {
1292  }
1293 
1294  iterator_base(const dict_type * dict)
1295  : m_dictionary(dict)
1296  , m_keys(dict->GetKeys())
1297  {
1298  this->SetPosition(0);
1299  }
1300 
1301  iterator_base(const dict_type * dict, const K & key)
1302  : m_dictionary(dict)
1303  , m_keys(dict->GetKeys())
1304  {
1305  this->SetPosition(m_keys.GetValuesIndex(key));
1306  }
1307 
1308  bool SetPosition(PINDEX position)
1309  {
1310  if (position >= this->m_keys.GetSize()) {
1311  this->m_position = P_MAX_INDEX;
1312  this->m_internal_first = NULL;
1313  this->m_internal_second.SetNULL();
1314  return false;
1315  }
1316 
1317  this->m_position = position;
1318  this->m_internal_first = &this->m_keys[position];
1320  return this->m_internal_second == NULL;
1321  }
1322 
1323  void Next() { while (this->SetPosition(this->m_position+1)) { } }
1324  void Prev() { while (this->SetPosition(this->m_position > 0 ? this->m_position+1 : P_MAX_INDEX)) { } }
1325 
1326  public:
1327  bool operator==(const iterator_base & it) const { return this->m_position == it.m_position; }
1328  bool operator!=(const iterator_base & it) const { return this->m_position != it.m_position; }
1329  };
1330 
1332  public:
1333  const K & first;
1335 
1336  private:
1337  iterator_pair() : first(reinterpret_cast<const K &>(0)) { }
1338  };
1339 
1340  class iterator : public iterator_base, public std::iterator<std::forward_iterator_tag, iterator_pair> {
1341  protected:
1342  iterator(dict_type * dict) : iterator_base(dict) { }
1343  iterator(dict_type * dict, const K & key) : iterator_base(dict, key) { }
1344 
1345  public:
1346  iterator() { }
1347 
1348  iterator operator++() { this->Next(); return *this; }
1349  iterator operator--() { this->Prev(); return *this; }
1350  iterator operator++(int) { iterator it = *this; this->Next(); return it; }
1351  iterator operator--(int) { iterator it = *this; this->Prev(); return it; }
1352 
1353  const iterator_pair * operator->() const { return reinterpret_cast<const iterator_pair *>(this); }
1354  const iterator_pair & operator* () const { return *reinterpret_cast<const iterator_pair *>(this); }
1355 
1356  friend class PSafeDictionary<K, D>;
1357  };
1358 
1359  iterator begin() { return iterator(this); }
1360  iterator end() { return iterator(); }
1361  iterator find(const K & key) { return iterator(this, key); }
1362 
1363 
1364  class const_iterator : public iterator_base, public std::iterator<std::forward_iterator_tag, iterator_pair> {
1365  protected:
1366  const_iterator(const dict_type * dict) : iterator_base(dict) { }
1367  const_iterator(const dict_type * dict, const K & key) : iterator_base(dict, key) { }
1368 
1369  public:
1371  const_iterator(const typename dict_type::iterator & it) : iterator_base(it) { }
1372 
1373  const_iterator operator++() { this->Next(); return *this; }
1374  const_iterator operator--() { this->Prev(); return *this; }
1375  const_iterator operator++(int) { const_iterator it = *this; this->Next(); return it; }
1376  const_iterator operator--(int) { const_iterator it = *this; this->Prev(); return it; }
1377 
1378  const iterator_pair * operator->() const { return reinterpret_cast<const iterator_pair *>(this); }
1379  const iterator_pair & operator* () const { return *reinterpret_cast<const iterator_pair *>(this); }
1380 
1381  friend class PSafeDictionary<K, D>;
1382  };
1383 
1384  const_iterator begin() const { return const_iterator(this); }
1385  const_iterator end() const { return const_iterator(); }
1386  const_iterator find(const K & key) const { return const_iterator(this, key); }
1387 
1388  void erase(const iterator & it) { this->RemoveAt(it->first); }
1389  void erase(const const_iterator & it) { this->RemoveAt(it->first); }
1391 };
1392 
1393 
1394 #endif // PTLIB_SAFE_COLLECTION_H
1395 
1396 
1397 // End Of File ///////////////////////////////////////////////////////////////