ATLAS Offline Software
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 
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 
35 std::atomic<bool> TConvertingBranchElement::fgDoDel = false;
36 
37 
38 namespace {
39 
40 
47 class TPushPopSafe
48 {
49 public:
50  TVirtualCollectionProxy* fProxy;
51  TPushPopSafe (TVirtualCollectionProxy* proxy, void* objectstart);
52  inline ~TPushPopSafe();
53 };
54 
55 
66 inline TPushPopSafe::TPushPopSafe (TVirtualCollectionProxy* proxy,
67  void* objectstart)
68  : fProxy (proxy)
69 {
70  if (fProxy)
71  fProxy->PushProxy (objectstart);
72 }
73 
74 
81 inline TPushPopSafe::~TPushPopSafe()
82 {
83  if (fProxy)
84  fProxy->PopProxy();
85 }
86 
87 
96 void 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 
113 std::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 
136 TStreamerInfo* 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 
167 bool 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 
206 bool 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 
248 bool 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)
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 
336 {
337 }
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.
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;
653  ConvResetType();
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) {
674  TConverterRegistry::Instance()->GetConverter (GetClassName(),
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 
843 Int_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 
1361 {
1363 }
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 
TConvertingBranchElement.h
A variant of TBranchElement that can call converters when reading objects in split mode.
StateLessPT_NewConfig.proxy
proxy
Definition: StateLessPT_NewConfig.py:407
TConvertingBranchElement::fConvOrigBranches
TObjArray * fConvOrigBranches
Pointer to tmp obj used for conversion.
Definition: TConvertingBranchElement.h:198
TConvertingBranchElement_init
void TConvertingBranchElement_init()
To allow calling Initialize without having to depend on the header.
Definition: TConvertingBranchElement.cxx:1360
TConvertingBranchElement::ConvResetType
void ConvResetType()
Recursively reset the type field of containers in conversions.
Definition: TConvertingBranchElement.cxx:738
TConvertingBranchElement::fgDoDel
static std::atomic< bool > fgDoDel
Flag that the next read should.
Definition: TConvertingBranchElement.h:213
TConvertingBranchElement::fConvDontReset
bool fConvDontReset
True if we're doing a container.
Definition: TConvertingBranchElement.h:210
TConvertingBranchElement::ReadSubBranches
Int_t ReadSubBranches(Long64_t entry, Int_t getall, bool dont_reset)
@branch Read in the subbranches of this branch.
Definition: TConvertingBranchElement.cxx:1110
ZDCMsg::Info
@ Info
Definition: ZDCMsg.h:20
TVirtualConverter.h
Base class for Root converters.
TConvertingBranchElement::InitializeOffsets
virtual void InitializeOffsets()
Initialize data member offsets.
Definition: TConvertingBranchElement.cxx:1286
runBeamSpotCalibration.helper
helper
Definition: runBeamSpotCalibration.py:115
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
runLayerRecalibration.branches
list branches
Definition: runLayerRecalibration.py:98
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
buildDatabase.alternate
def alternate(gen, dictionary, weight_dict, p_nom)
Definition: buildDatabase.py:110
createCoolChannelIdFile.buffer
buffer
Definition: createCoolChannelIdFile.py:11
lumiFormat.i
int i
Definition: lumiFormat.py:85
TConvertingBranchElement::GetEntry
virtual Int_t GetEntry(Long64_t entry, Int_t getall)
Read all branches into the previously-declared object.
Definition: TConvertingBranchElement.cxx:843
beamspotman.n
n
Definition: beamspotman.py:727
TVirtualConverter
Base class for converters for Root schema evolution.
Definition: TVirtualConverter.h:110
master.flag
bool flag
Definition: master.py:29
TConvertingBranchElement::ReadLeavesCollectionConverting
void ReadLeavesCollectionConverting(TBuffer &b)
Read leaves into I/O buffers for this branch.
Definition: TConvertingBranchElement.cxx:962
TConvertingBranchElement::ReadLeavesMemberBranchCountConverting
void ReadLeavesMemberBranchCountConverting(TBuffer &b)
Definition: TConvertingBranchElement.cxx:1054
checkCorrelInHIST.prefix
dictionary prefix
Definition: checkCorrelInHIST.py:391
file
TFile * file
Definition: tile_monitor.h:29
TConvertingBranchElement::SetDoDel
static void SetDoDel(bool flag)
Set the deletion flag.
Definition: TConvertingBranchElement.cxx:1449
add
bool add(const std::string &hname, TKey *tobj)
Definition: fastadd.cxx:55
python.getProblemFolderFromLogs.el
dictionary el
Definition: getProblemFolderFromLogs.py:48
TConvertingBranchElement::fConvClass
TClass * fConvClass
Conversion for this branch.
Definition: TConvertingBranchElement.h:196
beamspotman.dir
string dir
Definition: beamspotman.py:619
GetAllXsec.entry
list entry
Definition: GetAllXsec.py:132
TConvertingBranchElement::Initialize
static void Initialize()
Set up to allow for conversions in split mode.
Definition: TConvertingBranchElement.cxx:335
TConvertingBranchElement::fConv
TVirtualConverter * fConv
Definition: TConvertingBranchElement.h:195
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:76
TConvertingBranchElement
A variant of TBranchElement that can call converters when reading objects in split mode.
Definition: TConvertingBranchElement.h:72
checkTriggerxAOD.found
found
Definition: checkTriggerxAOD.py:328
TConvertingBranchElement::~TConvertingBranchElement
virtual ~TConvertingBranchElement()
Destructor.
Definition: TConvertingBranchElement.cxx:304
TConvertingBranchElement::Streamer
virtual void Streamer(TBuffer &R__b)
Read or write this object.
Definition: TConvertingBranchElement.cxx:1253
TConvertingBranchElement::ResetAddress
virtual void ResetAddress()
Reset branch addresses and maybe delete the object.
Definition: TConvertingBranchElement.cxx:1373
RTTAlgmain.address
address
Definition: RTTAlgmain.py:55
TConvertingBranchElement::fConvObject
char * fConvObject
Class for conversion.
Definition: TConvertingBranchElement.h:197
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
TConvertingBranchElement::fConvOrigType
Int_t fConvOrigType
Saved branch list. If we change.
Definition: TConvertingBranchElement.h:203
RTTAlgmain.branch
branch
Definition: RTTAlgmain.py:61
TConvertingBranchElement::SetAddress
virtual void SetAddress(void *add)
Set the address of the object to use for I/O.
Definition: TConvertingBranchElement.cxx:1343
TConverterRegistry.h
Registry for Root converters.
TConverterRegistry::Instance
static TConverterRegistry * Instance()
Return a pointer to the global registry instance.
Definition: TConverterRegistry.cxx:142
TVirtualConverter::DeletePersObj
virtual void DeletePersObj(void *persobj)
Destroy an instance of the persistent class.
Definition: TVirtualConverter.cxx:263
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
TConvertingBranchElement::InitInfo
virtual void InitInfo()
Initialize the TStreamerInfo pointer.
Definition: TConvertingBranchElement.cxx:706
pickleTool.object
object
Definition: pickleTool.py:29
L1Topo::Error
Error
The different types of error that can be flagged in the L1TopoRDO.
Definition: Error.h:16
str
Definition: BTagTrackIpAccessor.cxx:11
TConvertingBranchElement::TConvertingBranchElement
TConvertingBranchElement()
Constructor.
Definition: TConvertingBranchElement.cxx:287
TConverterRegistry::GetConverter
TVirtualConverter * GetConverter(const char *name, int checksum) const
Look up a converter in the registry by name and checksum.
Definition: TConverterRegistry.cxx:99
hotSpotInTAG.nb
nb
Definition: hotSpotInTAG.py:163
python.PyAthena.obj
obj
Definition: PyAthena.py:132
TVirtualConverter::ConvertVoid
virtual void ConvertVoid(void *transobj, const void *persobj)=0
Do the conversion.
dq_make_web_display.cl
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition: dq_make_web_display.py:25
PlotCalibFromCool.be
be
Definition: PlotCalibFromCool.py:398
TConvertingBranchElement::CheckForConversion
void CheckForConversion()
Check to see if we need to worry about conversions for this branch.
Definition: TConvertingBranchElement.cxx:596
python.ParticleTypeUtil.info
def info
Definition: ParticleTypeUtil.py:87
TConvertingBranchElement::kIsDummy
static constexpr unsigned int kIsDummy
Flag used to mark dummy nodes created by BuildConvertedElisions.
Definition: TConvertingBranchElement.h:155
TConvertingBranchElement::BuildConvertedElisions
void BuildConvertedElisions()
Add dummy nodes if needed to recover the correct tree structure.
Definition: TConvertingBranchElement.cxx:380
TConvertingBranchElement::fConvContainerFlag
bool fConvContainerFlag
Saved branch type. The original.
Definition: TConvertingBranchElement.h:208
TConvertingBranchElement::new_TConvertingBranchElement
static void * new_TConvertingBranchElement(void *p)
new() method for this object.
Definition: TConvertingBranchElement.cxx:349
pdg_comparison.conv
conv
Definition: pdg_comparison.py:321
PlotCalibFromCool.br
br
Definition: PlotCalibFromCool.py:355