PTLib Version 2.12.9

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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
158 PBoolean SafeReference();
159
170 PBoolean SafeDereference();
171
189 PBoolean LockReadOnly() const;
190
201 void UnlockReadOnly() const;
202
220 PBoolean LockReadWrite();
221
232 void UnlockReadWrite();
233
243 void SafeRemove();
244
252 PBoolean SafelyCanBeDeleted() const;
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
287 class PSafeLockReadOnly
288 {
289 public:
290 PSafeLockReadOnly(const PSafeObject & object);
291 ~PSafeLockReadOnly();
292 PBoolean Lock();
293 void Unlock();
294 PBoolean IsLocked() const { return locked; }
295 bool operator!() const { return !locked; }
296
297 protected:
298 PSafeObject & safeObject;
299 PBoolean locked;
300 };
301
302
303
306 class PSafeLockReadWrite
307 {
308 public:
309 PSafeLockReadWrite(const PSafeObject & object);
310 ~PSafeLockReadWrite();
311 PBoolean Lock();
312 void Unlock();
313 PBoolean IsLocked() const { return locked; }
314 bool operator!() const { return !locked; }
315
316 protected:
317 PSafeObject & safeObject;
318 PBoolean locked;
319 };
320
321
322
335 class PSafeCollection : public PObject
336 {
337 PCLASSINFO(PSafeCollection, PObject);
338 public:
344 PSafeCollection(
345 PCollection * collection
346 );
347
351 ~PSafeCollection();
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
402 void AllowDeleteObjects(
403 PBoolean yes = true
404 ) { deleteObjects = yes; }
405
410 void DisallowDeleteObjects() { deleteObjects = false; }
411
416 virtual PBoolean DeleteObjectsToBeRemoved();
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);
445 void CopySafeDictionary(PAbstractDictionary * other);
446 bool SafeAddObject(PSafeObject * obj, PSafeObject * old);
447 void SafeRemoveObject(PSafeObject * obj);
448 PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
449
450 PCollection * collection;
451 mutable PMutex collectionMutex;
452 bool deleteObjects;
453 PList<PSafeObject> toBeRemoved;
454 PMutex removalMutex;
455 PTimer * m_deleteObjectsTimer;
456
457 private:
458 PSafeCollection(const PSafeCollection & other) : PObject(other) { }
459 void operator=(const PSafeCollection &) { }
460
461 friend class PSafePtrBase;
462 };
463
464
465 enum PSafetyMode {
466 PSafeReference,
467 PSafeReadOnly,
468 PSafeReadWrite
469 };
470
483 class PSafePtrBase : public PObject
484 {
485 PCLASSINFO(PSafePtrBase, PObject);
486
489 protected:
497 PSafePtrBase(
498 PSafeObject * obj = NULL,
499 PSafetyMode mode = PSafeReference
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
608 enum EnterSafetyModeOption {
609 WithReference,
610 AlreadyReferenced
611 };
612 PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
613
614 enum ExitSafetyModeOption {
615 WithDereference,
616 NoDereference
617 };
618 void ExitSafetyMode(ExitSafetyModeOption ref);
619
620 virtual void LockPtr() { }
621 virtual void UnlockPtr() { }
622
623 protected:
624 const PSafeCollection * collection;
625 PSafeObject * currentObject;
626 PSafetyMode lockMode;
627 };
628
629
642 class PSafePtrMultiThreaded : public PSafePtrBase
643 {
644 PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
645
648 protected:
656 PSafePtrMultiThreaded(
657 PSafeObject * obj = NULL,
658 PSafetyMode mode = PSafeReference
659 );
660
668 PSafePtrMultiThreaded(
669 const PSafeCollection & safeCollection,
670 PSafetyMode mode,
671 PINDEX idx
672 );
673
681 PSafePtrMultiThreaded(
682 const PSafeCollection & safeCollection,
683 PSafetyMode mode,
684 PSafeObject * obj
685 );
686
692 PSafePtrMultiThreaded(
693 const PSafePtrMultiThreaded & enumerator
694 );
695
696 public:
699 ~PSafePtrMultiThreaded();
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;
746 PSafeObject * m_objectToDelete;
747 };
748
749
770 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
771 {
772 public:
782 PSafePtr(
783 T * obj = NULL,
784 PSafetyMode mode = PSafeReference
785 ) : BaseClass(obj, mode) { }
786
794 PSafePtr(
795 const PSafeCollection & safeCollection,
796 PSafetyMode mode = PSafeReadWrite,
797 PINDEX idx = 0
798 ) : BaseClass(safeCollection, mode, idx) { }
799
807 PSafePtr(
808 const PSafeCollection & safeCollection,
809 PSafetyMode mode,
810 PSafeObject * obj
811 ) : BaseClass(safeCollection, mode, obj) { }
812
818 PSafePtr(
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
922 T * operator++()
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
943 T * operator--()
944 {
945 BaseClass::Previous();
946 return dynamic_cast<T *>(BaseClass::currentObject);
947 }
949 };
950
951
955 template <class Base, class Derived>
956 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
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:
983 PSafeColl()
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);
1004 PWaitAndSignal lock1(collectionMutex);
1005 PWaitAndSignal lock2(other.collectionMutex);
1006 CopySafeCollection(dynamic_cast<Coll *>(other.collection));
1007 }
1008 return *this;
1009 }
1011
1018 virtual PSafePtr<Base> Append(
1019 Base * obj,
1020 PSafetyMode mode = PSafeReference
1021 ) {
1022 PWaitAndSignal mutex(collectionMutex);
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
1050 virtual PBoolean RemoveAt(
1051 PINDEX idx
1052 ) {
1053 return SafeRemoveAt(idx);
1054 }
1055
1061 virtual PSafePtr<Base> GetAt(
1062 PINDEX idx,
1063 PSafetyMode mode = PSafeReadWrite
1064 ) {
1065 return PSafePtr<Base>(*this, mode, idx);
1066 }
1067
1073 virtual PSafePtr<Base> FindWithLock(
1074 const Base & value,
1075 PSafetyMode mode = PSafeReadWrite
1076 ) {
1077 collectionMutex.Wait();
1078 PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
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:
1094 typedef PSafePtr<Base> value_type;
1095 };
1096
1097
1102 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
1103 {
1104 public:
1105 typedef PSafePtr<Base> value_type;
1106 };
1107
1108
1113 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
1114 {
1115 public:
1116 typedef PSafePtr<Base> value_type;
1117 };
1118
1119
1130 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
1131 {
1132 PCLASSINFO_WITH_CLONE(PSafeDictionaryBase, PSafeCollection);
1133 public:
1138 PSafeDictionaryBase()
1139 : PSafeCollection(new Coll) { }
1140
1144 PSafeDictionaryBase(const PSafeDictionaryBase & other)
1145 : PSafeCollection(new Coll)
1146 {
1147 PWaitAndSignal lock2(other.collectionMutex);
1148 CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1149 }
1150
1154 PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other)
1155 {
1156 if (&other != this) {
1157 RemoveAll(true);
1158 PWaitAndSignal lock1(collectionMutex);
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
1188 virtual PBoolean RemoveAt(
1189 const Key & key
1190 ) {
1191 PWaitAndSignal mutex(collectionMutex);
1192 return SafeRemove(dynamic_cast<Coll &>(*collection).GetAt(key));
1193 }
1194
1197 virtual PBoolean Contains(
1198 const Key & key
1199 ) {
1200 PWaitAndSignal lock(collectionMutex);
1201 return dynamic_cast<Coll &>(*collection).Contains(key);
1202 }
1203
1209 virtual PSafePtr<Base> GetAt(
1210 PINDEX idx,
1211 PSafetyMode mode = PSafeReadWrite
1212 ) {
1213 return PSafePtr<Base>(*this, mode, idx);
1214 }
1215
1221 virtual PSafePtr<Base> FindWithLock(
1222 const Key & key,
1223 PSafetyMode mode = PSafeReadWrite
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
1234 PArray<Key> GetKeys() const
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;
1256 typedef PSafePtr<D> value_type;
1257 typedef PSafeDictionary<K, D> dict_type;
1258
1261 class iterator;
1262 class const_iterator;
1263 class iterator_base {
1264 protected:
1265 K * m_internal_first; // Must be first two members
1266 value_type m_internal_second;
1267
1268 const dict_type * m_dictionary;
1269 PArray<K> m_keys;
1270 PINDEX m_position;
1271
1272 iterator_base()
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];
1305 this->m_internal_second = this->m_dictionary->FindWithLock(*this->m_internal_first, PSafeReference);
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
1317 class iterator_pair {
1318 public:
1319 const K & first;
1320 value_type second;
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:
1356 const_iterator() { }
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 ///////////////////////////////////////////////////////////////