Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TCollection.cxx
Go to the documentation of this file.
1 // @(#)root/cont:$Id$
2 // Author: Fons Rademakers 13/08/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TCollection
13 \ingroup Containers
14 Collection abstract base class. This class describes the base
15 protocol all collection classes have to implement. The ROOT
16 collection classes always store pointers to objects that inherit
17 from TObject. They never adopt the objects. Therefore, it is the
18 user's responsibility to take care of deleting the actual objects
19 once they are not needed anymore. In exceptional cases, when the
20 user is 100% sure nothing else is referencing the objects in the
21 collection, one can delete all objects and the collection at the
22 same time using the Delete() function.
23 
24 Collections can be iterated using an iterator object (see
25 TIterator). Depending on the concrete collection class there may be
26 some additional methods of iterating. See the respective classes.
27 
28 TCollection inherits from TObject since we want to be able to have
29 collections of collections.
30 
31 In a later release the collections may become templatized.
32 */
33 
34 #include "TCollection.h"
35 #include "Riostream.h"
36 #include "Varargs.h"
37 #include "TClass.h"
38 #include "TROOT.h"
39 #include "TBrowser.h"
40 #include "TObjectTable.h"
41 #include "TRegexp.h"
42 #include "TPRegexp.h"
43 #include "TVirtualMutex.h"
44 #include "TError.h"
45 #include "TSystem.h"
46 #include <sstream>
47 
48 #include "TSpinLockGuard.h"
49 
50 TVirtualMutex *gCollectionMutex = 0;
51 
52 TCollection *TCollection::fgCurrentCollection = 0;
53 TObjectTable *TCollection::fgGarbageCollection = 0;
54 Bool_t TCollection::fgEmptyingGarbage = kFALSE;
55 Int_t TCollection::fgGarbageStack = 0;
56 
57 ClassImp(TCollection);
58 ClassImp(TIter);
59 
60 #ifdef R__CHECK_COLLECTION_MULTI_ACCESS
61 
62 void TCollection::TErrorLock::ConflictReport(std::thread::id holder, const char *accesstype,
63  const TCollection *collection, const char *function)
64 {
65 
66  auto local = std::this_thread::get_id();
67  std::stringstream cur, loc;
68  if (holder == std::thread::id())
69  cur << "None";
70  else
71  cur << "0x" << std::hex << holder;
72  loc << "0x" << std::hex << local;
73 
74  // std::cerr << "Error in " << function << ": Access (" << accesstype << ") to a collection (" <<
75  // collection->IsA()->GetName() << ":" << collection <<
76  // ") from multiple threads at a time. holder=" << "0x" << std::hex << holder << " readers=" << fReadSet.size() <<
77  // "0x" << std::hex << local << std::endl;
78 
79  ::Error(function,
80  "Access (%s) to a collection (%s:%p) from multiple threads at a time. holder=%s readers=%lu intruder=%s",
81  accesstype, collection->IsA()->GetName(), collection, cur.str().c_str(), fReadSet.size(), loc.str().c_str());
82 
83  std::set<std::thread::id> tmp;
84  for (auto r : fReadSet) tmp.insert(r);
85  for (auto r : tmp) {
86  std::stringstream reader;
87  reader << "0x" << std::hex << r;
88  ::Error(function, " Readers includes %s", reader.str().c_str());
89  }
90  gSystem->StackTrace();
91 }
92 
93 void TCollection::TErrorLock::Lock(const TCollection *collection, const char *function)
94 {
95  auto local = std::this_thread::get_id();
96 
97  std::thread::id holder;
98 
99  if (fWriteCurrent.compare_exchange_strong(holder, local)) {
100  // fWriteCurrent was the default id and is now local.
101  ++fWriteCurrentRecurse;
102  // std::cerr << "#" << "0x" << std::hex << local << " acquired first " << collection << " lock:" << this <<
103  // std::endl;
104 
105  // Now check if there is any readers lingering
106  if (fReadCurrentRecurse) {
107  if (fReadSet.size() > 1 || fReadSet.find(local) != fReadSet.end()) {
108  ConflictReport(std::thread::id(), "WriteLock while ReadLock taken", collection, function);
109  }
110  }
111  } else {
112  // fWriteCurrent was not the default id and is still the 'holder' thread id
113  // this id is now also in the holder variable
114  if (holder == local) {
115  // The holder was actually this thread, no problem there, we
116  // allow re-entrancy.
117  // std::cerr << "#" << "0x" << std::hex << local << " re-entered " << fWriteCurrentRecurse << " " << collection
118  // << " lock:" << this << std::endl;
119  } else {
120  ConflictReport(holder, "WriteLock", collection, function);
121  }
122  ++fWriteCurrentRecurse;
123  }
124 }
125 
126 void TCollection::TErrorLock::Unlock()
127 {
128  auto local = std::this_thread::get_id();
129  auto none = std::thread::id();
130 
131  --fWriteCurrentRecurse;
132  if (fWriteCurrentRecurse == 0) {
133  if (fWriteCurrent.compare_exchange_strong(local, none)) {
134  // fWriteCurrent was local and is now none.
135 
136  // std::cerr << "#" << "0x" << std::hex << local << " zero and cleaned : " << std::dec << fWriteCurrentRecurse
137  // << " 0x" << std::hex << fWriteCurrent.load() << " lock:" << this << std::endl;
138  } else {
139  // fWriteCurrent was not local, just live it as is.
140 
141  // std::cerr << "#" << "0x" << std::hex << local << " zero but somebody else : " << "0x" << std::hex <<
142  // fWriteCurrent.load() << " lock:" << this << std::endl;
143  }
144  } else {
145  // std::cerr << "#" << "0x" << std::hex << local << " still holding " << "0x" << std::hex << fWriteCurrentRecurse
146  // << " lock:" << this << std::endl;
147  }
148 
149  // std::cerr << "#" << "0x" << std::hex << local << " ended with : " << std::dec << fWriteCurrentRecurse << " 0x" <<
150  // std::hex << fWriteCurrent.load() << " lock:" << this << std::endl;
151 }
152 
153 void TCollection::TErrorLock::ReadLock(const TCollection *collection, const char *function)
154 {
155  auto local = std::this_thread::get_id();
156 
157  {
158  ROOT::Internal::TSpinLockGuard guard(fSpinLockFlag);
159  fReadSet.insert(local); // this is not thread safe ...
160  }
161  ++fReadCurrentRecurse;
162 
163  if (fWriteCurrentRecurse) {
164  auto holder = fWriteCurrent.load();
165  if (holder != local) ConflictReport(holder, "ReadLock with WriteLock taken", collection, function);
166  }
167 }
168 
169 void TCollection::TErrorLock::ReadUnlock()
170 {
171  auto local = std::this_thread::get_id();
172  {
173  ROOT::Internal::TSpinLockGuard guard(fSpinLockFlag);
174  fReadSet.erase(local); // this is not thread safe ...
175  }
176  --fReadCurrentRecurse;
177 }
178 
179 #endif // R__CHECK_COLLECTION_MULTI_ACCESS
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 /// TNamed destructor.
183 
184 TCollection::~TCollection()
185 {
186  // Required since we overload TObject::Hash.
187  ROOT::CallRecursiveRemoveIfNeeded(*this);
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// Add all objects from collection col to this collection.
192 
193 void TCollection::AddAll(const TCollection *col)
194 {
195  TIter next(col);
196  TObject *obj;
197 
198  while ((obj = next()))
199  Add(obj);
200 }
201 
202 ////////////////////////////////////////////////////////////////////////////////
203 /// Add all arguments to the collection. The list of objects must be
204 /// terminated by 0, e.g.: l.AddVector(o1, o2, o3, o4, 0);
205 
206 void TCollection::AddVector(TObject *va_(obj1), ...)
207 {
208  va_list ap;
209  va_start(ap, va_(obj1));
210  TObject *obj;
211 
212  Add(va_(obj1));
213  while ((obj = va_arg(ap, TObject *)))
214  Add(obj);
215  va_end(ap);
216 }
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 /// Make sure all objects in this collection inherit from class cl.
220 
221 Bool_t TCollection::AssertClass(TClass *cl) const
222 {
223  TObject *obj;
224  TIter next(this);
225  Bool_t error = kFALSE;
226 
227  if (!cl) {
228  Error("AssertClass", "class == 0");
229  return kTRUE;
230  }
231 
232  for (int i = 0; (obj = next()); i++)
233  if (!obj->InheritsFrom(cl)) {
234  Error("AssertClass", "element %d is not an instance of class %s (%s)",
235  i, cl->GetName(), obj->ClassName());
236  error = kTRUE;
237  }
238  return error;
239 }
240 
241 ////////////////////////////////////////////////////////////////////////////////
242 /// Browse this collection (called by TBrowser).
243 /// If b=0, there is no Browse call TObject::Browse(0) instead.
244 /// This means TObject::Inspect() will be invoked indirectly
245 
246 void TCollection::Browse(TBrowser *b)
247 {
248  TIter next(this);
249  TObject *obj;
250 
251  if (b)
252  while ((obj = next())) b->Add(obj);
253  else
254  TObject::Browse(b);
255 }
256 
257 ////////////////////////////////////////////////////////////////////////////////
258 /// Make a clone of an collection using the Streamer facility.
259 /// If newname is specified, this will be the name of the new collection.
260 
261 TObject *TCollection::Clone(const char *newname) const
262 {
263  TCollection *new_collection = (TCollection*)TObject::Clone(newname);
264  if (newname && strlen(newname)) new_collection->SetName(newname);
265  return new_collection;
266 }
267 
268 
269 ////////////////////////////////////////////////////////////////////////////////
270 /// Compare two TCollection objects. Returns 0 when equal, -1 when this is
271 /// smaller and +1 when bigger (like strcmp()).
272 
273 Int_t TCollection::Compare(const TObject *obj) const
274 {
275  if (this == obj) return 0;
276  return fName.CompareTo(obj->GetName());
277 }
278 
279 ////////////////////////////////////////////////////////////////////////////////
280 /// Draw all objects in this collection.
281 
282 void TCollection::Draw(Option_t *option)
283 {
284  TIter next(this);
285  TObject *object;
286 
287  while ((object = next())) {
288  object->Draw(option);
289  }
290 }
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 /// Dump all objects in this collection.
294 
295 void TCollection::Dump() const
296 {
297  TIter next(this);
298  TObject *object;
299 
300  while ((object = next())) {
301  object->Dump();
302  }
303 }
304 
305 ////////////////////////////////////////////////////////////////////////////////
306 /// Find an object in this collection using its name. Requires a sequential
307 /// scan till the object has been found. Returns 0 if object with specified
308 /// name is not found.
309 
310 TObject *TCollection::FindObject(const char *name) const
311 {
312  TIter next(this);
313  TObject *obj;
314 
315  while ((obj = next()))
316  if (!strcmp(name, obj->GetName())) return obj;
317  return 0;
318 }
319 
320 ////////////////////////////////////////////////////////////////////////////////
321 /// Find an object in this collection by name.
322 
323 TObject *TCollection::operator()(const char *name) const
324 {
325  return FindObject(name);
326 }
327 
328 ////////////////////////////////////////////////////////////////////////////////
329 /// Find an object in this collection using the object's IsEqual()
330 /// member function. Requires a sequential scan till the object has
331 /// been found. Returns 0 if object is not found.
332 /// Typically this function is overridden by a more efficient version
333 /// in concrete collection classes (e.g. THashTable).
334 
335 TObject *TCollection::FindObject(const TObject *obj) const
336 {
337  TIter next(this);
338  TObject *ob;
339 
340  while ((ob = next()))
341  if (ob->IsEqual(obj)) return ob;
342  return 0;
343 }
344 
345 ////////////////////////////////////////////////////////////////////////////////
346 /// Return name of this collection.
347 /// if no name, return the collection class name.
348 
349 const char *TCollection::GetName() const
350 {
351  if (fName.Length() > 0) return fName.Data();
352  return ClassName();
353 }
354 
355 ////////////////////////////////////////////////////////////////////////////////
356 /// Increase the collection's capacity by delta slots.
357 
358 Int_t TCollection::GrowBy(Int_t delta) const
359 {
360  if (delta < 0) {
361  Error("GrowBy", "delta < 0");
362  delta = Capacity();
363  }
364  return Capacity() + TMath::Range(2, kMaxInt - Capacity(), delta);
365 }
366 
367 ////////////////////////////////////////////////////////////////////////////////
368 /// Returns true if object is a null pointer.
369 
370 Bool_t TCollection::IsArgNull(const char *where, const TObject *obj) const
371 {
372  return obj ? kFALSE : (Error(where, "argument is a null pointer"), kTRUE);
373 }
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 /// List (ls) all objects in this collection.
377 /// Wildcarding supported, eg option="xxx*" lists only objects
378 /// with names xxx*.
379 
380 void TCollection::ls(Option_t *option) const
381 {
382  TROOT::IndentLevel();
383  std::cout <<"OBJ: " << IsA()->GetName() << "\t" << GetName() << "\t" << GetTitle() << " : "
384  << Int_t(TestBit(kCanDelete)) << std::endl;
385 
386  TRegexp re(option,kTRUE);
387  TIter next(this);
388  TObject *object;
389  char *star = 0;
390  if (option) star = (char*)strchr(option,'*');
391 
392  TROOT::IncreaseDirLevel();
393  while ((object = next())) {
394  if (star) {
395  TString s = object->GetName();
396  if (s != option && s.Index(re) == kNPOS) continue;
397  }
398  object->ls(option);
399  }
400  TROOT::DecreaseDirLevel();
401 }
402 
403 ////////////////////////////////////////////////////////////////////////////////
404 /// 'Notify' all objects in this collection.
405 Bool_t TCollection::Notify()
406 {
407  Bool_t success = true;
408  for (auto obj : *this) success &= obj->Notify();
409  return success;
410 }
411 
412 ////////////////////////////////////////////////////////////////////////////////
413 /// Paint all objects in this collection.
414 
415 void TCollection::Paint(Option_t *option)
416 {
417  this->R__FOR_EACH(TObject,Paint)(option);
418 }
419 
420 ////////////////////////////////////////////////////////////////////////////////
421 /// Print the collection header.
422 
423 void TCollection::PrintCollectionHeader(Option_t*) const
424 {
425  TROOT::IndentLevel();
426  printf("Collection name='%s', class='%s', size=%d\n",
427  GetName(), ClassName(), GetSize());
428 }
429 
430 ////////////////////////////////////////////////////////////////////////////////
431 /// For given collection entry return the string that is used to
432 /// identify the object and, potentially, perform wildcard/regexp
433 /// filtering on.
434 
435 const char* TCollection::GetCollectionEntryName(TObject* entry) const
436 {
437  return entry->GetName();
438 }
439 
440 ////////////////////////////////////////////////////////////////////////////////
441 /// Print the collection entry.
442 
443 void TCollection::PrintCollectionEntry(TObject* entry, Option_t* option, Int_t recurse) const
444 {
445  TCollection* coll = dynamic_cast<TCollection*>(entry);
446  if (coll) {
447  coll->Print(option, recurse);
448  } else {
449  TROOT::IndentLevel();
450  entry->Print(option);
451  }
452 }
453 
454 ////////////////////////////////////////////////////////////////////////////////
455 /// Default print for collections, calls Print(option, 1).
456 /// This will print the collection header and Print() methods of
457 /// all the collection entries.
458 ///
459 /// If you want to override Print() for a collection class, first
460 /// see if you can accomplish it by overriding the following protected
461 /// methods:
462 /// ~~~ {.cpp}
463 /// void PrintCollectionHeader(Option_t* option) const;
464 /// const char* GetCollectionEntryName(TObject* entry) const;
465 /// void PrintCollectionEntry(TObject* entry, Option_t* option, Int_t recurse) const;
466 /// ~~~
467 /// Otherwise override the `Print(Option_t *option, Int_t)`
468 /// variant. Remember to declare:
469 /// ~~~ {.cpp}
470 /// using TCollection::Print;
471 /// ~~~
472 /// somewhere close to the method declaration.
473 
474 void TCollection::Print(Option_t *option) const
475 {
476  Print(option, 1);
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 /// Print the collection header and its elements.
481 ///
482 /// If recurse is non-zero, descend into printing of
483 /// collection-entries with recurse - 1.
484 /// This means, if recurse is negative, the recursion is infinite.
485 ///
486 /// Option is passed recursively.
487 
488 void TCollection::Print(Option_t *option, Int_t recurse) const
489 {
490  PrintCollectionHeader(option);
491 
492  if (recurse != 0)
493  {
494  TIter next(this);
495  TObject *object;
496 
497  TROOT::IncreaseDirLevel();
498  while ((object = next())) {
499  PrintCollectionEntry(object, option, recurse - 1);
500  }
501  TROOT::DecreaseDirLevel();
502  }
503 }
504 
505 ////////////////////////////////////////////////////////////////////////////////
506 /// Print the collection header and its elements that match the wildcard.
507 ///
508 /// If recurse is non-zero, descend into printing of
509 /// collection-entries with recurse - 1.
510 /// This means, if recurse is negative, the recursion is infinite.
511 ///
512 /// Option is passed recursively, but wildcard is only used on the
513 /// first level.
514 
515 void TCollection::Print(Option_t *option, const char* wildcard, Int_t recurse) const
516 {
517  PrintCollectionHeader(option);
518 
519  if (recurse != 0)
520  {
521  if (!wildcard) wildcard = "";
522  TRegexp re(wildcard, kTRUE);
523  Int_t nch = strlen(wildcard);
524  TIter next(this);
525  TObject *object;
526 
527  TROOT::IncreaseDirLevel();
528  while ((object = next())) {
529  TString s = GetCollectionEntryName(object);
530  if (nch == 0 || s == wildcard || s.Index(re) != kNPOS) {
531  PrintCollectionEntry(object, option, recurse - 1);
532  }
533  }
534  TROOT::DecreaseDirLevel();
535  }
536 }
537 
538 ////////////////////////////////////////////////////////////////////////////////
539 /// Print the collection header and its elements that match the regexp.
540 ///
541 /// If recurse is non-zero, descend into printing of
542 /// collection-entries with recurse - 1.
543 /// This means, if recurse is negative, the recursion is infinite.
544 ///
545 /// Option is passed recursively, but regexp is only used on the
546 /// first level.
547 
548 void TCollection::Print(Option_t *option, TPRegexp& regexp, Int_t recurse) const
549 {
550  PrintCollectionHeader(option);
551 
552  if (recurse != 0)
553  {
554  TIter next(this);
555  TObject *object;
556 
557  TROOT::IncreaseDirLevel();
558  while ((object = next())) {
559  TString s = GetCollectionEntryName(object);
560  if (regexp.MatchB(s)) {
561  PrintCollectionEntry(object, option, recurse - 1);
562  }
563  }
564  TROOT::DecreaseDirLevel();
565  }
566 }
567 
568 ////////////////////////////////////////////////////////////////////////////////
569 /// Remove object from this collection and recursively remove the object
570 /// from all other objects (and collections).
571 
572 void TCollection::RecursiveRemove(TObject *obj)
573 {
574  if (!obj) return;
575 
576  // Scan list and remove obj in the list itself
577  while (Remove(obj))
578  ;
579 
580  // Scan again the list and invoke RecursiveRemove for all objects
581  TIter next(this);
582  TObject *object;
583 
584  while ((object = next())) {
585  if (object->TestBit(kNotDeleted)) object->RecursiveRemove(obj);
586  }
587 }
588 
589 ////////////////////////////////////////////////////////////////////////////////
590 /// Remove all objects in collection col from this collection.
591 
592 void TCollection::RemoveAll(TCollection *col)
593 {
594  TIter next(col);
595  TObject *obj;
596 
597  while ((obj = next()))
598  Remove(obj);
599 }
600 
601 ////////////////////////////////////////////////////////////////////////////////
602 /// Stream all objects in the collection to or from the I/O buffer.
603 
604 void TCollection::Streamer(TBuffer &b)
605 {
606  Int_t nobjects;
607  TObject *obj;
608  UInt_t R__s, R__c;
609 
610  if (b.IsReading()) {
611  Version_t v = b.ReadVersion(&R__s, &R__c);
612  if (v > 2)
613  TObject::Streamer(b);
614  if (v > 1)
615  fName.Streamer(b);
616  b >> nobjects;
617  for (Int_t i = 0; i < nobjects; i++) {
618  b >> obj;
619  Add(obj);
620  }
621  b.CheckByteCount(R__s, R__c,TCollection::IsA());
622  } else {
623  R__c = b.WriteVersion(TCollection::IsA(), kTRUE);
624  TObject::Streamer(b);
625  fName.Streamer(b);
626  nobjects = GetSize();
627  b << nobjects;
628 
629  TIter next(this);
630 
631  while ((obj = next())) {
632  b << obj;
633  }
634  b.SetByteCount(R__c, kTRUE);
635  }
636 }
637 
638 ////////////////////////////////////////////////////////////////////////////////
639 /// Write all objects in this collection. By default all objects in
640 /// the collection are written individually (each object gets its
641 /// own key). Note, this is recursive, i.e. objects in collections
642 /// in the collection are also written individually. To write all
643 /// objects using a single key specify a name and set option to
644 /// TObject::kSingleKey (i.e. 1).
645 
646 Int_t TCollection::Write(const char *name, Int_t option, Int_t bsize) const
647 {
648  if ((option & kSingleKey)) {
649  return TObject::Write(name, option, bsize);
650  } else {
651  option &= ~kSingleKey;
652  Int_t nbytes = 0;
653  TIter next(this);
654  TObject *obj;
655  while ((obj = next())) {
656  nbytes += obj->Write(name, option, bsize);
657  }
658  return nbytes;
659  }
660 }
661 
662 ////////////////////////////////////////////////////////////////////////////////
663 /// Write all objects in this collection. By default all objects in
664 /// the collection are written individually (each object gets its
665 /// own key). Note, this is recursive, i.e. objects in collections
666 /// in the collection are also written individually. To write all
667 /// objects using a single key specify a name and set option to
668 /// TObject::kSingleKey (i.e. 1).
669 
670 Int_t TCollection::Write(const char *name, Int_t option, Int_t bsize)
671 {
672  return ((const TCollection*)this)->Write(name,option,bsize);
673 }
674 
675 ////////////////////////////////////////////////////////////////////////////////
676 /// Return the globally accessible collection.
677 
678 TCollection *TCollection::GetCurrentCollection()
679 {
680  return fgCurrentCollection;
681 }
682 
683 ////////////////////////////////////////////////////////////////////////////////
684 /// Set this collection to be the globally accesible collection.
685 
686 void TCollection::SetCurrentCollection()
687 {
688  fgCurrentCollection = this;
689 }
690 
691 ////////////////////////////////////////////////////////////////////////////////
692 /// Set up for garbage collection.
693 
694 void TCollection::StartGarbageCollection()
695 {
696  R__LOCKGUARD2(gCollectionMutex);
697  if (!fgGarbageCollection) {
698  fgGarbageCollection = new TObjectTable;
699  fgEmptyingGarbage = kFALSE;
700  fgGarbageStack = 0;
701  }
702  fgGarbageStack++;
703 }
704 
705 ////////////////////////////////////////////////////////////////////////////////
706 /// Do the garbage collection.
707 
708 void TCollection::EmptyGarbageCollection()
709 {
710  R__LOCKGUARD2(gCollectionMutex);
711  if (fgGarbageStack > 0) fgGarbageStack--;
712  if (fgGarbageCollection && fgGarbageStack == 0 && fgEmptyingGarbage == kFALSE) {
713  fgEmptyingGarbage = kTRUE;
714  fgGarbageCollection->Delete();
715  fgEmptyingGarbage = kFALSE;
716  SafeDelete(fgGarbageCollection);
717  }
718 }
719 
720 ////////////////////////////////////////////////////////////////////////////////
721 /// Add to the list of things to be cleaned up.
722 
723 void TCollection::GarbageCollect(TObject *obj)
724 {
725  {
726  R__LOCKGUARD2(gCollectionMutex);
727  if (fgGarbageCollection) {
728  if (!fgEmptyingGarbage) {
729  fgGarbageCollection->Add(obj);
730  return;
731  }
732  }
733  }
734  delete obj;
735 }
736 
737 ////////////////////////////////////////////////////////////////////////////////
738 /// Set whether this collection is the owner (enable==true)
739 /// of its content. If it is the owner of its contents,
740 /// these objects will be deleted whenever the collection itself
741 /// is delete. The objects might also be deleted or destructed when Clear
742 /// is called (depending on the collection).
743 
744 void TCollection::SetOwner(Bool_t enable)
745 {
746  if (enable)
747  SetBit(kIsOwner);
748  else
749  ResetBit(kIsOwner);
750 }
751 
752 ////////////////////////////////////////////////////////////////////////////////
753 /// Set this collection to use a RW lock upon access, making it thread safe.
754 /// Return the previous state.
755 ///
756 /// Note: To test whether the usage is enabled do:
757 /// collection->TestBit(TCollection::kUseRWLock);
758 
759 bool TCollection::UseRWLock()
760 {
761  bool prev = TestBit(TCollection::kUseRWLock);
762  SetBit(TCollection::kUseRWLock);
763  return prev;
764 }
765 
766 ////////////////////////////////////////////////////////////////////////////////
767 /// Copy a TIter. This involves allocating a new TIterator of the right
768 /// sub class and assigning it with the original.
769 
770 TIter::TIter(const TIter &iter)
771 {
772  if (iter.fIterator) {
773  fIterator = iter.GetCollection()->MakeIterator();
774  fIterator->operator=(*iter.fIterator);
775  } else
776  fIterator = 0;
777 }
778 
779 ////////////////////////////////////////////////////////////////////////////////
780 /// Assigning an TIter to another. This involves allocating a new TIterator
781 /// of the right sub class and assigning it with the original.
782 
783 TIter &TIter::operator=(const TIter &rhs)
784 {
785  if (this != &rhs) {
786  if (rhs.fIterator) {
787  delete fIterator;
788  fIterator = rhs.GetCollection()->MakeIterator();
789  fIterator->operator=(*rhs.fIterator);
790  }
791  }
792  return *this;
793 }
794 
795 ////////////////////////////////////////////////////////////////////////////////
796 /// Pointing to the first element of the container.
797 
798 TIter &TIter::Begin()
799 {
800  fIterator->Reset();
801  fIterator->Next();
802  return *this;
803 }
804 
805 ////////////////////////////////////////////////////////////////////////////////
806 /// Pointing to the element after the last - to a nullptr value in our case.
807 
808 TIter TIter::End()
809 {
810  return TIter(static_cast<TIterator*>(nullptr));
811 }
812 
813 ////////////////////////////////////////////////////////////////////////////////
814 /// Return an empty collection for use with nullptr TRangeCast
815 
816 const TCollection &ROOT::Internal::EmptyCollection()
817 {
818  static TObjArray sEmpty;
819  return sEmpty;
820 }
821 
822 ////////////////////////////////////////////////////////////////////////////////
823 /// Return true if 'cl' inherits from 'base'.
824 
825 bool ROOT::Internal::ContaineeInheritsFrom(TClass *cl, TClass *base)
826 {
827  return cl->InheritsFrom(base);
828 }