50 TVirtualMutex *gCollectionMutex = 0;
52 TCollection *TCollection::fgCurrentCollection = 0;
53 TObjectTable *TCollection::fgGarbageCollection = 0;
54 Bool_t TCollection::fgEmptyingGarbage = kFALSE;
55 Int_t TCollection::fgGarbageStack = 0;
57 ClassImp(TCollection);
60 #ifdef R__CHECK_COLLECTION_MULTI_ACCESS
62 void TCollection::TErrorLock::ConflictReport(std::thread::id holder,
const char *accesstype,
63 const TCollection *collection,
const char *
function)
66 auto local = std::this_thread::get_id();
67 std::stringstream cur, loc;
68 if (holder == std::thread::id())
71 cur <<
"0x" << std::hex << holder;
72 loc <<
"0x" << std::hex << local;
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());
83 std::set<std::thread::id> tmp;
84 for (
auto r : fReadSet) tmp.insert(r);
86 std::stringstream reader;
87 reader <<
"0x" << std::hex << r;
88 ::Error(
function,
" Readers includes %s", reader.str().c_str());
90 gSystem->StackTrace();
93 void TCollection::TErrorLock::Lock(
const TCollection *collection,
const char *
function)
95 auto local = std::this_thread::get_id();
97 std::thread::id holder;
99 if (fWriteCurrent.compare_exchange_strong(holder, local)) {
101 ++fWriteCurrentRecurse;
106 if (fReadCurrentRecurse) {
107 if (fReadSet.size() > 1 || fReadSet.find(local) != fReadSet.end()) {
108 ConflictReport(std::thread::id(),
"WriteLock while ReadLock taken", collection,
function);
114 if (holder == local) {
120 ConflictReport(holder,
"WriteLock", collection,
function);
122 ++fWriteCurrentRecurse;
126 void TCollection::TErrorLock::Unlock()
128 auto local = std::this_thread::get_id();
129 auto none = std::thread::id();
131 --fWriteCurrentRecurse;
132 if (fWriteCurrentRecurse == 0) {
133 if (fWriteCurrent.compare_exchange_strong(local, none)) {
153 void TCollection::TErrorLock::ReadLock(
const TCollection *collection,
const char *
function)
155 auto local = std::this_thread::get_id();
158 ROOT::Internal::TSpinLockGuard guard(fSpinLockFlag);
159 fReadSet.insert(local);
161 ++fReadCurrentRecurse;
163 if (fWriteCurrentRecurse) {
164 auto holder = fWriteCurrent.load();
165 if (holder != local) ConflictReport(holder,
"ReadLock with WriteLock taken", collection,
function);
169 void TCollection::TErrorLock::ReadUnlock()
171 auto local = std::this_thread::get_id();
173 ROOT::Internal::TSpinLockGuard guard(fSpinLockFlag);
174 fReadSet.erase(local);
176 --fReadCurrentRecurse;
179 #endif // R__CHECK_COLLECTION_MULTI_ACCESS
184 TCollection::~TCollection()
187 ROOT::CallRecursiveRemoveIfNeeded(*
this);
193 void TCollection::AddAll(
const TCollection *col)
198 while ((obj = next()))
206 void TCollection::AddVector(TObject *va_(obj1), ...)
209 va_start(ap, va_(obj1));
213 while ((obj = va_arg(ap, TObject *)))
221 Bool_t TCollection::AssertClass(TClass *cl)
const
225 Bool_t error = kFALSE;
228 Error(
"AssertClass",
"class == 0");
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());
246 void TCollection::Browse(TBrowser *b)
252 while ((obj = next())) b->Add(obj);
261 TObject *TCollection::Clone(
const char *newname)
const
263 TCollection *new_collection = (TCollection*)TObject::Clone(newname);
264 if (newname && strlen(newname)) new_collection->SetName(newname);
265 return new_collection;
273 Int_t TCollection::Compare(
const TObject *obj)
const
275 if (
this == obj)
return 0;
276 return fName.CompareTo(obj->GetName());
282 void TCollection::Draw(Option_t *option)
287 while ((
object = next())) {
288 object->Draw(option);
295 void TCollection::Dump()
const
300 while ((
object = next())) {
310 TObject *TCollection::FindObject(
const char *name)
const
315 while ((obj = next()))
316 if (!strcmp(name, obj->GetName()))
return obj;
323 TObject *TCollection::operator()(
const char *name)
const
325 return FindObject(name);
335 TObject *TCollection::FindObject(
const TObject *obj)
const
340 while ((ob = next()))
341 if (ob->IsEqual(obj))
return ob;
349 const char *TCollection::GetName()
const
351 if (fName.Length() > 0)
return fName.Data();
358 Int_t TCollection::GrowBy(Int_t delta)
const
361 Error(
"GrowBy",
"delta < 0");
364 return Capacity() + TMath::Range(2, kMaxInt - Capacity(), delta);
370 Bool_t TCollection::IsArgNull(
const char *where,
const TObject *obj)
const
372 return obj ? kFALSE : (Error(where,
"argument is a null pointer"), kTRUE);
380 void TCollection::ls(Option_t *option)
const
382 TROOT::IndentLevel();
383 std::cout <<
"OBJ: " << IsA()->GetName() <<
"\t" << GetName() <<
"\t" << GetTitle() <<
" : "
384 << Int_t(TestBit(kCanDelete)) << std::endl;
386 TRegexp re(option,kTRUE);
390 if (option) star = (
char*)strchr(option,
'*');
392 TROOT::IncreaseDirLevel();
393 while ((
object = next())) {
395 TString s =
object->GetName();
396 if (s != option && s.Index(re) == kNPOS)
continue;
400 TROOT::DecreaseDirLevel();
405 Bool_t TCollection::Notify()
407 Bool_t success =
true;
408 for (
auto obj : *
this) success &= obj->Notify();
415 void TCollection::Paint(Option_t *option)
417 this->R__FOR_EACH(TObject,Paint)(option);
423 void TCollection::PrintCollectionHeader(Option_t*)
const
425 TROOT::IndentLevel();
426 printf(
"Collection name='%s', class='%s', size=%d\n",
427 GetName(), ClassName(), GetSize());
435 const char* TCollection::GetCollectionEntryName(TObject* entry)
const
437 return entry->GetName();
443 void TCollection::PrintCollectionEntry(TObject* entry, Option_t* option, Int_t recurse)
const
445 TCollection* coll =
dynamic_cast<TCollection*
>(entry);
447 coll->Print(option, recurse);
449 TROOT::IndentLevel();
450 entry->Print(option);
474 void TCollection::Print(Option_t *option)
const
488 void TCollection::Print(Option_t *option, Int_t recurse)
const
490 PrintCollectionHeader(option);
497 TROOT::IncreaseDirLevel();
498 while ((
object = next())) {
499 PrintCollectionEntry(
object, option, recurse - 1);
501 TROOT::DecreaseDirLevel();
515 void TCollection::Print(Option_t *option,
const char* wildcard, Int_t recurse)
const
517 PrintCollectionHeader(option);
521 if (!wildcard) wildcard =
"";
522 TRegexp re(wildcard, kTRUE);
523 Int_t nch = strlen(wildcard);
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);
534 TROOT::DecreaseDirLevel();
548 void TCollection::Print(Option_t *option, TPRegexp& regexp, Int_t recurse)
const
550 PrintCollectionHeader(option);
557 TROOT::IncreaseDirLevel();
558 while ((
object = next())) {
559 TString s = GetCollectionEntryName(
object);
560 if (regexp.MatchB(s)) {
561 PrintCollectionEntry(
object, option, recurse - 1);
564 TROOT::DecreaseDirLevel();
572 void TCollection::RecursiveRemove(TObject *obj)
584 while ((
object = next())) {
585 if (object->TestBit(kNotDeleted)) object->RecursiveRemove(obj);
592 void TCollection::RemoveAll(TCollection *col)
597 while ((obj = next()))
604 void TCollection::Streamer(TBuffer &b)
611 Version_t v = b.ReadVersion(&R__s, &R__c);
613 TObject::Streamer(b);
617 for (Int_t i = 0; i < nobjects; i++) {
621 b.CheckByteCount(R__s, R__c,TCollection::IsA());
623 R__c = b.WriteVersion(TCollection::IsA(), kTRUE);
624 TObject::Streamer(b);
626 nobjects = GetSize();
631 while ((obj = next())) {
634 b.SetByteCount(R__c, kTRUE);
646 Int_t TCollection::Write(
const char *name, Int_t option, Int_t bsize)
const
648 if ((option & kSingleKey)) {
649 return TObject::Write(name, option, bsize);
651 option &= ~kSingleKey;
655 while ((obj = next())) {
656 nbytes += obj->Write(name, option, bsize);
670 Int_t TCollection::Write(
const char *name, Int_t option, Int_t bsize)
672 return ((
const TCollection*)
this)->Write(name,option,bsize);
678 TCollection *TCollection::GetCurrentCollection()
680 return fgCurrentCollection;
686 void TCollection::SetCurrentCollection()
688 fgCurrentCollection =
this;
694 void TCollection::StartGarbageCollection()
696 R__LOCKGUARD2(gCollectionMutex);
697 if (!fgGarbageCollection) {
698 fgGarbageCollection =
new TObjectTable;
699 fgEmptyingGarbage = kFALSE;
708 void TCollection::EmptyGarbageCollection()
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);
723 void TCollection::GarbageCollect(TObject *obj)
726 R__LOCKGUARD2(gCollectionMutex);
727 if (fgGarbageCollection) {
728 if (!fgEmptyingGarbage) {
729 fgGarbageCollection->Add(obj);
744 void TCollection::SetOwner(Bool_t enable)
759 bool TCollection::UseRWLock()
761 bool prev = TestBit(TCollection::kUseRWLock);
762 SetBit(TCollection::kUseRWLock);
770 TIter::TIter(
const TIter &iter)
772 if (iter.fIterator) {
773 fIterator = iter.GetCollection()->MakeIterator();
774 fIterator->operator=(*iter.fIterator);
783 TIter &TIter::operator=(
const TIter &rhs)
788 fIterator = rhs.GetCollection()->MakeIterator();
789 fIterator->operator=(*rhs.fIterator);
798 TIter &TIter::Begin()
810 return TIter(static_cast<TIterator*>(
nullptr));
816 const TCollection &ROOT::Internal::EmptyCollection()
818 static TObjArray sEmpty;
825 bool ROOT::Internal::ContaineeInheritsFrom(TClass *cl, TClass *base)
827 return cl->InheritsFrom(base);