ATLAS Offline Software
Loading...
Searching...
No Matches
TConvertingBranchElement.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
12
13
17#include "TClonesArray.h"
18#include "TStreamerElement.h"
19#include "TFile.h"
20#include "TTree.h"
21#include "TVirtualCollectionProxy.h"
22#include "TVirtualCollectionIterators.h"
23#include "TBranchRef.h"
24#include "TClassEdit.h"
25#include "TBasket.h"
26#include "TError.h"
27#include "TStreamerInfo.h"
28#include "TBufferFile.h"
29#include "TVirtualArray.h"
30#include "TROOT.h"
31#include "ESTLType.h"
32#include <cassert>
33#include <cstdlib>
34
35
36std::atomic<bool> TConvertingBranchElement::fgDoDel = false;
37
38
39namespace {
40
41
48class TPushPopSafe
49{
50public:
51 TVirtualCollectionProxy* fProxy;
52 TPushPopSafe (TVirtualCollectionProxy* proxy, void* objectstart);
53 inline ~TPushPopSafe();
54};
55
56
67inline TPushPopSafe::TPushPopSafe (TVirtualCollectionProxy* proxy,
68 void* objectstart)
69 : fProxy (proxy)
70{
71 if (fProxy)
72 fProxy->PushProxy (objectstart);
73}
74
75
82inline TPushPopSafe::~TPushPopSafe()
83{
84 if (fProxy)
85 fProxy->PopProxy();
86}
87
88
97void RemovePrefix(TString& str, const char* prefix)
98{
99 if (str.Length() && prefix && strlen(prefix)) {
100 if (!str.Index(prefix)) {
101 str.Remove(0, strlen(prefix));
102 }
103 }
104}
105
106
114std::string BasenameOfBranch (const std::string& fullname)
115{
116 std::string s = fullname;
117 size_t pos = s.rfind('.');
118 if (pos != std::string::npos) {
119 s = s.substr(pos+1);
120 }
121 while ((pos = s.rfind('[')) != std::string::npos) {
122 s.resize(pos);
123 }
124 return s;
125}
126
127
137TStreamerInfo* GetStreamerInfoFromFile (const TClass* cl, const TBranch* br)
138{
139 // Find the file holding this branch.
140 // (Can't rely on fInfo having being set up yet.)
141 TDirectory* dir = br->GetDirectory();
142 if (!dir) return nullptr;
143 TFile* file = dir->GetFile();
144 if (!file) return nullptr;
145 if (file->GetSeekInfo() == 0) return nullptr;
146
147 // Find the streamerinfo for this class.
148 const TList* silist = file->GetStreamerInfoCache();
149 TListIter li (silist);
150 TStreamerInfo* info;
151 while ((info = dynamic_cast<TStreamerInfo*> (li.Next())) != nullptr) {
152 if (strcmp (info->GetName(), cl->GetName()) == 0)
153 break;
154 }
155
156 return info;
157}
158
159
168bool DoesClassNeedConv (const TClass* cl, const TBranch* br)
169{
170 if (!cl) return false;
171 TStreamerInfo* info = GetStreamerInfoFromFile (cl, br);
172 if (!info) return false;
173
174 // Does this class have a conversion?
175 if (TConverterRegistry::Instance()->GetConverter (cl->GetName(),
176 info->GetCheckSum()))
177 return true;
178
179 // Do any contained classes have a conversion?
180 TObjArray* elems = info->GetElements();
181 int ndata = elems->GetEntriesFast();
182 for (int i = 0; i < ndata; ++i) {
183 TStreamerElement* elt =
184 reinterpret_cast<TStreamerElement*> (elems->At (i));
185 TClass* bcl = elt->GetClass();
186 // Note: we can have bcl==cl for a STL container.
187 // For example, the TStreamerInfo for vector<int> has a single
188 // TStreamerSTL element with a class that points
189 // back to vector<int>.
190 if (bcl && bcl != cl && DoesClassNeedConv (bcl, br))
191 return true;
192 }
193 return false;
194}
195
196
207bool BaseHasField1 (TStreamerBase* elt,
208 const TString& name,
209 const TBranch* br)
210{
211 // Find the TStreamerInfo for the class we're testing.
212 TClass* cl = elt->GetClassPointer();
213 if (!cl) return false;
214 TStreamerInfo* info = GetStreamerInfoFromFile (cl, br);
215 if (!info) return false;
216
217 // Go through each element looking for the name.
218 // Recursively check base classes.
219 TObjArray* elems = info->GetElements();
220 size_t ndata = elems->GetEntriesFast();
221 for (size_t ielt = 0; ielt < ndata; ielt++) {
222 TStreamerElement* selt =
223 reinterpret_cast<TStreamerElement*> (elems->At(ielt));
224 if (TStreamerBase* belt = dynamic_cast<TStreamerBase*> (selt)) {
225 if (BaseHasField1 (belt, name, br))
226 return true;
227 }
228 else {
229 if (name == selt->GetName())
230 return true;
231 }
232 }
233 return false;
234}
235
236
249bool BaseHasField (TStreamerBase* elt,
250 TString bname,
251 const TString& namedot,
252 const TBranch* br)
253{
254 if (!elt) return false;
255 RemovePrefix (bname, namedot.Data());
256 Ssiz_t i = bname.Index ("[");
257 if (i != kNPOS)
258 bname.Remove (i);
259 i = bname.Index (".");
260 if (i != kNPOS)
261 bname.Remove (i);
262 return BaseHasField1 (elt, bname, br);
263}
264
265
266 struct R__PushCache {
267 TBufferFile &fBuffer;
268 TVirtualArray *fOnfileObject;
269
270 R__PushCache(TBufferFile &b, TVirtualArray *in, UInt_t size) : fBuffer(b), fOnfileObject(in) {
271 if (fOnfileObject) {
272 fOnfileObject->SetSize(size);
273 fBuffer.PushDataCache( fOnfileObject );
274 }
275 }
276 ~R__PushCache() {
277 if (fOnfileObject) fBuffer.PopDataCache();
278 }
279 };
280
281
282} // anonymous namespace
283
284
289: fConv(nullptr)
290, fConvClass(nullptr)
291, fConvObject(nullptr)
292, fConvOrigBranches(nullptr)
293, fConvOrigType(-1)
294, fConvContainerFlag(false)
295, fConvDontReset(false)
296{
297}
298
299
306{
307 // If we made a temporary object instance for conversions, delete it.
308 if (fConv && fConvObject)
309 fConv->DeletePersObj (fConvObject);
310
311 // If we contain dummy branches, delete them here.
312 // In that case, we should also delete the saved original branch list.
313 if (fConvOrigBranches) {
314 Int_t nbranches = fBranches.GetEntriesFast();
315 for (Int_t i = 0; i < nbranches; i++) {
316 if (fBranches[i]->TestBit (kIsDummy))
317 delete fBranches[i];
318 }
319 fBranches = *fConvOrigBranches;
320 delete fConvOrigBranches;
321 }
322
323 // If we're a dummy ourselves, we should delete the branch list.
324 if (TestBit (kIsDummy))
325 fBranches.Clear();
326
327 // Try to delete the object, if requested.
328 if (fgDoDel)
330}
331
332
339
340
351{
352 if (p)
353 return new (p) TConvertingBranchElement;
354 return new TConvertingBranchElement;
355}
356
357
382{
383 // Can't do anything if we can't find the @c TStreamerInfo.
384 if (!fInfo) return;
385
386 // The class of this branch's element.
387 TClass* topclass = nullptr;
388 if (fID < 0)
389 topclass = gROOT->GetClass (GetClassName());
390 else {
391 std::string s = BasenameOfBranch (GetName());
392 int offset = 0;
393 TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
394 if (elt)
395 topclass = elt->GetClass();
396 }
397 if (!topclass) return;
398
399 // Here's the plan.
400 // We start by adding all branches to the @c branches list.
401 // Then we walk through the members of this class (using the
402 // @c TStreamerInfo).
403 // If this member is contained in the branch list, then we
404 // remove it from @c branches and add it to @c noconv_branches
405 // (it wasn't elided).
406 // If it's not in the branch list, then it was elided.
407 // We look then to see if the corresponding class (or anything
408 // it contains) requires a conversion. If so, then we build
409 // a dummy node for it, and add the dummy to @c conv_dummies.
410 // We then look through @c branches, find any that actually
411 // belong to the new dummy node, remove them from @c branches,
412 // and add them to the dummy.
413 // If no conversion is needed, then we don't need to do anything
414 // at this point.
415 //
416 // When we're done scanning all the members of the class, we take
417 // anything remaining in @c branches and move to @c noconv_branches
418 // (these correspond to branches with elided nodes, but with
419 // no conversions required.) Then, if we made any dummy nodes,
420 // then we replace our branch list with the concatenation of the
421 // dummy list and the @c noconv_branches list (saving the original
422 // branch list so that we can restore it later, if needed).
423 std::vector<TBranch*> conv_dummies;
424 std::vector<TBranch*> noconv_branches;
425 std::vector<TBranch*> branches;
426
427 // To start with, add all our child branches to @c branches.
428 Int_t nbranches = fBranches.GetEntriesFast();
429 branches.reserve (nbranches);
430 for (Int_t i=0; i < nbranches; i++) {
431 TBranch* b = dynamic_cast<TBranchElement*> (fBranches[i]);
432 if (b)
433 branches.push_back (b);
434 }
435
436 // Get the @c TStreamerInfo for this class.
437 // If this class is a container, then we actually want
438 // to get the @c TStreamerInfo for the contained class.
439 TStreamerInfo* info = GetStreamerInfoFromFile (topclass, this);
440 if (!info && fType == 4) {
441 TVirtualCollectionProxy* proxy = topclass->GetCollectionProxy();
442 if (!proxy) return;
443 topclass = proxy->GetValueClass();
444 if (!topclass) return;
445 info = GetStreamerInfoFromFile (topclass, this);
446 }
447 else if (fType == 3) {
448 topclass = gROOT->GetClass (fClonesName);
449 if (!topclass) return;
450 info = GetStreamerInfoFromFile (topclass, this);
451 }
452 if (!info) return;
453
454 // Now walk through all elements in the @c TStreamerInfo.
455 TObjArray* elems = info->GetElements();
456 size_t ndata = elems->GetEntriesFast();
457 for (size_t ielt = 0; ielt < ndata; ++ielt) {
458 // The element.
459 TStreamerElement* elt =
460 reinterpret_cast<TStreamerElement*> (elems->At(ielt));
461
462 // See if there's a branch corresponding to this element.
463 // If so, add it to the noconv list.
464 bool found = false;
465 for (unsigned i=0; i < branches.size(); i++) {
466 TBranchElement* b = dynamic_cast<TBranchElement*>(branches[i]);
467
468 // Test branch @b to see if corresponds to the SI element @ elt.
469 if (b && gROOT->GetClass (b->GetClassName()) == topclass) {
470 if (dynamic_cast<TStreamerBase*> (elt) != 0 && b->GetType() == 1) {
471 // For a base class, the test above is sufficient.
472 found = true;
473 }
474 else {
475 // Test the name.
476 std::string s = BasenameOfBranch (b->GetName());
477 if (s == elt->GetName())
478 found = true;
479 }
480
481 if (found) {
482 // We found a branch matching the element.
483 // Move the branch from @c branches to @c noconv_branches,
484 // and exit the loop over branches.
485 noconv_branches.push_back (b);
486 branches.erase (branches.begin()+i);
487 break;
488 }
489 }
490 }
491
492 if (!found) {
493 // We didn't find a branch corresponding to this element.
494 // Maybe this is an elided class.
495 // If this is a class type, then see if it or anything
496 // it contains has a conversion. If so, then build a dummy
497 // node for it.
498 TClass* cl = elt->GetClass();
499 if (cl && DoesClassNeedConv (cl, this)) {
500 // It needs a conversion. Make a dummy node.
501 TClass* clparent = gROOT->GetClass (info->GetName());
503 dum->SetBit (kIsDummy);
504 TString name;
505 if (fID < 0)
506 name = elt->GetName();
507 else {
508 name = GetName();
509 if (fType == 1) {
510 Ssiz_t i = name.Length()-1;
511 while (i >= 0 && name[i] != '.')
512 --i;
513 name.Remove (i+1);
514 }
515 else
516 name += ".";
517 name += elt->GetName();
518 }
519 dum->SetName (name);
520 dum->SetTitle (name);
521 TString namedot = name + ".";
522 dum->SetParentClass (clparent);
523 dum->SetClassName (info->GetName());
524 dum->fCheckSum = info->GetCheckSum();
525 dum->fClassVersion = topclass->GetClassVersion();
526 dum->fID = ielt;
527 dum->fTree = this->fTree;
528 dum->fDirectory = this->fDirectory;
529 dum->fBranchClass = topclass;
530 if (dynamic_cast<TStreamerBase*> (elt) != nullptr) {
531 dum->fType = 1;
532 Ssiz_t i = namedot.Length()-2;
533 while (i >= 0 && namedot[i] != '.')
534 --i;
535 namedot.Remove (i+1);
536 }
537 else
538 dum->fType = 2;
539
540 // Add the dummy node to @c conv_dummies.
541 conv_dummies.push_back (dum);
542
543 // Find all branches that are a part of this class and
544 // move them from @c branches to the dummy node
545 for (unsigned i=0; i < branches.size(); ) {
546 TString bname = branches[i]->GetName();
547 if (bname.Index (namedot) == 0 &&
548 (dum->fType == 2 ||
549 BaseHasField (dynamic_cast<TStreamerBase*>(elt),
550 bname,
551 namedot,
552 this)))
553 {
554 dum->GetListOfBranches()->Add (branches[i]);
556 dynamic_cast<TConvertingBranchElement*> (branches[i]))
557 {
558 be->fParentClass = cl;
559 }
560 branches.erase (branches.begin()+i);
561 }
562 else {
563 ++i;
564 }
565 }
566 }
567 }
568 // End of loop over elements.
569 }
570
571 // Any remaining branches go to @c noconv_branches.
572 for (unsigned int i=0; i < branches.size(); i++)
573 noconv_branches.push_back (branches[i]);
574
575 if (conv_dummies.size() > 0) {
576 // We made some dummies.
577 // Replace our branch list with the concatenation
578 // of the dummy list (@c conv_dummies) and the branches
579 // that don't need special processing (@c noconv_branches --- because
580 // they either did not have an elision or they didn't require
581 // a conversion).
582 fConvOrigBranches = new TObjArray;
583 *fConvOrigBranches = fBranches;
584 fBranches.Clear();
585 for (unsigned int i=0; i < conv_dummies.size(); i++)
586 fBranches.Add (conv_dummies[i]);
587 for (unsigned int i=0; i < noconv_branches.size(); i++)
588 fBranches.Add (noconv_branches[i]);
589 }
590}
591
592
598{
599 // Need @c TStreamerInfo in order to do anything.
600 if (!fInfo) return;
601
602 // Restore any elided tree nodes if there's a conversion.
604
605 // See if this element is a class.
606 const char* classname = 0;
607 int checksum = 0;
608
609 if (fID < 0) {
610 // Special case for top-level branch.
611 classname = GetClassName();
612 checksum = fCheckSum;
613 }
614 else {
615 // Otherwise, we need to look at the streamerinfo element.
616 std::string s = BasenameOfBranch (GetName());
617 int offset = 0;
618 TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
619 if (elt) {
620 TClass* cl = elt->GetClass();
621 if (cl) {
622 classname = cl->GetName();
623 TStreamerInfo* info = GetStreamerInfoFromFile (cl, this);
624 if (info)
625 checksum = info->GetCheckSum();
626 }
627 }
628 }
629
630 if (classname) {
631 // Ok, this branch represents a class.
632 // See if there's a conversion for it.
633 TVirtualConverter* conv =
634 TConverterRegistry::Instance()->GetConverter (classname, checksum);
635
636 // If there's not a conversion and this class is a container,
637 // then we need to see if something in the container needs a conversion.
638 if (!conv && (fType == 4 || fType == 3)) {
639 // Find the contained class.
640 TClass* contclass = gROOT->GetClass (fClonesName.Data());
641 if (contclass) {
642 TStreamerInfo* info = GetStreamerInfoFromFile (contclass, this);
643 if (info) {
644 // Found the contained class with its @c TStreamerInfo.
645 // See if the contained class has a conversion.
646 conv =
647 TConverterRegistry::Instance()->GetConverter (fClonesName.Data(),
648 info->GetCheckSum());
649
650 // If the contained class, or anything it contains, has a conversion,
651 // then we need to deal with conversions when reading this container.
652 if (conv || DoesClassNeedConv (contclass, this)) {
653 fConvContainerFlag = true;
655 }
656 }
657 }
658 }
659
660 if (conv) {
661 TClass* convclass = conv->GetPersClass();
662 if (convclass) {
663 // We have a conversion! Remember the converter and persistent
664 // class, and create the temporary persistent class instance.
665 fConv = conv;
666 fConvClass = convclass;
667 fConvObject = (char*)conv->NewPersObj();
668 }
669 }
670 }
671
672 // Now see if the class containing this element has a conversion.
673 if (fID > -1) {
674 TVirtualConverter* conv =
676 fCheckSum);
677 if (conv) {
678 TClass* convclass = conv->GetPersClass();
679 if (convclass) {
680 // The class containing this class has a conversion.
681 // Change the @c TStreamerInfo to correspond to the
682 // appropriate persistent class; also change the parent class
683 // pointer.
684 Bool_t optim = TStreamerInfo::CanOptimize();
685 TStreamerInfo::Optimize(kFALSE);
686 TStreamerInfo* info =
687 dynamic_cast<TStreamerInfo*> (convclass->GetStreamerInfo (0));
688 if (info)
689 fInfo = info;
690 TStreamerInfo::Optimize(optim);
691 fParentClass = convclass;
692 }
693 }
694 }
695}
696
697
708{
709 // Do the standard stuff.
710 TBranchElement::InitInfo();
711
712 // Check for a conversion.
713 if (fInfo) {
714 const_cast<TConvertingBranchElement*>(this)->CheckForConversion();
715
716 // Re-find the fID.
717 const_cast<TConvertingBranchElement*>(this)->fInit = kFALSE;
718 TBranchElement::InitInfo();
719 }
720
721 // Change ReadLeaves implementation if needed.
722 // The base class implementation works here except for the case
723 // of an STL associative container. We need to change the code
724 // for that to notice @c fConvDontReset and to use @c ReadSubBranches.
725 if (fType == 4)
727 else if (fType == 2 && (fConvOrigType == 41 || fConvOrigType == 31))
729}
730
731
740{
741 Int_t nbranches = fBranches.GetEntriesFast();
742 for (Int_t i=0; i < nbranches; i++) {
744 dynamic_cast<TConvertingBranchElement*> (fBranches[i]);
745 if (b) {
746 if (b->fType == 41 || b->fType == 31) {
747 b->fConvOrigType = b->fType;
748 b->fType = 2;
749 }
750 b->ConvResetType();
751 }
752 }
753}
754
755
844Int_t TConvertingBranchElement::GetEntry(Long64_t entry, Int_t getall)
845{
846 // The first part of this just copies the base class @c GetEntry.
847 // Differences from the base class implementation will be pointed out below.
848
849 // Remember which entry we are reading.
850 fReadEntry = entry;
851
852 // If our tree has a branch ref, make it remember the entry and
853 // this branch. This allows a TRef::GetObject() call done during
854 // the following I/O operation, for example in a custom streamer,
855 // to search for the referenced object in the proper element of the
856 // proper branch.
857 TBranchRef* bref = fTree->GetBranchRef();
858 if (bref) {
859 bref->SetParent(this, fBranchID);
860 bref->SetRequestedEntry(entry);
861 }
862
863 Int_t nbytes = 0;
864
865 SetupAddresses();
866
867 Int_t nbranches = fBranches.GetEntriesFast();
868 if (nbranches) {
869 // -- Branch has daughters.
870 // One must always read the branch counter.
871 // In the case when one reads consecutively twice the same entry,
872 // the user may have cleared the TClonesArray between the GetEntry calls.
873 if ((fType == 3) || (fType == 4)) {
874 Int_t nb = TBranch::GetEntry(entry, getall);
875 if (nb < 0) {
876 return nb;
877 }
878 nbytes += nb;
879 }
880
881 // Here's a difference from the @c TBranchElement base class.
882 // First, we need to pick up the current state of the
883 // @c fConvDontReset flag (and clear it in the process).
884 // Instead of looping over branches here, we factor out
885 // that part into @c ReadSubBranches.
886 bool dont_reset = fConvDontReset;
887 fConvDontReset = false;
888 switch(fSTLtype) {
889 case ROOT::kSTLset:
890 case ROOT::kSTLmultiset:
891 case ROOT::kSTLmap:
892 case ROOT::kSTLmultimap:
893 break;
894 default:
895 // Read non-container composite and list/vector.
896 // Associative containers will get entirely read
897 // within the @c GetEntry call above (when it calls @c ReadLeaves).
898 nbytes += ReadSubBranches (entry, getall, dont_reset);
899 break;
900 }
901 }
902 else {
903 // -- Terminal branch.
904 // Difference from base implementation: pick up the dont_reset flag here.
905 bool dont_reset = fConvDontReset;
906 fConvDontReset = false;
907
908 if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
909 Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
910 if (nb < 0) {
911 return nb;
912 }
913 nbytes += nb;
914 }
915 Int_t nb = 0;
916
917 // The base implementation just calls @c TBranch::GetEntry here.
918 // But we need to pay attention to the dont_reset flag.
919 // If it's set, we can't call @c TBranch::GetEntry (because
920 // that would reset the buffer pointer back to the
921 // beginning of the container). Instead, we pick up the
922 // buffer pointer and call @c ReadLeaves `by hand'.
923 if (dont_reset) {
924 TBasket* basket = (TBasket*)GetBasket(GetReadBasket());
925 TBuffer* buffer = basket->GetBufferRef();
926 Int_t bufbegin = buffer->Length();
927
928 // Suppress false positive seen with gcc.
929#if __GNUC__ >= 11 && __GNUC__ <= 14
930# pragma GCC diagnostic push
931# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
932#endif
933 (this->*fReadLeaves) (*buffer);
934#if __GNUC__ >= 11 && __GNUC__ <= 14
935# pragma GCC diagnostic pop
936#endif
937
938 nb = buffer->Length() - bufbegin;
939 }
940 else
941 nb = TBranch::GetEntry (entry, getall);
942
943 // Rest is the same as the base implementation.
944 if (nb < 0) {
945 return nb;
946 }
947 nbytes += nb;
948 }
949
950 if (fTree->Debug() > 0) {
951 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
952 Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
953 }
954 }
955 return nbytes;
956}
957
958
964{
965 // -- Read leaves into i/o buffers for this branch.
966 // Case of a collection (fType == 4).
967
968 ValidateAddress();
969 if (fObject == 0)
970 {
971 // We have nowhere to copy the data (probably because the data member was
972 // 'dropped' from the current schema) so let's no copy it in a random place.
973 return;
974 }
975
976 // STL container master branch (has only the number of elements).
977 Int_t n;
978 b >> n;
979 if ((n < 0) || (n > fMaximum)) {
980 if (IsMissingCollection()) {
981 n = 0;
982 b.SetBufferOffset(b.Length()-sizeof(n));
983 } else {
984 Error("ReadLeaves", "Incorrect size read for the container in %s\n\tThe size read is %d while the maximum is %d\n\tThe size is reset to 0 for this entry (%lld)", GetName(), n, fMaximum, GetReadEntry());
985 n = 0;
986 }
987 }
988 fNdata = n;
989
990 R__PushCache onfileObject((static_cast<TBufferFile&>(b)),fOnfileObject,n);
991
992 if (!fObject) {
993 return;
994 }
995 // Note: Proxy-helper needs to "embrace" the entire
996 // streaming of this STL container if the container
997 // is a set/multiset/map/multimap (what we do not
998 // know here).
999 // For vector/list/deque Allocate == Resize
1000 // and Commit == noop.
1001 // TODO: Exception safety a la TPushPop
1002 TVirtualCollectionProxy* proxy = GetCollectionProxy();
1003 TVirtualCollectionProxy::TPushPop helper(proxy, fObject);
1004 void* alternate = proxy->Allocate(fNdata, true);
1005 if(fSTLtype != ROOT::kSTLvector && proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers ) {
1006 fPtrIterators->CreateIterators(alternate, proxy);
1007 } else {
1008 fIterators->CreateIterators(alternate, proxy);
1009 }
1010
1011 //Int_t nbranches = fBranches.GetEntriesFast();
1012 switch (fSTLtype) {
1013 case ROOT::kSTLset:
1014 case ROOT::kSTLmultiset:
1015 case ROOT::kSTLmap:
1016 case ROOT::kSTLmultimap:
1017 {
1018 // Change for conversions:
1019 // Use @c ReadSubBranches and obey @c fConvDontReset.
1020 bool dont_reset = fConvDontReset;
1021 fConvDontReset = false;
1022 ReadSubBranches (GetReadEntry(), 1, dont_reset);
1023 }
1024 break;
1025 default:
1026 break;
1027 }
1028 //------------------------------------------------------------------------
1029 // We have split this stuff, so we need to create the the pointers
1030 //-----------------------------------------------------------------------
1031 if( proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers )
1032 {
1033 TClass *elClass = proxy->GetValueClass();
1034
1035 //--------------------------------------------------------------------
1036 // The allocation is done in this strange way because ReadLeaves
1037 // is being called many times by TTreeFormula!!!
1038 //--------------------------------------------------------------------
1039 Int_t i = 0;
1040 if( !fNdata || *(void**)proxy->At( 0 ) != 0 )
1041 i = fNdata;
1042
1043 for( ; i < fNdata; ++i )
1044 {
1045 void **el = (void**)proxy->At( i );
1046 // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
1047 *el = elClass->New();
1048 }
1049 }
1050
1051 proxy->Commit(alternate);
1052}
1053
1054
1056{
1057 // -- Read leaves into i/o buffers for this branch.
1058 // For split-class branch, base class branch, data member branch, or top-level branch.
1059 // which do have a branch count and are not a counter.
1060
1061 assert(fStreamerType != TVirtualStreamerInfo::kCounter);
1062
1063 ValidateAddress();
1064 if (fObject == 0)
1065 {
1066 // We have nowhere to copy the data (probably because the data member was
1067 // 'dropped' from the current schema) so let's no copy it in a random place.
1068 return;
1069 }
1070
1071 R__PushCache onfileObject((static_cast<TBufferFile&>(b)),fOnfileObject,1);
1072 // If not a TClonesArray or STL container master branch
1073 // or sub-branch and branch inherits from tobject,
1074 // then register with the buffer so that pointers are
1075 // handled properly.
1076 if (TestBit(kBranchObject)) {
1077 b.ResetMap();
1078 b.MapObject((TObject*) fObject);
1079 } else if (TestBit(kBranchAny)) {
1080 b.ResetMap();
1081 b.MapObject(fObject, fBranchClass);
1082 }
1083
1084 fNdata = (Int_t) fBranchCount->GetValue(0, 0);
1085 TStreamerInfo *info = GetInfo();
1086 if (!info) {
1087 return;
1088 }
1089 // Since info is not null, fReadActionSequence is not null either.
1090 //b.ReadSequence(*fReadActionSequence, fObject);
1091 // FIXME!
1092 // ReadSequence doesn't work here, since it gets structure offsets
1093 // from TConfiguration, and those haven't been adjusted to take
1094 // into account the use of the temporary conversion objects.
1095 // FIXME!
1096 std::abort();
1097 //doesn't work
1098 //info->ReadBuffer (b, (char**)&fObject, fID);
1099}
1100
1101
1112 Int_t getall,
1113 bool dont_reset)
1114{
1115 Int_t nbytes = 0;
1116 Int_t nbranches = fBranches.GetEntriesFast();
1117
1118 if (fConvContainerFlag) {
1119 if (fNdata > 0) {
1120 // We're reading a container that needs a conversion.
1121 // We're going to invert the loop order so that we read
1122 // a single object at a time,
1123 // Remember the number of entries in the container, but change
1124 // the number we advertise to 1.
1125 UInt_t save_ndata = fNdata;
1126 fNdata = 1;
1127
1128 // Get either the container proxy or the clones array, as appropriate.
1129 TVirtualCollectionProxy* proxy = 0;
1130 TClonesArray* clones = 0;
1131 if (fType == 4)
1132 proxy = GetCollectionProxy();
1133 else if (fType == 3)
1134 clones = (TClonesArray*)fObject;
1135 else
1136 abort();
1137
1138 // If we had a proxy, associate it with the container object.
1139 // This is safe for the case where proxy is null.
1140 TPushPopSafe helper (proxy,fObject);
1141
1142 // For each element, we may have to call @c SetAddress for each
1143 // branch. This is used to avoid doing this repeatedly
1144 // with the same address (as would happen if we're reading into
1145 // the temporary persistent object).
1146 std::vector<char*> last_addrs (nbranches, (char*)0);
1147
1148 // Loop over elements.
1149 for (UInt_t j = 0; j < save_ndata; j++) {
1150 // Find the address of the element we want to initialize.
1151 // How we do this depends on whether we have a @c TClonesArray
1152 // or a proxy.
1153 char* addr = 0;
1154 if (proxy)
1155 addr = (char*)(proxy->At(j));
1156 else {
1157 if (!clones) std::abort();
1158 addr = (char*)((*clones)[j]);
1159 }
1160
1161 // The address of the object we want to read.
1162 // If we have a conversion on the class contained directly
1163 // in the container, then this will be the temporary persistent
1164 // object. Otherwise, it will be the address we found in the
1165 // last line.
1166 char* obj = fConvObject ? fConvObject : addr;
1167
1168 // Loop over branches for a single object.
1169 for (Int_t i = 0; i < nbranches; ++i) {
1170 TBranch* branch = (TBranch*) fBranches[i];
1171
1172 // If this isn't the first element in the container,
1173 // then we'll need to set the dont_reset flag.
1174 if (j > 0) {
1176 dynamic_cast<TConvertingBranchElement*>(branch);
1177 if (be)
1178 be->fConvDontReset = true;
1179 }
1180
1181 // Find the address for this member,
1182 char* this_addr = obj + fBranchOffset[i];
1183
1184 // Call @c SetAddress if it's different from the last one we set.
1185 if (this_addr != last_addrs[i]) {
1186 last_addrs[i] = this_addr;
1187 branch->SetAddress (obj + fBranchOffset[i]);
1188 }
1189
1190 // Read the branch.
1191 Int_t nb = branch->GetEntry(entry, getall);
1192
1193 // Bookkeeping.
1194 if (nb < 0) {
1195 return nb;
1196 }
1197 nbytes += nb;
1198 }
1199
1200 // End of loop over branches.
1201 // We just read one complete object.
1202 // Call the converter, if needed.
1203 if (fConv)
1204 fConv->ConvertVoid (addr, obj);
1205 }
1206
1207 // End of loop over entries. Restore @c fNdata.
1208 fNdata = save_ndata;
1209 }
1210 }
1211 else {
1212 // Non-container case.
1213 // We're reading a single object.
1214 // Loop over branches.
1215 for (Int_t i = 0; i < nbranches; ++i) {
1216 TBranch* branch = (TBranch*) fBranches[i];
1217
1218 // If @c dont_reset is set, we need to propagate it to our children.
1219 if (dont_reset) {
1221 dynamic_cast<TConvertingBranchElement*>(branch);
1222 if (!be) return -1;
1223 be->fConvDontReset = true;
1224 }
1225
1226 // Read the branch.
1227 Int_t nb = branch->GetEntry(entry, getall);
1228
1229 // Bookkeeping.
1230 if (nb < 0) {
1231 return nb;
1232 }
1233 nbytes += nb;
1234 }
1235
1236 // Done reading the object. Call the converter if needed.
1237 if (fConv)
1238 fConv->ConvertVoid (fObject, fConvObject);
1239 }
1240 return nbytes;
1241}
1242
1243
1254void TConvertingBranchElement::Streamer(TBuffer& R__b)
1255{
1256 TObjArray brsave;
1257 Int_t type_save = 0;
1258
1259 if (!R__b.IsReading()) {
1260 if (fConvOrigType == -1)
1261 fConvOrigType = fType;
1262
1263 type_save = fType;
1264 fType = fConvOrigType;
1265 if (fConvOrigBranches) {
1266 brsave = fBranches;
1267 fBranches = *fConvOrigBranches;
1268 }
1269 }
1270
1271 TBranchElement::Streamer (R__b);
1272
1273 if (!R__b.IsReading()) {
1274 fType = type_save;
1275 if (fConvOrigBranches) {
1276 fBranches = brsave;
1277 }
1278 }
1279}
1280
1281
1282
1288{
1289 // previously in InitializeOffsets, after:
1290 // if (fType == 1) {
1291 // pClass = branchElem->GetClassPointer();
1292 // } else {
1293 // pClass = subBranch->GetParentClass();
1294 // }
1295 //
1296 // i had:
1297 //
1298 // if (fConvClass) pClass = fConvClass;
1299 //
1300 // This is a hack so we don't need to modify the base class
1301 // InitializeOffsets.
1302 //
1303 TStreamerElement* branchElem = 0;
1304 TClass* cl_orig = 0;
1305 if (fConvClass && fID > -1) {
1306 TStreamerInfo* si = GetInfo();
1307 branchElem = si->GetElem(fID);
1308 if (branchElem) {
1309 if (branchElem && branchElem->IsBase()) {
1310 cl_orig = branchElem->GetClassPointer();
1311 branchElem->Update (cl_orig, fConvClass);
1312 }
1313 else
1314 branchElem = 0;
1315 }
1316 }
1317
1318 if (fConvClass) {
1319 Int_t nbranches = fBranches.GetEntriesFast();
1320 for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
1322 dynamic_cast<TConvertingBranchElement*> (fBranches[subBranchIdx]);
1323 if (br) {
1324 br->fParentClass = fConvClass;
1325 }
1326 }
1327 }
1328
1329 TBranchElement::InitializeOffsets();
1330
1331 if (branchElem)
1332 branchElem->Update (fConvClass, cl_orig);
1333}
1334
1335
1345{
1346 TBranchElement::SetAddress (add);
1347 if (fConvObject) {
1348 Int_t nbranches = fBranches.GetEntriesFast();
1349 for (Int_t i = 0; i < nbranches; ++i) {
1350 TBranch* abranch = (TBranch*) fBranches[i];
1351 abranch->SetAddress(fConvObject + fBranchOffset[i]);
1352 }
1353 }
1354}
1355
1356
1357
1362{
1364}
1365
1366
1375{
1376 char* object = fObject;
1377 char* address = fAddress;
1378 TBranchElement::ResetAddress();
1379
1380 if (fgDoDel) {
1381 fObject = object;
1382 fAddress = address;
1383
1384 // This is copied from the disabled code of TBranchElement::ReleaseObject.
1385 if (fID < 0) {
1386 // -- We are a top-level branch.
1387 if (fAddress && (*((char**) fAddress) != fObject)) {
1388 // The semantics of fAddress and fObject are violated.
1389 // Assume the user changed the pointer on us.
1390 if (TestBit(kDeleteObject)) {
1391 Warning("ReleaseObject", "branch: %s, You have overwritten the pointer to an object which I owned!", GetName());
1392 Warning("ReleaseObject", "This is a memory leak. Please use SetAddress() to change the pointer instead.");
1393 ResetBit(kDeleteObject);
1394 }
1395 }
1396 }
1397
1398 // Delete any object we may have allocated during a call to SetAddress.
1399 // (sss - added fAddress check to fix coverity warning)
1400 if (fAddress && fObject && TestBit(kDeleteObject)) {
1401 ResetBit(kDeleteObject);
1402 if (fType == 3) {
1403 // -- We are a TClonesArray master branch.
1404 TClonesArray::Class()->Destructor(fObject);
1405 fObject = 0;
1406 if ((fStreamerType == TVirtualStreamerInfo::kObjectp) ||
1407 (fStreamerType == TVirtualStreamerInfo::kObjectP)) {
1408 // -- We are a pointer to a TClonesArray.
1409 // We must zero the pointer in the object.
1410 *((char**) fAddress) = 0;
1411 }
1412 } else if (fType == 4) {
1413 // -- We are an STL container master branch.
1414 TVirtualCollectionProxy* proxy = GetCollectionProxy();
1415 if (!proxy) {
1416 Warning("ResetAddress", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
1417 fObject = 0;
1418 } else {
1419 proxy->Destructor(fObject);
1420 fObject = 0;
1421 }
1422 if (fStreamerType == TVirtualStreamerInfo::kSTLp) {
1423 // -- We are a pointer to an STL container.
1424 // We must zero the pointer in the object.
1425 *((char**) fAddress) = 0;
1426 }
1427 } else {
1428 // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
1429 TClass* cl = fBranchClass.GetClass();
1430 if (!cl) {
1431 Warning("ResetAddress", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
1432 fObject = 0;
1433 } else {
1434 cl->Destructor(fObject);
1435 fObject = 0;
1436 }
1437 }
1438 }
1439
1440 fObject = 0;
1441 fAddress = 0;
1442 }
1443}
1444
1445
1451{
1452 fgDoDel = flag;
1453}
1454
1455
1456
size_t size() const
Number of registered mappings.
void TConvertingBranchElement_init()
Registry for Root converters.
A variant of TBranchElement that can call converters when reading objects in split mode.
Base class for Root converters.
static TConverterRegistry * Instance()
Return a pointer to the global registry instance.
TVirtualConverter * GetConverter(const char *name, int checksum) const
Look up a converter in the registry by name and checksum.
Int_t fConvOrigType
Saved branch list. If we change.
virtual void SetAddress(void *add)
Set the address of the object to use for I/O.
void ReadLeavesMemberBranchCountConverting(TBuffer &b)
virtual void ResetAddress()
Reset branch addresses and maybe delete the object.
bool fConvDontReset
True if we're doing a container.
void ConvResetType()
Recursively reset the type field of containers in conversions.
bool fConvContainerFlag
Saved branch type. The original.
TClass * fConvClass
Conversion for this branch.
static void SetDoDel(bool flag)
Set the deletion flag.
static std::atomic< bool > fgDoDel
Flag that the next read should.
static void * new_TConvertingBranchElement(void *p)
new() method for this object.
static constexpr unsigned int kIsDummy
Flag used to mark dummy nodes created by BuildConvertedElisions.
char * fConvObject
Class for conversion.
virtual void InitializeOffsets()
Initialize data member offsets.
virtual Int_t GetEntry(Long64_t entry, Int_t getall)
Read all branches into the previously-declared object.
void ReadLeavesCollectionConverting(TBuffer &b)
Read leaves into I/O buffers for this branch.
virtual ~TConvertingBranchElement()
Destructor.
static void Initialize()
Set up to allow for conversions in split mode.
Int_t ReadSubBranches(Long64_t entry, Int_t getall, bool dont_reset)
@branch Read in the subbranches of this branch.
virtual void Streamer(TBuffer &R__b)
Read or write this object.
virtual void InitInfo()
Initialize the TStreamerInfo pointer.
void CheckForConversion()
Check to see if we need to worry about conversions for this branch.
void BuildConvertedElisions()
Add dummy nodes if needed to recover the correct tree structure.
TObjArray * fConvOrigBranches
Pointer to tmp obj used for conversion.
Base class for converters for Root schema evolution.
bool add(const std::string &hname, TKey *tobj)
Definition fastadd.cxx:55
Error
The different types of error that can be flagged in the L1TopoRDO.
Definition Error.h:16
float j(const xAOD::IParticle &, const xAOD::TrackMeasurementValidation &hit, const Eigen::Matrix3d &jab_inv)
@ Info
Definition ZDCMsg.h:20
alternate(gen, dictionary, weight_dict, p_nom)
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
bool flag
Definition master.py:29
TFile * file