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