136 ClassImp(TClonesArray);
140 using Updater_t = void (*)(Int_t nobjects, TObject **from, TObject **to);
141 Updater_t gClonesArrayTF1Updater =
nullptr;
142 Updater_t gClonesArrayTFormulaUpdater =
nullptr;
144 bool R__SetClonesArrayTF1Updater(Updater_t func) {
145 gClonesArrayTF1Updater = func;
149 bool R__SetClonesArrayTFormulaUpdater(Updater_t func) {
150 gClonesArrayTFormulaUpdater = func;
155 static inline void R__ReleaseMemory(TClass *cl, TObject *obj)
157 if (obj && obj->TestBit(TObject::kNotDeleted)) {
164 if (TObject::GetObjectStat() && gObjectTable) {
165 gObjectTable->RemoveQuietly(obj);
167 ::operator
delete(obj);
175 TClonesArray::TClonesArray() : TObjArray()
191 TClonesArray::TClonesArray(
const char *classname, Int_t s, Bool_t) : TObjArray(s)
194 SetClass(classname,s);
207 TClonesArray::TClonesArray(
const TClass *cl, Int_t s, Bool_t) : TObjArray(s)
216 TClonesArray::TClonesArray(
const TClonesArray& tc): TObjArray(tc)
218 fKeep =
new TObjArray(tc.fSize);
221 BypassStreamer(kTRUE);
223 for (Int_t i = 0; i < fSize; i++) {
224 if (tc.fCont[i]) fCont[i] = tc.fCont[i]->Clone();
225 fKeep->fCont[i] = fCont[i];
232 TClonesArray& TClonesArray::operator=(
const TClonesArray& tc)
234 if (
this == &tc)
return *
this;
236 if (fClass != tc.fClass) {
237 Error(
"operator=",
"cannot copy TClonesArray's when classes are different");
241 if (tc.fSize > fSize)
242 Expand(TMath::Max(tc.fSize, GrowBy(fSize)));
246 for (i = 0; i < fSize; i++)
247 if (fKeep->fCont[i]) {
248 R__ReleaseMemory(fClass,fKeep->fCont[i]);
249 fKeep->fCont[i] =
nullptr;
253 BypassStreamer(kTRUE);
255 for (i = 0; i < tc.fSize; i++) {
256 if (tc.fCont[i]) fKeep->fCont[i] = tc.fCont[i]->Clone();
257 fCont[i] = fKeep->fCont[i];
268 TClonesArray::~TClonesArray()
271 for (Int_t i = 0; i < fKeep->fSize; i++) {
272 R__ReleaseMemory(fClass,fKeep->fCont[i]);
273 fKeep->fCont[i] =
nullptr;
308 void TClonesArray::BypassStreamer(Bool_t bypass)
311 SetBit(kBypassStreamer);
313 ResetBit(kBypassStreamer);
319 void TClonesArray::Compress()
323 TObject **tmp =
new TObject* [fSize];
325 for (Int_t i = 0; i < fSize; i++) {
328 fKeep->fCont[j] = fKeep->fCont[i];
331 tmp[je] = fKeep->fCont[i];
339 for ( ; j < fSize; j++) {
341 fKeep->fCont[j] = tmp[jf];
364 TObject *TClonesArray::ConstructedAt(Int_t idx)
366 TObject *obj = (*this)[idx];
367 if ( obj && obj->TestBit(TObject::kNotDeleted) ) {
370 return (fClass) ?
static_cast<TObject*
>(fClass->New(obj)) : 0;
386 TObject *TClonesArray::ConstructedAt(Int_t idx, Option_t *clear_options)
388 TObject *obj = (*this)[idx];
389 if ( obj && obj->TestBit(TObject::kNotDeleted) ) {
390 obj->Clear(clear_options);
393 return (fClass) ?
static_cast<TObject*
>(fClass->New(obj)) : 0;
407 void TClonesArray::Clear(Option_t *option)
409 if (option && option[0] ==
'C') {
410 const char *cplus = strstr(option,
"+");
416 Int_t n = GetEntriesFast();
417 for (Int_t i = 0; i < n; i++) {
418 TObject *obj = UncheckedAt(i);
421 obj->ResetBit( kHasUUID );
422 obj->ResetBit( kIsReferenced );
423 obj->SetUniqueID( 0 );
439 void TClonesArray::Delete(Option_t *)
441 if ( fClass->TestBit(TClass::kIsEmulation) ) {
444 for (Int_t i = 0; i < fSize; i++) {
445 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
446 fClass->Destructor(fCont[i],kTRUE);
450 for (Int_t i = 0; i < fSize; i++) {
451 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
452 fCont[i]->~TObject();
466 void TClonesArray::Expand(Int_t newSize)
469 Error (
"Expand",
"newSize must be positive (%d)", newSize);
473 Error(
"ExpandCreate",
"Not initialized properly, fKeep is still a nullptr");
476 if (newSize == fSize)
478 if (newSize < fSize) {
481 for (
int i = newSize; i < fSize; i++)
482 if (fKeep->fCont[i]) {
483 R__ReleaseMemory(fClass,fKeep->fCont[i]);
484 fKeep->fCont[i] =
nullptr;
488 TObjArray::Expand(newSize);
489 fKeep->Expand(newSize);
500 void TClonesArray::ExpandCreate(Int_t n)
503 Error(
"ExpandCreate",
"n must be positive (%d)", n);
507 Error(
"ExpandCreate",
"Not initialized properly, fKeep is still a nullptr");
511 Expand(TMath::Max(n, GrowBy(fSize)));
514 for (i = 0; i < n; i++) {
515 if (!fKeep->fCont[i]) {
516 fKeep->fCont[i] = (TObject*)fClass->New();
517 }
else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
519 fClass->New(fKeep->fCont[i]);
521 fCont[i] = fKeep->fCont[i];
524 for (i = n; i < fSize; i++)
525 if (fKeep->fCont[i]) {
526 R__ReleaseMemory(fClass,fKeep->fCont[i]);
527 fKeep->fCont[i] =
nullptr;
544 void TClonesArray::ExpandCreateFast(Int_t n)
546 Int_t oldSize = fKeep->GetSize();
548 Expand(TMath::Max(n, GrowBy(fSize)));
551 for (i = 0; i < n; i++) {
552 if (i >= oldSize || !fKeep->fCont[i]) {
553 fKeep->fCont[i] = (TObject*)fClass->New();
554 }
else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
556 fClass->New(fKeep->fCont[i]);
558 fCont[i] = fKeep->fCont[i];
561 memset(fCont + n, 0, (fLast - n + 1) *
sizeof(TObject*));
570 TObject *TClonesArray::RemoveAt(Int_t idx)
572 if (!BoundsOk(
"RemoveAt", idx))
return 0;
574 int i = idx-fLowerBound;
576 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
577 fCont[i]->~TObject();
584 do { fLast--; }
while (fLast >= 0 && fCont[fLast] == 0);
594 TObject *TClonesArray::Remove(TObject *obj)
598 Int_t i = IndexOf(obj) - fLowerBound;
600 if (i == -1)
return 0;
602 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
603 fCont[i]->~TObject();
609 do { fLast--; }
while (fLast >= 0 && fCont[fLast] == 0);
617 void TClonesArray::RemoveRange(Int_t idx1, Int_t idx2)
619 if (!BoundsOk(
"RemoveRange", idx1))
return;
620 if (!BoundsOk(
"RemoveRange", idx2))
return;
625 Bool_t change = kFALSE;
626 for (TObject **obj=fCont+idx1; obj<=fCont+idx2; obj++) {
628 if ((*obj)->TestBit(kNotDeleted)) {
636 if (change) Changed();
637 if (idx1 < fLast || fLast > idx2)
return;
638 do { fLast--; }
while (fLast >= 0 && fCont[fLast] == 0);
651 void TClonesArray::SetClass(
const TClass *cl, Int_t s)
654 Error(
"SetClass",
"TClonesArray already initialized with another class");
657 fClass = (TClass*)cl;
660 Error(
"SetClass",
"called with a null pointer");
663 const char *classname = fClass->GetName();
664 if (!fClass->IsTObject()) {
666 Error(
"SetClass",
"%s does not inherit from TObject", classname);
669 if (fClass->GetBaseClassOffset(TObject::Class())!=0) {
671 Error(
"SetClass",
"%s must inherit from TObject as the left most base class.", classname);
674 Int_t nch = strlen(classname)+2;
675 char *name =
new char[nch];
676 snprintf(name,nch,
"%ss", classname);
680 fKeep =
new TObjArray(s);
682 BypassStreamer(kTRUE);
688 void TClonesArray::SetClass(
const char *classname, Int_t s)
690 SetClass(TClass::GetClass(classname),s);
699 void TClonesArray::SetOwner(Bool_t )
708 void TClonesArray::Sort(Int_t upto)
710 Int_t nentries = GetAbsLast()+1;
711 if (nentries <= 0 || fSorted)
return;
712 for (Int_t i = 0; i < fSize; i++)
714 if (!fCont[i]->IsSortable()) {
715 Error(
"Sort",
"objects in array are not sortable");
720 QSort(fCont, fKeep->fCont, 0, TMath::Min(nentries, upto-fLowerBound));
731 void TClonesArray::Streamer(TBuffer &b)
742 Version_t v = b.ReadVersion(&R__s, &R__c);
744 const Int_t kOldBypassStreamer = BIT(14);
745 if (TestBit(kOldBypassStreamer)) BypassStreamer();
748 TObject::Streamer(b);
754 Ssiz_t pos = s.Index(
";");
757 s = s(pos+1, s.Length()-pos-1);
760 TClass *cl = TClass::GetClass(classv);
762 Error(
"Streamer",
"expecting class %s but it was not found by TClass::GetClass\n",
764 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
770 nobjects = -nobjects;
775 fKeep =
new TObjArray(fSize);
778 }
else if (cl != fClass && classv == fClass->GetName()) {
790 if (fKeep->GetSize() < nobjects)
794 Int_t oldLast = fLast;
798 if (CanBypassStreamer() && !b.TestBit(TBuffer::kCannotHandleMemberWiseStreaming)) {
799 for (Int_t i = 0; i < nobjects; i++) {
800 if (!fKeep->fCont[i]) {
801 fKeep->fCont[i] = (TObject*)fClass->New();
802 }
else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
804 fClass->New(fKeep->fCont[i]);
807 fCont[i] = fKeep->fCont[i];
809 if (clv < 8 && classv ==
"TF1") {
812 TClonesArray temp(
"ROOT::v5::TF1Data");
813 temp.ExpandCreate(nobjects);
814 b.ReadClones(&temp, nobjects, clv);
816 if (gClonesArrayTF1Updater)
817 gClonesArrayTF1Updater(nobjects, temp.GetObjectRef(
nullptr), this->GetObjectRef(
nullptr));
818 }
else if (clv <= 8 && clv > 3 && clv != 6 && classv ==
"TFormula") {
821 TClonesArray temp(
"ROOT::v5::TFormula");
822 temp.ExpandCreate(nobjects);
823 b.ReadClones(&temp, nobjects, clv);
825 if (gClonesArrayTFormulaUpdater)
826 gClonesArrayTFormulaUpdater(nobjects, temp.GetObjectRef(
nullptr), this->GetObjectRef(
nullptr));
829 b.ReadClones(
this, nobjects, clv);
832 for (Int_t i = 0; i < nobjects; i++) {
835 if (!fKeep->fCont[i])
836 fKeep->fCont[i] = (TObject*)fClass->New();
837 else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
839 fClass->New(fKeep->fCont[i]);
842 fCont[i] = fKeep->fCont[i];
843 b.StreamObject(fKeep->fCont[i]);
847 for (Int_t i = TMath::Max(nobjects,0); i < oldLast+1; ++i) fCont[i] = 0;
849 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
855 b.ForceWriteInfoClones(
this);
862 Bool_t bypass = kFALSE;
863 if (b.TestBit(TBuffer::kCannotHandleMemberWiseStreaming)) {
864 bypass = CanBypassStreamer();
865 BypassStreamer(kFALSE);
868 R__c = b.WriteVersion(TClonesArray::IsA(), kTRUE);
869 TObject::Streamer(b);
871 s.Form(
"%s;%d", fClass->GetName(), fClass->GetClassVersion());
873 nobjects = GetEntriesFast();
876 if (CanBypassStreamer()) {
877 b.WriteClones(
this,nobjects);
879 for (Int_t i = 0; i < nobjects; i++) {
886 b.StreamObject(fCont[i]);
890 b.SetByteCount(R__c, kTRUE);
906 TObject *&TClonesArray::operator[](Int_t idx)
909 Error(
"operator[]",
"out of bounds at %d in %lx", idx, (Long_t)
this);
913 Error(
"operator[]",
"invalid class specified in TClonesArray ctor");
917 Expand(TMath::Max(idx+1, GrowBy(fSize)));
919 if (!fKeep->fCont[idx]) {
920 fKeep->fCont[idx] = (TObject*) TStorage::ObjectAlloc(fClass->Size());
927 fKeep->fCont[idx]->fBits &= ~kNotDeleted;
929 fCont[idx] = fKeep->fCont[idx];
931 fLast = TMath::Max(idx, GetAbsLast());
940 TObject *TClonesArray::operator[](Int_t idx)
const
942 if (idx < 0 || idx >= fSize) {
943 Error(
"operator[]",
"out of bounds at %d in %lx", idx, (Long_t)
this);
954 TObject *TClonesArray::New(Int_t idx)
957 Error(
"New",
"out of bounds at %d in %lx", idx, (Long_t)
this);
961 Error(
"New",
"invalid class specified in TClonesArray ctor");
965 return (TObject *)fClass->New(
operator[](idx));
978 void TClonesArray::AbsorbObjects(TClonesArray *tc)
981 if (tc == 0 || tc ==
this || tc->GetEntriesFast() == 0)
return;
982 AbsorbObjects(tc, 0, tc->GetEntriesFast() - 1);
991 void TClonesArray::AbsorbObjects(TClonesArray *tc, Int_t idx1, Int_t idx2)
994 if (tc == 0 || tc ==
this || tc->GetEntriesFast() == 0)
return;
995 if (fClass != tc->fClass) {
996 Error(
"AbsorbObjects",
"cannot absorb objects when classes are different");
1001 Error(
"AbsorbObjects",
"range is not valid: idx1>idx2");
1004 if (idx2 >= tc->GetEntriesFast()) {
1005 Error(
"AbsorbObjects",
"range is not valid: idx2 out of bounds");
1010 Bool_t wasSorted = IsSorted() && tc->IsSorted() &&
1011 (Last() == 0 || Last()->Compare(tc->First()) == -1);
1014 Int_t oldSize = GetEntriesFast();
1015 Int_t newSize = oldSize + (idx2-idx1+1);
1020 for (Int_t i = idx1; i <= idx2; i++) {
1021 Int_t newindex = oldSize+i -idx1;
1022 fCont[newindex] = tc->fCont[i];
1023 R__ReleaseMemory(fClass,fKeep->fCont[newindex]);
1024 (*fKeep)[newindex] = (*(tc->fKeep))[i];
1026 (*(tc->fKeep))[i] = 0;
1030 for (Int_t i = idx2+1; i < tc->GetEntriesFast(); i++) {
1031 tc->fCont[i-(idx2-idx1+1)] = tc->fCont[i];
1032 (*(tc->fKeep))[i-(idx2-idx1+1)] = (*(tc->fKeep))[i];
1034 (*(tc->fKeep))[i] = 0;
1036 tc->fLast = tc->GetEntriesFast() - 2 - (idx2 - idx1);
1047 void TClonesArray::MultiSort(Int_t nTCs, TClonesArray** tcs, Int_t upto)
1049 Int_t nentries = GetAbsLast()+1;
1050 if (nentries <= 1 || fSorted)
return;
1051 Bool_t sortedCheck = kTRUE;
1052 for (Int_t i = 0; i < fSize; i++) {
1054 if (!fCont[i]->IsSortable()) {
1055 Error(
"MultiSort",
"objects in array are not sortable");
1059 if (sortedCheck && i > 1) {
1060 if (ObjCompare(fCont[i], fCont[i-1]) < 0) sortedCheck = kFALSE;
1068 for (
int i = 0; i < nTCs; i++) {
1069 if (tcs[i] ==
this) {
1070 Error(
"MultiSort",
"tcs[%d] = \"this\"", i);
1073 if (tcs[i]->GetEntriesFast() != GetEntriesFast()) {
1074 Error(
"MultiSort",
"tcs[%d] has length %d != length of this (%d)",
1075 i, tcs[i]->GetEntriesFast(), this->GetEntriesFast());
1081 TObject*** b =
new TObject**[nBs];
1082 for (
int i = 0; i < nTCs; i++) {
1083 b[2*i] = tcs[i]->fCont;
1084 b[2*i+1] = tcs[i]->fKeep->fCont;
1086 b[nBs-1] = fKeep->fCont;
1087 QSort(fCont, nBs, b, 0, TMath::Min(nentries, upto-fLowerBound));