ATLAS Offline Software
TConvertingBranchElement.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 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(); i++) {
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  --i;
578  }
579  }
580  }
581  }
582  // End of loop over elements.
583  }
584 
585  // Any remaining branches go to @c noconv_branches.
586  for (unsigned int i=0; i < branches.size(); i++)
587  noconv_branches.push_back (branches[i]);
588 
589  if (conv_dummies.size() > 0) {
590  // We made some dummies.
591  // Replace our branch list with the concatenation
592  // of the dummy list (@c conv_dummies) and the branches
593  // that don't need special processing (@c noconv_branches --- because
594  // they either did not have an elision or they didn't require
595  // a conversion).
596  fConvOrigBranches = new TObjArray;
597  *fConvOrigBranches = fBranches;
598  fBranches.Clear();
599  for (unsigned int i=0; i < conv_dummies.size(); i++)
600  fBranches.Add (conv_dummies[i]);
601  for (unsigned int i=0; i < noconv_branches.size(); i++)
602  fBranches.Add (noconv_branches[i]);
603  }
604 }
605 
606 
612 {
613  // Need @c TStreamerInfo in order to do anything.
614  if (!fInfo) return;
615 
616  // Restore any elided tree nodes if there's a conversion.
618 
619  // See if this element is a class.
620  const char* classname = 0;
621  int checksum = 0;
622 
623  if (fID < 0) {
624  // Special case for top-level branch.
625  classname = GetClassName();
626  checksum = fCheckSum;
627  }
628  else {
629  // Otherwise, we need to look at the streamerinfo element.
630  std::string s = BasenameOfBranch (GetName());
631  int offset = 0;
632  TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
633  if (elt) {
634  TClass* cl = elt->GetClass();
635  if (cl) {
636  classname = cl->GetName();
637  TStreamerInfo* info = GetStreamerInfoFromFile (cl, this);
638  if (info)
639  checksum = info->GetCheckSum();
640  }
641  }
642  }
643 
644  if (classname) {
645  // Ok, this branch represents a class.
646  // See if there's a conversion for it.
648  TConverterRegistry::Instance()->GetConverter (classname, checksum);
649 
650  // If there's not a conversion and this class is a container,
651  // then we need to see if something in the container needs a conversion.
652  if (!conv && (fType == 4 || fType == 3)) {
653  // Find the contained class.
654  TClass* contclass = gROOT->GetClass (fClonesName.Data());
655  if (contclass) {
656  TStreamerInfo* info = GetStreamerInfoFromFile (contclass, this);
657  if (info) {
658  // Found the contained class with its @c TStreamerInfo.
659  // See if the contained class has a conversion.
660  conv =
661  TConverterRegistry::Instance()->GetConverter (fClonesName.Data(),
662  info->GetCheckSum());
663 
664  // If the contained class, or anything it contains, has a conversion,
665  // then we need to deal with conversions when reading this container.
666  if (conv || DoesClassNeedConv (contclass, this)) {
667  fConvContainerFlag = true;
668  ConvResetType();
669  }
670  }
671  }
672  }
673 
674  if (conv) {
675  TClass* convclass = conv->GetPersClass();
676  if (convclass) {
677  // We have a conversion! Remember the converter and persistent
678  // class, and create the temporary persistent class instance.
679  fConv = conv;
680  fConvClass = convclass;
681  fConvObject = (char*)conv->NewPersObj();
682  }
683  }
684  }
685 
686  // Now see if the class containing this element has a conversion.
687  if (fID > -1) {
689  TConverterRegistry::Instance()->GetConverter (GetClassName(),
690  fCheckSum);
691  if (conv) {
692  TClass* convclass = conv->GetPersClass();
693  if (convclass) {
694  // The class containing this class has a conversion.
695  // Change the @c TStreamerInfo to correspond to the
696  // appropriate persistent class; also change the parent class
697  // pointer.
698  Bool_t optim = TStreamerInfo::CanOptimize();
699  TStreamerInfo::Optimize(kFALSE);
700  TStreamerInfo* info =
701  dynamic_cast<TStreamerInfo*> (convclass->GetStreamerInfo (0));
702  if (info)
703  fInfo = info;
704  TStreamerInfo::Optimize(optim);
705  fParentClass = convclass;
706  }
707  }
708  }
709 }
710 
711 
722 {
723  // Do the standard stuff.
724  TBranchElement::InitInfo();
725 
726  // Check for a conversion.
727  if (fInfo) {
728  const_cast<TConvertingBranchElement*>(this)->CheckForConversion();
729 
730  // Re-find the fID.
731  const_cast<TConvertingBranchElement*>(this)->fInit = kFALSE;
732  TBranchElement::InitInfo();
733  }
734 
735  // Change ReadLeaves implementation if needed.
736  // The base class implementation works here except for the case
737  // of an STL associative container. We need to change the code
738  // for that to notice @c fConvDontReset and to use @c ReadSubBranches.
739  if (fType == 4)
741  else if (fType == 2 && (fConvOrigType == 41 || fConvOrigType == 31))
743 }
744 
745 
754 {
755  Int_t nbranches = fBranches.GetEntriesFast();
756  for (Int_t i=0; i < nbranches; i++) {
758  dynamic_cast<TConvertingBranchElement*> (fBranches[i]);
759  if (b) {
760  if (b->fType == 41 || b->fType == 31) {
761  b->fConvOrigType = b->fType;
762  b->fType = 2;
763  }
764  b->ConvResetType();
765  }
766  }
767 }
768 
769 
858 Int_t TConvertingBranchElement::GetEntry(Long64_t entry, Int_t getall)
859 {
860  // The first part of this just copies the base class @c GetEntry.
861  // Differences from the base class implementation will be pointed out below.
862 
863  // Remember which entry we are reading.
864  fReadEntry = entry;
865 
866  // If our tree has a branch ref, make it remember the entry and
867  // this branch. This allows a TRef::GetObject() call done during
868  // the following I/O operation, for example in a custom streamer,
869  // to search for the referenced object in the proper element of the
870  // proper branch.
871  TBranchRef* bref = fTree->GetBranchRef();
872  if (bref) {
873  bref->SetParent(this, fBranchID);
874  bref->SetRequestedEntry(entry);
875  }
876 
877  Int_t nbytes = 0;
878 
879  SetupAddresses();
880 
881  Int_t nbranches = fBranches.GetEntriesFast();
882  if (nbranches) {
883  // -- Branch has daughters.
884  // One must always read the branch counter.
885  // In the case when one reads consecutively twice the same entry,
886  // the user may have cleared the TClonesArray between the GetEntry calls.
887  if ((fType == 3) || (fType == 4)) {
888  Int_t nb = TBranch::GetEntry(entry, getall);
889  if (nb < 0) {
890  return nb;
891  }
892  nbytes += nb;
893  }
894 
895  // Here's a difference from the @c TBranchElement base class.
896  // First, we need to pick up the current state of the
897  // @c fConvDontReset flag (and clear it in the process).
898  // Instead of looping over branches here, we factor out
899  // that part into @c ReadSubBranches.
900  bool dont_reset = fConvDontReset;
901  fConvDontReset = false;
902  switch(fSTLtype) {
903  case TClassEdit::kSet:
904  case TClassEdit::kMultiSet:
905  case TClassEdit::kMap:
906  case TClassEdit::kMultiMap:
907  break;
908  default:
909  // Read non-container composite and list/vector.
910  // Associative containers will get entirely read
911  // within the @c GetEntry call above (when it calls @c ReadLeaves).
912  nbytes += ReadSubBranches (entry, getall, dont_reset);
913  break;
914  }
915  }
916  else {
917  // -- Terminal branch.
918  // Difference from base implementation: pick up the dont_reset flag here.
919  bool dont_reset = fConvDontReset;
920  fConvDontReset = false;
921 
922  if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
923  Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
924  if (nb < 0) {
925  return nb;
926  }
927  nbytes += nb;
928  }
929  Int_t nb = 0;
930 
931  // The base implementation just calls @c TBranch::GetEntry here.
932  // But we need to pay attention to the dont_reset flag.
933  // If it's set, we can't call @c TBranch::GetEntry (because
934  // that would reset the buffer pointer back to the
935  // beginning of the container). Instead, we pick up the
936  // buffer pointer and call @c ReadLeaves `by hand'.
937  if (dont_reset) {
938  TBasket* basket = (TBasket*)GetBasket(GetReadBasket());
939  TBuffer* buffer = basket->GetBufferRef();
940  Int_t bufbegin = buffer->Length();
941 
942  // Suppress false positive seen with gcc.
943 #if __GNUC__ >= 11 && __GNUC__ <= 13
944 # pragma GCC diagnostic push
945 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
946 #endif
947  (this->*fReadLeaves) (*buffer);
948 #if __GNUC__ >= 11 && __GNUC__ <= 13
949 # pragma GCC diagnostic pop
950 #endif
951 
952  nb = buffer->Length() - bufbegin;
953  }
954  else
955  nb = TBranch::GetEntry (entry, getall);
956 
957  // Rest is the same as the base implementation.
958  if (nb < 0) {
959  return nb;
960  }
961  nbytes += nb;
962  }
963 
964  if (fTree->Debug() > 0) {
965  if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
966  Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
967  }
968  }
969  return nbytes;
970 }
971 
972 
978 {
979  // -- Read leaves into i/o buffers for this branch.
980  // Case of a collection (fType == 4).
981 
982  ValidateAddress();
983  if (fObject == 0)
984  {
985  // We have nowhere to copy the data (probably because the data member was
986  // 'dropped' from the current schema) so let's no copy it in a random place.
987  return;
988  }
989 
990  // STL container master branch (has only the number of elements).
991  Int_t n;
992  b >> n;
993  if ((n < 0) || (n > fMaximum)) {
994  if (IsMissingCollection()) {
995  n = 0;
996  b.SetBufferOffset(b.Length()-sizeof(n));
997  } else {
998  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());
999  n = 0;
1000  }
1001  }
1002  fNdata = n;
1003 
1004  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,n);
1005 
1006  if (!fObject) {
1007  return;
1008  }
1009  // Note: Proxy-helper needs to "embrace" the entire
1010  // streaming of this STL container if the container
1011  // is a set/multiset/map/multimap (what we do not
1012  // know here).
1013  // For vector/list/deque Allocate == Resize
1014  // and Commit == noop.
1015  // TODO: Exception safety a la TPushPop
1016  TVirtualCollectionProxy* proxy = GetCollectionProxy();
1017  TVirtualCollectionProxy::TPushPop helper(proxy, fObject);
1018  void* alternate = proxy->Allocate(fNdata, true);
1019  if(fSTLtype != TClassEdit::kVector && proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers ) {
1020  fPtrIterators->CreateIterators(alternate, proxy);
1021  } else {
1022  fIterators->CreateIterators(alternate, proxy);
1023  }
1024 
1025  //Int_t nbranches = fBranches.GetEntriesFast();
1026  switch (fSTLtype) {
1027  case TClassEdit::kSet:
1028  case TClassEdit::kMultiSet:
1029  case TClassEdit::kMap:
1030  case TClassEdit::kMultiMap:
1031  {
1032  // Change for conversions:
1033  // Use @c ReadSubBranches and obey @c fConvDontReset.
1034  bool dont_reset = fConvDontReset;
1035  fConvDontReset = false;
1036  ReadSubBranches (GetReadEntry(), 1, dont_reset);
1037  }
1038  break;
1039  default:
1040  break;
1041  }
1042  //------------------------------------------------------------------------
1043  // We have split this stuff, so we need to create the the pointers
1044  //-----------------------------------------------------------------------
1045  if( proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers )
1046  {
1047  TClass *elClass = proxy->GetValueClass();
1048 
1049  //--------------------------------------------------------------------
1050  // The allocation is done in this strange way because ReadLeaves
1051  // is being called many times by TTreeFormula!!!
1052  //--------------------------------------------------------------------
1053  Int_t i = 0;
1054  if( !fNdata || *(void**)proxy->At( 0 ) != 0 )
1055  i = fNdata;
1056 
1057  for( ; i < fNdata; ++i )
1058  {
1059  void **el = (void**)proxy->At( i );
1060  // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
1061  *el = elClass->New();
1062  }
1063  }
1064 
1065  proxy->Commit(alternate);
1066 }
1067 
1068 
1070 {
1071  // -- Read leaves into i/o buffers for this branch.
1072  // For split-class branch, base class branch, data member branch, or top-level branch.
1073  // which do have a branch count and are not a counter.
1074 
1075  assert(fStreamerType != TVirtualStreamerInfo::kCounter);
1076 
1077  ValidateAddress();
1078  if (fObject == 0)
1079  {
1080  // We have nowhere to copy the data (probably because the data member was
1081  // 'dropped' from the current schema) so let's no copy it in a random place.
1082  return;
1083  }
1084 
1085  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
1086  // If not a TClonesArray or STL container master branch
1087  // or sub-branch and branch inherits from tobject,
1088  // then register with the buffer so that pointers are
1089  // handled properly.
1090  if (TestBit(kBranchObject)) {
1091  b.ResetMap();
1092  b.MapObject((TObject*) fObject);
1093  } else if (TestBit(kBranchAny)) {
1094  b.ResetMap();
1095  b.MapObject(fObject, fBranchClass);
1096  }
1097 
1098  fNdata = (Int_t) fBranchCount->GetValue(0, 0);
1099  TStreamerInfo *info = GetInfo();
1100  if (!info) {
1101  return;
1102  }
1103  // Since info is not null, fReadActionSequence is not null either.
1104  //b.ReadSequence(*fReadActionSequence, fObject);
1105  // FIXME!
1106  // ReadSequence doesn't work here, since it gets structure offsets
1107  // from TConfiguration, and those haven't been adjusted to take
1108  // into account the use of the temporary conversion objects.
1109  // FIXME!
1110  std::abort();
1111  //doesn't work
1112  //info->ReadBuffer (b, (char**)&fObject, fID);
1113 }
1114 
1115 
1126  Int_t getall,
1127  bool dont_reset)
1128 {
1129  Int_t nbytes = 0;
1130  Int_t nbranches = fBranches.GetEntriesFast();
1131 
1132  if (fConvContainerFlag) {
1133  if (fNdata > 0) {
1134  // We're reading a container that needs a conversion.
1135  // We're going to invert the loop order so that we read
1136  // a single object at a time,
1137  // Remember the number of entries in the container, but change
1138  // the number we advertise to 1.
1139  UInt_t save_ndata = fNdata;
1140  fNdata = 1;
1141 
1142  // Get either the container proxy or the clones array, as appropriate.
1143  TVirtualCollectionProxy* proxy = 0;
1144  TClonesArray* clones = 0;
1145  if (fType == 4)
1146  proxy = GetCollectionProxy();
1147  else if (fType == 3)
1148  clones = (TClonesArray*)fObject;
1149  else
1150  abort();
1151 
1152  // If we had a proxy, associate it with the container object.
1153  // This is safe for the case where proxy is null.
1154  TPushPopSafe helper (proxy,fObject);
1155 
1156  // For each element, we may have to call @c SetAddress for each
1157  // branch. This is used to avoid doing this repeatedly
1158  // with the same address (as would happen if we're reading into
1159  // the temporary persistent object).
1160  std::vector<char*> last_addrs (nbranches, (char*)0);
1161 
1162  // Loop over elements.
1163  for (UInt_t j = 0; j < save_ndata; j++) {
1164  // Find the address of the element we want to initialize.
1165  // How we do this depends on whether we have a @c TClonesArray
1166  // or a proxy.
1167  char* addr = 0;
1168  if (proxy)
1169  addr = (char*)(proxy->At(j));
1170  else {
1171  if (!clones) std::abort();
1172  addr = (char*)((*clones)[j]);
1173  }
1174 
1175  // The address of the object we want to read.
1176  // If we have a conversion on the class contained directly
1177  // in the container, then this will be the temporary persistent
1178  // object. Otherwise, it will be the address we found in the
1179  // last line.
1180  char* obj = fConvObject ? fConvObject : addr;
1181 
1182  // Loop over branches for a single object.
1183  for (Int_t i = 0; i < nbranches; ++i) {
1184  TBranch* branch = (TBranch*) fBranches[i];
1185 
1186  // If this isn't the first element in the container,
1187  // then we'll need to set the dont_reset flag.
1188  if (j > 0) {
1190  dynamic_cast<TConvertingBranchElement*>(branch);
1191  if (be)
1192  be->fConvDontReset = true;
1193  }
1194 
1195  // Find the address for this member,
1196  char* this_addr = obj + fBranchOffset[i];
1197 
1198  // Call @c SetAddress if it's different from the last one we set.
1199  if (this_addr != last_addrs[i]) {
1200  last_addrs[i] = this_addr;
1201  branch->SetAddress (obj + fBranchOffset[i]);
1202  }
1203 
1204  // Read the branch.
1205  Int_t nb = branch->GetEntry(entry, getall);
1206 
1207  // Bookkeeping.
1208  if (nb < 0) {
1209  return nb;
1210  }
1211  nbytes += nb;
1212  }
1213 
1214  // End of loop over branches.
1215  // We just read one complete object.
1216  // Call the converter, if needed.
1217  if (fConv)
1218  fConv->ConvertVoid (addr, obj);
1219  }
1220 
1221  // End of loop over entries. Restore @c fNdata.
1222  fNdata = save_ndata;
1223  }
1224  }
1225  else {
1226  // Non-container case.
1227  // We're reading a single object.
1228  // Loop over branches.
1229  for (Int_t i = 0; i < nbranches; ++i) {
1230  TBranch* branch = (TBranch*) fBranches[i];
1231 
1232  // If @c dont_reset is set, we need to propagate it to our children.
1233  if (dont_reset) {
1235  dynamic_cast<TConvertingBranchElement*>(branch);
1236  if (!be) return -1;
1237  be->fConvDontReset = true;
1238  }
1239 
1240  // Read the branch.
1241  Int_t nb = branch->GetEntry(entry, getall);
1242 
1243  // Bookkeeping.
1244  if (nb < 0) {
1245  return nb;
1246  }
1247  nbytes += nb;
1248  }
1249 
1250  // Done reading the object. Call the converter if needed.
1251  if (fConv)
1252  fConv->ConvertVoid (fObject, fConvObject);
1253  }
1254  return nbytes;
1255 }
1256 
1257 
1269 {
1270  TObjArray brsave;
1271  Int_t type_save = 0;
1272 
1273  if (!R__b.IsReading()) {
1274  if (fConvOrigType == -1)
1275  fConvOrigType = fType;
1276 
1277  type_save = fType;
1278  fType = fConvOrigType;
1279  if (fConvOrigBranches) {
1280  brsave = fBranches;
1281  fBranches = *fConvOrigBranches;
1282  }
1283  }
1284 
1285  TBranchElement::Streamer (R__b);
1286 
1287  if (!R__b.IsReading()) {
1288  fType = type_save;
1289  if (fConvOrigBranches) {
1290  fBranches = brsave;
1291  }
1292  }
1293 }
1294 
1295 
1296 
1302 {
1303  // previously in InitializeOffsets, after:
1304  // if (fType == 1) {
1305  // pClass = branchElem->GetClassPointer();
1306  // } else {
1307  // pClass = subBranch->GetParentClass();
1308  // }
1309  //
1310  // i had:
1311  //
1312  // if (fConvClass) pClass = fConvClass;
1313  //
1314  // This is a hack so we don't need to modify the base class
1315  // InitializeOffsets.
1316  //
1317  TStreamerElement* branchElem = 0;
1318  TClass* cl_orig = 0;
1319  if (fConvClass && fID > -1) {
1320  TStreamerInfo* si = GetInfo();
1321  branchElem = si->GetElem(fID);
1322  if (branchElem) {
1323  if (branchElem && branchElem->IsBase()) {
1324  cl_orig = branchElem->GetClassPointer();
1325  branchElem->Update (cl_orig, fConvClass);
1326  }
1327  else
1328  branchElem = 0;
1329  }
1330  }
1331 
1332  if (fConvClass) {
1333  Int_t nbranches = fBranches.GetEntriesFast();
1334  for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
1336  dynamic_cast<TConvertingBranchElement*> (fBranches[subBranchIdx]);
1337  if (br) {
1338  br->fParentClass = fConvClass;
1339  }
1340  }
1341  }
1342 
1343  TBranchElement::InitializeOffsets();
1344 
1345  if (branchElem)
1346  branchElem->Update (fConvClass, cl_orig);
1347 }
1348 
1349 
1359 {
1360  TBranchElement::SetAddress (add);
1361  if (fConvObject) {
1362  Int_t nbranches = fBranches.GetEntriesFast();
1363  for (Int_t i = 0; i < nbranches; ++i) {
1364  TBranch* abranch = (TBranch*) fBranches[i];
1365  abranch->SetAddress(fConvObject + fBranchOffset[i]);
1366  }
1367  }
1368 }
1369 
1370 
1371 
1376 {
1378 }
1379 
1380 
1389 {
1390  char* object = fObject;
1391  char* address = fAddress;
1392  TBranchElement::ResetAddress();
1393 
1394  if (fgDoDel) {
1395  fObject = object;
1396  fAddress = address;
1397 
1398  // This is copied from the disabled code of TBranchElement::ReleaseObject.
1399  if (fID < 0) {
1400  // -- We are a top-level branch.
1401  if (fAddress && (*((char**) fAddress) != fObject)) {
1402  // The semantics of fAddress and fObject are violated.
1403  // Assume the user changed the pointer on us.
1404  if (TestBit(kDeleteObject)) {
1405  Warning("ReleaseObject", "branch: %s, You have overwritten the pointer to an object which I owned!", GetName());
1406  Warning("ReleaseObject", "This is a memory leak. Please use SetAddress() to change the pointer instead.");
1407  ResetBit(kDeleteObject);
1408  }
1409  }
1410  }
1411 
1412  // Delete any object we may have allocated during a call to SetAddress.
1413  // (sss - added fAddress check to fix coverity warning)
1414  if (fAddress && fObject && TestBit(kDeleteObject)) {
1415  ResetBit(kDeleteObject);
1416  if (fType == 3) {
1417  // -- We are a TClonesArray master branch.
1418  TClonesArray::Class()->Destructor(fObject);
1419  fObject = 0;
1420  if ((fStreamerType == TVirtualStreamerInfo::kObjectp) ||
1421  (fStreamerType == TVirtualStreamerInfo::kObjectP)) {
1422  // -- We are a pointer to a TClonesArray.
1423  // We must zero the pointer in the object.
1424  *((char**) fAddress) = 0;
1425  }
1426  } else if (fType == 4) {
1427  // -- We are an STL container master branch.
1428  TVirtualCollectionProxy* proxy = GetCollectionProxy();
1429  if (!proxy) {
1430  Warning("ResetAddress", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
1431  fObject = 0;
1432  } else {
1433  proxy->Destructor(fObject);
1434  fObject = 0;
1435  }
1436  if (fStreamerType == TVirtualStreamerInfo::kSTLp) {
1437  // -- We are a pointer to an STL container.
1438  // We must zero the pointer in the object.
1439  *((char**) fAddress) = 0;
1440  }
1441  } else {
1442  // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
1443  TClass* cl = fBranchClass.GetClass();
1444  if (!cl) {
1445  Warning("ResetAddress", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
1446  fObject = 0;
1447  } else {
1448  cl->Destructor(fObject);
1449  fObject = 0;
1450  }
1451  }
1452  }
1453 
1454  fObject = 0;
1455  fAddress = 0;
1456  }
1457 }
1458 
1459 
1465 {
1466  fgDoDel = flag;
1467 }
1468 
1469 
1470 
grepfile.info
info
Definition: grepfile.py:38
TConvertingBranchElement.h
A variant of TBranchElement that can call converters when reading objects in split mode.
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
StateLessPT_NewConfig.proxy
proxy
Definition: StateLessPT_NewConfig.py:392
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
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:1375
TConvertingBranchElement::ConvResetType
void ConvResetType()
Recursively reset the type field of containers in conversions.
Definition: TConvertingBranchElement.cxx:753
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:1125
TVirtualConverter.h
Base class for Root converters.
TConvertingBranchElement::InitializeOffsets
virtual void InitializeOffsets()
Initialize data member offsets.
Definition: TConvertingBranchElement.cxx:1301
runBeamSpotCalibration.helper
helper
Definition: runBeamSpotCalibration.py:112
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
runLayerRecalibration.branches
list branches
Definition: runLayerRecalibration.py:98
buildDatabase.alternate
def alternate(gen, dictionary, weight_dict, p_nom)
Definition: buildDatabase.py:110
createCoolChannelIdFile.buffer
buffer
Definition: createCoolChannelIdFile.py:12
lumiFormat.i
int i
Definition: lumiFormat.py:92
TConvertingBranchElement::GetEntry
virtual Int_t GetEntry(Long64_t entry, Int_t getall)
Read all branches into the previously-declared object.
Definition: TConvertingBranchElement.cxx:858
beamspotman.n
n
Definition: beamspotman.py:731
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:977
TConvertingBranchElement::ReadLeavesMemberBranchCountConverting
void ReadLeavesMemberBranchCountConverting(TBuffer &b)
Definition: TConvertingBranchElement.cxx:1069
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:1464
plotIsoValidation.el
el
Definition: plotIsoValidation.py:197
add
bool add(const std::string &hname, TKey *tobj)
Definition: fastadd.cxx:55
TConvertingBranchElement::fConvClass
TClass * fConvClass
Conversion for this branch.
Definition: TConvertingBranchElement.h:198
beamspotman.dir
string dir
Definition: beamspotman.py:623
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:195
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
TConvertingBranchElement::kIsDummy
@ kIsDummy
Definition: TConvertingBranchElement.h:156
TConvertingBranchElement
A variant of TBranchElement that can call converters when reading objects in split mode.
Definition: TConvertingBranchElement.h:72
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:1268
TConvertingBranchElement::ResetAddress
virtual void ResetAddress()
Reset branch addresses and maybe delete the object.
Definition: TConvertingBranchElement.cxx:1388
RTTAlgmain.address
address
Definition: RTTAlgmain.py:55
TConvertingBranchElement::fConvObject
char * fConvObject
Class for conversion.
Definition: TConvertingBranchElement.h:199
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
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:1358
TConverterRegistry.h
Registry for Root converters.
CondAlgsOpts.found
int found
Definition: CondAlgsOpts.py:101
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
TConvertingBranchElement::InitInfo
virtual void InitInfo()
Initialize the TStreamerInfo pointer.
Definition: TConvertingBranchElement.cxx:721
pickleTool.object
object
Definition: pickleTool.py:30
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:164
python.PyAthena.obj
obj
Definition: PyAthena.py:135
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:26
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:611
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