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 0;
142  TFile* file = dir->GetFile();
143  if (!file) return 0;
144  if (file->GetSeekInfo() == 0) return 0;
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())) != 0) {
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(0)
289 , fConvClass(0)
290 , fConvObject(0)
291 , fConvOrigBranches(0)
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 #if 0
338  static bool initialized = false;
339  if (initialized)
340  return;
341  initialized = true;
342 
343  TClass* cl = gROOT->GetClass ("TBranchElement", true);
344  if (!cl) {
345  ::Error ("TConvertingBranchElement",
346  "Can't find TClass for TBranchElement");
347  return;
348  }
349 
350  // Change the @c New() method for @c TBranchElement to make
351  // an instance of this class instead.
353 #endif
354 }
355 
356 
367 {
368  if (p)
369  return new (p) TConvertingBranchElement;
370  return new TConvertingBranchElement;
371 }
372 
373 
398 {
399  // Can't do anything if we can't find the @c TStreamerInfo.
400  if (!fInfo) return;
401 
402  // The class of this branch's element.
403  TClass* topclass = 0;
404  if (fID < 0)
405  topclass = gROOT->GetClass (GetClassName());
406  else {
407  std::string s = BasenameOfBranch (GetName());
408  int offset = 0;
409  TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
410  if (elt)
411  topclass = elt->GetClass();
412  }
413  if (!topclass) return;
414 
415  // Here's the plan.
416  // We start by adding all branches to the @c branches list.
417  // Then we walk through the members of this class (using the
418  // @c TStreamerInfo).
419  // If this member is contained in the branch list, then we
420  // remove it from @c branches and add it to @c noconv_branches
421  // (it wasn't elided).
422  // If it's not in the branch list, then it was elided.
423  // We look then to see if the corresponding class (or anything
424  // it contains) requires a conversion. If so, then we build
425  // a dummy node for it, and add the dummy to @c conv_dummies.
426  // We then look through @c branches, find any that actually
427  // belong to the new dummy node, remove them from @c branches,
428  // and add them to the dummy.
429  // If no conversion is needed, then we don't need to do anything
430  // at this point.
431  //
432  // When we're done scanning all the members of the class, we take
433  // anything remaining in @c branches and move to @c noconv_branches
434  // (these correspond to branches with elided nodes, but with
435  // no conversions required.) Then, if we made any dummy nodes,
436  // then we replace our branch list with the concatenation of the
437  // dummy list and the @c noconv_branches list (saving the original
438  // branch list so that we can restore it later, if needed).
439  std::vector<TBranch*> conv_dummies;
440  std::vector<TBranch*> noconv_branches;
441  std::vector<TBranch*> branches;
442 
443  // To start with, add all our child branches to @c branches.
444  Int_t nbranches = fBranches.GetEntriesFast();
445  branches.reserve (nbranches);
446  for (Int_t i=0; i < nbranches; i++) {
447  TBranch* b = dynamic_cast<TBranchElement*> (fBranches[i]);
448  if (b)
449  branches.push_back (b);
450  }
451 
452  // Get the @c TStreamerInfo for this class.
453  // If this class is a container, then we actually want
454  // to get the @c TStreamerInfo for the contained class.
455  TStreamerInfo* info = GetStreamerInfoFromFile (topclass, this);
456  if (!info && fType == 4) {
457  TVirtualCollectionProxy* proxy = topclass->GetCollectionProxy();
458  if (!proxy) return;
459  topclass = proxy->GetValueClass();
460  if (!topclass) return;
461  info = GetStreamerInfoFromFile (topclass, this);
462  }
463  else if (fType == 3) {
464  topclass = gROOT->GetClass (fClonesName);
465  if (!topclass) return;
466  info = GetStreamerInfoFromFile (topclass, this);
467  }
468  if (!info) return;
469 
470  // Now walk through all elements in the @c TStreamerInfo.
471  TObjArray* elems = info->GetElements();
472  size_t ndata = elems->GetEntriesFast();
473  for (size_t ielt = 0; ielt < ndata; ++ielt) {
474  // The element.
475  TStreamerElement* elt =
476  reinterpret_cast<TStreamerElement*> (elems->At(ielt));
477 
478  // See if there's a branch corresponding to this element.
479  // If so, add it to the noconv list.
480  bool found = false;
481  for (unsigned i=0; i < branches.size(); i++) {
482  TBranchElement* b = dynamic_cast<TBranchElement*>(branches[i]);
483 
484  // Test branch @b to see if corresponds to the SI element @ elt.
485  if (b && gROOT->GetClass (b->GetClassName()) == topclass) {
486  if (dynamic_cast<TStreamerBase*> (elt) != 0 && b->GetType() == 1) {
487  // For a base class, the test above is sufficient.
488  found = true;
489  }
490  else {
491  // Test the name.
492  std::string s = BasenameOfBranch (b->GetName());
493  if (s == elt->GetName())
494  found = true;
495  }
496 
497  if (found) {
498  // We found a branch matching the element.
499  // Move the branch from @c branches to @c noconv_branches,
500  // and exit the loop over branches.
501  noconv_branches.push_back (b);
502  branches.erase (branches.begin()+i);
503  break;
504  }
505  }
506  }
507 
508  if (!found) {
509  // We didn't find a branch corresponding to this element.
510  // Maybe this is an elided class.
511  // If this is a class type, then see if it or anything
512  // it contains has a conversion. If so, then build a dummy
513  // node for it.
514  TClass* cl = elt->GetClass();
515  if (cl && DoesClassNeedConv (cl, this)) {
516  // It needs a conversion. Make a dummy node.
517  TClass* clparent = gROOT->GetClass (info->GetName());
519  dum->SetBit (kIsDummy);
520  TString name;
521  if (fID < 0)
522  name = elt->GetName();
523  else {
524  name = GetName();
525  if (fType == 1) {
526  Ssiz_t i = name.Length()-1;
527  while (i >= 0 && name[i] != '.')
528  --i;
529  name.Remove (i+1);
530  }
531  else
532  name += ".";
533  name += elt->GetName();
534  }
535  dum->SetName (name);
536  dum->SetTitle (name);
537  TString namedot = name + ".";
538  dum->SetParentClass (clparent);
539  dum->SetClassName (info->GetName());
540  dum->fCheckSum = info->GetCheckSum();
541  dum->fClassVersion = topclass->GetClassVersion();
542  dum->fID = ielt;
543  dum->fTree = this->fTree;
544  dum->fDirectory = this->fDirectory;
545  dum->fBranchClass = topclass;
546  if (dynamic_cast<TStreamerBase*> (elt) != 0) {
547  dum->fType = 1;
548  Ssiz_t i = namedot.Length()-2;
549  while (i >= 0 && namedot[i] != '.')
550  --i;
551  namedot.Remove (i+1);
552  }
553  else
554  dum->fType = 2;
555 
556  // Add the dummy node to @c conv_dummies.
557  conv_dummies.push_back (dum);
558 
559  // Find all branches that are a part of this class and
560  // move them from @c branches to the dummy node
561  for (unsigned i=0; i < branches.size(); ) {
562  TString bname = branches[i]->GetName();
563  if (bname.Index (namedot) == 0 &&
564  (dum->fType == 2 ||
565  BaseHasField (dynamic_cast<TStreamerBase*>(elt),
566  bname,
567  namedot,
568  this)))
569  {
570  dum->GetListOfBranches()->Add (branches[i]);
572  dynamic_cast<TConvertingBranchElement*> (branches[i]))
573  {
574  be->fParentClass = cl;
575  }
576  branches.erase (branches.begin()+i);
577  }
578  else {
579  ++i;
580  }
581  }
582  }
583  }
584  // End of loop over elements.
585  }
586 
587  // Any remaining branches go to @c noconv_branches.
588  for (unsigned int i=0; i < branches.size(); i++)
589  noconv_branches.push_back (branches[i]);
590 
591  if (conv_dummies.size() > 0) {
592  // We made some dummies.
593  // Replace our branch list with the concatenation
594  // of the dummy list (@c conv_dummies) and the branches
595  // that don't need special processing (@c noconv_branches --- because
596  // they either did not have an elision or they didn't require
597  // a conversion).
598  fConvOrigBranches = new TObjArray;
599  *fConvOrigBranches = fBranches;
600  fBranches.Clear();
601  for (unsigned int i=0; i < conv_dummies.size(); i++)
602  fBranches.Add (conv_dummies[i]);
603  for (unsigned int i=0; i < noconv_branches.size(); i++)
604  fBranches.Add (noconv_branches[i]);
605  }
606 }
607 
608 
614 {
615  // Need @c TStreamerInfo in order to do anything.
616  if (!fInfo) return;
617 
618  // Restore any elided tree nodes if there's a conversion.
620 
621  // See if this element is a class.
622  const char* classname = 0;
623  int checksum = 0;
624 
625  if (fID < 0) {
626  // Special case for top-level branch.
627  classname = GetClassName();
628  checksum = fCheckSum;
629  }
630  else {
631  // Otherwise, we need to look at the streamerinfo element.
632  std::string s = BasenameOfBranch (GetName());
633  int offset = 0;
634  TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
635  if (elt) {
636  TClass* cl = elt->GetClass();
637  if (cl) {
638  classname = cl->GetName();
639  TStreamerInfo* info = GetStreamerInfoFromFile (cl, this);
640  if (info)
641  checksum = info->GetCheckSum();
642  }
643  }
644  }
645 
646  if (classname) {
647  // Ok, this branch represents a class.
648  // See if there's a conversion for it.
650  TConverterRegistry::Instance()->GetConverter (classname, checksum);
651 
652  // If there's not a conversion and this class is a container,
653  // then we need to see if something in the container needs a conversion.
654  if (!conv && (fType == 4 || fType == 3)) {
655  // Find the contained class.
656  TClass* contclass = gROOT->GetClass (fClonesName.Data());
657  if (contclass) {
658  TStreamerInfo* info = GetStreamerInfoFromFile (contclass, this);
659  if (info) {
660  // Found the contained class with its @c TStreamerInfo.
661  // See if the contained class has a conversion.
662  conv =
663  TConverterRegistry::Instance()->GetConverter (fClonesName.Data(),
664  info->GetCheckSum());
665 
666  // If the contained class, or anything it contains, has a conversion,
667  // then we need to deal with conversions when reading this container.
668  if (conv || DoesClassNeedConv (contclass, this)) {
669  fConvContainerFlag = true;
670  ConvResetType();
671  }
672  }
673  }
674  }
675 
676  if (conv) {
677  TClass* convclass = conv->GetPersClass();
678  if (convclass) {
679  // We have a conversion! Remember the converter and persistent
680  // class, and create the temporary persistent class instance.
681  fConv = conv;
682  fConvClass = convclass;
683  fConvObject = (char*)conv->NewPersObj();
684  }
685  }
686  }
687 
688  // Now see if the class containing this element has a conversion.
689  if (fID > -1) {
691  TConverterRegistry::Instance()->GetConverter (GetClassName(),
692  fCheckSum);
693  if (conv) {
694  TClass* convclass = conv->GetPersClass();
695  if (convclass) {
696  // The class containing this class has a conversion.
697  // Change the @c TStreamerInfo to correspond to the
698  // appropriate persistent class; also change the parent class
699  // pointer.
700  Bool_t optim = TStreamerInfo::CanOptimize();
701  TStreamerInfo::Optimize(kFALSE);
702  TStreamerInfo* info =
703  dynamic_cast<TStreamerInfo*> (convclass->GetStreamerInfo (0));
704  if (info)
705  fInfo = info;
706  TStreamerInfo::Optimize(optim);
707  fParentClass = convclass;
708  }
709  }
710  }
711 }
712 
713 
724 {
725  // Do the standard stuff.
726  TBranchElement::InitInfo();
727 
728  // Check for a conversion.
729  if (fInfo) {
730  const_cast<TConvertingBranchElement*>(this)->CheckForConversion();
731 
732  // Re-find the fID.
733  const_cast<TConvertingBranchElement*>(this)->fInit = kFALSE;
734  TBranchElement::InitInfo();
735  }
736 
737  // Change ReadLeaves implementation if needed.
738  // The base class implementation works here except for the case
739  // of an STL associative container. We need to change the code
740  // for that to notice @c fConvDontReset and to use @c ReadSubBranches.
741  if (fType == 4)
743  else if (fType == 2 && (fConvOrigType == 41 || fConvOrigType == 31))
745 }
746 
747 
756 {
757  Int_t nbranches = fBranches.GetEntriesFast();
758  for (Int_t i=0; i < nbranches; i++) {
760  dynamic_cast<TConvertingBranchElement*> (fBranches[i]);
761  if (b) {
762  if (b->fType == 41 || b->fType == 31) {
763  b->fConvOrigType = b->fType;
764  b->fType = 2;
765  }
766  b->ConvResetType();
767  }
768  }
769 }
770 
771 
860 Int_t TConvertingBranchElement::GetEntry(Long64_t entry, Int_t getall)
861 {
862  // The first part of this just copies the base class @c GetEntry.
863  // Differences from the base class implementation will be pointed out below.
864 
865  // Remember which entry we are reading.
866  fReadEntry = entry;
867 
868  // If our tree has a branch ref, make it remember the entry and
869  // this branch. This allows a TRef::GetObject() call done during
870  // the following I/O operation, for example in a custom streamer,
871  // to search for the referenced object in the proper element of the
872  // proper branch.
873  TBranchRef* bref = fTree->GetBranchRef();
874  if (bref) {
875  bref->SetParent(this, fBranchID);
876  bref->SetRequestedEntry(entry);
877  }
878 
879  Int_t nbytes = 0;
880 
881  SetupAddresses();
882 
883  Int_t nbranches = fBranches.GetEntriesFast();
884  if (nbranches) {
885  // -- Branch has daughters.
886  // One must always read the branch counter.
887  // In the case when one reads consecutively twice the same entry,
888  // the user may have cleared the TClonesArray between the GetEntry calls.
889  if ((fType == 3) || (fType == 4)) {
890  Int_t nb = TBranch::GetEntry(entry, getall);
891  if (nb < 0) {
892  return nb;
893  }
894  nbytes += nb;
895  }
896 
897  // Here's a difference from the @c TBranchElement base class.
898  // First, we need to pick up the current state of the
899  // @c fConvDontReset flag (and clear it in the process).
900  // Instead of looping over branches here, we factor out
901  // that part into @c ReadSubBranches.
902  bool dont_reset = fConvDontReset;
903  fConvDontReset = false;
904  switch(fSTLtype) {
905  case TClassEdit::kSet:
906  case TClassEdit::kMultiSet:
907  case TClassEdit::kMap:
908  case TClassEdit::kMultiMap:
909  break;
910  default:
911  // Read non-container composite and list/vector.
912  // Associative containers will get entirely read
913  // within the @c GetEntry call above (when it calls @c ReadLeaves).
914  nbytes += ReadSubBranches (entry, getall, dont_reset);
915  break;
916  }
917  }
918  else {
919  // -- Terminal branch.
920  // Difference from base implementation: pick up the dont_reset flag here.
921  bool dont_reset = fConvDontReset;
922  fConvDontReset = false;
923 
924  if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
925  Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
926  if (nb < 0) {
927  return nb;
928  }
929  nbytes += nb;
930  }
931  Int_t nb = 0;
932 
933  // The base implementation just calls @c TBranch::GetEntry here.
934  // But we need to pay attention to the dont_reset flag.
935  // If it's set, we can't call @c TBranch::GetEntry (because
936  // that would reset the buffer pointer back to the
937  // beginning of the container). Instead, we pick up the
938  // buffer pointer and call @c ReadLeaves `by hand'.
939  if (dont_reset) {
940  TBasket* basket = (TBasket*)GetBasket(GetReadBasket());
941  TBuffer* buffer = basket->GetBufferRef();
942  Int_t bufbegin = buffer->Length();
943 
944  // Suppress false positive seen with gcc.
945 #if __GNUC__ >= 11 && __GNUC__ <= 14
946 # pragma GCC diagnostic push
947 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
948 #endif
949  (this->*fReadLeaves) (*buffer);
950 #if __GNUC__ >= 11 && __GNUC__ <= 14
951 # pragma GCC diagnostic pop
952 #endif
953 
954  nb = buffer->Length() - bufbegin;
955  }
956  else
957  nb = TBranch::GetEntry (entry, getall);
958 
959  // Rest is the same as the base implementation.
960  if (nb < 0) {
961  return nb;
962  }
963  nbytes += nb;
964  }
965 
966  if (fTree->Debug() > 0) {
967  if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
968  Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
969  }
970  }
971  return nbytes;
972 }
973 
974 
980 {
981  // -- Read leaves into i/o buffers for this branch.
982  // Case of a collection (fType == 4).
983 
984  ValidateAddress();
985  if (fObject == 0)
986  {
987  // We have nowhere to copy the data (probably because the data member was
988  // 'dropped' from the current schema) so let's no copy it in a random place.
989  return;
990  }
991 
992  // STL container master branch (has only the number of elements).
993  Int_t n;
994  b >> n;
995  if ((n < 0) || (n > fMaximum)) {
996  if (IsMissingCollection()) {
997  n = 0;
998  b.SetBufferOffset(b.Length()-sizeof(n));
999  } else {
1000  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());
1001  n = 0;
1002  }
1003  }
1004  fNdata = n;
1005 
1006  R__PushCache onfileObject((static_cast<TBufferFile&>(b)),fOnfileObject,n);
1007 
1008  if (!fObject) {
1009  return;
1010  }
1011  // Note: Proxy-helper needs to "embrace" the entire
1012  // streaming of this STL container if the container
1013  // is a set/multiset/map/multimap (what we do not
1014  // know here).
1015  // For vector/list/deque Allocate == Resize
1016  // and Commit == noop.
1017  // TODO: Exception safety a la TPushPop
1018  TVirtualCollectionProxy* proxy = GetCollectionProxy();
1019  TVirtualCollectionProxy::TPushPop helper(proxy, fObject);
1020  void* alternate = proxy->Allocate(fNdata, true);
1021  if(fSTLtype != TClassEdit::kVector && proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers ) {
1022  fPtrIterators->CreateIterators(alternate, proxy);
1023  } else {
1024  fIterators->CreateIterators(alternate, proxy);
1025  }
1026 
1027  //Int_t nbranches = fBranches.GetEntriesFast();
1028  switch (fSTLtype) {
1029  case TClassEdit::kSet:
1030  case TClassEdit::kMultiSet:
1031  case TClassEdit::kMap:
1032  case TClassEdit::kMultiMap:
1033  {
1034  // Change for conversions:
1035  // Use @c ReadSubBranches and obey @c fConvDontReset.
1036  bool dont_reset = fConvDontReset;
1037  fConvDontReset = false;
1038  ReadSubBranches (GetReadEntry(), 1, dont_reset);
1039  }
1040  break;
1041  default:
1042  break;
1043  }
1044  //------------------------------------------------------------------------
1045  // We have split this stuff, so we need to create the the pointers
1046  //-----------------------------------------------------------------------
1047  if( proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers )
1048  {
1049  TClass *elClass = proxy->GetValueClass();
1050 
1051  //--------------------------------------------------------------------
1052  // The allocation is done in this strange way because ReadLeaves
1053  // is being called many times by TTreeFormula!!!
1054  //--------------------------------------------------------------------
1055  Int_t i = 0;
1056  if( !fNdata || *(void**)proxy->At( 0 ) != 0 )
1057  i = fNdata;
1058 
1059  for( ; i < fNdata; ++i )
1060  {
1061  void **el = (void**)proxy->At( i );
1062  // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
1063  *el = elClass->New();
1064  }
1065  }
1066 
1067  proxy->Commit(alternate);
1068 }
1069 
1070 
1072 {
1073  // -- Read leaves into i/o buffers for this branch.
1074  // For split-class branch, base class branch, data member branch, or top-level branch.
1075  // which do have a branch count and are not a counter.
1076 
1077  assert(fStreamerType != TVirtualStreamerInfo::kCounter);
1078 
1079  ValidateAddress();
1080  if (fObject == 0)
1081  {
1082  // We have nowhere to copy the data (probably because the data member was
1083  // 'dropped' from the current schema) so let's no copy it in a random place.
1084  return;
1085  }
1086 
1087  R__PushCache onfileObject((static_cast<TBufferFile&>(b)),fOnfileObject,1);
1088  // If not a TClonesArray or STL container master branch
1089  // or sub-branch and branch inherits from tobject,
1090  // then register with the buffer so that pointers are
1091  // handled properly.
1092  if (TestBit(kBranchObject)) {
1093  b.ResetMap();
1094  b.MapObject((TObject*) fObject);
1095  } else if (TestBit(kBranchAny)) {
1096  b.ResetMap();
1097  b.MapObject(fObject, fBranchClass);
1098  }
1099 
1100  fNdata = (Int_t) fBranchCount->GetValue(0, 0);
1101  TStreamerInfo *info = GetInfo();
1102  if (!info) {
1103  return;
1104  }
1105  // Since info is not null, fReadActionSequence is not null either.
1106  //b.ReadSequence(*fReadActionSequence, fObject);
1107  // FIXME!
1108  // ReadSequence doesn't work here, since it gets structure offsets
1109  // from TConfiguration, and those haven't been adjusted to take
1110  // into account the use of the temporary conversion objects.
1111  // FIXME!
1112  std::abort();
1113  //doesn't work
1114  //info->ReadBuffer (b, (char**)&fObject, fID);
1115 }
1116 
1117 
1128  Int_t getall,
1129  bool dont_reset)
1130 {
1131  Int_t nbytes = 0;
1132  Int_t nbranches = fBranches.GetEntriesFast();
1133 
1134  if (fConvContainerFlag) {
1135  if (fNdata > 0) {
1136  // We're reading a container that needs a conversion.
1137  // We're going to invert the loop order so that we read
1138  // a single object at a time,
1139  // Remember the number of entries in the container, but change
1140  // the number we advertise to 1.
1141  UInt_t save_ndata = fNdata;
1142  fNdata = 1;
1143 
1144  // Get either the container proxy or the clones array, as appropriate.
1145  TVirtualCollectionProxy* proxy = 0;
1146  TClonesArray* clones = 0;
1147  if (fType == 4)
1148  proxy = GetCollectionProxy();
1149  else if (fType == 3)
1150  clones = (TClonesArray*)fObject;
1151  else
1152  abort();
1153 
1154  // If we had a proxy, associate it with the container object.
1155  // This is safe for the case where proxy is null.
1156  TPushPopSafe helper (proxy,fObject);
1157 
1158  // For each element, we may have to call @c SetAddress for each
1159  // branch. This is used to avoid doing this repeatedly
1160  // with the same address (as would happen if we're reading into
1161  // the temporary persistent object).
1162  std::vector<char*> last_addrs (nbranches, (char*)0);
1163 
1164  // Loop over elements.
1165  for (UInt_t j = 0; j < save_ndata; j++) {
1166  // Find the address of the element we want to initialize.
1167  // How we do this depends on whether we have a @c TClonesArray
1168  // or a proxy.
1169  char* addr = 0;
1170  if (proxy)
1171  addr = (char*)(proxy->At(j));
1172  else {
1173  if (!clones) std::abort();
1174  addr = (char*)((*clones)[j]);
1175  }
1176 
1177  // The address of the object we want to read.
1178  // If we have a conversion on the class contained directly
1179  // in the container, then this will be the temporary persistent
1180  // object. Otherwise, it will be the address we found in the
1181  // last line.
1182  char* obj = fConvObject ? fConvObject : addr;
1183 
1184  // Loop over branches for a single object.
1185  for (Int_t i = 0; i < nbranches; ++i) {
1186  TBranch* branch = (TBranch*) fBranches[i];
1187 
1188  // If this isn't the first element in the container,
1189  // then we'll need to set the dont_reset flag.
1190  if (j > 0) {
1192  dynamic_cast<TConvertingBranchElement*>(branch);
1193  if (be)
1194  be->fConvDontReset = true;
1195  }
1196 
1197  // Find the address for this member,
1198  char* this_addr = obj + fBranchOffset[i];
1199 
1200  // Call @c SetAddress if it's different from the last one we set.
1201  if (this_addr != last_addrs[i]) {
1202  last_addrs[i] = this_addr;
1203  branch->SetAddress (obj + fBranchOffset[i]);
1204  }
1205 
1206  // Read the branch.
1207  Int_t nb = branch->GetEntry(entry, getall);
1208 
1209  // Bookkeeping.
1210  if (nb < 0) {
1211  return nb;
1212  }
1213  nbytes += nb;
1214  }
1215 
1216  // End of loop over branches.
1217  // We just read one complete object.
1218  // Call the converter, if needed.
1219  if (fConv)
1220  fConv->ConvertVoid (addr, obj);
1221  }
1222 
1223  // End of loop over entries. Restore @c fNdata.
1224  fNdata = save_ndata;
1225  }
1226  }
1227  else {
1228  // Non-container case.
1229  // We're reading a single object.
1230  // Loop over branches.
1231  for (Int_t i = 0; i < nbranches; ++i) {
1232  TBranch* branch = (TBranch*) fBranches[i];
1233 
1234  // If @c dont_reset is set, we need to propagate it to our children.
1235  if (dont_reset) {
1237  dynamic_cast<TConvertingBranchElement*>(branch);
1238  if (!be) return -1;
1239  be->fConvDontReset = true;
1240  }
1241 
1242  // Read the branch.
1243  Int_t nb = branch->GetEntry(entry, getall);
1244 
1245  // Bookkeeping.
1246  if (nb < 0) {
1247  return nb;
1248  }
1249  nbytes += nb;
1250  }
1251 
1252  // Done reading the object. Call the converter if needed.
1253  if (fConv)
1254  fConv->ConvertVoid (fObject, fConvObject);
1255  }
1256  return nbytes;
1257 }
1258 
1259 
1271 {
1272  TObjArray brsave;
1273  Int_t type_save = 0;
1274 
1275  if (!R__b.IsReading()) {
1276  if (fConvOrigType == -1)
1277  fConvOrigType = fType;
1278 
1279  type_save = fType;
1280  fType = fConvOrigType;
1281  if (fConvOrigBranches) {
1282  brsave = fBranches;
1283  fBranches = *fConvOrigBranches;
1284  }
1285  }
1286 
1287  TBranchElement::Streamer (R__b);
1288 
1289  if (!R__b.IsReading()) {
1290  fType = type_save;
1291  if (fConvOrigBranches) {
1292  fBranches = brsave;
1293  }
1294  }
1295 }
1296 
1297 
1298 
1304 {
1305  // previously in InitializeOffsets, after:
1306  // if (fType == 1) {
1307  // pClass = branchElem->GetClassPointer();
1308  // } else {
1309  // pClass = subBranch->GetParentClass();
1310  // }
1311  //
1312  // i had:
1313  //
1314  // if (fConvClass) pClass = fConvClass;
1315  //
1316  // This is a hack so we don't need to modify the base class
1317  // InitializeOffsets.
1318  //
1319  TStreamerElement* branchElem = 0;
1320  TClass* cl_orig = 0;
1321  if (fConvClass && fID > -1) {
1322  TStreamerInfo* si = GetInfo();
1323  branchElem = si->GetElem(fID);
1324  if (branchElem) {
1325  if (branchElem && branchElem->IsBase()) {
1326  cl_orig = branchElem->GetClassPointer();
1327  branchElem->Update (cl_orig, fConvClass);
1328  }
1329  else
1330  branchElem = 0;
1331  }
1332  }
1333 
1334  if (fConvClass) {
1335  Int_t nbranches = fBranches.GetEntriesFast();
1336  for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
1338  dynamic_cast<TConvertingBranchElement*> (fBranches[subBranchIdx]);
1339  if (br) {
1340  br->fParentClass = fConvClass;
1341  }
1342  }
1343  }
1344 
1345  TBranchElement::InitializeOffsets();
1346 
1347  if (branchElem)
1348  branchElem->Update (fConvClass, cl_orig);
1349 }
1350 
1351 
1361 {
1362  TBranchElement::SetAddress (add);
1363  if (fConvObject) {
1364  Int_t nbranches = fBranches.GetEntriesFast();
1365  for (Int_t i = 0; i < nbranches; ++i) {
1366  TBranch* abranch = (TBranch*) fBranches[i];
1367  abranch->SetAddress(fConvObject + fBranchOffset[i]);
1368  }
1369  }
1370 }
1371 
1372 
1373 
1378 {
1380 }
1381 
1382 
1391 {
1392  char* object = fObject;
1393  char* address = fAddress;
1394  TBranchElement::ResetAddress();
1395 
1396  if (fgDoDel) {
1397  fObject = object;
1398  fAddress = address;
1399 
1400  // This is copied from the disabled code of TBranchElement::ReleaseObject.
1401  if (fID < 0) {
1402  // -- We are a top-level branch.
1403  if (fAddress && (*((char**) fAddress) != fObject)) {
1404  // The semantics of fAddress and fObject are violated.
1405  // Assume the user changed the pointer on us.
1406  if (TestBit(kDeleteObject)) {
1407  Warning("ReleaseObject", "branch: %s, You have overwritten the pointer to an object which I owned!", GetName());
1408  Warning("ReleaseObject", "This is a memory leak. Please use SetAddress() to change the pointer instead.");
1409  ResetBit(kDeleteObject);
1410  }
1411  }
1412  }
1413 
1414  // Delete any object we may have allocated during a call to SetAddress.
1415  // (sss - added fAddress check to fix coverity warning)
1416  if (fAddress && fObject && TestBit(kDeleteObject)) {
1417  ResetBit(kDeleteObject);
1418  if (fType == 3) {
1419  // -- We are a TClonesArray master branch.
1420  TClonesArray::Class()->Destructor(fObject);
1421  fObject = 0;
1422  if ((fStreamerType == TVirtualStreamerInfo::kObjectp) ||
1423  (fStreamerType == TVirtualStreamerInfo::kObjectP)) {
1424  // -- We are a pointer to a TClonesArray.
1425  // We must zero the pointer in the object.
1426  *((char**) fAddress) = 0;
1427  }
1428  } else if (fType == 4) {
1429  // -- We are an STL container master branch.
1430  TVirtualCollectionProxy* proxy = GetCollectionProxy();
1431  if (!proxy) {
1432  Warning("ResetAddress", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
1433  fObject = 0;
1434  } else {
1435  proxy->Destructor(fObject);
1436  fObject = 0;
1437  }
1438  if (fStreamerType == TVirtualStreamerInfo::kSTLp) {
1439  // -- We are a pointer to an STL container.
1440  // We must zero the pointer in the object.
1441  *((char**) fAddress) = 0;
1442  }
1443  } else {
1444  // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
1445  TClass* cl = fBranchClass.GetClass();
1446  if (!cl) {
1447  Warning("ResetAddress", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
1448  fObject = 0;
1449  } else {
1450  cl->Destructor(fObject);
1451  fObject = 0;
1452  }
1453  }
1454  }
1455 
1456  fObject = 0;
1457  fAddress = 0;
1458  }
1459 }
1460 
1461 
1467 {
1468  fgDoDel = flag;
1469 }
1470 
1471 
1472 
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:200
TConvertingBranchElement_init
void TConvertingBranchElement_init()
To allow calling Initialize without having to depend on the header.
Definition: TConvertingBranchElement.cxx:1377
TConvertingBranchElement::ConvResetType
void ConvResetType()
Recursively reset the type field of containers in conversions.
Definition: TConvertingBranchElement.cxx:755
TConvertingBranchElement::fgDoDel
static std::atomic< bool > fgDoDel
Flag that the next read should.
Definition: TConvertingBranchElement.h:215
TConvertingBranchElement::fConvDontReset
bool fConvDontReset
True if we're doing a container.
Definition: TConvertingBranchElement.h:212
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:1127
TVirtualConverter.h
Base class for Root converters.
TConvertingBranchElement::InitializeOffsets
virtual void InitializeOffsets()
Initialize data member offsets.
Definition: TConvertingBranchElement.cxx:1303
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:860
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:979
TConvertingBranchElement::ReadLeavesMemberBranchCountConverting
void ReadLeavesMemberBranchCountConverting(TBuffer &b)
Definition: TConvertingBranchElement.cxx:1071
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:1466
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:198
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:197
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:1270
TConvertingBranchElement::ResetAddress
virtual void ResetAddress()
Reset branch addresses and maybe delete the object.
Definition: TConvertingBranchElement.cxx:1390
RTTAlgmain.address
address
Definition: RTTAlgmain.py:55
TConvertingBranchElement::kIsDummy
@ kIsDummy
Definition: TConvertingBranchElement.h:156
TConvertingBranchElement::fConvObject
char * fConvObject
Class for conversion.
Definition: TConvertingBranchElement.h:199
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
TConvertingBranchElement::fConvOrigType
Int_t fConvOrigType
Saved branch list. If we change.
Definition: TConvertingBranchElement.h:205
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:1360
TConverterRegistry.h
Registry for Root converters.
TConverterRegistry::Instance
static TConverterRegistry * Instance()
Return a pointer to the global registry instance.
Definition: TConverterRegistry.cxx:143
TVirtualConverter::DeletePersObj
virtual void DeletePersObj(void *persobj)
Destroy an instance of the persistent class.
Definition: TVirtualConverter.cxx:264
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:723
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:100
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:613
python.ParticleTypeUtil.info
def info
Definition: ParticleTypeUtil.py:87
TConvertingBranchElement::BuildConvertedElisions
void BuildConvertedElisions()
Add dummy nodes if needed to recover the correct tree structure.
Definition: TConvertingBranchElement.cxx:397
TConvertingBranchElement::fConvContainerFlag
bool fConvContainerFlag
Saved branch type. The original.
Definition: TConvertingBranchElement.h:210
TConvertingBranchElement::new_TConvertingBranchElement
static void * new_TConvertingBranchElement(void *p)
new() method for this object.
Definition: TConvertingBranchElement.cxx:366
pdg_comparison.conv
conv
Definition: pdg_comparison.py:321
PlotCalibFromCool.br
br
Definition: PlotCalibFromCool.py:355