Logo ROOT   6.12/07
Reference Guide
TBranchElement.cxx
Go to the documentation of this file.
1 // @(#)root/tree:$Id$
2 // Authors Rene Brun , Philippe Canal, Markus Frank 14/01/2001
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TBranchElement
13 \ingroup tree
14 
15 A Branch for the case of an object.
16 */
17 
18 #include "TBranchElement.h"
19 
20 #include "TBasket.h"
21 #include "TBranchObject.h"
22 #include "TBranchRef.h"
23 #include "TBrowser.h"
24 #include "TClass.h"
25 #include "TClassEdit.h"
26 #include "TClonesArray.h"
27 #include "TDataMember.h"
28 #include "TDataType.h"
29 #include "TError.h"
30 #include "TMath.h"
31 #include "TFile.h"
32 #include "TFolder.h"
33 #include "TLeafElement.h"
34 #include "TRealData.h"
35 #include "TStreamerElement.h"
36 #include "TStreamerInfo.h"
37 #include "TTree.h"
40 #include "TVirtualMutex.h"
41 #include "TVirtualPad.h"
42 #include "TBranchSTL.h"
43 #include "TVirtualArray.h"
44 #include "TBufferFile.h"
45 #include "TInterpreter.h"
46 #include "TROOT.h"
47 
48 #include "TStreamerInfoActions.h"
49 #include "TSchemaRuleSet.h"
50 
52 
53 ////////////////////////////////////////////////////////////////////////////////
54 
55 namespace {
56  void RemovePrefix(TString& str, const char* prefix) {
57  // -- Remove a prefix from a string.
58  if (str.Length() && prefix && strlen(prefix)) {
59  if (!str.Index(prefix)) {
60  str.Remove(0, strlen(prefix));
61  }
62  }
63  }
64  struct R__PushCache {
65  TBufferFile &fBuffer;
66  TVirtualArray *fOnfileObject;
67 
68  R__PushCache(TBufferFile &b, TVirtualArray *in, UInt_t size) : fBuffer(b), fOnfileObject(in) {
69  if (fOnfileObject) {
70  fOnfileObject->SetSize(size);
71  fBuffer.PushDataCache( fOnfileObject );
72  }
73  }
74  ~R__PushCache() {
75  if (fOnfileObject) fBuffer.PopDataCache();
76  }
77  };
78 }
79 
80 ////////////////////////////////////////////////////////////////////////////////
81 /// Modify the container type of the branches
82 
84  const Int_t nbranches = branches->GetEntriesFast();
85  for (Int_t i = 0; i < nbranches; ++i) {
86  TBranchElement* br = (TBranchElement*) branches->At(i);
87  switch (br->GetType()) {
88  case 31: br->SetType(41); break;
89  case 41: {
90  br->SetType(31);
91  br->fCollProxy = 0;
92  break;
93  }
94  }
95  br->SetReadLeavesPtr();
96  br->SetFillLeavesPtr();
97  // Note: This is a tail recursion.
98  SwitchContainer(br->GetListOfBranches());
99  }
100 }
101 
102 ////////////////////////////////////////////////////////////////////////////////
103 
104 namespace {
105  Bool_t CanSelfReference(TClass *cl) {
106  if (cl) {
107  if (cl->GetCollectionProxy()) {
108  TClass *inside = cl->GetCollectionProxy()->GetValueClass();
109  if (inside) {
110  return CanSelfReference(inside);
111  } else {
112  return kFALSE;
113  }
114  }
115  const static TClassRef stringClass("std::string");
116  if (cl == stringClass || cl == TString::Class()) {
117  return kFALSE;
118  }
119  // Here we could scan through the TStreamerInfo to see if there
120  // is any pointer anywhere and know whether this is a possibility
121  // of selfreference (but watch out for very indirect cases).
122  return kTRUE;
123  }
124  return kFALSE;
125  }
126 }
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Default and I/O constructor.
130 
132 : TBranch()
133 , fClassName()
134 , fParentName()
135 , fClonesName()
136 , fCollProxy(0)
137 , fCheckSum(0)
138 , fClassVersion(0)
139 , fID(0)
140 , fType(0)
141 , fStreamerType(-1)
142 , fMaximum(0)
143 , fSTLtype(ROOT::kNotSTL)
144 , fNdata(1)
145 , fBranchCount(0)
146 , fBranchCount2(0)
147 , fInfo(0)
148 , fObject(0)
149 , fOnfileObject(0)
150 , fInit(kFALSE)
151 , fInInitInfo(kFALSE)
152 , fInitOffsets(kFALSE)
153 , fTargetClass()
154 , fCurrentClass()
155 , fParentClass()
156 , fBranchClass()
157 , fClonesClass()
158 , fBranchOffset(0)
159 , fBranchID(-1)
160 , fReadActionSequence(0)
161 , fFillActionSequence(0)
162 , fIterators(0)
163 , fWriteIterators(0)
164 , fPtrIterators(0)
165 {
166  fNleaves = 0;
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////
172 /// Constructor when the branch object is not a TClonesArray nor an STL container.
173 ///
174 /// If splitlevel > 0 this branch in turn is split into sub-branches.
175 
176 TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
177 : TBranch()
178 , fClassName(sinfo->GetName())
179 , fParentName()
180 , fClonesName()
181 , fCollProxy(0)
182 , fCheckSum(sinfo->GetCheckSum())
184 , fID(id)
185 , fType(0)
186 , fStreamerType(-1)
187 , fMaximum(0)
189 , fNdata(1)
190 , fBranchCount(0)
191 , fBranchCount2(0)
192 , fInfo(sinfo)
193 , fObject(0)
194 , fOnfileObject(0)
195 , fInit(kTRUE)
199 , fCurrentClass()
200 , fParentClass()
201 , fBranchClass(sinfo->GetClass())
202 , fClonesClass()
203 , fBranchOffset(0)
204 , fBranchID(-1)
207 , fIterators(0)
208 , fWriteIterators(0)
209 , fPtrIterators(0)
210 {
211  Init(tree, 0, bname,sinfo,id,pointer,basketsize,splitlevel,btype);
212 }
213 
214 ////////////////////////////////////////////////////////////////////////////////
215 /// Constructor when the branch object is not a TClonesArray nor an STL container.
216 ///
217 /// If splitlevel > 0 this branch in turn is split into sub-branches.
218 
219 TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
220 : TBranch()
221 , fClassName(sinfo->GetName())
222 , fParentName()
223 , fClonesName()
224 , fCollProxy(0)
225 , fCheckSum(sinfo->GetCheckSum())
227 , fID(id)
228 , fType(0)
229 , fStreamerType(-1)
230 , fMaximum(0)
232 , fNdata(1)
233 , fBranchCount(0)
234 , fBranchCount2(0)
235 , fInfo(sinfo)
236 , fObject(0)
237 , fOnfileObject(0)
238 , fInit(kTRUE)
242 , fCurrentClass()
243 , fParentClass()
244 , fBranchClass(sinfo->GetClass())
245 , fClonesClass()
246 , fBranchOffset(0)
247 , fBranchID(-1)
250 , fIterators(0)
251 , fWriteIterators(0)
252 , fPtrIterators(0)
253 {
254  Init(parent ? parent->GetTree() : 0, parent, bname,sinfo,id,pointer,basketsize,splitlevel,btype);
255 }
256 
257 ////////////////////////////////////////////////////////////////////////////////
258 /// Init when the branch object is not a TClonesArray nor an STL container.
259 ///
260 /// If splitlevel > 0 this branch in turn is split into sub-branches.
261 
262 void TBranchElement::Init(TTree *tree, TBranch *parent,const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
263 {
264  TString name(bname);
265 
266  // Set our TNamed attributes.
267  SetName(name);
268  SetTitle(name);
269 
270  // Set our TBranch attributes.
271  fSplitLevel = splitlevel;
272  fTree = tree;
273  if (fTree == 0) return;
274  fMother = parent ? parent->GetMother() : this;
275  fParent = parent;
277  fFileName = "";
278 
279  // Clear the bit kAutoDelete to specify that when reading
280  // the object should not be deleted before calling Streamer.
281 
283 
286 
287  //---------------------------------------------------------------------------
288  // Handling the splitting of the STL collections of pointers
289  /////////////////////////////////////////////////////////////////////////////
290 
291  Int_t splitSTLP = splitlevel - (splitlevel%TTree::kSplitCollectionOfPointers);
292  splitlevel %= TTree::kSplitCollectionOfPointers;
293 
294  fCompress = -1;
295  if (fTree->GetDirectory()) {
296  TFile* bfile = fTree->GetDirectory()->GetFile();
297  if (bfile) {
299  }
300  }
301 
302  //
303  // Initialize streamer type and element.
304  //
305 
306  if (id > -1) {
307  // We are *not* a top-level branch.
308  TStreamerElement* element = sinfo->GetElement(id);
309  fStreamerType = element->GetType();
310  }
311 
312  //
313  // Handle varying-length datatypes by allocating an offsets array.
314  //
315  // The fBits part of a TObject is of varying length because the pidf
316  // is streamed only when the TObject is referenced by a TRef.
317  //
318 
319  fEntryOffsetLen = 0;
322  }
323 
324  //
325  // Make sure the basket is big enough to contain the
326  // entry offset array plus 100 bytes of data.
327  //
328 
329  if (basketsize < (100 + fEntryOffsetLen)) {
330  basketsize = 100 + fEntryOffsetLen;
331  }
332  fBasketSize = basketsize;
333 
334  //
335  // Allocate and initialize the basket control arrays.
336  //
337 
341 
342  for (Int_t i = 0; i < fMaxBaskets; ++i) {
343  fBasketBytes[i] = 0;
344  fBasketEntry[i] = 0;
345  fBasketSeek[i] = 0;
346  }
347 
348  // We need to keep track of the counter branch if we have
349  // one, since we cannot set it until we have created our
350  // leaf, which we do last.
351  TBranchElement* brOfCounter = 0;
352 
353  if (id < 0) {
354  // -- We are a top-level branch. Don't split a top-level branch, TTree::Bronch will do that work.
355  if (fBranchClass.GetClass()) {
356  Bool_t hasCustomStreamer = kFALSE;
357  Bool_t canSelfReference = CanSelfReference(fBranchClass);
358  if (fBranchClass.GetClass()->IsTObject()) {
359  if (canSelfReference) SetBit(kBranchObject);
361  } else {
362  if (canSelfReference) SetBit(kBranchAny);
364  }
365  if (hasCustomStreamer) {
366  fType = -1;
367  }
368  }
369  } else {
370  // -- We are a sub-branch of a split object.
371  TStreamerElement* element = sinfo->GetElement(id);
373  // -- If we are an object data member which inherits from TObject,
374  // flag it so that later during i/o we will register the object
375  // with the buffer so that pointers are handled correctly.
376  if (CanSelfReference(fBranchClass)) {
377  if (fBranchClass.GetClass()->IsTObject()) {
379  } else {
381  }
382  }
383  }
384  if (element->IsA() == TStreamerBasicPointer::Class()) {
385  // -- Fixup title with counter if we are a varying length array data member.
387  TString countname;
388  countname = bname;
389  Ssiz_t dot = countname.Last('.');
390  if (dot>=0) {
391  countname.Remove(dot+1);
392  } else {
393  countname = "";
394  }
395  countname += bp->GetCountName();
396  brOfCounter = (TBranchElement *)fTree->GetBranch(countname);
397  countname.Form("%s[%s]",name.Data(),bp->GetCountName());
398  SetTitle(countname);
399 
400  } else if (element->IsA() == TStreamerLoop::Class()) {
401  // -- Fixup title with counter if we are a varying length array data member.
402  TStreamerLoop *bp = (TStreamerLoop *)element;
403  TString countname;
404  countname = bname;
405  Ssiz_t dot = countname.Last('.');
406  if (dot>=0) {
407  countname.Remove(dot+1);
408  } else {
409  countname = "";
410  }
411  countname += bp->GetCountName();
412  brOfCounter = (TBranchElement *)fTree->GetBranch(countname);
413  countname.Form("%s[%s]",name.Data(),bp->GetCountName());
414  SetTitle(countname);
415 
416  }
417 
418  if (splitlevel > 0) {
419  // -- Create sub branches if requested by splitlevel.
420  const char* elemType = element->GetTypeName();
421  TClass *elementClass = element->GetClassPointer();
422  fSTLtype = elementClass ? elementClass->GetCollectionType() : ROOT::kNotSTL;
423  if (element->CannotSplit()) {
424  fSplitLevel = 0;
425  } else if (element->IsA() == TStreamerBase::Class()) {
426  // -- We are a base class element.
427  // Note: This does not include an STL container class which is
428  // being used as a base class because the streamer element
429  // in that case is not the base streamer element it is the
430  // STL streamer element.
431  fType = 1;
432  TClass* clOfElement = element->GetClassPointer();
433  Int_t nbranches = fBranches.GetEntriesFast();
434  // Note: The following code results in base class branches
435  // having two different cases for what their parent
436  // class will be, this is very annoying. It is also
437  // very annoying that the naming conventions for the
438  // sub-branch names are different as well.
439  if (!strcmp(name, clOfElement->GetName())) {
440  // -- If the branch's name is the same as the base class name,
441  // which happens when we are a child branch of a top-level
442  // branch whose name does not end in a dot and also has no
443  // internal dots, elide the branch name, and keep the branch
444  // heirarchy rooted at the ultimate parent, this keeps the base
445  // class part of the branch name from propagating downwards.
446  // FIXME: We are eliding the base class here, creating a break in the branch hierarchy.
447  // Note: We can use parent class (cltop) != branch class (elemClass) to detection elision.
448  Unroll("", fBranchClass.GetClass(), clOfElement, pointer, basketsize, splitlevel+splitSTLP, 0);
451  return;
452  }
453  // If the branch's name is not the same as the base class name,
454  // keep the branch name as a prefix (i.e., continue the branch
455  // heirarchy), but start a new class heirarchy at the base class.
456  //
457  // Note: If the parent branch was created by the branch constructor
458  // which takes a folder as a parameter, then this case will
459  // be used, because the branch name will be the same as the
460  // parent branch name.
461  // Note: This means that the sub-branches of a base class branch
462  // created by TTree::Bronch() have the base class name as
463  // as part of the branch name, while those created by
464  // Unroll() do not, ouch!!!
465  //
466  Unroll(name, clOfElement, clOfElement, pointer, basketsize, splitlevel+splitSTLP, 0);
467  if (strchr(bname, '.')) {
468  // Note: How can this happen?
469  // Answer: This is the case when using the new branch
470  // naming convention where the top-level branch ends in dot.
471  // Note: Well actually not entirely, we could also be a sub-branch
472  // of a split class, even when the top-level branch does not
473  // end in a dot.
474  // Note: Or the top-level branch could have been created by the
475  // branch constructor which takes a folder as input, in which
476  // case the top-level branch name will have internal dots
477  // representing the folder hierarchy.
480  return;
481  }
482  if (nbranches == fBranches.GetEntriesFast()) {
483  // -- We did not add any branches in the Unroll, finalize our name to be the base class name, because Unroll did not do it for us.
484  if (strlen(bname)) {
485  name.Form("%s.%s", bname, clOfElement->GetName());
486  } else {
487  name.Form("%s", clOfElement->GetName());
488  }
489  SetName(name);
490  SetTitle(name);
491  }
494  return;
495  } else if (element->GetClassPointer() == TClonesArray::Class()) {
496  // -- We are a TClonesArray element.
497  Bool_t ispointer = element->IsaPointer();
498  TClonesArray *clones;
499  if (ispointer) {
500  char **ppointer = (char**)(pointer);
501  clones = (TClonesArray*)(*ppointer);
502  } else {
503  clones = (TClonesArray*)pointer;
504  }
505  // basket->DeleteEntryOffset(); //entryoffset not required for the clonesarray counter
506  fEntryOffsetLen = 0;
507  // ===> Create a leafcount
508  TLeaf* leaf = new TLeafElement(this, name, fID, fStreamerType);
509  fNleaves = 1;
510  fLeaves.Add(leaf);
511  fTree->GetListOfLeaves()->Add(leaf);
512  if (!clones) {
514  return;
515  }
516  TClass* clOfClones = clones->GetClass();
517  if (!clOfClones) {
520  return;
521  }
522  fType = 3;
523  // ===> create sub branches for each data member of a TClonesArray
524  //check that the contained objects class name is part of the element title
525  //This name is mandatory when reading the Tree later on and
526  //the parent class with the pointer to the TClonesArray is not available.
527  fClonesName = clOfClones->GetName();
528  fClonesClass = clOfClones;
529  TString aname;
530  aname.Form(" (%s)", clOfClones->GetName());
531  TString atitle = element->GetTitle();
532  if (!atitle.Contains(aname)) {
533  atitle += aname;
534  element->SetTitle(atitle.Data());
535  }
536  TString branchname( name );
537  branchname += "_";
538  SetTitle(branchname);
539  leaf->SetName(branchname);
540  leaf->SetTitle(branchname);
541  Unroll(name, clOfClones, clOfClones, pointer, basketsize, splitlevel+splitSTLP, 31);
542  BuildTitle(name);
545  return;
546  } else if (((fSTLtype >= ROOT::kSTLvector) && (fSTLtype < ROOT::kSTLend)) || ((fSTLtype > -ROOT::kSTLend) && (fSTLtype <= -ROOT::kSTLvector))) {
547  // -- We are an STL container element.
548  TClass* contCl = elementClass;
549  fCollProxy = contCl->GetCollectionProxy()->Generate();
550  TClass* valueClass = GetCollectionProxy()->GetValueClass();
551  // Check to see if we can split the container.
552  Bool_t cansplit = kTRUE;
553  if (!valueClass) {
554  cansplit = kFALSE;
555  } else if ((valueClass == TString::Class()) || (valueClass == TClass::GetClass("string"))) {
556  cansplit = kFALSE;
557  } else if (GetCollectionProxy()->HasPointers() && !splitSTLP ) {
558  cansplit = kFALSE;
559  } else if (!valueClass->CanSplit() && !(GetCollectionProxy()->HasPointers() && splitSTLP)) {
560  cansplit = kFALSE;
561  } else if (valueClass->GetCollectionProxy()) {
562  // -- A collection was stored in a collection, we choose not to split it.
563  // Note: Splitting it would require extending TTreeFormula
564  // to understand how to access it.
565  cansplit = kFALSE;
566  }
567  if (cansplit) {
568  // -- Do the splitting work if we are allowed to.
569  fType = 4;
570  // Create a leaf for the master branch (the counter).
571  TLeaf *leaf = new TLeafElement(this, name, fID, fStreamerType);
572  fNleaves = 1;
573  fLeaves.Add(leaf);
574  fTree->GetListOfLeaves()->Add(leaf);
575  // Check that the contained objects class name is part of the element title.
576  // This name is mandatory when reading the tree later on and
577  // the parent class with the pointer to the STL container is not available.
578  fClonesName = valueClass->GetName();
579  fClonesClass = valueClass;
580  TString aname;
581  aname.Form(" (%s)", valueClass->GetName());
582  TString atitle = element->GetTitle();
583  if (!atitle.Contains(aname)) {
584  atitle += aname;
585  element->SetTitle(atitle.Data());
586  }
587  TString branchname (name);
588  branchname += "_";
589  SetTitle(branchname);
590  leaf->SetName(branchname);
591  leaf->SetTitle(branchname);
592  // Create sub branches for each data member of an STL container.
593  Unroll(name, valueClass, valueClass, pointer, basketsize, splitlevel+splitSTLP, 41);
594  BuildTitle(name);
597  return;
598  }
599  } else if (!strchr(elemType, '*') && ((fStreamerType == TVirtualStreamerInfo::kObject) || (fStreamerType == TVirtualStreamerInfo::kAny))) {
600  // -- Create sub-branches for members that are classes.
601  //
602  // Note: This can only happen if we were called directly
603  // (usually by TClass::Bronch) because Unroll never
604  // calls us for an element of this type.
605  fType = 2;
606  TClass* clm = elementClass;
607  Int_t err = Unroll(name, clm, clm, pointer, basketsize, splitlevel+splitSTLP, 0);
608  if (err >= 0) {
609  // Return on success.
610  // FIXME: Why not on error too?
613  return;
614  }
615  }
616  }
617  }
618 
619  //
620  // Create a leaf to represent this branch.
621  //
622 
623  TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
624  leaf->SetTitle(GetTitle());
625  fNleaves = 1;
626  fLeaves.Add(leaf);
627  fTree->GetListOfLeaves()->Add(leaf);
628 
629  //
630  // If we have a counter branch set it now that we have
631  // created our leaf, we cannot do it before then.
632  //
633 
634  if (brOfCounter) {
635  SetBranchCount(brOfCounter);
636  }
637 
640 }
641 
642 ////////////////////////////////////////////////////////////////////////////////
643 /// Constructor when the branch object is a TClonesArray.
644 ///
645 /// If splitlevel > 0 this branch in turn is split into sub branches.
646 
647 TBranchElement::TBranchElement(TTree *tree, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress)
648 : TBranch()
649 , fClassName("TClonesArray")
650 , fParentName()
651 , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo())
652 , fInit(kTRUE)
656 , fCurrentClass()
657 , fParentClass()
659 , fBranchID(-1)
662 , fIterators(0)
663 , fWriteIterators(0)
664 , fPtrIterators(0)
665 {
666  Init(tree, 0, bname, clones, basketsize, splitlevel, compress);
667 }
668 
669 ////////////////////////////////////////////////////////////////////////////////
670 /// Constructor when the branch object is a TClonesArray.
671 ///
672 /// If splitlevel > 0 this branch in turn is split into sub branches.
673 
674 TBranchElement::TBranchElement(TBranch *parent, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress)
675 : TBranch()
676 , fClassName("TClonesArray")
677 , fParentName()
678 , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo())
679 , fInit(kTRUE)
683 , fCurrentClass()
684 , fParentClass()
686 , fBranchID(-1)
689 , fIterators(0)
690 , fWriteIterators(0)
691 , fPtrIterators(0)
692 {
693  Init(parent ? parent->GetTree() : 0, parent, bname, clones, basketsize, splitlevel, compress);
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////////
697 /// Init when the branch object is a TClonesArray.
698 ///
699 /// If splitlevel > 0 this branch in turn is split into sub branches.
700 
701 void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress)
702 {
703  fCollProxy = 0;
704  fSplitLevel = splitlevel;
705  fID = 0;
706  fInit = kTRUE;
707  fStreamerType = -1;
708  fType = 0;
709  fClassVersion = TClonesArray::Class()->GetClassVersion();
711  fBranchCount = 0;
712  fBranchCount2 = 0;
713  fObject = 0;
714  fOnfileObject = 0;
715  fMaximum = 0;
716  fBranchOffset = 0;
719 
720  fTree = tree;
721  fMother = parent ? parent->GetMother() : this;
722  fParent = parent;
724  fFileName = "";
725 
726  SetName(bname);
727  const char* name = GetName();
728  SetTitle(name);
729  //fClassName = fInfo->GetName();
730  fCompress = compress;
731  if (compress == -1 && fTree->GetDirectory()) {
732  TFile *bfile = fTree->GetDirectory()->GetFile();
733  if (bfile) fCompress = bfile->GetCompressionSettings();
734  }
735 
736  if (basketsize < 100) basketsize = 100;
737  fBasketSize = basketsize;
741 
742  for (Int_t i=0;i<fMaxBaskets;i++) {
743  fBasketBytes[i] = 0;
744  fBasketEntry[i] = 0;
745  fBasketSeek[i] = 0;
746  }
747 
748  // Reset the bit kAutoDelete to specify that when reading
749  // the object should not be deleted before calling the streamer.
751 
752  // create sub branches if requested by splitlevel
753  if (splitlevel%TTree::kSplitCollectionOfPointers > 0) {
754  TClass* clonesClass = clones->GetClass();
755  if (!clonesClass) {
756  Error("Init","Missing class object of the TClonesArray %s\n",clones->GetName());
757  return;
758  }
759  fType = 3;
760  // ===> Create a leafcount
761  TLeaf* leaf = new TLeafElement(this, name, fID, fStreamerType);
762  fNleaves = 1;
763  fLeaves.Add(leaf);
764  fTree->GetListOfLeaves()->Add(leaf);
765  // ===> create sub branches for each data member of a TClonesArray
766  fClonesName = clonesClass->GetName();
767  fClonesClass = clonesClass;
768  std::string branchname = name + std::string("_");
769  SetTitle(branchname.c_str());
770  leaf->SetName(branchname.c_str());
771  leaf->SetTitle(branchname.c_str());
772  Unroll(name, clonesClass, clonesClass, 0, basketsize, splitlevel, 31);
773  BuildTitle(name);
776  return;
777  }
778 
779  if (!clones->GetClass() || CanSelfReference(clones->GetClass())) {
781  }
782  TLeaf *leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
783  leaf->SetTitle(GetTitle());
784  fNleaves = 1;
785  fLeaves.Add(leaf);
786  fTree->GetListOfLeaves()->Add(leaf);
787 
790 }
791 
792 ////////////////////////////////////////////////////////////////////////////////
793 /// Constructor when the branch object is an STL collection.
794 ///
795 /// If splitlevel > 0 this branch in turn is split into sub branches.
796 
797 TBranchElement::TBranchElement(TTree *tree, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress)
798 : TBranch()
799 , fClassName(cont->GetCollectionClass()->GetName())
800 , fParentName()
801 , fInit(kTRUE)
805 , fCurrentClass()
806 , fParentClass()
807 , fBranchClass(cont->GetCollectionClass())
808 , fBranchID(-1)
811 , fIterators(0)
812 , fWriteIterators(0)
813 , fPtrIterators(0)
814 {
815  Init(tree, 0, bname, cont, basketsize, splitlevel, compress);
816 }
817 
818 ////////////////////////////////////////////////////////////////////////////////
819 /// Constructor when the branch object is an STL collection.
820 ///
821 /// If splitlevel > 0 this branch in turn is split into sub branches.
822 
823 TBranchElement::TBranchElement(TBranch *parent, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress)
824 : TBranch()
825 , fClassName(cont->GetCollectionClass()->GetName())
826 , fParentName()
827 , fInit(kTRUE)
831 , fCurrentClass()
832 , fParentClass()
833 , fBranchClass(cont->GetCollectionClass())
834 , fBranchID(-1)
837 , fIterators(0)
838 , fWriteIterators(0)
839 , fPtrIterators(0)
840 {
841  Init(parent ? parent->GetTree() : 0, parent, bname, cont, basketsize, splitlevel, compress);
842 }
843 
844 ////////////////////////////////////////////////////////////////////////////////
845 /// Init when the branch object is an STL collection.
846 ///
847 /// If splitlevel > 0 this branch in turn is split into sub branches.
848 
849 void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress)
850 {
851  fCollProxy = cont->Generate();
852  TString name( bname );
853  if (name[name.Length()-1]=='.') {
854  name.Remove(name.Length()-1);
855  }
857  fSplitLevel = splitlevel;
858  fInfo = 0;
859  fID = -1;
860  fInit = kTRUE;
861  fStreamerType = -1; // TVirtualStreamerInfo::kSTLp;
862  fType = 0;
865  fBranchCount = 0;
866  fBranchCount2 = 0;
867  fObject = 0;
868  fOnfileObject = 0;
869  fMaximum = 0;
870  fBranchOffset = 0;
871 
872  //Must be set here so that write actions will be properly matched to the ReadLeavesPtr
873  fSTLtype = cont->GetCollectionType();
874  if (fSTLtype < 0) {
875  fSTLtype = -fSTLtype;
876  }
877 
878  fTree = tree;
879  fMother = parent ? parent->GetMother() : this;
880  fParent = parent;
882  fFileName = "";
883 
884  SetName(name);
885  SetTitle(name);
886  //fClassName = fBranchClass.GetClass()->GetName();
887  fCompress = compress;
888  if ((compress == -1) && fTree->GetDirectory()) {
889  TFile* bfile = fTree->GetDirectory()->GetFile();
890  if (bfile) {
892  }
893  }
894 
895  if (basketsize < 100) {
896  basketsize = 100;
897  }
898  fBasketSize = basketsize;
899 
903 
904  for (Int_t i = 0; i < fMaxBaskets; ++i) {
905  fBasketBytes[i] = 0;
906  fBasketEntry[i] = 0;
907  fBasketSeek[i] = 0;
908  }
909 
910  // Reset the bit kAutoDelete to specify that, when reading,
911  // the object should not be deleted before calling the streamer.
913 
914  // create sub branches if requested by splitlevel
916  (cont->HasPointers() && splitlevel > TTree::kSplitCollectionOfPointers && cont->GetValueClass() && cont->GetValueClass()->CanSplit() ) )
917  {
918  fType = 4;
919  // ===> Create a leafcount
920  TLeaf* leaf = new TLeafElement(this, name, fID, fStreamerType);
921  fNleaves = 1;
922  fLeaves.Add(leaf);
923  fTree->GetListOfLeaves()->Add(leaf);
924  // ===> create sub branches for each data member of an STL container value class
925  TClass* valueClass = cont->GetValueClass();
926  if (!valueClass) {
927  return;
928  }
929  fClonesName = valueClass->GetName();
930  fClonesClass = valueClass;
931  TString branchname( name );
932  branchname += "_";
933  SetTitle(branchname);
934  leaf->SetName(branchname);
935  leaf->SetTitle(branchname);
936  Unroll(name, valueClass, valueClass, 0, basketsize, splitlevel, 41);
937  BuildTitle(name);
940  return;
941  }
942 
943  TLeaf *leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
944  leaf->SetTitle(GetTitle());
945  fNleaves = 1;
946  fLeaves.Add(leaf);
947  fTree->GetListOfLeaves()->Add(leaf);
950 }
951 
952 ////////////////////////////////////////////////////////////////////////////////
953 /// Destructor.
954 
956 {
957  // Release any allocated I/O buffers.
958  if (fOnfileObject && TestBit(kOwnOnfileObj)) {
959  delete fOnfileObject;
960  fOnfileObject = 0;
961  }
962  ResetAddress();
963 
964  delete[] fBranchOffset;
965  fBranchOffset = 0;
966 
967  fInfo = 0;
968  fBranchCount2 = 0;
969  fBranchCount = 0;
970 
971  if (fType == 4 || fType == 0) {
972  // Only the top level TBranchElement containing an STL container,
973  // owns the collectionproxy.
974  delete fCollProxy;
975  }
976  fCollProxy = 0;
977 
978  delete fReadActionSequence;
979  delete fFillActionSequence;
980  delete fIterators;
981  delete fWriteIterators;
982  delete fPtrIterators;
983 }
984 
985 //
986 // This function is located here to allow inlining by the optimizer.
987 //
988 ////////////////////////////////////////////////////////////////////////////////
989 /// Get streamer info for the branch class.
990 
992 {
993  // Note: we need to find a way to reduce the complexity of
994  // this often executed condition.
995  if (!fInfo || (fInfo && (!fInit || !fInfo->IsCompiled()))) {
996  const_cast<TBranchElement*>(this)->InitInfo();
997  }
998  return fInfo;
999 }
1000 
1001 ////////////////////////////////////////////////////////////////////////////////
1002 /// Get streamer info for the branch class.
1003 
1005 {
1006  return GetInfoImp();
1007 }
1008 
1009 ////////////////////////////////////////////////////////////////////////////////
1010 /// Browse the branch content.
1011 
1013 {
1014  Int_t nbranches = fBranches.GetEntriesFast();
1015  if (nbranches > 0) {
1016  TList persistentBranches;
1017  TBranch* branch=0;
1018  TIter iB(&fBranches);
1019  while((branch=(TBranch*)iB())) {
1020  if (branch->IsFolder()) persistentBranches.Add(branch);
1021  else {
1022  // only show branches corresponding to persistent members
1023  TClass* cl=0;
1024  if (strlen(GetClonesName()))
1025  // this works both for top level branches and for sub-branches,
1026  // as GetClonesName() is properly updated for sub-branches
1027  cl=fClonesClass;
1028  else {
1030 
1031  // check if we're in a sub-branch of this class
1032  // we can only find out asking the streamer given our ID
1033  TStreamerElement *element=0;
1034  TClass* clsub=0;
1035  if (fID>=0 && GetInfoImp()
1036  && GetInfoImp()->IsCompiled()
1037  && ((element=GetInfoImp()->GetElement(fID)))
1038  && ((clsub=element->GetClassPointer())))
1039  cl=clsub;
1040  }
1041  if (cl) {
1042  TString strMember=branch->GetName();
1043  Size_t mempos=strMember.Last('.');
1044  if (mempos!=kNPOS)
1045  strMember.Remove(0, (Int_t)mempos+1);
1046  mempos=strMember.First('[');
1047  if (mempos!=kNPOS)
1048  strMember.Remove((Int_t)mempos);
1049  TDataMember* m=cl->GetDataMember(strMember);
1050  if (!m || m->IsPersistent()) persistentBranches.Add(branch);
1051  } else persistentBranches.Add(branch);
1052  } // branch if not a folder
1053  }
1054  persistentBranches.Browse(b);
1055  // add all public const methods without params
1056  if (GetBrowsables() && GetBrowsables()->GetSize())
1057  GetBrowsables()->Browse(b);
1058  } else {
1059  if (GetBrowsables() && GetBrowsables()->GetSize()) {
1060  GetBrowsables()->Browse(b);
1061  return;
1062  }
1063  // Get the name and strip any extra brackets
1064  // in order to get the full arrays.
1065  TString slash("/");
1066  TString escapedSlash("\\/");
1067  TString name = GetName();
1068  Int_t pos = name.First('[');
1069  if (pos != kNPOS) {
1070  name.Remove(pos);
1071  }
1072  TString mothername;
1073  if (GetMother()) {
1074  mothername = GetMother()->GetName();
1075  pos = mothername.First('[');
1076  if (pos != kNPOS) {
1077  mothername.Remove(pos);
1078  }
1079  Int_t len = mothername.Length();
1080  if (len) {
1081  if (mothername(len-1) != '.') {
1082  // We do not know for sure whether the mother's name is
1083  // already preprended. So we need to check:
1084  // a) it is prepended
1085  // b) it is NOT the name of a daugher (i.e. mothername.mothername exist)
1086  TString doublename = mothername;
1087  doublename.Append(".");
1088  Int_t isthere = (name.Index(doublename) == 0);
1089  if (!isthere) {
1090  name.Prepend(doublename);
1091  } else {
1092  if (GetMother()->FindBranch(mothername)) {
1093  doublename.Append(mothername);
1094  isthere = (name.Index(doublename) == 0);
1095  if (!isthere) {
1096  mothername.Append(".");
1097  name.Prepend(mothername);
1098  }
1099  } else {
1100  // Nothing to do because the mother's name is
1101  // already in the name.
1102  }
1103  }
1104  } else {
1105  // If the mother's name end with a dot then
1106  // the daughter probably already contains the mother's name
1107  if (name.Index(mothername) == kNPOS) {
1108  name.Prepend(mothername);
1109  }
1110  }
1111  }
1112  }
1113  name.ReplaceAll(slash, escapedSlash);
1114  GetTree()->Draw(name, "", b ? b->GetDrawOption() : "");
1115  if (gPad) {
1116  gPad->Update();
1117  }
1118  }
1119 }
1120 
1121 ////////////////////////////////////////////////////////////////////////////////
1122 /// Set branch and leaf name and title in the case of a container sub-branch.
1123 
1125 {
1126  TString branchname;
1127 
1128  Int_t nbranches = fBranches.GetEntries();
1129 
1130  for (Int_t i = 0; i < nbranches; ++i) {
1132  if (fType == 3) {
1133  bre->SetType(31);
1134  } else if (fType == 4) {
1135  bre->SetType(41);
1136  } else {
1137  Error("BuildTitle", "This cannot happen, fType of parent is not 3 or 4!");
1138  }
1139  bre->fCollProxy = GetCollectionProxy();
1140  bre->BuildTitle(name);
1141  const char* fin = strrchr(bre->GetTitle(), '.');
1142  if (fin == 0) {
1143  continue;
1144  }
1145  // The branch counter for a sub-branch of a container is the container master branch.
1146  bre->SetBranchCount(this);
1147  TLeafElement* lf = (TLeafElement*) bre->GetListOfLeaves()->At(0);
1148  // If branch name is of the form fTracks.fCovar[3][4], then
1149  // set the title to fCovar[fTracks_].
1150  branchname = fin+1;
1151  Ssiz_t dim = branchname.First('[');
1152  if (dim>=0) {
1153  branchname.Remove(dim);
1154  }
1155  branchname += TString::Format("[%s_]",name);
1156  bre->SetTitle(branchname);
1157  if (lf) {
1158  lf->SetTitle(branchname);
1159  }
1160  // Is there a secondary branchcount?
1161  //
1162  // fBranchCount2 points to the secondary branchcount
1163  // in case a TClonesArray element itself has a branchcount.
1164  //
1165  // Example: In Event class with TClonesArray fTracks of Track objects.
1166  // if the Track object has two members
1167  // Int_t fNpoint;
1168  // Float_t *fPoints; //[fNpoint]
1169  // In this case the TBranchElement fTracks.fPoints has
1170  // -its primary branchcount pointing to the branch fTracks
1171  // -its secondary branchcount pointing to fTracks.fNpoint
1172  Int_t stype = bre->GetStreamerType();
1173  // FIXME: Should 60 be included here?
1174  if ((stype > 40) && (stype < 61)) {
1175  TString name2 (bre->GetName());
1176  Ssiz_t bn = name2.Last('.');
1177  if (bn<0) {
1178  continue;
1179  }
1180  TStreamerBasicPointer *el = (TStreamerBasicPointer*)bre->GetInfoImp()->GetElements()->FindObject(name2.Data()+bn+1);
1181  name2.Remove(bn+1);
1182  if (el) name2 += el->GetCountName();
1184  bre->SetBranchCount2(bc2);
1185  }
1186  bre->SetReadLeavesPtr();
1187  bre->SetFillLeavesPtr();
1188  }
1189 }
1190 
1191 ////////////////////////////////////////////////////////////////////////////////
1192 /// Loop on all leaves of this branch to fill the basket buffer.
1193 ///
1194 /// The function returns the number of bytes committed to the
1195 /// individual branches. If a write error occurs, the number of
1196 /// bytes returned is -1. If no data are written, because, e.g.,
1197 /// the branch is disabled, the number of bytes returned is 0.
1198 ///
1199 /// Note: We not not use any member functions from TLeafElement!
1200 
1202 {
1203  Int_t nbytes = 0;
1204  Int_t nwrite = 0;
1205  Int_t nerror = 0;
1206  Int_t nbranches = fBranches.GetEntriesFast();
1207 
1208  ValidateAddress();
1209 
1210  //
1211  // If we are a top-level branch, update addresses.
1212  //
1213 
1214  if (fID < 0) {
1215  if (!fObject) {
1216  Error("Fill", "attempt to fill branch %s while addresss is not set", GetName());
1217  return 0;
1218  }
1219  }
1220 
1221  //
1222  // If the tree has a TRefTable, set the current branch if
1223  // branch is not a basic type.
1224  //
1225 
1226  // FIXME: This test probably needs to be extended past 10.
1227  if ((fType >= -1) && (fType < 10)) {
1228  TBranchRef* bref = fTree->GetBranchRef();
1229  if (bref) {
1230  fBranchID = bref->SetParent(this, fBranchID);
1231  }
1232  }
1233 
1234  if (!nbranches) {
1235  // No sub-branches.
1236  if (!TestBit(kDoNotProcess)) {
1237  nwrite = TBranch::FillImpl(imtHelper);
1238  if (nwrite < 0) {
1239  Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1240  ++nerror;
1241  } else {
1242  nbytes += nwrite;
1243  }
1244  }
1245  } else {
1246  // We have sub-branches.
1247  if (fType == 3 || fType == 4) {
1248  // TClonesArray or STL container counter
1249  nwrite = TBranch::FillImpl(imtHelper);
1250  if (nwrite < 0) {
1251  Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1252  ++nerror;
1253  } else {
1254  nbytes += nwrite;
1255  }
1256  } else {
1257  ++fEntries;
1258  }
1259  for (Int_t i = 0; i < nbranches; ++i) {
1260  TBranchElement* branch = (TBranchElement*) fBranches[i];
1261  if (!branch->TestBit(kDoNotProcess)) {
1262  nwrite = branch->FillImpl(imtHelper);
1263  if (nwrite < 0) {
1264  Error("Fill", "Failed filling branch:%s.%s, nbytes=%d", GetName(), branch->GetName(), nwrite);
1265  nerror++;
1266  } else {
1267  nbytes += nwrite;
1268  }
1269  }
1270  }
1271  }
1272 
1273  if (fTree->Debug() > 0) {
1274  // Debugging.
1275  Long64_t entry = fEntries;
1276  if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
1277  printf("Fill: %lld, branch=%s, nbytes=%d\n", entry, GetName(), nbytes);
1278  }
1279  }
1280 
1281  if (nerror != 0) {
1282  return -1;
1283  }
1284 
1285  return nbytes;
1286 }
1287 
1288 ////////////////////////////////////////////////////////////////////////////////
1289 /// Write leaves into i/o buffers for this branch.
1290 /// For the case where the branch is set in MakeClass mode (decomposed object).
1291 
1293 {
1294  ValidateAddress();
1295 
1296  //
1297  // Silently do nothing if we have no user i/o buffer.
1298  //
1299 
1300  if (!fObject) {
1301  return;
1302  }
1303 
1304  // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1305  if(fType == 3) {
1306  // fClonesClass can not be zero since we are of type 3, see TBranchElement::Init
1308  if (!si) {
1309  Error("FillLeaves", "Cannot get streamer info for branch '%s' class '%s'", GetName(), fClonesClass->GetName());
1310  return;
1311  }
1312  b.ForceWriteInfo(si,kFALSE);
1313  Int_t* nptr = (Int_t*) fAddress;
1314  b << *nptr;
1315  } else if (fType == 31) {
1316  // -- TClonesArray sub-branch. Write out the entries in the TClonesArray.
1317  // -- A MakeClass() tree, we must use fAddress instead of fObject.
1318  if (!fAddress) {
1319  // FIXME: Enable this message.
1320  //Error("FillLeaves", "Branch address not set for branch '%s'!", GetName());
1321  return;
1322  }
1323  Int_t atype = fStreamerType;
1324  if (atype > 54) {
1325  // Note: We are not supporting kObjectp, kAny, kObjectp,
1326  // kObjectP, kTString, kTObject, kTNamed, kAnyp,
1327  // kAnyP, kSTLp, kSTL, kSTLstring, kStreamer,
1328  // kStreamLoop here, nor pointers to varying length
1329  // arrays of them either.
1330  // Nor do we support pointers to varying length
1331  // arrays of kBits, kLong64, kULong64, nor kBool.
1332  return;
1333  }
1334  Int_t* nn = (Int_t*) fBranchCount->GetAddress();
1335  if (!nn) {
1336  Error("FillLeaves", "The branch counter address was zero!");
1337  return;
1338  }
1339  Int_t n = *nn;
1340  if (atype > 40) {
1341  // Note: We are not supporting pointer to varying length array.
1342  Error("FillLeaves", "Clonesa: %s, n=%d, sorry not supported yet", GetName(), n);
1343  return;
1344  }
1345  if (atype > 20) {
1346  atype -= 20;
1348  n = n * leaf->GetLenStatic();
1349  }
1350  switch (atype) {
1351  // Note: Type 0 is a base class and cannot happen here, see Unroll().
1352  case TVirtualStreamerInfo::kChar /* 1 */: { b.WriteFastArray((Char_t*) fAddress, n); break; }
1353  case TVirtualStreamerInfo::kShort /* 2 */: { b.WriteFastArray((Short_t*) fAddress, n); break; }
1354  case TVirtualStreamerInfo::kInt /* 3 */: { b.WriteFastArray((Int_t*) fAddress, n); break; }
1355  case TVirtualStreamerInfo::kLong /* 4 */: { b.WriteFastArray((Long_t*) fAddress, n); break; }
1356  case TVirtualStreamerInfo::kFloat /* 5 */: { b.WriteFastArray((Float_t*) fAddress, n); break; }
1357  case TVirtualStreamerInfo::kCounter /* 6 */: { b.WriteFastArray((Int_t*) fAddress, n); break; }
1358  // FIXME: We do nothing with type 7 (TVirtualStreamerInfo::kCharStar, char*) here!
1359  case TVirtualStreamerInfo::kDouble /* 8 */: { b.WriteFastArray((Double_t*) fAddress, n); break; }
1360  case TVirtualStreamerInfo::kDouble32 /* 9 */: {
1362  // coverity[returned_null] structurally si->fComp (used in GetElem) can not be null.
1363  TStreamerElement* se = si->GetElement(fID);
1364  Double_t* xx = (Double_t*) fAddress;
1365  for (Int_t ii = 0; ii < n; ++ii) {
1366  b.WriteDouble32(&(xx[ii]),se);
1367  }
1368  break;
1369  }
1370  case TVirtualStreamerInfo::kFloat16 /* 19 */: {
1372  // coverity[dereference] structurally si can not be null.
1374  Float_t* xx = (Float_t*) fAddress;
1375  for (Int_t ii = 0; ii < n; ++ii) {
1376  b.WriteFloat16(&(xx[ii]),se);
1377  }
1378  break;
1379  }
1380  // Note: Type 10 is unused for now.
1381  case TVirtualStreamerInfo::kUChar /* 11 */: { b.WriteFastArray((UChar_t*) fAddress, n); break; }
1382  case TVirtualStreamerInfo::kUShort /* 12 */: { b.WriteFastArray((UShort_t*) fAddress, n); break; }
1383  case TVirtualStreamerInfo::kUInt /* 13 */: { b.WriteFastArray((UInt_t*) fAddress, n); break; }
1384  case TVirtualStreamerInfo::kULong /* 14 */: { b.WriteFastArray((ULong_t*) fAddress, n); break; }
1385  // FIXME: This is wrong!!! TVirtualStreamerInfo::kBits is a variable length type.
1386  case TVirtualStreamerInfo::kBits /* 15 */: { b.WriteFastArray((UInt_t*) fAddress, n); break; }
1387  case TVirtualStreamerInfo::kLong64 /* 16 */: { b.WriteFastArray((Long64_t*) fAddress, n); break; }
1388  case TVirtualStreamerInfo::kULong64 /* 17 */: { b.WriteFastArray((ULong64_t*) fAddress, n); break; }
1389  case TVirtualStreamerInfo::kBool /* 18 */: { b.WriteFastArray((Bool_t*) fAddress, n); break; }
1390  }
1391  }
1392 }
1393 
1394 ////////////////////////////////////////////////////////////////////////////////
1395 /// Write leaves into i/o buffers for this branch.
1396 /// Case of a collection (fType == 4).
1397 
1399 {
1400  // -- STL container top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1401  ValidateAddress();
1402 
1403  //
1404  // Silently do nothing if we have no user i/o buffer.
1405  //
1406 
1407  if (!fObject) {
1408  return;
1409  }
1410 
1412  Int_t n = 0;
1413  // We are in a block so the helper pops as soon as possible.
1415  n = proxy->Size();
1416 
1417  if (n > fMaximum) {
1418  fMaximum = n;
1419  }
1420  b << n;
1421 
1424  } else {
1425  //NOTE: this does not work for not vectors since the CreateIterators expects a TGenCollectionProxy::TStaging as its argument!
1426  //NOTE: and those not work in general yet, since the TStaging object is neither created nor passed.
1427  // We need to review how to avoid the need for a TStaging during the writing.
1430  } else {
1432  }
1433  }
1434 
1435 }
1436 
1437 ////////////////////////////////////////////////////////////////////////////////
1438 /// Write leaves into i/o buffers for this branch.
1439 /// Case of a data member within a collection (fType == 41).
1440 
1442 {
1443  ValidateAddress();
1444 
1445  //
1446  // Silently do nothing if we have no user i/o buffer.
1447  //
1448 
1449  if (!fObject) {
1450  return;
1451  }
1452 
1453  // FIXME: This wont work if a pointer to vector is split!
1455  // Note: We cannot pop the proxy here because we need it for the i/o.
1457  if (!si) {
1458  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1459  return;
1460  }
1461 
1463  R__ASSERT(0!=iter);
1465 }
1466 
1467 ////////////////////////////////////////////////////////////////////////////////
1468 /// Write leaves into i/o buffers for this branch.
1469 /// Case of a data member within a collection (fType == 41).
1470 
1472 {
1473  ValidateAddress();
1474 
1475  //
1476  // Silently do nothing if we have no user i/o buffer.
1477  //
1478 
1479  if (!fObject) {
1480  return;
1481  }
1482 
1483  // FIXME: This wont work if a pointer to vector is split!
1485 
1486  // Note: We cannot pop the proxy here because we need it for the i/o.
1488  if (!si) {
1489  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1490  return;
1491  }
1492 
1494  b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1495 
1496 }
1497 
1498 ////////////////////////////////////////////////////////////////////////////////
1499 /// Write leaves into i/o buffers for this branch.
1500 /// Case of a data member within a collection (fType == 41).
1501 
1503 {
1504  ValidateAddress();
1505 
1506  //
1507  // Silently do nothing if we have no user i/o buffer.
1508  //
1509 
1510  if (!fObject) {
1511  return;
1512  }
1513 
1514  // FIXME: This wont work if a pointer to vector is split!
1516  // Note: We cannot pop the proxy here because we need it for the i/o.
1518  if (!si) {
1519  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1520  return;
1521  }
1522 
1524  R__ASSERT(0!=iter);
1525  b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1526 
1527 }
1528 
1529 ////////////////////////////////////////////////////////////////////////////////
1530 /// Write leaves into i/o buffers for this branch.
1531 /// Case of a data member within a collection (fType == 41).
1532 
1534 {
1535  ValidateAddress();
1536 
1537  //
1538  // Silently do nothing if we have no user i/o buffer.
1539  //
1540 
1541  if (!fObject) {
1542  return;
1543  }
1544 
1545  // FIXME: This wont work if a pointer to vector is split!
1547  // Note: We cannot pop the proxy here because we need it for the i/o.
1549  if (!si) {
1550  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1551  return;
1552  }
1553 
1555  R__ASSERT(0!=iter);
1556  b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1557 
1558 }
1559 
1560 ////////////////////////////////////////////////////////////////////////////////
1561 /// Write leaves into i/o buffers for this branch.
1562 /// Case of a TClonesArray (fType == 3).
1563 
1565 {
1566  // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1567  ValidateAddress();
1568 
1569  //
1570  // Silently do nothing if we have no user i/o buffer.
1571  //
1572 
1573  if (!fObject) {
1574  return;
1575  }
1576 
1577  TClonesArray* clones = (TClonesArray*) fObject;
1578  Int_t n = clones->GetEntriesFast();
1579  if (n > fMaximum) {
1580  fMaximum = n;
1581  }
1582  b << n;
1583 }
1584 
1585 ////////////////////////////////////////////////////////////////////////////////
1586 /// Write leaves into i/o buffers for this branch.
1587 /// Case of a data member within a TClonesArray (fType == 31).
1588 
1590 {
1591  ValidateAddress();
1592 
1593  //
1594  // Silently do nothing if we have no user i/o buffer.
1595  //
1596 
1597  if (!fObject) {
1598  return;
1599  }
1600 
1601  TClonesArray* clones = (TClonesArray*) fObject;
1602  Int_t n = clones->GetEntriesFast();
1604  if (!si) {
1605  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1606  return;
1607  }
1608 
1609  char **arr = (char **)clones->GetObjectRef(0);
1610  char **end = arr + n;
1612 }
1613 
1614 ////////////////////////////////////////////////////////////////////////////////
1615 /// Write leaves into i/o buffers for this branch.
1616 /// Case of a non TObject, non collection class with a custom streamer
1617 
1619 {
1620  ValidateAddress();
1621 
1622  //
1623  // Silently do nothing if we have no user i/o buffer.
1624  //
1625 
1626  if (!fObject) {
1627  return;
1628  }
1629 
1630  //
1631  // Remember tobjects written to the buffer so that
1632  // pointers are handled correctly later.
1633 
1634  if (TestBit(kBranchObject)) {
1635  b.MapObject((TObject*) fObject);
1636  } else if (TestBit(kBranchAny)) {
1638  }
1639 
1641 }
1642 
1643 ////////////////////////////////////////////////////////////////////////////////
1644 /// Write leaves into i/o buffers for this branch.
1645 /// For split-class branch, base class branch, data member branch, or top-level branch.
1646 /// which do have a branch count and are not a counter.
1647 
1649 {
1650  FillLeavesMember(b);
1651  /*
1652  ValidateAddress();
1653 
1654  //
1655  // Silently do nothing if we have no user i/o buffer.
1656  //
1657 
1658  if (!fObject) {
1659  return;
1660  }
1661  */
1662 }
1663 
1664 ////////////////////////////////////////////////////////////////////////////////
1665 /// Write leaves into i/o buffers for this branch.
1666 /// For split-class branch, base class branch, data member branch, or top-level branch.
1667 /// which do not have a branch count and are a counter.
1668 
1670 {
1671  ValidateAddress();
1672 
1673  //
1674  // Silently do nothing if we have no user i/o buffer.
1675  //
1676 
1677  if (!fObject) {
1678  return;
1679  }
1680  // -- Top-level, data member, base class, or split class branch.
1681  // A non-split top-level branch (0, and fID == -1)), a non-split object (0, and fID > -1), or a base class (1), or a split (non-TClonesArray, non-STL container) object (2). Write out the object.
1682  // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1683  // FIXME: What happens with a split base class branch,
1684  // or a split class branch???
1685  TStreamerInfo* si = GetInfoImp();
1686  if (!si) {
1687  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1688  return;
1689  }
1690  // Since info is not null, fFillActionSequence is not null either.
1692  // Int_t n = si->WriteBufferAux(b, &fObject, fID, 1, 0, 0);
1693 
1694  Int_t n = *(Int_t*)(fObject + si->TStreamerInfo::GetElementOffset(fID)); // or GetInfoImp()->GetTypedValue<Int_t>(&fObject, fID, j, -1);
1695  if (n > fMaximum) {
1696  fMaximum = n;
1697  }
1698 
1699 }
1700 
1701 ////////////////////////////////////////////////////////////////////////////////
1702 /// Write leaves into i/o buffers for this branch.
1703 /// For split-class branch, base class branch, data member branch, or top-level branch.
1704 /// which do not have a branch count and are not a counter.
1705 
1707 {
1708  ValidateAddress();
1709 
1710  //
1711  // Silently do nothing if we have no user i/o buffer.
1712  //
1713 
1714  if (!fObject) {
1715  return;
1716  }
1717 
1718  if (TestBit(kBranchObject)) {
1719  b.MapObject((TObject*) fObject);
1720  } else if (TestBit(kBranchAny)) {
1722  }
1723 
1724  // -- Top-level, data member, base class, or split class branch.
1725  // A non-split top-level branch (0, and fID == -1)), a non-split object (0, and fID > -1), or a base class (1), or a split (non-TClonesArray, non-STL container) object (2). Write out the object.
1726  // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1727  // FIXME: What happens with a split base class branch,
1728  // or a split class branch???
1729  TStreamerInfo* si = GetInfoImp();
1730  if (!si) {
1731  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1732  return;
1733  }
1734  // Since info is not null, fFillActionSequence is not null either.
1736 
1737 }
1738 
1739 ////////////////////////////////////////////////////////////////////////////////
1740 /// Remove trailing dimensions and make sure
1741 /// there is a trailing dot.
1742 
1743 static void R__CleanName(std::string &name)
1744 {
1745  if (name[name.length()-1]==']') {
1746  std::size_t dim = name.find_first_of("[");
1747  if (dim != std::string::npos) {
1748  name.erase(dim);
1749  }
1750  }
1751  if (name[name.size()-1] != '.') {
1752  name += '.';
1753  }
1754 }
1755 
1756 ////////////////////////////////////////////////////////////////////////////////
1757 /// Find the immediate sub-branch with passed name.
1758 
1760 {
1761  // The default behavior of TBranch::FindBranch is sometimes
1762  // incorrect if this branch represent a base class, since
1763  // the base class name might or might not be in the name
1764  // of the sub-branches and might or might not be in the
1765  // name being passed.
1766 
1767  if (fID >= 0) {
1769  TStreamerElement* se = si->GetElement(fID);
1770  if (se && se->IsBase()) {
1771  // We allow the user to pass only the last dotted component of the name.
1772  UInt_t len = strlen(name);
1773  std::string longnm;
1774  longnm.reserve(fName.Length()+len+3); // Enough space of fName + name + dots
1775  longnm = fName.Data();
1776  R__CleanName(longnm);
1777  longnm += name;
1778  std::string longnm_parent;
1779  longnm_parent.reserve(fName.Length()+len+3);
1780  longnm_parent = (GetMother()->GetSubBranch(this)->GetName());
1781  R__CleanName(longnm_parent);
1782  longnm_parent += name; // Name without the base class name
1783 
1784  UInt_t namelen = strlen(name);
1785 
1786  TBranch* branch = 0;
1787  Int_t nbranches = fBranches.GetEntries();
1788  for(Int_t i = 0; i < nbranches; ++i) {
1789  branch = (TBranch*) fBranches.UncheckedAt(i);
1790 
1791  const char *brname = branch->GetName();
1792  UInt_t brlen = strlen(brname);
1793  if (brname[brlen-1]==']') {
1794  const char *dim = strchr(brname,'[');
1795  if (dim) {
1796  brlen = dim - brname;
1797  }
1798  }
1799  if (namelen == brlen /* same effective size */
1800  && strncmp(name,brname,brlen) == 0) {
1801  return branch;
1802  }
1803  if (brlen == longnm.length()
1804  && strncmp(longnm.c_str(),brname,brlen) == 0) {
1805  return branch;
1806  }
1807  // This check is specific to base class
1808  if (brlen == longnm_parent.length()
1809  && strncmp(longnm_parent.c_str(),brname,brlen) == 0) {
1810  return branch;
1811  }
1812 
1813  if (namelen>brlen && name[brlen]=='.' && strncmp(name,brname,brlen)==0) {
1814  // The prefix subbranch name match the branch name.
1815  return branch->FindBranch(name+brlen+1);
1816  }
1817  }
1818  }
1819  }
1820  TBranch *result = TBranch::FindBranch(name);
1821  if (!result) {
1822  // Look in base classes if any
1823  Int_t nbranches = fBranches.GetEntries();
1824  for(Int_t i = 0; i < nbranches; ++i) {
1825  TObject *obj = fBranches.UncheckedAt(i);
1826  if(obj->IsA() != TBranchElement :: Class() )
1827  continue;
1828  TBranchElement *br = (TBranchElement*)obj;
1829  TVirtualStreamerInfo* si = br->GetInfoImp();
1830  if (si && br->GetID() >= 0) {
1831  TStreamerElement* se = si->GetElement(br->GetID());
1832  if (se && se->IsBase()) {
1833  result = br->FindBranch(name);
1834  }
1835  }
1836  }
1837  }
1838  return result;
1839 }
1840 
1841 ////////////////////////////////////////////////////////////////////////////////
1842 /// Find the leaf corresponding to the name 'searchname'.
1843 
1845 {
1846  TLeaf *leaf = TBranch::FindLeaf(name);
1847 
1848  if (leaf==0 && GetListOfLeaves()->GetEntries()==1) {
1849  TBranch *br = GetMother()->GetSubBranch( this );
1850  if( br->IsA() != TBranchElement::Class() )
1851  return 0;
1852 
1853  TBranchElement *parent = (TBranchElement*)br;
1854  if (parent==this || parent->GetID()<0 ) return 0;
1855 
1856  TVirtualStreamerInfo* si = parent->GetInfoImp();
1857  TStreamerElement* se = si->GetElement(parent->GetID());
1858 
1859  if (! se->IsBase() ) return 0;
1860 
1861  br = GetMother()->GetSubBranch( parent );
1862  if( br->IsA() != TBranchElement::Class() )
1863  return 0;
1864 
1865  TBranchElement *grand_parent = (TBranchElement*)br;
1866 
1867  std::string longname( grand_parent->GetName() );
1868  R__CleanName(longname);
1869  longname += name;
1870 
1871  std::string leafname( GetListOfLeaves()->At(0)->GetName() );
1872 
1873  if ( longname == leafname ) {
1874  return (TLeaf*)GetListOfLeaves()->At(0);
1875  }
1876  }
1877  return leaf;
1878 }
1879 
1880 ////////////////////////////////////////////////////////////////////////////////
1881 /// Get the branch address.
1882 ///
1883 /// If we are *not* owned by a MakeClass() tree:
1884 ///
1885 /// - If we are a top-level branch, return a pointer
1886 /// - to the pointer to our object.
1887 ///
1888 /// If we are *not* a top-level branch, return a pointer
1889 /// to our object.
1890 ///
1891 /// If we are owned by a MakeClass() tree:
1892 ///
1893 /// - Return a pointer to our object.
1894 
1896 {
1897  ValidateAddress();
1898  return fAddress;
1899 }
1900 
1901 
1902 // For a mother branch of type 3 or 4, find the 'correct' StreamerInfo for the
1903 // content of the collection by find a sub-branch corresponding to a direct data member
1904 // of the containee class (valueClass)
1905 // Default to the current StreamerInfo if none are found.
1907 {
1908  TStreamerInfo *localInfo = nullptr;
1909 
1910  // Search for the correct version.
1911  for(auto subbe : TRangeDynCast<TBranchElement>( branches )) {
1912  if (!subbe->fInfo)
1913  subbe->SetupInfo();
1914  if (valueClass == subbe->fInfo->GetClass()) { // Use GetInfo to provoke its creation.
1915  localInfo = subbe->fInfo;
1916  break;
1917  }
1918  }
1919  if (!localInfo) {
1920  // This is likely sub-optimal as we really should call GetFile but it is non-const.
1921  auto file = fDirectory ? fDirectory->GetFile() : nullptr;
1922  if (file && file->GetSeekInfo()) {
1923  localInfo = (TStreamerInfo*)file->GetStreamerInfoCache()->FindObject(valueClass->GetName());
1924  if (localInfo) {
1925  if (valueClass->IsVersioned()) {
1926  localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1927  } else {
1928  localInfo = (TStreamerInfo*)valueClass->FindStreamerInfo(localInfo->GetCheckSum());
1929  if (localInfo) {
1930  // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
1931  localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1932  }
1933  }
1934  }
1935  }
1936  }
1937  if (!localInfo)
1938  localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo();
1939 
1940  if (localInfo) {
1941  // See if we need any conversion.
1942  TClass *targetValueClass = fInfo->GetClass()->GetCollectionProxy()
1944  : nullptr;
1945  // For TClonesArray, the rest of the code probably does not support change in
1946  // value class, but if it does, we would have to look up the target value class
1947  // in the TClonesArray instance.
1948  // if (type == 3 && instance) targetValueClass = ((TClonesArray*)instance)->GetClass();
1949 
1950  if (targetValueClass && localInfo->GetClass() != targetValueClass) {
1951  localInfo = (TStreamerInfo*)targetValueClass->GetConversionStreamerInfo(localInfo->GetClass(),
1952  localInfo->GetClassVersion());
1953  }
1954  }
1955  return localInfo;
1956 }
1957 
1958 namespace {
1959 static void GatherArtificialElements(const TObjArray &branches, TStreamerInfoActions::TIDs &ids, TString prefix, TStreamerInfo *info, Int_t offset) {
1960  size_t ndata = info->GetNelement();
1961  for (size_t i =0; i < ndata; ++i) {
1962  TStreamerElement *nextel = info->GetElement(i);
1963 
1964  if (nextel->GetType() == TStreamerInfo::kCacheDelete
1965  || nextel->GetType() == TStreamerInfo::kCacheNew) {
1966  continue;
1967  }
1968 
1969  TString ename = prefix + nextel->GetName();
1970 
1971  if (ename[0]=='*')
1972  ename.Remove(0,1);
1973 
1974  Ssiz_t pos;
1975  while ((pos = ename.Last('[')) != TString::kNPOS) {
1976  ename = ename.Remove(pos);
1977  }
1978 
1979  TBranchElement *be = (TBranchElement*)branches.FindObject(ename);
1980  if (nextel->IsA() == TStreamerArtificial::Class()
1981  && be == nullptr) {
1982 
1983  ids.push_back(i);
1984  ids.back().fElement = nextel;
1985  ids.back().fInfo = info;
1986  }
1987 
1988  if (nextel->CannotSplit() || nextel->IsTransient() || nextel->GetOffset() == TStreamerInfo::kMissing)
1989  continue;
1990 
1991  TClass *elementClass = nextel->GetClassPointer();
1992  if (elementClass && (!be || be->GetType() == -2)) {
1993  TStreamerInfo *nextinfo = nullptr;
1994 
1995  // nextinfo_version = ....
1996  auto search = be ? be->GetListOfBranches() : &branches;
1997  TVirtualArray *onfileObject = nullptr;
1998  for(auto subbe : TRangeDynCast<TBranchElement>( *search )) {
1999 
2000  if (elementClass == subbe->GetInfo()->GetClass()) { // Use GetInfo to provoke its creation.
2001  nextinfo = subbe->GetInfo();
2002  onfileObject = subbe->GetOnfileObject();
2003  break;
2004  }
2005  }
2006  if (!nextinfo) {
2007  nextinfo = (TStreamerInfo *)elementClass->GetStreamerInfo();
2008  if (elementClass->GetCollectionProxy() && elementClass->GetCollectionProxy()->GetValueClass()) {
2009  nextinfo = (TStreamerInfo *)elementClass->GetCollectionProxy()->GetValueClass()->GetStreamerInfo(); // NOTE: need to find the right version
2010  }
2011  }
2012  ids.emplace_back(nextinfo, offset + nextel->GetOffset());
2013  if (!onfileObject && nextinfo && nextinfo->GetNelement() && nextinfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew) {
2014  onfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), 1 /* is that always right? */ );
2015  ids.back().fNestedIDs->fOwnOnfileObject = kTRUE;
2016  }
2017  ids.back().fNestedIDs->fOnfileObject = onfileObject;
2018  GatherArtificialElements(branches, ids.back().fNestedIDs->fIDs, ename + ".", nextinfo, offset + nextel->GetOffset());
2019  if (ids.back().fNestedIDs->fIDs.empty())
2020  ids.pop_back();
2021  }
2022  }
2023 };
2024 } // Anonymous namespace.
2025 
2026 
2027 ////////////////////////////////////////////////////////////////////////////////
2028 /// Set the value of fInfo. This is part one of InitInfo.
2029 /// To be used as:
2030 /// if (!fInfo)
2031 /// SetupInfo();
2032 /// It would only be used within InitInfo (and its callees)
2033 
2035 {
2036  // We did not already have streamer info, so now we must find it.
2037  TClass* cl = fBranchClass.GetClass();
2038 
2039  //------------------------------------------------------------------------
2040  // Check if we're dealing with the name change
2041  //////////////////////////////////////////////////////////////////////////
2042 
2043  TClass* targetClass = 0;
2044  if( fTargetClass.GetClassName()[0] ) {
2045  targetClass = fTargetClass;
2046  if (!targetClass && GetCollectionProxy()) {
2047  // We are in the case where the branch holds a custom collection
2048  // proxy but the dictionary is not loaded, calling
2049  // GetCollectionProxy had the side effect of creating the TClass
2050  // corresponding to this emulated collection.
2051  targetClass = fTargetClass;
2052  }
2053  if ( !targetClass ) {
2054  Error( "InitInfo", "The target class dictionary is not present!" );
2055  return;
2056  }
2057  } else {
2058  targetClass = cl;
2059  }
2060  if (cl) {
2061  //---------------------------------------------------------------------
2062  // Get the streamer info for given version
2063  ///////////////////////////////////////////////////////////////////////
2064 
2065  {
2066  if ( (cl->Property() & kIsAbstract) && cl == targetClass) {
2067  TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this);
2068  if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
2069  // Our parent's class is emulated and we represent an abstract class.
2070  // and the target class has not been set explicilty.
2071  TString target = cl->GetName();
2072  target += "@@emulated";
2073  fTargetClass.SetName(target);
2074 
2075  if (!fTargetClass) {
2077  }
2078  targetClass = fTargetClass;
2079  }
2080  }
2081  if( targetClass != cl ) {
2083  } else {
2085  }
2086  }
2087 
2088  // FIXME: Check that the found streamer info checksum matches our branch class checksum here.
2089  // Check to see if the class code was unloaded/reloaded
2090  // since we were created.
2092  if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) {
2093  // Try to compensate for a class that got unloaded on us.
2094  // Search through the streamer infos by checksum
2095  // and take the first match.
2096 
2097  TStreamerInfo* info;
2098  if( targetClass != cl )
2099  info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum );
2100  else {
2101  info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum );
2102  if (info) {
2103  // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
2104  info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion());
2105  }
2106  }
2107  if( info ) {
2108  fInfo = info;
2109  // We no longer reset the class version so that in case the user is passing us later
2110  // the address of a class that require (another) Conversion we can find the proper
2111  // StreamerInfo.
2112  // fClassVersion = fInfo->GetClassVersion();
2113  }
2114  }
2115  }
2116 }
2117 
2118 
2119 ////////////////////////////////////////////////////////////////////////////////
2120 /// Init the streamer info for the branch class, try to compensate for class
2121 /// code unload/reload and schema evolution.
2122 
2124 {
2125  if (!fInfo)
2126  SetupInfo();
2127 
2128  //
2129  // Fixup cached streamer info if necessary.
2130  //
2131  // FIXME: What if the class code was unloaded/reloaded since we were cached?
2132 
2133  if (fInfo) {
2134 
2135  if (!fInfo->IsCompiled()) {
2136  // Streamer info has not yet been compiled.
2137 
2138  Error("InitInfo","StreamerInfo is not compiled.");
2139  }
2140  // return immediately if we are called recursively.
2141  if (fInInitInfo)
2142  return;
2143  fInInitInfo = kTRUE;
2144  if (!fInit) {
2145  // We were read in from a file, figure out what our fID should be,
2146  // schema evolution must be considered.
2147  //
2148  // Force our fID to be the id of the first streamer element that matches our name.
2149  //
2150  auto SetOnfileObject = [this](TStreamerInfo *info) {
2151  Int_t arrlen = 1;
2152  if (fType==31 || fType==41) {
2153  TLeaf *leaf = (TLeaf*)fLeaves.At(0);
2154  if (leaf) {
2155  arrlen = leaf->GetMaximum();
2156  }
2157  }
2158  Bool_t toplevel = (fType == 3 || fType == 4 || (fType == 0 && fID == -2));
2159  Bool_t seenExisting = kFALSE;
2160 
2161  fOnfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), arrlen );
2162  // Propage this to all the other branch of this type.
2164  Int_t nbranches = branches->GetEntriesFast();
2165  TBranchElement *lastbranch = this;
2166 
2167  TClass *currentClass = fBranchClass;
2168  auto currentVersion = fClassVersion;
2169  if (toplevel) {
2170  // Note: Fragile/wrong when using conversion StreamerInfo?
2171  currentClass = info->GetClass();
2172  currentVersion = info->GetClassVersion();
2173  }
2174 
2175  for (Int_t i = 0; i < nbranches; ++i) {
2176  TBranchElement* subbranch = (TBranchElement*)branches->At(i);
2177  Bool_t match = kFALSE;
2178  if (this != subbranch) {
2179 
2180  if (!subbranch->fInfo)
2181  subbranch->SetupInfo();
2182 
2183  if (subbranch->fInfo == info)
2184  match = kTRUE;
2185  else if (subbranch->fInfo == nullptr && subbranch->fBranchClass == currentClass) {
2186  if (!toplevel) {
2187  if (subbranch->fCheckSum == fCheckSum)
2188  match = kTRUE;
2189  } else {
2190  if (!subbranch->fBranchClass->IsForeign() && subbranch->fClassVersion == currentVersion)
2191  match = kTRUE;
2192  else if (subbranch->fCheckSum == info->GetCheckSum()) {
2193  match = kTRUE;
2194  }
2195  }
2196  }
2197  }
2198  if (match) {
2199  if (subbranch->fOnfileObject && subbranch->fOnfileObject != fOnfileObject) {
2200  if (seenExisting) {
2201  Error("SetOnfileObject (lambda)", "2 distincts fOnfileObject are in the hierarchy of %s for type %s",
2202  toplevel ? GetName() : GetMother()->GetSubBranch(this)->GetName(), info->GetName());
2203  } else {
2204  delete fOnfileObject;
2205  fOnfileObject = subbranch->fOnfileObject;
2206  seenExisting = kTRUE;
2207  }
2208  }
2209  subbranch->fOnfileObject = fOnfileObject;
2210  lastbranch = subbranch;
2211  }
2212  }
2213  if (toplevel) {
2215  if (lastbranch != this)
2216  lastbranch->ResetBit(kOwnOnfileObj);
2217  } else {
2218  lastbranch->SetBit(kOwnOnfileObj);
2219  }
2220  };
2221  if (GetID() > -1) {
2222  // We are *not* a top-level branch.
2223  std::string s(GetName());
2224  size_t pos = s.rfind('.');
2225  if (pos != std::string::npos) {
2226  s = s.substr(pos+1);
2227  }
2228  while ((pos = s.rfind('[')) != std::string::npos) {
2229  s = s.substr(0, pos);
2230  }
2231  int offset = 0;
2232  TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
2233  if (elt && offset!=TStreamerInfo::kMissing) {
2234  size_t ndata = fInfo->GetNelement();
2235  fNewIDs.clear();
2236  for (size_t i = 0; i < ndata; ++i) {
2237  if (fInfo->GetElement(i) == elt) {
2239  && (i+1) < ndata
2240  && s == fInfo->GetElement(i)->GetName())
2241  {
2242  // If the TStreamerElement we found is storing the information in the
2243  // cache and is a repeater, we need to use the real one (the next one).
2244  // (At least until the cache/repeat mechanism is properly handle by
2245  // ReadLeaves).
2246  // fID = i+1;
2247  fID = i;
2248  if (fType != 2) {
2249  if (elt->TestBit(TStreamerElement::kRepeat)) {
2250  fNewIDs.push_back(fID+1);
2251  fNewIDs.back().fElement = fInfo->GetElement(i+1);
2252  fNewIDs.back().fInfo = fInfo;
2253  } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) {
2254  fNewIDs.push_back(fID+1);
2255  fNewIDs.back().fElement = fInfo->GetElement(i+1);
2256  fNewIDs.back().fInfo = fInfo;
2257  }
2258  }
2259  } else {
2260  fID = i;
2261  }
2262  if (elt->TestBit (TStreamerElement::kCache)) {
2264  }
2265  break;
2266  }
2267  }
2268  for (size_t i = fID+1+(fNewIDs.size()); i < ndata; ++i) {
2269  TStreamerElement *nextel = fInfo->GetElement(i);
2270 
2271  std::string ename = nextel->GetName();
2272  if (ename[0] == '*')
2273  ename = ename.substr(1);
2274 
2275  while ((pos = ename.rfind('[')) != std::string::npos) {
2276  ename = ename.substr(0, pos);
2277  }
2278 
2279  if (s != ename) {
2280  // We moved on to the next set
2281  break;
2282  }
2283  // Add all (and only) the Artificial Elements that follows this StreamerInfo.
2284  // fprintf(stderr,"%s/%d[%zu] passing trhough %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2285  if (fType==31||fType==41) {
2286  // The nested objects are unfolded and their branch can not be used to
2287  // execute StreamerElements of this StreamerInfo.
2288  if ((nextel->GetType() == TStreamerInfo::kObject
2289  || nextel->GetType() == TStreamerInfo::kAny)
2290  && nextel->GetClassPointer()->CanSplit())
2291  {
2292  continue;
2293  }
2294  }
2295  if (nextel->GetOffset() == TStreamerInfo::kMissing) {
2296  // This element will be 'skipped', it's TBranchElement's fObject will null
2297  // and thus can not be used to execute the artifical StreamerElements
2298  continue;
2299  }
2300  if (nextel->IsA() != TStreamerArtificial::Class()
2301  || nextel->GetType() == TStreamerInfo::kCacheDelete ) {
2302  continue;
2303  }
2304  // NOTE: We should verify that the rule's source are 'before'
2305  // or 'at' this branch.
2306  // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2307  fNewIDs.push_back(i);
2308  fNewIDs.back().fElement = nextel;
2309  fNewIDs.back().fInfo = fInfo;
2310  }
2311  } else if (elt && offset==TStreamerInfo::kMissing) {
2312  // Still re-assign fID properly.
2313  fNewIDs.clear();
2314  size_t ndata = fInfo->GetNelement();
2315  for (size_t i = 0; i < ndata; ++i) {
2316  if (fInfo->GetElement(i) == elt) {
2317  fID = i;
2318  break;
2319  }
2320  }
2321  } else {
2322  // We have not even found the element .. this is strange :(
2323  // fNewIDs.clear();
2324  // fID = -3;
2325  // SetBit(kDoNotProcess);
2326  }
2327  if (fOnfileObject==0 && (fType==31 || fType==41 || (0 <= fType && fType <=2) ) && fInfo->GetNelement()
2329  {
2330  SetOnfileObject(fInfo);
2331  }
2332  }
2333  if (fType == 3 || fType == 4 || (fType == 0 && fID == -2)) {
2334  // Need to add the rule targetting transient members.
2335  TStreamerInfo *localInfo = fInfo;
2336  if (fType == 3 || fType == 4) {
2337  // Don't we have real version information?
2338  // Not unless there is a subbranch with a non-split element of the class.
2339  // Search for the correct version.
2340  localInfo = FindOnfileInfo(fClonesClass, fBranches);
2341  }
2342 
2343  TString prefix(GetName());
2344  if (prefix[prefix.Length()-1] != '.') {
2345  if (fType == 3 || fType == 4) {
2346  prefix += ".";
2347  } else {
2348  prefix = "";
2349  }
2350  }
2351  fNewIDs.clear();
2352 
2353  GatherArtificialElements(fBranches, fNewIDs, prefix, localInfo, 0);
2354 
2355  if (!fNewIDs.empty() && fOnfileObject == nullptr && localInfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew)
2356  {
2357  SetOnfileObject(localInfo);
2358  }
2359 
2360  }
2361  fInit = kTRUE;
2362 
2363  // Get the action sequence we need to copy for reading.
2366  } else if (!fReadActionSequence) {
2367  // Get the action sequence we need to copy for reading.
2370  }
2371  SetReadLeavesPtr();
2372  SetFillLeavesPtr();
2373  fInInitInfo = kFALSE;
2374  }
2375 }
2376 
2377 ////////////////////////////////////////////////////////////////////////////////
2378 /// Return the collection proxy describing the branch content, if any.
2379 
2381 {
2382  if (fCollProxy) {
2383  return fCollProxy;
2384  }
2385  TBranchElement* thiscast = const_cast<TBranchElement*>(this);
2386  if (fType == 4) {
2387  // STL container top-level branch.
2388  const char* className = 0;
2389  TClass* cl = nullptr;
2390  if (fID < 0) {
2391  // We are a top-level branch.
2392  if (fBranchClass.GetClass()) {
2393  cl = fBranchClass.GetClass();
2394  }
2395  } else {
2396  // We are not a top-level branch.
2397  TVirtualStreamerInfo* si = thiscast->GetInfoImp();
2398  TStreamerElement* se = si->GetElement(fID);
2399  cl = se->GetClassPointer();
2400  }
2401  if (!cl) {
2402  // The TClass was not created but we do know (since it
2403  // is used as a collection) that it 'className' was a
2404  // class, so let's create it by hand!.
2405 
2406  if (fID < 0) {
2409  className = cl->GetName();
2410  } else {
2411  cl = new TClass(className, fClassVersion);
2413  className = cl->GetName();
2414  }
2415  }
2417  if (!proxy) {
2418  // humm, we must have an older file with a custom collection
2419  // let's try to work-around it.
2420  TString equiv;
2421  equiv.Form("vector<%s>",fClonesName.Data());
2422  TClass *clequiv = TClass::GetClass(equiv);
2423  proxy = clequiv->GetCollectionProxy();
2424  if (!proxy) {
2425  Fatal("GetCollectionProxy",
2426  "Can not create a Collection Proxy of any kind for the class \"%s\" needed by the branch \"%s\" of the TTree \"%s\"!",
2427  className, GetName(), GetTree()->GetName());
2428  }
2429  if (gDebug > 0) Info("GetCollectionProxy",
2430  "Fixing the collection proxy of the class \"%s\" \n"
2431  "\tneeded by the branch \"%s\" of the TTree \"%s\" to be similar to \"%s\".",
2432  className, GetName(), GetTree()->GetName(),equiv.Data());
2433  cl->CopyCollectionProxy( *proxy );
2434  }
2435  fCollProxy = proxy->Generate();
2436  fSTLtype = proxy->GetCollectionType();
2437  } else if (fType == 41) {
2438  // STL container sub-branch.
2440  }
2441  return fCollProxy;
2442 }
2443 
2444 ////////////////////////////////////////////////////////////////////////////////
2445 /// Return a pointer to the current type of the data member corresponding to branch element.
2446 
2448 {
2449  TClass* cl = fCurrentClass;
2450  if (cl) {
2451  return cl;
2452  }
2453 
2454  TStreamerInfo* brInfo = (TStreamerInfo*)GetInfoImp();
2455  if (!brInfo) {
2457  R__ASSERT(cl && cl->GetCollectionProxy());
2458  fCurrentClass = cl;
2459  return cl;
2460  }
2461  TClass* motherCl = brInfo->GetClass();
2462  if (motherCl->GetCollectionProxy()) {
2463  cl = motherCl->GetCollectionProxy()->GetCollectionClass();
2464  if (cl) {
2465  fCurrentClass = cl;
2466  }
2467  return cl;
2468  }
2469  if (GetID() < 0 || GetID()>=brInfo->GetNelement()) {
2470  return 0;
2471  }
2472  TStreamerElement* currentStreamerElement = brInfo->GetElement(GetID());
2473  TDataMember* dm = (TDataMember*) motherCl->GetListOfDataMembers()->FindObject(currentStreamerElement->GetName());
2474 
2475  TString newType;
2476  if (!dm) {
2477  // Either the class is not loaded or the data member is gone
2478  if (!motherCl->IsLoaded()) {
2479  TVirtualStreamerInfo* newInfo = motherCl->GetStreamerInfo();
2480  if (newInfo != brInfo) {
2481  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(currentStreamerElement->GetName());
2482  if (newElems) {
2483  if (newElems->GetClassPointer())
2484  newType = newElems->GetClassPointer()->GetName();
2485  else
2486  newType = newElems->GetTypeName();
2487  }
2488  }
2489  if (newType.Length()==0) {
2490  if (currentStreamerElement->GetClassPointer())
2491  newType = currentStreamerElement->GetClassPointer()->GetName();
2492  else
2493  newType = currentStreamerElement->GetTypeName();
2494  }
2495  }
2496  } else {
2497  newType = dm->GetTypeName();
2498  }
2499  cl = TClass::GetClass(newType);
2500  if (cl) {
2501  fCurrentClass = cl;
2502  }
2503  return cl;
2504 }
2505 
2506 ////////////////////////////////////////////////////////////////////////////////
2507 /// Read all branches of a BranchElement and return total number of bytes.
2508 ///
2509 /// - If entry = 0, then use current entry number + 1.
2510 /// - If entry < 0, then reset entry number to 0.
2511 ///
2512 /// Returns the number of bytes read from the input buffer.
2513 /// - If entry does not exist, then returns 0.
2514 /// - If an I/O error occurs, then returns -1.
2515 ///
2516 /// See IMPORTANT REMARKS in TTree::GetEntry.
2517 
2519 {
2520  // Remember which entry we are reading.
2521  fReadEntry = entry;
2522 
2523  // If our tree has a branch ref, make it remember the entry and
2524  // this branch. This allows a TRef::GetObject() call done during
2525  // the following I/O operation, for example in a custom streamer,
2526  // to search for the referenced object in the proper element of the
2527  // proper branch.
2528  TBranchRef* bref = fTree->GetBranchRef();
2529  if (R__unlikely(bref)) {
2530  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
2531  fBranchID = bref->SetParent(this, fBranchID);
2532  bref->SetRequestedEntry(entry);
2533  }
2534 
2535  Int_t nbytes = 0;
2536 
2537  if (R__unlikely(IsAutoDelete())) {
2540  } else {
2542  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
2544  }
2545  }
2546 
2547  Int_t nbranches = fBranches.GetEntriesFast();
2548  if (nbranches) {
2549  // -- Branch has daughters.
2550  // One must always read the branch counter.
2551  // In the case when one reads consecutively twice the same entry,
2552  // the user may have cleared the TClonesArray between the GetEntry calls.
2553  if ((fType == 3) || (fType == 4)) {
2554  Int_t nb = TBranch::GetEntry(entry, getall);
2555  if (nb < 0) {
2556  return nb;
2557  }
2558  nbytes += nb;
2559  }
2560  switch(fSTLtype) {
2561  case ROOT::kSTLset:
2562  case ROOT::kSTLmultiset:
2565  case ROOT::kSTLmap:
2566  case ROOT::kSTLmultimap:
2569  break;
2570  default:
2571  ValidateAddress(); // There is no ReadLeave for this node, so we need to do the validation here.
2572  for (Int_t i = 0; i < nbranches; ++i) {
2573  TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2574  Int_t nb = branch->GetEntry(entry, getall);
2575  if (nb < 0) {
2576  return nb;
2577  }
2578  nbytes += nb;
2579  }
2580  break;
2581  }
2583  if (fType == 3) {
2584  // Apply the unattached rules; by definition they do not need any
2585  // input from a buffer.
2587 
2588  auto ndata = GetNdata();
2589 
2590  TClonesArray* clones = (TClonesArray*) fObject;
2591  if (clones->IsZombie()) {
2592  return -1;
2593  }
2594  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2595 
2596  char **arr = (char **)clones->GetObjectRef();
2597  char **end = arr + fNdata;
2598 
2600  } else if (fType == 4) {
2601  // Apply the unattached rules; by definition they do not need any
2602  // input from a buffer.
2604 
2605  auto ndata = GetNdata();
2606 
2607  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2610 
2612  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
2613  } else {
2614  // Apply the unattached rules; by definition they do not need any
2615  // input from a buffer.
2617  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
2619  }
2620  }
2621  } else {
2622  // -- Terminal branch.
2623  if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
2624  Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
2625  if (nb < 0) {
2626  return nb;
2627  }
2628  nbytes += nb;
2629  }
2630  Int_t nb = TBranch::GetEntry(entry, getall);
2631  if (nb < 0) {
2632  return nb;
2633  }
2634  nbytes += nb;
2635  }
2636 
2637  if (R__unlikely(fTree->Debug() > 0)) {
2638  if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
2639  Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
2640  }
2641  }
2642  return nbytes;
2643 }
2644 
2645 ////////////////////////////////////////////////////////////////////////////////
2646 /// Fill expectedClass and expectedType with information on the data type of the
2647 /// object/values contained in this branch (and thus the type of pointers
2648 /// expected to be passed to Set[Branch]Address
2649 /// return 0 in case of success and > 0 in case of failure.
2650 
2652 {
2653  expectedClass = 0;
2654  expectedType = kOther_t;
2655 
2657  if ((type == -1) || (fID == -1)) {
2658  expectedClass = fBranchClass;
2659  } else {
2660  // Case of an object data member. Here we allow for the
2661  // variable name to be ommitted. Eg, for Event.root with split
2662  // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
2663  TStreamerElement* element = GetInfoImp()->GetElement(fID);
2664  if (element) {
2665  expectedClass = element->GetClassPointer();
2666  if (!expectedClass) {
2667  TDataType* data = gROOT->GetType(element->GetTypeNameBasic());
2668  if (!data) {
2669  Error("GetExpectedType", "Did not find the type number for %s", element->GetTypeNameBasic());
2670  return 1;
2671  } else {
2672  expectedType = (EDataType) data->GetType();
2673  }
2674  }
2675  } else {
2676  Error("GetExpectedType", "Did not find the type for %s",GetName());
2677  return 2;
2678  }
2679  }
2680  return 0;
2681 }
2682 
2683 ////////////////////////////////////////////////////////////////////////////////
2684 /// Return icon name depending on type of branch element.
2685 
2686 const char* TBranchElement::GetIconName() const
2687 {
2688  if (IsFolder()) {
2689  return "TBranchElement-folder";
2690  } else {
2691  return "TBranchElement-leaf";
2692  }
2693 }
2694 
2695 ////////////////////////////////////////////////////////////////////////////////
2696 /// Return whether this branch is in a mode where the object are decomposed
2697 /// or not (Also known as MakeClass mode).
2698 
2700 {
2701  return TestBit(kDecomposedObj); // Same as TestBit(kMakeClass)
2702 }
2703 
2704 ////////////////////////////////////////////////////////////////////////////////
2705 /// Return maximum count value of the branchcount if any.
2706 
2708 {
2709  if (fBranchCount) {
2710  return fBranchCount->GetMaximum();
2711  }
2712  return fMaximum;
2713 }
2714 
2715 ////////////////////////////////////////////////////////////////////////////////
2716 /// Return a pointer to our object.
2717 
2719 {
2720  ValidateAddress();
2721  return fObject;
2722 }
2723 
2724 ////////////////////////////////////////////////////////////////////////////////
2725 /// Return a pointer to the parent class of the branch element.
2726 
2728 {
2729  return fParentClass.GetClass();
2730 }
2731 
2732 ////////////////////////////////////////////////////////////////////////////////
2733 /// Return type name of element in the branch.
2734 
2735 const char* TBranchElement::GetTypeName() const
2736 {
2737  if (fType == 3 || fType == 4) {
2738  return "Int_t";
2739  }
2740  // FIXME: Use symbolic constants here.
2741  if ((fStreamerType < 1) || (fStreamerType > 59)) {
2742  if (fBranchClass.GetClass()) {
2743  if (fID>=0) {
2744  return GetInfoImp()->GetElement(fID)->GetTypeName();
2745  } else {
2746  return fBranchClass.GetClass()->GetName();
2747  }
2748  } else {
2749  return 0;
2750  }
2751  }
2752  const char *types[20] = {
2753  "",
2754  "Char_t",
2755  "Short_t",
2756  "Int_t",
2757  "Long_t",
2758  "Float_t",
2759  "Int_t",
2760  "char*",
2761  "Double_t",
2762  "Double32_t",
2763  "",
2764  "UChar_t",
2765  "UShort_t",
2766  "UInt_t",
2767  "ULong_t",
2768  "UInt_t",
2769  "Long64_t",
2770  "ULong64_t",
2771  "Bool_t",
2772  "Float16_t"
2773  };
2774  Int_t itype = fStreamerType % 20;
2775  return types[itype];
2776 }
2777 
2778 ////////////////////////////////////////////////////////////////////////////////
2779 
2780 template Double_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2781 template Long64_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2782 template LongDouble_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2783 
2784 template <typename T>
2786 {
2787  // -- Returns the branch value.
2788  //
2789  // If the leaf is an array, j is the index in the array.
2790  //
2791  // If leaf is an array inside a TClonesArray, len should be the length
2792  // of the array.
2793  //
2794  // If subarr is true, then len is actually the index within the sub-array.
2795  //
2796 
2797  ValidateAddress();
2798 
2799  Int_t prID = fID;
2800  char *object = fObject;
2801  if (TestBit(kCache)) {
2802  if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2803  prID = fID+1;
2804  } else if (fOnfileObject) {
2805  object = fOnfileObject->GetObjectAt(0);
2806  }
2807  }
2808 
2809  if (!j && fBranchCount) {
2810  Long64_t entry = fTree->GetReadEntry();
2811  // Since reloading the index, will reset the ClonesArray, let's
2812  // skip the load if we already read this entry.
2813  if (entry != fBranchCount->GetReadEntry()) {
2814  fBranchCount->TBranch::GetEntry(entry);
2815  }
2816  if (fBranchCount2 && entry != fBranchCount2->GetReadEntry()) {
2817  fBranchCount2->TBranch::GetEntry(entry);
2818  }
2819  }
2820 
2821  if (TestBit(kDecomposedObj)) {
2822  if (!fAddress) {
2823  return 0;
2824  }
2825  if ((fType == 3) || (fType == 4)) {
2826  // Top-level branch of a TClonesArray.
2827  return fNdata;
2828  } else if ((fType == 31) || (fType == 41)) {
2829  // sub branch of a TClonesArray
2830  Int_t atype = fStreamerType;
2831  if (atype < 20) {
2832  atype += 20;
2833  }
2834  return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
2835  } else if (fType <= 2) {
2836  // branch in split mode
2837  // FIXME: This should probably be < 60 instead!
2838  if ((fStreamerType > 40) && (fStreamerType < 55)) {
2839  Int_t atype = fStreamerType - 20;
2840  return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
2841  } else {
2842  return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
2843  }
2844  }
2845  }
2846 
2847  if (object == 0)
2848  {
2849  // We have nowhere to read the data from (probably because the data member was
2850  // 'dropped' from the current schema).
2851  return 0;
2852  }
2853 
2854  if (fType == 31) {
2855  TClonesArray* clones = (TClonesArray*) object;
2856  if (subarr) {
2857  return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j, len, fOffset);
2858  }
2859  return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j/len, j%len, fOffset);
2860  } else if (fType == 41) {
2863  {
2864  if (subarr)
2865  return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
2866 
2867  return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
2868  }
2869  else
2870  {
2871  if (subarr)
2872  return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
2873  return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
2874  }
2875  } else {
2876  if (GetInfoImp()) {
2877  return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
2878  }
2879  return 0;
2880  }
2881 }
2882 
2883 ////////////////////////////////////////////////////////////////////////////////
2884 /// Returns pointer to first data element of this branch.
2885 /// Currently used only for members of type character.
2886 
2888 {
2889  ValidateAddress();
2890 
2891  Int_t prID = fID;
2892  char *object = fObject;
2893  if (TestBit(kCache)) {
2894  if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2895  prID = fID+1;
2896  } else if (fOnfileObject) {
2897  object = fOnfileObject->GetObjectAt(0);
2898  }
2899  }
2900 
2901  if (fBranchCount) {
2902  Long64_t entry = fTree->GetReadEntry();
2903  fBranchCount->TBranch::GetEntry(entry);
2904  if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
2905  }
2906  if (TestBit(kDecomposedObj)) {
2907  if (!fAddress) {
2908  return 0;
2909  }
2910  if (fType == 3) { //top level branch of a TClonesArray
2911  //return &fNdata;
2912  return 0;
2913  } else if (fType == 4) { //top level branch of a TClonesArray
2914  //return &fNdata;
2915  return 0;
2916  } else if (fType == 31) { // sub branch of a TClonesArray
2917  //Int_t atype = fStreamerType;
2918  //if (atype < 20) atype += 20;
2919  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2920  return 0;
2921  } else if (fType == 41) { // sub branch of a TClonesArray
2922  //Int_t atype = fStreamerType;
2923  //if (atype < 20) atype += 20;
2924  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2925  return 0;
2926  } else if (fType <= 2) { // branch in split mode
2927  // FIXME: This should probably be < 60 instead!
2928  if (fStreamerType > 40 && fStreamerType < 55) {
2929  //Int_t atype = fStreamerType - 20;
2930  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2931  return 0;
2932  } else {
2933  //return GetInfoImp()->GetValue(object, fID, j, -1);
2934  return 0;
2935  }
2936  }
2937  }
2938 
2939  if (fType == 31) {
2940  return 0;
2941  } else if (fType == 41) {
2942  return 0;
2943  } else if (prID < 0) {
2944  return object;
2945  } else {
2946  //return GetInfoImp()->GetValue(object,fID,j,-1);
2947  if (!GetInfoImp() || !object) return 0;
2948  char **val = (char**)(object+GetInfoImp()->TStreamerInfo::GetElementOffset(prID));
2949  return *val;
2950  }
2951 }
2952 
2953 ////////////////////////////////////////////////////////////////////////////////
2954 /// Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a container sub-branch.
2955 ///
2956 /// Note: The offsets are zero for data members so that when
2957 /// SetAddress recursively sets their address, they will get the
2958 /// same address as their containing class because i/o is based
2959 /// on streamer info offsets from the addresss of the containing
2960 /// class.
2961 ///
2962 /// Offsets are non-zero for base-class sub-branches that are
2963 /// not the leftmost direct base class. They are laid out in
2964 /// memory sequentially and only the leftmost direct base class
2965 /// has the same address as the derived class. The streamer
2966 /// offsets need to be added to the address of the base class
2967 /// subobject which is not the same as the address of the
2968 /// derived class for the non-leftmost direct base classes.
2969 
2971 {
2972  Int_t nbranches = fBranches.GetEntriesFast();
2973 
2974  // See https://sft.its.cern.ch/jira/browse/ROOT-8742
2975  // and https://sft.its.cern.ch/jira/browse/ROOT-9253
2976  // As of commit e21b4f1a3b, removing this lock lead to a failure
2977  // in the test testSetAddress[Loop].
2978  // As of commit 4f8b237849, removing this lock does not lead to
2979  // a visible failure in test. This might be due to the underlying
2980  // problem (missing lock or ?) being solved somewhere else or some
2981  // other pertubation reducing the failure rate.
2982  // Having the lock here is not too costly as InitializeOffsets is
2983  // one called once in the lifetime of the TBranch.
2985 
2986  if (fID < 0) {
2987  // -- We are a top-level branch. Let's mark whether we need to use MapObject.
2988  if (CanSelfReference(fBranchClass)) {
2989  if (fBranchClass.GetClass()->IsTObject()) {
2991  } else {
2992  SetBit(kBranchAny);
2993  }
2994  }
2995  }
2996  if (nbranches) {
2997  // Allocate space for the new sub-branch offsets.
2998  delete[] fBranchOffset;
2999  fBranchOffset = 0;
3000  fBranchOffset = new Int_t[nbranches];
3001  // Make sure we can instantiate our class meta info.
3002  if (!fBranchClass.GetClass()) {
3003  Warning("InitializeOffsets", "No branch class set for branch: %s", GetName());
3004  fInitOffsets = kTRUE;
3005  return;
3006  }
3007  // Make sure we can instantiate our class streamer info.
3008  if (!GetInfoImp()) {
3009  Warning("InitializeOffsets", "No streamer info available for branch: %s of class: %s", GetName(), fBranchClass.GetClass()->GetName());
3010  fInitOffsets = kTRUE;
3011  return;
3012  }
3013 
3014  // Get the class we are a member of now (which is the
3015  // type of our containing subobject) and get our offset
3016  // inside of our containing subobject (our local offset).
3017  // Note: branchElem stays zero if we are a top-level branch,
3018  // we have to be careful about this later.
3019  TStreamerElement* branchElem = 0;
3020  Int_t localOffset = 0;
3021  TClass* branchClass = fBranchClass.GetClass();
3022  Bool_t renamed = kFALSE;
3023  if (fID > -1) {
3024  // -- Branch is *not* a top-level branch.
3025  // Instead of the streamer info class, we want the class of our
3026  // specific element in the streamer info. We could be a data
3027  // member of a base class or a split class, in which case our
3028  // streamer info will be for our containing sub-object, while
3029  // we are actually a different type.
3031  // Note: We tested to make sure the streamer info was available previously.
3032  if (!si->IsCompiled()) {
3033  Warning("InitializeOffsets", "Streamer info for branch: %s has no elements array!", GetName());
3034  fInitOffsets = kTRUE;
3035  return;
3036  }
3037  // FIXME: Check that fID is in range.
3038  branchElem = si->GetElement(fID);
3039  if (!branchElem) {
3040  Warning("InitializeOffsets", "Cannot get streamer element for branch: %s!", GetName());
3041  fInitOffsets = kTRUE;
3042  return;
3043  } else if (branchElem->TestBit(TStreamerElement::kRepeat)) {
3044  // If we have a repeating streamerElement, use the next
3045  // one as it actually hold the 'real' data member('s offset)
3046  if (si->GetElement(fID+1)) {
3047  branchElem = si->GetElement(fID+1);
3048  }
3049  }
3050  localOffset = branchElem->GetOffset();
3051  branchClass = branchElem->GetClassPointer();
3052  if (localOffset == TStreamerInfo::kMissing) {
3053  fObject = 0;
3054  } else {
3055  renamed = branchClass && branchElem->GetNewClass() && (branchClass != branchElem->GetNewClass());
3056  }
3057  } else {
3058  renamed = fTargetClass != fBranchClass;
3059  }
3060  if (!branchClass) {
3061  Error("InitializeOffsets", "Could not find class for branch: %s", GetName());
3062  fInitOffsets = kTRUE;
3063  return;
3064  }
3065 
3066  //------------------------------------------------------------------------
3067  // Extract the name of the STL branch in case it has been split.
3068  //////////////////////////////////////////////////////////////////////////
3069 
3070  TString stlParentName;
3071  Bool_t stlParentNameUpdated = kFALSE;
3072  if( fType == 4 )
3073  {
3074  TBranch *br = GetMother()->GetSubBranch( this );
3075  stlParentName = br->GetName();
3076  stlParentName.Strip( TString::kTrailing, '.' );
3077 
3078  // We may ourself contain the 'Mother' branch name.
3079  // To avoid code duplication, we delegate the removal
3080  // of the mother's name to the first sub-branch loop.
3081  }
3082 
3083  // Loop over our sub-branches and compute their offsets.
3084  for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
3085  bool alternateElement = false;
3086 
3087  fBranchOffset[subBranchIdx] = 0;
3088  TBranchElement* subBranch = dynamic_cast<TBranchElement*> (fBranches[subBranchIdx]);
3089  if (subBranch == 0) {
3090  // -- Skip sub-branches that are not TBranchElements.
3091  continue;
3092  }
3093 
3094  if (renamed) {
3095  if (subBranch->fBranchClass == branchClass) {
3096  if (branchElem) subBranch->SetTargetClass(branchElem->GetNewClass()->GetName());
3097  else subBranch->SetTargetClass(fTargetClass->GetName());
3098  }
3099  }
3100 
3101  TVirtualStreamerInfo* sinfo = subBranch->GetInfoImp();
3102  if (!sinfo) {
3103  Warning("InitializeOffsets", "No streamer info for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3104  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3105  continue;
3106  }
3107  if (!sinfo->IsCompiled()) {
3108  Warning("InitializeOffsets", "No elements array for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3109  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3110  continue;
3111  }
3112  // FIXME: Make sure subBranch->fID is in range.
3113  TStreamerElement* subBranchElement = sinfo->GetElement(subBranch->fID);
3114  if (!subBranchElement) {
3115  Warning("InitializeOffsets", "No streamer element for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3116  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3117  continue;
3118  } else if (subBranchElement->TestBit(TStreamerElement::kRepeat)) {
3119  // If we have a repeating streamerElement, use the next
3120  // one as it actually hold the 'real' data member('s offset)
3121  if (sinfo->GetElement(subBranch->fID+1)) {
3122  subBranchElement = sinfo->GetElement(subBranch->fID+1);
3123  }
3124  } else if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3125  // We have a cached item which is not a repeated but we might still
3126  // have some Actions triggered by a rule that affect real
3127  // data member(s).
3128  if (subBranch->fReadActionSequence && subBranch->fReadActionSequence->fActions.size() > 1) {
3129  typedef TStreamerInfoActions::ActionContainer_t::iterator iterator;
3130  iterator end = subBranch->fReadActionSequence->fActions.end();
3131  for(iterator iter = subBranch->fReadActionSequence->fActions.begin();
3132  iter != end; ++iter) {
3133  TStreamerInfoActions::TConfiguration *config = iter->fConfiguration;
3134  UInt_t id = config->fElemId;
3135  TStreamerElement *e = (TStreamerElement*)config->fInfo->GetElements()->At(id);
3136  if (e && !e->TestBit(TStreamerElement::kCache)) {
3137  subBranchElement = e;
3138  alternateElement = true;
3139  break;
3140  }
3141  }
3142  }
3143  }
3144 
3145  localOffset = subBranchElement->GetOffset();
3146  if (localOffset == TStreamerInfo::kMissing) {
3147  subBranch->fObject = 0;
3148  }
3149  {
3150  Int_t streamerType = subBranchElement->GetType();
3151  if (streamerType > TStreamerInfo::kObject
3152  && subBranch->GetListOfBranches()->GetEntries()==0
3153  && CanSelfReference(subBranchElement->GetClass()))
3154  {
3155  subBranch->SetBit(kBranchAny);
3156  } else {
3157  subBranch->ResetBit(kBranchAny);
3158  }
3159  }
3160 
3161  if (subBranchElement->GetNewType()<0) {
3162  subBranch->ResetBit(kBranchAny);
3163  subBranch->ResetBit(kBranchObject);
3164  }
3165 
3166  // Note: This call is expensive, do it only once.
3167  TBranch* mother = GetMother();
3168  if (!mother) {
3169  Warning("InitializeOffsets", "Branch '%s' has no mother!", GetName());
3170  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3171  continue;
3172  }
3173  TString motherName(mother->GetName());
3174  Bool_t motherDot = kFALSE;
3175  if (motherName.Length() && strchr(motherName.Data(), '.')) {
3176  motherDot = kTRUE;
3177  }
3178  Bool_t motherDotAtEnd = kFALSE;
3179  if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
3180  motherDotAtEnd = kTRUE;
3181  }
3182 
3183  Bool_t isBaseSubBranch = kFALSE;
3184  if ((subBranch->fType == 1) || (subBranchElement && subBranchElement->IsBase())) {
3185  // -- Base class sub-branch (1).
3186  //
3187  // Note: Our type will not be 1, even though we are
3188  // a base class branch, if we are not split (see the
3189  // constructor), or if we are an STL container master
3190  // branch and a base class branch at the same time
3191  // or an std::string.
3192  isBaseSubBranch = kTRUE;
3193  }
3194 
3195  Bool_t isContDataMember = kFALSE;
3196  if ((subBranch->fType == 31) || (subBranch->fType == 41)) {
3197  // -- Container data member sub-branch (31 or 41).
3198  isContDataMember = kTRUE;
3199  }
3200 
3201  // I am either a data member sub-branch (0), or a base class
3202  // sub-branch (1), or TClonesArray master sub-branch (3),
3203  // or an STL container master sub-branch (4), or TClonesArray
3204  // data member sub-branch (31), or an STL container data member
3205  // sub-branch (41).
3206  //
3207  // My parent branch is either a top-level branch ((0), fID==(-2,-1)),
3208  // or a base class sub-branch (1), or a split-class branch (2),
3209  // or a TClonesArray master branch (3), or an STL container
3210  // master branch (4).
3211  //
3212 
3213  //
3214  // We need to extract from our name the name
3215  // of the data member which contains us, so
3216  // that we may then do a by-name lookup in the
3217  // dictionary meta info of our parent class to
3218  // get our offset in our parent class.
3219  //
3220 
3221  // Get our name.
3222  TString dataName(subBranch->GetName());
3223  if (motherDotAtEnd) {
3224  // -- Remove the top-level branch name from our name.
3225  dataName.Remove(0, motherName.Length());
3226  // stlParentNameUpdated is false the first time in this loop.
3227  if (!stlParentNameUpdated && stlParentName.Length()) {
3228  stlParentName.Remove(0, motherName.Length());
3229  stlParentNameUpdated = kTRUE;
3230  }
3231  } else if (motherDot) {
3232  // -- Remove the top-level branch name from our name, folder case.
3233  //
3234  // Note: We are in the case where our mother was created
3235  // by the branch constructor which takes a folder
3236  // as an argument. The mother branch has internal
3237  // dots in its name to represent the folder heirarchy.
3238  // The TTree::Bronch() routine has handled us as a
3239  // special case, we must compensate.
3240  if ((fID < 0) && (subBranchElement->IsA() == TStreamerBase::Class())) {
3241  // -- Our name is the mother name, remove it.
3242  // Note: The test is our parent is a top-level branch
3243  // and our streamer is the base class streamer,
3244  // this matches the exact test in TTree::Bronch().
3245  if (dataName.Length() == motherName.Length()) {
3246  dataName.Remove(0, motherName.Length());
3247  // stlParentNameUpdated is false the first time in this loop.
3248  if (!stlParentNameUpdated && stlParentName.Length()) {
3249  stlParentName.Remove(0, motherName.Length());
3250  }
3251  }
3252  } else {
3253  // -- Remove the mother name and the dot.
3254  if (dataName.Length() > motherName.Length()) {
3255  dataName.Remove(0, motherName.Length() + 1);
3256  if (!stlParentNameUpdated && stlParentName.Length()) {
3257  stlParentName.Remove(0, motherName.Length());
3258  }
3259  }
3260  }
3261  }
3262  stlParentNameUpdated = kTRUE;
3263  if (isBaseSubBranch) {
3264  // -- Remove the base class name suffix from our name.
3265  // Note: The pattern is the name of the base class.
3266  TString pattern(subBranchElement->GetName());
3267  if (pattern.Length() <= dataName.Length()) {
3268  if (!strcmp(dataName.Data() + (dataName.Length() - pattern.Length()), pattern.Data())) {
3269  // The branch name contains the name of the base class in it.
3270  // This name is not reproduced in the sub-branches, so we need to
3271  // remove it.
3272  dataName.Remove(dataName.Length() - pattern.Length());
3273  }
3274  }
3275  // Remove any leading dot.
3276  if (dataName.Length()) {
3277  if (dataName[0] == '.') {
3278  dataName.Remove(0, 1);
3279  }
3280  }
3281  // Note: We intentionally leave any trailing dot
3282  // in our modified name here.
3283  }
3284 
3285  // Get our parent branch's name.
3286  TString parentName(GetName());
3287  if (motherDotAtEnd) {
3288  // -- Remove the top-level branch name from our parent's name.
3289  parentName.Remove(0, motherName.Length());
3290  } else if (motherDot) {
3291  // -- Remove the top-level branch name from our parent's name, folder case.
3292  //
3293  // Note: We are in the case where our mother was created
3294  // by the branch constructor which takes a folder
3295  // as an argument. The mother branch has internal
3296  // dots in its name to represent the folder heirarchy.
3297  // The TTree::Bronch() routine has handled us as a
3298  // special case, we must compensate.
3299  if ((fID > -1) && (mother == mother->GetSubBranch(this)) && (branchElem->IsA() == TStreamerBase::Class())) {
3300  // -- Our parent's name is the mother name, remove it.
3301  // Note: The test is our parent's parent is a top-level branch
3302  // and our parent's streamer is the base class streamer,
3303  // this matches the exact test in TTree::Bronch().
3304  if (parentName.Length() == motherName.Length()) {
3305  parentName.Remove(0, motherName.Length());
3306  }
3307  } else {
3308  // -- Remove the mother name and the dot.
3309  if (parentName.Length() > motherName.Length()) {
3310  parentName.Remove(0, motherName.Length() + 1);
3311  }
3312  }
3313  }
3314  // FIXME: Do we need to use the other tests for a base class here?
3315  if (fType == 1) {
3316  // -- Our parent is a base class sub-branch, remove the base class name suffix from its name.
3317  if (mother != mother->GetSubBranch(this)) {
3318  // -- My parent's parent is not a top-level branch.
3319  // Remove the base class name suffix from the parent name.
3320  // Note: The pattern is the name of the base class.
3321  // coverity[var_deref_model] branchElem is non zero here since fType==1 and thus fID > -1
3322  TString pattern(branchElem->GetName());
3323  if (pattern.Length() <= parentName.Length()) {
3324  if (!strcmp(parentName.Data() + (parentName.Length() - pattern.Length()), pattern.Data())) {
3325  // The branch name contains the name of the base class in it.
3326  // This name is not reproduced in the sub-branches, so we need to
3327  // remove it.
3328  parentName.Remove(parentName.Length() - pattern.Length());
3329  }
3330  }
3331  }
3332  // Note: We intentionally leave any trailing dots
3333  // in the modified parent name here.
3334  }
3335 
3336  // Remove the parent branch name part from our name,
3337  // but only if the parent branch is not a top-level branch.
3338  // FIXME: We should not assume parent name does not have length 0.
3339  if (fID > -1) {
3340  RemovePrefix(dataName, parentName);
3341  }
3342 
3343  // Remove any leading dot.
3344  if (dataName.Length()) {
3345  if (dataName[0] == '.') {
3346  dataName.Remove(0, 1);
3347  }
3348  }
3349 
3350  // Remove any trailing dot.
3351  if (dataName.Length()) {
3352  if (dataName[dataName.Length()-1] == '.') {
3353  dataName.Remove(dataName.Length() - 1, 1);
3354  }
3355  }
3356 
3357  //
3358  // Now that we have our data member name, find our offset
3359  // in our parent class.
3360  //
3361  // Note: Our data member name can have many dots in it
3362  // if branches were elided between our parent branch
3363  // and us by Unroll().
3364  //
3365  // FIXME: This may not work if our member name is ambiguous.
3366  //
3367 
3368  Int_t offset = 0;
3369  if (dataName.Length()) {
3370  // -- We have our data member name, do a lookup in the dictionary meta info of our parent class.
3371  // Get our parent class.
3372  TClass* pClass = 0;
3373  // First check whether this sub-branch is part of the 'cache' (because the data member it
3374  // represents is no longer in the current class layout.
3375  TStreamerInfo *subInfo = subBranch->GetInfoImp();
3376  //if (subInfo && subBranch->TestBit(kCache)) { // subInfo->GetElements()->At(subBranch->GetID())->TestBit(TStreamerElement::kCache)) {
3377  if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3378  pClass = ((TStreamerElement*)subInfo->GetElements()->At(0))->GetClassPointer();
3379  }
3380  // FIXME: Do we need the other base class tests here?
3381  if (!pClass) {
3382  if (fType == 1) {
3383  // -- Parent branch is a base class branch.
3384  // FIXME: Is using branchElem here the right thing?
3385  pClass = branchElem->GetClassPointer();
3386  if (pClass->Property() & kIsAbstract) {
3387  // the class is abstract, let see if the
3388 
3389  TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this);
3390  if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
3391  // Our parent's class is emulated and we represent an abstract class.
3392  // and the target class has not been set explicilty.
3393  TString target = pClass->GetName();
3394  target += "@@emulated";
3395 
3396  pClass = TClass::GetClass(target);
3397  }
3398  }
3399  } else {
3400  // -- Parent branch is *not* a base class branch.
3401  // FIXME: This sometimes returns a null pointer.
3402  pClass = subBranch->GetParentClass();
3403  }
3404  }
3405  if (!pClass) {
3406  // -- No parent class, fix it.
3407  // FIXME: This is probably wrong!
3408  // Assume parent class is our parent branch's clones class or value class.
3409  if (GetClonesName() && strlen(GetClonesName())) {
3410  pClass = fClonesClass;
3411  if (!pClass) {
3412  Warning("InitializeOffsets", "subBranch: '%s' has no parent class, and cannot get class for clones class: '%s'!", subBranch->GetName(), GetClonesName());
3413  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3414  continue;
3415  }
3416  Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3417  }
3419  pClass = fBranchCount->fCollProxy->GetValueClass();
3420  Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass ? pClass->GetName() : "unknowned class");
3421  }
3422  if (!pClass) {
3423  // -- Still no parent class, assume our parent class is our parent branch's class.
3424  // FIXME: This is probably wrong!
3425  pClass = branchClass;
3426  // FIXME: Enable this warning!
3427  //Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3428  }
3429  }
3430  if (renamed && pClass) {
3431  if (pClass == branchClass) {
3432  pClass = branchElem->GetNewClass();
3433  } else if (fCollProxy && pClass == branchClass->GetCollectionProxy()->GetValueClass()) {
3434  pClass = fCollProxy->GetValueClass();
3435  }
3436  }
3437 
3438  //------------------------------------------------------------------
3439  // If we have the are the sub-branch of the TBranchSTL, we need
3440  // to remove it's name to get the correct real data offsets
3441  ////////////////////////////////////////////////////////////////////
3442 
3443  if( dynamic_cast<TBranchSTL*>(fParent) && stlParentName.Length() )
3444  {
3445  if( !strncmp( stlParentName.Data(), dataName.Data(), stlParentName.Length()-1 )
3446  && dataName[ stlParentName.Length() ] == '.' )
3447  dataName.Remove( 0, stlParentName.Length()+1 );
3448  }
3449 
3450  // Find our offset in our parent class using
3451  // a lookup by name in the dictionary meta info
3452  // for our parent class.
3453 
3454  if (alternateElement) {
3455  Ssiz_t dotpos = dataName.Last('.');
3456  Ssiz_t endpos = dataName.Length();
3457  if (dotpos != kNPOS) ++dotpos; else dotpos = 0;
3458  dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
3459  }
3460  TRealData* rd = pClass->GetRealData(dataName);
3461  if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
3462  // -- Data member exists in the dictionary meta info, get the offset.
3463  // If we are using an alternateElement, it is the target of a rule
3464  // and might be indeed transient.
3465  offset = rd->GetThisOffset();
3466  } else if (subBranchElement->TestBit(TStreamerElement::kWholeObject)) {
3467  // We are a rule with no specific target, it applies to the whole
3468  // object, let's set the offset to zero
3469  offset = 0;
3470  } else {
3471  // -- No dictionary meta info for this data member, it must no
3472  // longer exist
3473  if (fEntries == 0) {
3474  // ... unless we creating the branch in which case
3475  // we have an internal error.
3476  if (pClass->GetListOfRealData()->GetEntries() == 0) {
3477  // We are probably missing the ShowMember, let's
3478  // just issue an error.
3479  Error("InitializeOffsets",
3480  "Could not find the real data member '%s' when constructing the branch '%s' [Likely missing ShowMember].",
3481  dataName.Data(),GetName());
3482  } else if (subInfo && subInfo->GetClassVersion()!=subInfo->GetClass()->GetClassVersion()) {
3483  // In the case where we are cloning a TTree that was created with an older version of the layout, we may not
3484  // able to find all the members
3485  Info("InitializeOffsets",
3486  "TTree created with an older schema, some data might not be copied in 'slow-cloning' mode; fast-cloning should have the correct result. '%s' is missing when constructing the branch '%s'. ",
3487  dataName.Data(),GetName());
3488  } else {
3489  // Something really bad happen.
3490  Fatal("InitializeOffsets",
3491  "Could not find the real data member '%s' when constructing the branch '%s' [Likely an internal error, please report to the developers].",
3492  dataName.Data(),GetName());
3493  }
3494  }
3495  localOffset = TStreamerInfo::kMissing;
3496  }
3497  } else {
3498  // -- We have no data member name, ok for a base class, not good otherwise.
3499  if (isBaseSubBranch) {
3500  // I am a direct base class of my parent class, my local offset is enough.
3501  } else {
3502  Warning("InitializeOffsets", "Could not find the data member name for branch '%s' with parent branch '%s', assuming offset is zero!", subBranch->GetName(), GetName());
3503  }
3504  }
3505 
3506  //
3507  // Ok, do final calculations for fOffset and fBranchOffset.
3508  //
3509 
3510  if (isContDataMember) {
3511  // -- Container data members set fOffset instead of fBranchOffset.
3512  // The fOffset is what should be added to the start of the entry
3513  // in the collection (i.e., its current absolute address) to find
3514  // the beginning of the data member described by the current branch.
3515  //
3516  // Compensate for the i/o routines adding our local offset later.
3517  if (subBranch->fObject == 0 && localOffset == TStreamerInfo::kMissing) {
3518  subBranch->SetOffset(TStreamerInfo::kMissing);
3519  // We stil need to set fBranchOffset in the case of a missing
3520  // element so that SetAddress is (as expected) not called
3521  // recursively in this case.
3522  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3523  } else {
3524  if (isBaseSubBranch) {
3525  // The value of 'offset' for a base class does not include its
3526  // 'localOffset'.
3527  subBranch->SetOffset(offset);
3528  } else {
3529  // The value of 'offset' for a regular data member does include its
3530  // 'localOffset', we need to remove it explicitly.
3531  subBranch->SetOffset(offset - localOffset);
3532  }
3533  }
3534  } else {
3535  // -- Set fBranchOffset for sub-branch.
3536  Int_t isSplit = 0 != subBranch->GetListOfBranches()->GetEntriesFast();
3537  if (subBranch->fObject == 0 && localOffset == TStreamerInfo::kMissing) {
3538  // The branch is missing
3539  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3540 
3541  } else if (isSplit) {
3542  if (isBaseSubBranch) {
3543  // We are split, so we need to add in our local offset
3544  // to get our absolute address for our children.
3545  fBranchOffset[subBranchIdx] = offset + localOffset;
3546  } else {
3547  // We are split so our offset will never be
3548  // used in an i/o, so we do not have to subtract
3549  // off our local offset like below.
3550  fBranchOffset[subBranchIdx] = offset;
3551  }
3552  } else {
3553  if (isBaseSubBranch) {
3554  // We are not split, so our local offset will be
3555  // added later by the i/o routines.
3556  fBranchOffset[subBranchIdx] = offset;
3557  } else {
3558  // Compensate for the fact that the i/o routines
3559  // are going to add my local offset later.
3560  fBranchOffset[subBranchIdx] = offset - localOffset;
3561  }
3562  }
3563  }
3564  }
3565  }
3566  else {
3567  if (fID > -1) {
3568  // Branch is *not* a top-level branch.
3569  // Let's check if the target member is still present in memory
3571  fObject = 0;
3572  }
3573  }
3574  }
3575  const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
3576  if (fReadActionSequence && isSplitNode) {
3577  TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3578  auto index = parent->fBranches.IndexOf(this);
3579  if (index >= 0) {
3580  fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
3581  }
3582  }
3583 
3584  fInitOffsets = kTRUE;
3585 }
3586 
3587 ////////////////////////////////////////////////////////////////////////////////
3588 /// Return kTRUE if more than one leaf, kFALSE otherwise.
3589 
3591 {
3592  Int_t nbranches = fBranches.GetEntriesFast();
3593  if (nbranches >= 1) {
3594  return kTRUE;
3595  }
3596  TList* browsables = const_cast<TBranchElement*>(this)->GetBrowsables();
3597  return browsables && browsables->GetSize();
3598 }
3599 
3600 ////////////////////////////////////////////////////////////////////////////////
3601 /// Detect a collection written using a zero pointer in old versions of root.
3602 /// In versions of ROOT older than 4.00/03, if a collection (TClonesArray
3603 /// or STL container) was split but the pointer to the collection was zeroed
3604 /// out, nothing was saved. Hence there is no __easy__ way to detect the
3605 /// case. In newer versions, a zero is written so that a 'missing' collection
3606 /// appears to be an empty collection.
3607 
3609 {
3610  Bool_t ismissing = kFALSE;
3612  if (basket && fTree) {
3613  Long64_t entry = fTree->GetReadEntry();
3615  Long64_t last;
3616  if (fReadBasket == fWriteBasket) {
3617  last = fEntryNumber - 1;
3618  } else {
3619  last = fBasketEntry[fReadBasket+1] - 1;
3620  }
3621  Int_t* entryOffset = basket->GetEntryOffset();
3622  Int_t bufbegin;
3623  Int_t bufnext;
3624  if (entryOffset) {
3625  bufbegin = entryOffset[entry-first];
3626 
3627  if (entry < last) {
3628  bufnext = entryOffset[entry+1-first];
3629  } else {
3630  bufnext = basket->GetLast();
3631  }
3632  if (bufnext == bufbegin) {
3633  ismissing = kTRUE;
3634  } else {
3635  // fixed length buffer so this is not the case here.
3636  if (basket->GetNevBufSize() == 0) {
3637  ismissing = kTRUE;
3638  }
3639  }
3640  }
3641  }
3642  return ismissing;
3643 }
3644 
3645 ////////////////////////////////////////////////////////////////////////////////
3646 /// Print branch parameters.
3647 
3648 static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids)
3649 {
3650  for(auto &cursor : ids) {
3651  auto id = cursor.fElemID;
3652  if (id >= 0)
3653  info->GetElement(id)->ls();
3654  else if (cursor.fNestedIDs) {
3655  Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
3656  PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
3657  }
3658  }
3659 }
3660 
3661 void TBranchElement::Print(Option_t* option) const
3662 {
3663  Int_t nbranches = fBranches.GetEntriesFast();
3664  if (strncmp(option,"debugAddress",strlen("debugAddress"))==0) {
3665  if (strlen(option)==strlen("debugAddress")) {
3666  Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s\n",
3667  "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject");
3668  }
3669  if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3670  else Printf("%-24s ", GetName());
3671 
3672  TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3673  Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3674  TVirtualStreamerInfo *info = ((TBranchElement*)this)->GetInfoImp();
3675 
3676  Printf("%-16s %2d %4d %-16s %-16s %8x %8x %s\n",
3677  info ? info->GetName() : "StreamerInfo unvailable", GetID(), GetType(),
3679  (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3680  GetOffset(), GetObject());
3681  for (Int_t i = 0; i < nbranches; ++i) {
3682  TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3683  subbranch->Print("debugAddressSub");
3684  }
3685  return;
3686  }
3687  if (strncmp(option,"debugInfo",strlen("debugInfo"))==0) {
3688  Printf("Branch %s uses:",GetName());
3689  if (fID>=0) {
3690  // GetInfoImp()->GetElement(fID)->ls();
3691  // for(UInt_t i=0; i< fIDs.size(); ++i) {
3692  // GetInfoImp()->GetElement(fIDs[i])->ls();
3693  // }
3694  TStreamerInfo *localInfo = GetInfoImp();
3695  if (fType == 3 || fType == 4) {
3696  // Search for the correct version.
3697  localInfo = FindOnfileInfo(fClonesClass, fBranches);
3698  }
3699  Printf(" With elements:");
3700  if (fType != 3 && fType != 4)
3701  localInfo->GetElement(fID)->ls();
3702  PrintElements(localInfo, fNewIDs);
3703  Printf(" with read actions:");
3705  Printf(" with write actions:");
3707  } else if (!fNewIDs.empty() && GetInfoImp()) {
3708  TStreamerInfo *localInfo = GetInfoImp();
3709  if (fType == 3 || fType == 4) {
3710  localInfo = (TStreamerInfo *)fClonesClass->GetStreamerInfo();
3711  }
3712  PrintElements(localInfo, fNewIDs);
3713  Printf(" with read actions:");
3715  Printf(" with write actions:");
3717  }
3718  TString suboption = "debugInfoSub";
3719  suboption += (option+strlen("debugInfo"));
3720  for (Int_t i = 0; i < nbranches; ++i) {
3721  TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3722  subbranch->Print(suboption);
3723  }
3724  Printf(" ");
3725  return;
3726  }
3727  if (nbranches) {
3728  if (fID == -2) {
3729  if (strcmp(GetName(),GetTitle()) == 0) {
3730  Printf("*Branch :%-66s *",GetName());
3731  } else {
3732  Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3733  }
3734  Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3735  Printf("*............................................................................*");
3736  }
3737  if (fType >= 2) {
3738  TBranch::Print(option);
3739  }
3740  for (Int_t i=0;i<nbranches;i++) {
3741  TBranch *branch = (TBranch*)fBranches.At(i);
3742  branch->Print(option);
3743  }
3744  } else {
3745  TBranch::Print(option);
3746  }
3747 }
3748 
3749 ////////////////////////////////////////////////////////////////////////////////
3750 /// Prints values of leaves.
3751 
3753 {
3754  ValidateAddress();
3755 
3756  TStreamerInfo *info = GetInfoImp();
3757  Int_t prID = fID;
3758  char *object = fObject;
3759  if (TestBit(kCache)) {
3761  prID = fID+1;
3762  } else if (fOnfileObject) {
3763  object = fOnfileObject->GetObjectAt(0);
3764  }
3765  }
3766 
3767  if (TestBit(kDecomposedObj)) {
3768  if (!fAddress) {
3769  return;
3770  }
3771  if (fType == 3 || fType == 4) {
3772  // TClonesArray or STL container top-level branch.
3773  printf(" %-15s = %d\n", GetName(), fNdata);
3774  return;
3775  } else if (fType == 31 || fType == 41) {
3776  // TClonesArray or STL container sub-branch.
3777  Int_t n = TMath::Min(10, fNdata);
3780  // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
3781  // printed as a string and could print weird characters.
3782  // So we print an unsigned char instead (not perfect, but better).
3783  atype = TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kUChar;
3784  }
3785  if (atype > 54) {
3786  // FIXME: More logic required here (like in ReadLeaves)
3787  printf(" %-15s = %d\n", GetName(), fNdata);
3788  return;
3789  }
3790  if (fStreamerType > 20) {
3791  atype -= 20;
3793  n = n * leaf->GetLenStatic();
3794  }
3795  if (GetInfoImp()) {
3796  GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3797  }
3798  return;
3799  } else if (fType <= 2) {
3800  // Branch in split mode.
3801  // FIXME: This should probably be < 60 instead.
3802  if ((fStreamerType > 40) && (fStreamerType < 55)) {
3803  Int_t atype = fStreamerType - 20;
3804  TBranchElement* counterElement = (TBranchElement*) fBranchCount;
3805  Int_t n = (Int_t) counterElement->GetValue(0, 0);
3806  if (GetInfoImp()) {
3807  GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3808  }
3809  } else {
3810  if (GetInfoImp()) {
3811  GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3812  }
3813  }
3814  return;
3815  }
3816  } else if (fType == 3) {
3817  printf(" %-15s = %d\n", GetName(), fNdata);
3818  } else if (fType == 31) {
3819  TClonesArray* clones = (TClonesArray*) object;
3820  if (GetInfoImp()) {
3821  GetInfoImp()->PrintValueClones(GetName(), clones, prID, fOffset, lenmax);
3822  }
3823  } else if (fType == 41) {
3825  if (GetInfoImp()) {
3826  GetInfoImp()->PrintValueSTL(GetName(), ((TBranchElement*) this)->GetCollectionProxy(), prID, fOffset, lenmax);
3827  }
3828  } else {
3829  if (GetInfoImp()) {
3830  GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3831  }
3832  }
3833 }
3834 
3835 ////////////////////////////////////////////////////////////////////////////////
3836 /// Unconfiguration Read Leave function.
3837 
3839 {
3840  Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
3841 }
3842 
3843 ////////////////////////////////////////////////////////////////////////////////
3844 /// Read leaves into i/o buffers for this branch.
3845 /// For the case where the branch is set in MakeClass mode (decomposed object).
3846 
3848 {
3849  ValidateAddress();
3850 
3851  if (fType == 3 || fType == 4) {
3852  // Top level branch of a TClonesArray.
3853  Int_t *n = (Int_t*) fAddress;
3854  b >> n[0];
3855  if ((n[0] < 0) || (n[0] > fMaximum)) {
3856  if (IsMissingCollection()) {
3857  n[0] = 0;
3858  b.SetBufferOffset(b.Length() - sizeof(n));
3859  } else {
3860  Error("ReadLeaves", "Incorrect size read for the container in %s\nThe size read is %d when the maximum is %d\nThe size is reset to 0 for this entry (%lld)", GetName(), n[0], fMaximum, GetReadEntry());
3861  n[0] = 0;
3862  }
3863  }
3864  fNdata = n[0];
3865  if (fType == 4) {
3866  Int_t nbranches = fBranches.GetEntriesFast();
3867  switch(fSTLtype) {
3868  case ROOT::kSTLset:
3869  case ROOT::kSTLmultiset:
3870  case ROOT::kSTLmap:
3871  case ROOT::kSTLmultimap:
3872  for (Int_t i=0; i<nbranches; i++) {
3873  TBranch *branch = (TBranch*)fBranches[i];
3874  Int_t nb = branch->GetEntry(GetReadEntry(), 1);
3875  if (nb < 0) {
3876  break;
3877  }
3878  }
3879  break;
3880  default:
3881  break;
3882  }
3883  }
3884  return;
3885  } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
3887  Int_t atype = fStreamerType;
3888  // FIXME: This should probably be > 59 instead.
3889  if (atype > 54) return;
3890  if (!fAddress) {
3891  return;
3892  }
3893  Int_t n = fNdata;
3894  if (atype>40) {
3895  atype -= 40;
3896  if (!fBranchCount2) return;
3897  const char *len_where = (char*)fBranchCount2->fAddress;
3898  if (!len_where) return;
3899  Int_t len_atype = fBranchCount2->fStreamerType;
3900  Int_t length;
3901  Int_t k;
3902  Char_t isArray;
3903  for( k=0; k<n; k++) {
3904  char **where = &(((char**)fAddress)[k]);
3905  delete [] *where;
3906  *where = 0;
3907  switch(len_atype) {
3908  case 1: {length = ((Char_t*) len_where)[k]; break;}
3909  case 2: {length = ((Short_t*) len_where)[k]; break;}
3910  case 3: {length = ((Int_t*) len_where)[k]; break;}
3911  case 4: {length = ((Long_t*) len_where)[k]; break;}
3912  //case 5: {length = ((Float_t*) len_where)[k]; break;}
3913  case 6: {length = ((Int_t*) len_where)[k]; break;}
3914  //case 8: {length = ((Double_t*)len_where)[k]; break;}
3915  case 11: {length = ((UChar_t*) len_where)[k]; break;}
3916  case 12: {length = ((UShort_t*) len_where)[k]; break;}
3917  case 13: {length = ((UInt_t*) len_where)[k]; break;}
3918  case 14: {length = ((ULong_t*) len_where)[k]; break;}
3919  case 15: {length = ((UInt_t*) len_where)[k]; break;}
3920  case 16: {length = ((Long64_t*) len_where)[k]; break;}
3921  case 17: {length = ((ULong64_t*)len_where)[k]; break;}
3922  case 18: {length = ((Bool_t*) len_where)[k]; break;}
3923  default: continue;
3924  }
3925  b >> isArray;
3926  if (length <= 0) continue;
3927  if (isArray == 0) continue;
3928  switch (atype) {
3929  case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
3930  case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
3931  case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
3932  case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
3933  case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
3934  case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
3935  case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
3936  case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
3937  case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
3938  case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
3939  case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
3940  case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
3941  case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
3942  case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
3943  case 18: {*where=new char[sizeof(Bool_t)*length]; b.ReadFastArray((Bool_t*) *where, length); break;}
3944  }
3945  }
3946  return;
3947  }
3948  if (atype > 20) {
3949  atype -= 20;
3951  n *= leaf->GetLenStatic();
3952  }
3953  switch (atype) {
3954  case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
3955  case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
3956  case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
3957  case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
3958  case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
3959  case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
3960  case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
3961  case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
3962  case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
3963  case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
3964  case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
3965  case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
3966  case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
3967  case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
3968  case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
3969  case 9: {
3972  Double_t *xx = (Double_t*) fAddress;
3973  for (Int_t ii=0;ii<n;ii++) {
3974  b.ReadDouble32(&(xx[ii]),se);
3975  }
3976  break;
3977  }
3978  case 19: {
3981  Float_t *xx = (Float_t*) fAddress;
3982  for (Int_t ii=0;ii<n;ii++) {
3983  b.ReadFloat16(&(xx[ii]),se);
3984  }
3985  break;
3986  }
3987  }
3988  return;
3989  } else if (fType <= 2) { // branch in split mode
3990  // FIXME: This should probably be < 60 instead.
3991  if (fStreamerType > 40 && fStreamerType < 55) {
3992  Int_t atype = fStreamerType - 40;
3993  Int_t n;
3994  if (fBranchCount==0) {
3995  // Missing fBranchCount. let's attempts to recover.
3996 
3997  TString countname( GetName() );
3998  Ssiz_t dot = countname.Last('.');
3999  if (dot>=0) {
4000  countname.Remove(dot+1);
4001  } else {
4002  countname = "";
4003  }
4004  TString counter( GetTitle() );
4005  Ssiz_t loc = counter.Last('[');
4006  if (loc>=0) {
4007  counter.Remove(0,loc+1);
4008  }
4009  loc = counter.Last(']');
4010  if (loc>=0) {
4011  counter.Remove(loc);
4012  }
4013  countname += counter;
4014  SetBranchCount((TBranchElement *)fTree->GetBranch(countname));
4015  }
4016  if (fBranchCount) {
4017  n = (Int_t)fBranchCount->GetValue(0,0);
4018  } else {
4019  Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4020  n = 0;
4021  }
4022  fNdata = n;
4023  Char_t isArray;
4024  b >> isArray;
4025  switch (atype) {
4026  case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4027  case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4028  case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4029  case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4030  case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4031  case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4032  case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4033  case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4034  case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4035  case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4036  case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4037  case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4038  case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
4039  case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4040  case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
4041  case 9: {
4044  Double_t *xx = (Double_t*) fAddress;
4045  for (Int_t ii=0;ii<n;ii++) {
4046  b.ReadDouble32(&(xx[ii]),se);
4047  }
4048  break;
4049  }
4050  case 19: {
4053  Float_t *xx = (Float_t*) fAddress;
4054  for (Int_t ii=0;ii<n;ii++) {
4055  b.ReadFloat16(&(xx[ii]),se);
4056  }
4057  break;
4058  }
4059  }
4060  } else {
4061  fNdata = 1;
4062  if (fAddress) {
4063  if (fType<0) {
4064  // Non TObject, Non collection classes with a custom streamer.
4065 
4066  // if (fObject)
4068  } else {
4069  TStreamerInfo *info = GetInfoImp();
4070  if (!info) {
4071  return;
4072  }
4073  // Since info is not null, fReadActionSequence is not null either.
4075  }
4077  fNdata = (Int_t) GetValue(0, 0);
4078  }
4079  } else {
4080  fNdata = 0;
4081  }
4082  }
4083  return;
4084  }
4085 }
4086 
4087 ////////////////////////////////////////////////////////////////////////////////
4088 /// Read leaves into i/o buffers for this branch.
4089 /// Case of a collection (fType == 4).
4090 
4092 {
4093  ValidateAddress();
4094  if (fObject == 0)
4095  {
4096  // We have nowhere to copy the data (probably because the data member was
4097  // 'dropped' from the current schema) so let's no copy it in a random place.
4098  return;
4099  }
4100 
4101  // STL container master branch (has only the number of elements).
4102  Int_t n;
4103  b >> n;
4104  if ((n < 0) || (n > fMaximum)) {
4105  if (IsMissingCollection()) {
4106  n = 0;
4107  b.SetBufferOffset(b.Length()-sizeof(n));
4108  } else {
4109  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());
4110  n = 0;
4111  }
4112  }
4113  fNdata = n;
4114 
4115  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,n);
4116 
4117  // Note: Proxy-helper needs to "embrace" the entire
4118  // streaming of this STL container if the container
4119  // is a set/multiset/map/multimap (what we do not
4120  // know here).
4121  // For vector/list/deque Allocate == Resize
4122  // and Commit == noop.
4123  // TODO: Exception safety a la TPushPop
4126  void* alternate = proxy->Allocate(fNdata, true);
4128  fPtrIterators->CreateIterators(alternate, proxy);
4129  } else {
4130  fIterators->CreateIterators(alternate, proxy);
4131  }
4132 
4133  Int_t nbranches = fBranches.GetEntriesFast();
4134  switch (fSTLtype) {
4135  case ROOT::kSTLset:
4138  case ROOT::kSTLmultiset:
4139  case ROOT::kSTLmap:
4140  case ROOT::kSTLmultimap:
4143  for (Int_t i = 0; i < nbranches; ++i) {
4144  TBranch *branch = (TBranch*) fBranches[i];
4145  Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4146  if (nb < 0) {
4147  // Give up on i/o failure.
4148  // FIXME: We need an error message here.
4149  break;
4150  }
4151  }
4152  break;
4153  default:
4154  break;
4155  }
4156  //------------------------------------------------------------------------
4157  // We have split this stuff, so we need to create the the pointers
4158  /////////////////////////////////////////////////////////////////////////////
4159 
4161  {
4162  TClass *elClass = proxy->GetValueClass();
4163 
4164  //--------------------------------------------------------------------
4165  // The allocation is done in this strange way because ReadLeaves
4166  // is being called many times by TTreeFormula!!!
4167  //////////////////////////////////////////////////////////////////////////
4168 
4169  Int_t i = 0;
4170  // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4171  if( !fNdata || *(void**)proxy->At( 0 ) != 0 )
4172  i = fNdata;
4173 
4174  for( ; i < fNdata; ++i )
4175  {
4176  void **el = (void**)proxy->At( i );
4177  // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4178  *el = elClass->New();
4179  }
4180  }
4181 
4182  proxy->Commit(alternate);
4183 }
4184 
4185 ////////////////////////////////////////////////////////////////////////////////
4186 /// Read leaves into i/o buffers for this branch.
4187 /// Case of a data member within a collection (fType == 41).
4188 
4190 {
4191  ValidateAddress();
4192  if (fObject == 0)
4193  {
4194  // We have nowhere to copy the data (probably because the data member was
4195  // 'dropped' from the current schema) so let's no copy it in a random place.
4196  return;
4197  }
4198 
4199  // STL container sub-branch (contains the elements).
4201  if (!fNdata) {
4202  return;
4203  }
4204 
4205  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4206 
4207  TStreamerInfo *info = GetInfoImp();
4208  if (info == 0) return;
4209 
4212 
4213  // R__ASSERT(0);
4215  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4216 }
4217 
4218 ////////////////////////////////////////////////////////////////////////////////
4219 /// Read leaves into i/o buffers for this branch.
4220 /// Case of a data member within a collection (fType == 41).
4221 
4223 {
4224  ValidateAddress();
4225  if (fObject == 0)
4226  {
4227  // We have nowhere to copy the data (probably because the data member was
4228  // 'dropped' from the current schema) so let's no copy it in a random place.
4229  return;
4230  }
4231 
4232  // STL container sub-branch (contains the elements).
4234  if (!fNdata) {
4235  return;
4236  }
4237  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4238 
4239  TStreamerInfo *info = GetInfoImp();
4240  if (info == 0) return;
4241 
4244 
4247 }
4248 
4249 ////////////////////////////////////////////////////////////////////////////////
4250 /// Read leaves into i/o buffers for this branch.
4251 /// Case of a data member within a collection (fType == 41).
4252 
4254 {
4255  ValidateAddress();
4256  if (fObject == 0)
4257  {
4258  // We have nowhere to copy the data (probably because the data member was
4259  // 'dropped' from the current schema) so let's no copy it in a random place.
4260  return;
4261  }
4262 
4263  // STL container sub-branch (contains the elements).
4265  if (!fNdata) {
4266  return;
4267  }
4268  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4269 
4270  TStreamerInfo *info = GetInfoImp();
4271  if (info == 0) return;
4272  // Since info is not null, fReadActionSequence is not null either.
4273 
4274  // Still calling PushPop for the legacy entries.
4277 
4279  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4280 }
4281 
4282 ////////////////////////////////////////////////////////////////////////////////
4283 /// Read leaves into i/o buffers for this branch.
4284 /// Case of a TClonesArray (fType == 3).
4285 
4287 {
4288  ValidateAddress();
4289  if (fObject == 0)
4290  {
4291  // We have nowhere to copy the data (probably because the data member was
4292  // 'dropped' from the current schema) so let's no copy it in a random place.
4293  return;
4294  }
4295 
4296  // TClonesArray master branch (has only the number of elements).
4297  Int_t n;
4298  b >> n;
4299  if ((n < 0) || (n > fMaximum)) {
4300  if (IsMissingCollection()) {
4301  n = 0;
4302  b.SetBufferOffset(b.Length()-sizeof(n));
4303  } else {
4304  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());
4305  n = 0;
4306  }
4307  }
4308  fNdata = n;
4309  TClonesArray* clones = (TClonesArray*) fObject;
4310  if (clones->IsZombie()) {
4311  return;
4312  }
4313  // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4314  // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4315  // clones->Clear();
4316  clones->ExpandCreateFast(fNdata);
4317 }
4318 
4319 ////////////////////////////////////////////////////////////////////////////////
4320 /// Read leaves into i/o buffers for this branch.
4321 /// Case of a data member within a TClonesArray (fType == 31).
4322 
4324 {
4325  // No need to validate the address here, if we are a member of a split ClonesArray,
4326  // fID is positive
4327  // ValidateAddress();
4328 
4329  if (fObject == 0)
4330  {
4331  // We have nowhere to copy the data (probably because the data member was
4332  // 'dropped' from the current schema) so let's no copy it in a random place.
4333  return;
4334  }
4335 
4336  // TClonesArray sub-branch (contains the elements).
4338  TClonesArray* clones = (TClonesArray*) fObject;
4339  if (clones->IsZombie()) {
4340  return;
4341  }
4342  TStreamerInfo *info = GetInfoImp();
4343  if (info==0) return;
4344  // Since info is not null, fReadActionSequence is not null either.
4345 
4346  // Note, we could (possibly) save some more, by configuring the action
4347  // based on the value of fOnfileObject rather than pushing in on a stack.
4348  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4349 
4350  char **arr = (char **)clones->GetObjectRef();
4351  char **end = arr + fNdata;
4353 }
4354 
4355 ////////////////////////////////////////////////////////////////////////////////
4356 /// Read leaves into i/o buffers for this branch.
4357 /// For split-class branch, base class branch, data member branch, or top-level branch.
4358 /// which do not have a branch count and are not a counter.
4359 
4361 {
4362  R__ASSERT(fBranchCount==0);
4364 
4365  ValidateAddress();
4366  if (fObject == 0)
4367  {
4368  // We have nowhere to copy the data (probably because the data member was
4369  // 'dropped' from the current schema) so let's no copy it in a random place.
4370  return;
4371  }
4372 
4373  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4374  // If not a TClonesArray or STL container master branch
4375  // or sub-branch and branch inherits from tobject,
4376  // then register with the buffer so that pointers are
4377  // handled properly.
4378  if (TestBit(kBranchObject)) {
4379  b.MapObject((TObject*) fObject);
4380  } else if (TestBit(kBranchAny)) {
4382  }
4383 
4384  fNdata = 1;
4385  TStreamerInfo *info = GetInfoImp();
4386  if (!info) {
4387  return;
4388  }
4389  // Since info is not null, fReadActionSequence is not null either.
4391 }
4392 
4393 ////////////////////////////////////////////////////////////////////////////////
4394 /// Read leaves into i/o buffers for this branch.
4395 /// For split-class branch, base class branch, data member branch, or top-level branch.
4396 /// which do have a branch count and are not a counter.
4397 
4399 {
4401 
4402  ValidateAddress();
4403  if (fObject == 0)
4404  {
4405  // We have nowhere to copy the data (probably because the data member was
4406  // 'dropped' from the current schema) so let's no copy it in a random place.
4407  return;
4408  }
4409 
4410  // If not a TClonesArray or STL container master branch
4411  // or sub-branch and branch inherits from tobject,
4412  // then register with the buffer so that pointers are
4413  // handled properly.
4414  if (TestBit(kBranchObject)) {
4415  b.MapObject((TObject*) fObject);
4416  } else if (TestBit(kBranchAny)) {
4418  }
4419 
4420  fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4421  TStreamerInfo *info = GetInfoImp();
4422  if (!info) {
4423  return;
4424  }
4425  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1); // Here we have a single object that contains a variable size C-style array.
4426  // Since info is not null, fReadActionSequence is not null either.
4428 }
4429 
4430 ////////////////////////////////////////////////////////////////////////////////
4431 /// Read leaves into i/o buffers for this branch.
4432 /// For split-class branch, base class branch, data member branch, or top-level branch.
4433 /// which do not have a branch count and are a counter.
4434 
4436 {
4437  ValidateAddress();
4438  if (fObject == 0)
4439  {
4440  // We have nowhere to copy the data (probably because the data member was
4441  // 'dropped' from the current schema) so let's no copy it in a random place.
4442  return;
4443  }
4444 
4445  // If not a TClonesArray or STL container master branch
4446  // or sub-branch and branch inherits from tobject,
4447  // then register with the buffer so that pointers are
4448  // handled properly.
4449  if (TestBit(kBranchObject)) {
4450  b.MapObject((TObject*) fObject);
4451  } else if (TestBit(kBranchAny)) {
4453  }
4454 
4455  TStreamerInfo *info = GetInfoImp();
4456  if (!info) {
4457  return;
4458  }
4459 
4460  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4461 
4462  // Since info is not null, fReadActionSequence is not null either.
4464  fNdata = (Int_t) GetValue(0, 0);
4465 }
4466 
4467 ////////////////////////////////////////////////////////////////////////////////
4468 /// Read leaves into i/o buffers for this branch.
4469 /// Non TObject, Non collection classes with a custom streamer.
4470 
4472 {
4473  ValidateAddress();
4474  if (fObject == 0)
4475  {
4476  // We have nowhere to copy the data (probably because the data member was
4477  // 'dropped' from the current schema) so let's no copy it in a random place.
4478  return;
4479  }
4480 
4481  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4483 }
4484 
4485 ////////////////////////////////////////////////////////////////////////////////
4486 /// Unconfiguration Fill Leave function.
4487 
4489 {
4490  Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4491 }
4492 
4493 ////////////////////////////////////////////////////////////////////////////////
4494 /// Delete any object we may have allocated on a previous call to SetAddress.
4495 
4497 {
4498  if (fObject && TestBit(kDeleteObject)) {
4499  if (IsAutoDelete() && fAddress != (char*)&fObject) {
4500  *((char**) fAddress) = 0;
4501  }
4503  if (fType == 3) {
4504  // -- We are a TClonesArray master branch.
4505  TClonesArray::Class()->Destructor(fObject);
4506  fObject = 0;
4509  // -- We are a pointer to a TClonesArray.
4510  // We must zero the pointer in the object.
4511  *((char**) fAddress) = 0;
4512  }
4513  } else if (fType == 4) {
4514  // -- We are an STL container master branch.
4516 
4517  if (!proxy) {
4518  Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4519  fObject = 0;
4520  } else {
4522  if (needDelete && fID >= 0) {
4525  needDelete = !se->TestBit(TStreamerElement::kDoNotDelete);
4526  }
4527  if (needDelete) {
4528  TVirtualCollectionProxy::TPushPop helper(proxy,fObject);
4529  proxy->Clear("force");
4530  }
4531  proxy->Destructor(fObject);
4532  fObject = 0;
4533  }
4535  // -- We are a pointer to an STL container.
4536  // We must zero the pointer in the object.
4537  *((char**) fAddress) = 0;
4538  }
4539  } else {
4540  // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4541  TClass* cl = fBranchClass.GetClass();
4542  if (!cl) {
4543  Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4544  fObject = 0;
4545  } else {
4547 
4548  if (proxy) {
4549  if (fID >= 0) {
4551  TStreamerElement* se = si->GetElement(fID);
4553  TVirtualCollectionProxy::TPushPop helper(proxy,fObject);
4554  proxy->Clear("force");
4555  }
4557  TVirtualCollectionProxy::TPushPop helper(proxy,fObject);
4558  proxy->Clear("force");
4559  }
4560 
4561  }
4562  cl->Destructor(fObject);
4563  fObject = 0;
4564  }
4565  }
4566  }
4567 }
4568 
4569 ////////////////////////////////////////////////////////////////////////////////
4570 /// Reset a Branch.
4571 ///
4572 /// Existing i/o buffers are deleted.
4573 /// Entries, max and min are reset.
4574 ///
4575 
4577 {
4578  Int_t nbranches = fBranches.GetEntriesFast();
4579  for (Int_t i = 0; i < nbranches; ++i) {
4580  TBranch* branch = (TBranch*) fBranches[i];
4581  branch->Reset(option);
4582  }
4583  fBranchID = -1;
4584  TBranch::Reset(option);
4585 }
4586 
4587 ////////////////////////////////////////////////////////////////////////////////
4588 /// Reset a Branch after a Merge operation (drop data but keep customizations)
4589 ///
4590 
4592 {
4593  Int_t nbranches = fBranches.GetEntriesFast();
4594  for (Int_t i = 0; i < nbranches; ++i) {
4595  TBranch* branch = (TBranch*) fBranches[i];
4596  branch->ResetAfterMerge(info);
4597  }
4599 }
4600 
4601 ////////////////////////////////////////////////////////////////////////////////
4602 /// Set branch address to zero and free all allocated memory.
4603 
4605 {
4606  for (Int_t i = 0; i < fNleaves; ++i) {
4607  TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
4608  //if (leaf) leaf->SetAddress(0);
4609  leaf->SetAddress(0);
4610  }
4611 
4612  // Note: We *must* do the sub-branches first, otherwise
4613  // we may delete the object containing the sub-branches
4614  // before giving them a chance to cleanup.
4615  Int_t nbranches = fBranches.GetEntriesFast();
4616  for (Int_t i = 0; i < nbranches; ++i) {
4617  TBranch* br = (TBranch*) fBranches[i];
4618  if (br) br->ResetAddress();
4619  }
4620 
4621  //
4622  // SetAddress may have allocated an object.
4623  //
4624 
4625  ReleaseObject();
4626 
4628  fAddress = 0;
4629  fObject = 0;
4630 }
4631 
4632 ////////////////////////////////////////////////////////////////////////////////
4633 /// Release ownership of any allocated objects.
4634 ///
4635 /// Note: This interface was added so that clone trees could
4636 /// be told they do not own the allocated objects.
4637 
4639 {
4642  for (Int_t i = 0; i < nb; ++i) {
4643  TBranch* br = (TBranch*) fBranches[i];
4644  if (br->InheritsFrom(TBranchElement::Class())) {
4645  ((TBranchElement*) br)->ResetDeleteObject();
4646  }
4647  }
4648 }
4649 
4650 ////////////////////////////////////////////////////////////////////////////////
4651 /// \brief Reset offset and StremerInfo information from this branch.
4652 /// \param[in] recurse When true call ResetInitInfo on all subbranches.
4653 ///
4654 
4656 {
4657  fInfo = nullptr;
4658  fInit = kFALSE;
4659  fInitOffsets = kFALSE;
4660  fCurrentClass = nullptr;
4661  delete fReadActionSequence;
4662  fReadActionSequence = nullptr;
4663  delete fFillActionSequence;
4664  fFillActionSequence = nullptr;
4665 
4666  if (recurse) {
4667  Int_t nbranches = fBranches.GetEntriesFast();
4668  for (Int_t i = 0; i < nbranches; ++i) {
4670  sub->ResetInitInfo(kTRUE);
4671  }
4672  }
4673 }
4674 
4675 ////////////////////////////////////////////////////////////////////////////////
4676 /// Point this branch at an object.
4677 ///
4678 /// For a sub-branch, addr is a pointer to the branch object.
4679 ///
4680 /// For a top-level branch the meaning of addr is as follows:
4681 ///
4682 /// If addr is zero, then we allocate a branch object
4683 /// internally and the branch is the owner of the allocated
4684 /// object, not the caller. However the caller may obtain
4685 /// a pointer to the branch object with GetObject().
4686 ///
4687 /// Example:
4688 /// ~~~ {.cpp}
4689 /// branch->SetAddress(0);
4690 /// Event* event = branch->GetObject();
4691 /// ... Do some work.
4692 /// ~~~
4693 /// If addr is not zero, but the pointer addr points at is
4694 /// zero, then we allocate a branch object and set the passed
4695 /// pointer to point at the allocated object. The caller
4696 /// owns the allocated object and is responsible for deleting
4697 /// it when it is no longer needed.
4698 ///
4699 /// Example:
4700 /// ~~~ {.cpp}
4701 /// Event* event = 0;
4702 /// branch->SetAddress(&event);
4703 /// ... Do some work.
4704 /// delete event;
4705 /// event = 0;
4706 /// ~~~
4707 /// If addr is not zero and the pointer addr points at is
4708 /// also not zero, then the caller has allocated a branch
4709 /// object and is asking us to use it. The caller owns it
4710 /// and must delete it when it is no longer needed.
4711 ///
4712 /// Example:
4713 /// ~~~ {.cpp}
4714 /// Event* event = new Event();
4715 /// branch->SetAddress(&event);
4716 /// ... Do some work.
4717 /// delete event;
4718 /// event = 0;
4719 /// ~~~
4720 /// These rules affect users of TTree::Branch(),
4721 /// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4722 /// as well because those routines call this one.
4723 ///
4724 /// An example of a tree with branches with objects allocated
4725 /// and owned by us:
4726 /// ~~~ {.cpp}
4727 /// TFile* f1 = new TFile("myfile_original.root");
4728 /// TTree* t1 = (TTree*) f->Get("MyTree");
4729 /// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4730 /// TTree* t2 = t1->Clone(0);
4731 /// for (Int_t i = 0; i < 10; ++i) {
4732 /// t1->GetEntry(i);
4733 /// t2->Fill();
4734 /// }
4735 /// t2->Write()
4736 /// delete f2;
4737 /// f2 = 0;
4738 /// delete f1;
4739 /// f1 = 0;
4740 /// ~~~
4741 /// An example of a branch with an object allocated by us,
4742 /// but owned by the caller:
4743 /// ~~~ {.cpp}
4744 /// TFile* f = new TFile("myfile.root", "recreate");
4745 /// TTree* t = new TTree("t", "A test tree.")
4746 /// Event* event = 0;
4747 /// TBranchElement* br = t->Branch("event.", &event);
4748 /// for (Int_t i = 0; i < 10; ++i) {
4749 /// ... Fill event with meaningful data in some way.
4750 /// t->Fill();
4751 /// }
4752 /// t->Write();
4753 /// delete event;
4754 /// event = 0;
4755 /// delete f;
4756 /// f = 0;
4757 /// ~~~
4758 /// Notice that the only difference between this example
4759 /// and the following example is that the event pointer
4760 /// is zero when the branch is created.
4761 ///
4762 /// An example of a branch with an object allocated and
4763 /// owned by the caller:
4764 /// ~~~ {.cpp}
4765 /// TFile* f = new TFile("myfile.root", "recreate");
4766 /// TTree* t = new TTree("t", "A test tree.")
4767 /// Event* event = new Event();
4768 /// TBranchElement* br = t->Branch("event.", &event);
4769 /// for (Int_t i = 0; i < 10; ++i) {
4770 /// ... Fill event with meaningful data in some way.
4771 /// t->Fill();
4772 /// }
4773 /// t->Write();
4774 /// delete event;
4775 /// event = 0;
4776 /// delete f;
4777 /// f = 0;
4778 /// ~~~
4779 /// If AutoDelete is on (see TBranch::SetAutoDelete),
4780 /// the top level objet will be deleted and recreate
4781 /// each time an entry is read, whether or not the
4782 /// TTree owns the object.
4783 
4785 {
4786  //
4787  // Don't bother if we are disabled.
4788  //
4789 
4790  if (TestBit(kDoNotProcess)) {
4791  return;
4792  }
4793 
4794  //
4795  // FIXME: When would this happen?
4796  //
4797 
4798  if (fType < -1) {
4799  return;
4800  }
4801 
4802  //
4803  // Special case when called from code generated by TTree::MakeClass.
4804  //
4805 
4806  if (Long_t(addr) == -1) {
4807  // FIXME: Do we have to release an object here?
4808  // ReleaseObject();
4809  fAddress = (char*) -1;
4810  fObject = (char*) -1;
4812  return;
4813  }
4814 
4815  //
4816  // Reset last read entry number, we have a new user object now.
4817  //
4818 
4819  fReadEntry = -1;
4820 
4821  //
4822  // Make sure our branch class is instantiated.
4823  //
4824  TClass* clOfBranch = fBranchClass.GetClass();
4825  if( fTargetClass.GetClassName()[0] ) {
4826  clOfBranch = fTargetClass;
4827  }
4828 
4829  //
4830  // Try to build the streamer info.
4831  //
4832 
4833  TStreamerInfo *info = GetInfoImp();
4834 
4835  // FIXME: Warn about failure to get the streamer info here?
4836 
4837  //
4838  // We may have allocated an object last time we were called.
4839  //
4840 
4841  if (fObject && TestBit(kDeleteObject)){
4842  ReleaseObject();
4843  }
4844 
4845  //
4846  // Remember the pointer to the pointer to our object.
4847  //
4848 
4849  fAddress = (char*) addr;
4850  if (fAddress != (char*)(&fObject)) {
4851  fObject = 0;
4852  }
4854 
4855  //
4856  // Do special stuff if we got called from a MakeClass class.
4857  // Allow sub-branches to have independently set addresses.
4858  //
4859 
4860  if (TestBit(kDecomposedObj)) {
4861  if (fID > -1) {
4862  // We are *not* a top-level branch.
4863  if (!info) {
4864  // No streamer info, give up.
4865  // FIXME: We should have an error message here.
4866  fObject = fAddress;
4867  } else {
4868  // Compensate for the fact that the i/o routines
4869  // will add the streamer offset to the address.
4870  fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
4871  }
4872  return;
4873  }
4874  }
4875 
4876  //
4877  // Check whether the container type is still the same
4878  // to support schema evolution; what is written on the file
4879  // may no longer match the class code which is loaded.
4880  //
4881 
4882  if (fType == 3) {
4883  // split TClonesArray, counter/master branch.
4884  TClass* clm = fClonesClass;
4885  if (clm) {
4886  // In case clm derives from an abstract class.
4887  clm->BuildRealData();
4888  clm->GetStreamerInfo();
4889  }
4890  TClass* newType = GetCurrentClass();
4891  if (newType && (newType != TClonesArray::Class())) {
4892  // The data type of the container has changed.
4893  //
4894  // Let's check if it is a compatible type:
4895  Bool_t matched = kFALSE;
4896  if (newType->GetCollectionProxy()) {
4897  TClass *content = newType->GetCollectionProxy()->GetValueClass();
4898  if (clm == content) {
4899  matched = kTRUE;
4900  } else {
4901  Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
4902  }
4903  } else {
4904  Warning("SetAddress", "The type of the %s was changed from TClonesArray to %s but we do not have a TVirtualCollectionProxy for that container type!", GetName(), newType->GetName());
4905  }
4906  if (matched) {
4907  // Change from 3/31 to 4/41
4908  SetType(4);
4909  // Set the proxy.
4910  fSTLtype = newType->GetCollectionType();
4911  fCollProxy = newType->GetCollectionProxy()->Generate();
4912 
4914  SetReadLeavesPtr();
4915  SetFillLeavesPtr();
4916 
4922  } else {
4924  }
4925  } else {
4926  // FIXME: Must maintain fObject here as well.
4927  fAddress = 0;
4928  }
4929  }
4930  } else if (fType == 4) {
4931  // split STL container, counter/master branch.
4932  TClass* newType = GetCurrentClass();
4933  if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
4934  // Let's check if it is a compatible type:
4935  TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
4937  if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
4938  delete fCollProxy;
4939  Int_t nbranches = GetListOfBranches()->GetEntries();
4940  fCollProxy = newType->GetCollectionProxy()->Generate();
4942  for (Int_t i = 0; i < nbranches; ++i) {
4944  br->fCollProxy = 0;
4945  if (br->fReadActionSequence) {
4946  br->SetReadActionSequence();
4947  }
4948  if (br->fFillActionSequence) {
4949  br->SetFillActionSequence();
4950  }
4951  }
4954  SetReadLeavesPtr();
4955  SetFillLeavesPtr();
4956  delete fIterators;
4957  delete fPtrIterators;
4963  } else {
4965  }
4966  }
4967  else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=0) && (newProxy->GetValueClass()!=0)) {
4968  // Let see if there is a rule to convert the content of the collection into each other.
4969  if (newType->GetSchemaRules()->HasRuleWithSourceClass( oldProxy->GetCollectionClass()->GetName())) {
4970  TClass *oldValueClass = oldProxy->GetValueClass();
4971  delete fCollProxy;
4972  Int_t nbranches = GetListOfBranches()->GetEntries();
4973  fCollProxy = newType->GetCollectionProxy()->Generate();
4975  for (Int_t i = 0; i < nbranches; ++i) {
4977  br->fCollProxy = 0;
4978  if (br->fBranchClass == oldValueClass) {
4980  }
4981  if (br->fReadActionSequence) {
4982  br->SetReadActionSequence();
4983  }
4984  if (br->fFillActionSequence) {
4985  br->SetFillActionSequence();
4986  }
4987  }
4990  SetReadLeavesPtr();
4991  SetFillLeavesPtr();
4992  delete fIterators;
4993  delete fPtrIterators;
4999  } else {
5001  }
5002  } else {
5003  Error("SetAddress","For %s, we can not convert %s into %s\n",
5004  GetName(),oldProxy->GetCollectionClass()->GetName(),newType->GetName());
5005  fAddress = 0;
5006  fObject = 0;
5007  return;
5008  }
5009  }
5010  else if ((newType == TClonesArray::Class()) && (oldProxy->GetValueClass() && !oldProxy->HasPointers() && oldProxy->GetValueClass()->IsTObject()))
5011  {
5012  // The new collection and the old collection are not compatible,
5013  // we cannot use the new collection to read the data.
5014  // Actually we could check if the new collection is a
5015  // compatible ROOT collection.
5016 
5017  // We cannot insure that the TClonesArray is set for the
5018  // proper class (oldProxy->GetValueClass()), so we assume that
5019  // the transformation was done properly by the class designer.
5020 
5021  // Change from 4/41 to 3/31
5022  SetType(3);
5023  // Reset the proxy.
5024  fSTLtype = kNone;
5025  switch(fStreamerType) {
5029  break;
5033  break;
5036  break;
5037  }
5038  fClonesClass = oldProxy->GetValueClass();
5040  delete fCollProxy;
5041  fCollProxy = 0;
5042  TClass* clm = fClonesClass;
5043  if (clm) {
5044  clm->BuildRealData(); //just in case clm derives from an abstract class
5045  clm->GetStreamerInfo();
5046  }
5048  SetReadLeavesPtr();
5049  SetFillLeavesPtr();
5050  delete fIterators;
5051  fIterators = 0;
5052  delete fPtrIterators;
5053  fPtrIterators =0;
5054  } else {
5055  // FIXME: We must maintain fObject here as well.
5056  Error("SetAddress","For %s can not convert %s into %s\n",GetName(),GetCurrentClass()->GetName(),newType->GetName());
5057  fAddress = 0;
5058  return;
5059  }
5060  } else {
5061  if (!fIterators && !fPtrIterators) {
5067  } else {
5069  }
5070  }
5071  }
5072  }
5073 
5074  //
5075  // Establish the semantics of fObject and fAddress.
5076  //
5077  // Top-level branch:
5078  // fObject is a ptr to the object,
5079  // fAddress is a ptr to a pointer to the object.
5080  //
5081  // Sub-branch:
5082  // fObject is a ptr to the object,
5083  // fAddress is the same as fObject.
5084  //
5085  //
5086  // There are special cases for TClonesArray and STL containers.
5087  // If there is no user-provided object, we allocate one. We must
5088  // also initialize any STL container proxy.
5089  //
5090 
5091  if (fType == 3) {
5092  // -- We are a TClonesArray master branch.
5093  if (fAddress) {
5094  // -- We have been given a non-zero address, allocate if necessary.
5096  // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5097  // Case of an embedded TClonesArray.
5098  fObject = fAddress;
5099  // Check if it has already been properly built.
5100  TClonesArray* clones = (TClonesArray*) fObject;
5101  if (!clones->GetClass()) {
5103  }
5104  } else {
5105  // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5106  // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5107  if ((fStreamerType != -1) &&
5110  Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5111  } else if (fStreamerType == -1) {
5112  // -- We are a top-level branch.
5113  TClonesArray** pp = (TClonesArray**) fAddress;
5114  if (!*pp) {
5115  // -- Caller wants us to allocate the clones array, but they will own it.
5116  *pp = new TClonesArray(fClonesClass);
5117  }
5118  fObject = (char*) *pp;
5119  } else {
5120  // -- We are a pointer to a TClonesArray.
5121  // Note: We do this so that the default constructor,
5122  // or the i/o constructor can be lazy.
5123  TClonesArray** pp = (TClonesArray**) fAddress;
5124  if (!*pp) {
5125  // -- Caller wants us to allocate the clones array, but they will own it.
5126  *pp = new TClonesArray(fClonesClass);
5127  }
5128  fObject = (char*) *pp;
5129  }
5130  }
5131  } else {
5132  // -- We have been given a zero address, allocate for top-level only.
5134  // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5135  // Case of an embedded TClonesArray.
5136  Error("SetAddress", "Embedded TClonesArray given a zero address for branch '%s'", GetName());
5137  } else {
5138  // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5139  // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5140  if ((fStreamerType != -1) &&
5143  Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5144  } else if (fStreamerType == -1) {
5145  // -- We are a top-level branch.
5146  // Idea: Consider making a zero address not allocate.
5148  fObject = (char*) new TClonesArray(fClonesClass);
5149  fAddress = (char*) &fObject;
5150  } else {
5151  // -- We are a sub-branch which is a pointer to a TClonesArray.
5152  Error("SetAddress", "Embedded pointer to a TClonesArray given a zero address for branch '%s'", GetName());
5153  }
5154  }
5155  }
5156  } else if (fType == 4) {
5157  // -- We are an STL container master branch.
5158  //
5159  // Initialize fCollProxy.
5161  if (fAddress) {
5162  // -- We have been given a non-zero address, allocate if necessary.
5166  // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5167  // Case of an embedded STL container.
5168  // Note: We test for the kObject and kAny types to support
5169  // the (unwise) choice of inheriting from an STL container.
5170  fObject = fAddress;
5171  } else {
5172  // We are either a top-level branch or subbranch which is a pointer to an STL container.
5173  // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5175  Error("SetAddress", "STL container with fStreamerType: %d", fStreamerType);
5176  } else if (fStreamerType == -1) {
5177  // -- We are a top-level branch.
5178  void** pp = (void**) fAddress;
5179  if (!*pp) {
5180  // -- Caller wants us to allocate the STL container, but they will own it.
5181  *pp = proxy->New();
5182  if (!(*pp)) {
5183  Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5184  // FIXME: Should we do this? Lots of other code wants
5185  // fAddress to be zero if no fObject, but is
5186  // that a good thing?
5187  fAddress = 0;
5188  }
5189  }
5190  fObject = (char*) *pp;
5191  } else {
5192  // -- We are a pointer to an STL container.
5193  // Note: We do this so that the default constructor,
5194  // or the i/o constructor can be lazy.
5195  void** pp = (void**) fAddress;
5196  if (!*pp) {
5197  // -- Caller wants us to allocate the STL container, but they will own it.
5198  *pp = proxy->New();
5199  if (!(*pp)) {
5200  Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5201  // FIXME: Should we do this? Lots of other code wants
5202  // fAddress to be zero if no fObject, but is
5203  // that a good thing?
5204  fAddress = 0;
5205  }
5206  }
5207  fObject = (char*) *pp;
5208  }
5209  }
5210  } else {
5211  // -- We have been given a zero address, allocate for top-level only.
5215  // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5216  // Case of an embedded STL container.
5217  // Note: We test for the kObject and kAny types to support
5218  // the (unwise) choice of inheriting from an STL container.
5219  Error("SetAddress", "Embedded STL container given a zero address for branch '%s'", GetName());
5220  } else {
5221  // We are either a top-level branch or sub-branch which is a pointer to an STL container.
5222  // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5224  Error("SetAddress", "STL container with fStreamerType: %d", fStreamerType);
5225  } else if (fStreamerType == -1) {
5226  // -- We are a top-level branch, allocate.
5228  fObject = (char*) proxy->New();
5229  if (fObject) {
5230  fAddress = (char*) &fObject;
5231  } else {
5232  Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5233  // FIXME: Should we do this? Lots of other code wants
5234  // fAddress to be zero if no fObject, but is
5235  // that a good thing?
5236  fAddress = 0;
5237  }
5238  } else {
5239  // -- We are a sub-branch which is a pointer to an STL container.
5240  Error("SetAddress", "Embedded pointer to an STL container given a zero address for branch '%s'", GetName());
5241  }
5242  }
5243  }
5244  } else if (fType == 41) {
5245  // -- We are an STL container sub-branch.
5246  // Initialize fCollProxy.
5248  // We are not at top-level branch.
5249  fObject = fAddress;
5250  } else if (fID < 0) {
5251  // -- We are a top-level branch.
5252  char** pp = (char**) fAddress;
5253  if (pp && *pp) {
5254  // -- Caller provided an i/o buffer for us to use.
5255  fObject = *pp;
5256  } else {
5257  // -- Caller did not provide an i/o buffer for us to use, we must make one for ourselves.
5258  if (clOfBranch) {
5259  if (!pp) {
5260  // -- Caller wants us to own the object.
5262  }
5263  fObject = (char*) clOfBranch->New();
5264  if (pp) {
5265  *pp = fObject;
5266  } else {
5267  fAddress = (char*) &fObject;
5268  }
5269  } else {
5270  Error("SetAddress", "I have no TClass for branch %s, so I cannot allocate an I/O buffer!", GetName());
5271  if (pp) {
5272  fObject = 0;
5273  *pp = 0;
5274  }
5275  }
5276  }
5277  } else {
5278  // -- We are *not* a top-level branch.
5279  fObject = fAddress;
5280  }
5281 
5282  if (!info) {
5283  // FIXME: We need and error message here, no streamer info, so cannot set offsets.
5284  return;
5285  }
5286 
5287  // We do this only once because it depends only on
5288  // the type of our object, not on its address.
5289  if (!fInitOffsets) {
5290  // R__LOCKGUARD(gInterpreterMutex);
5292  }
5293 
5294  // We are split, recurse down to our sub-branches.
5295  //
5296  // FIXME: This is a tail recursion, we burn stack.
5297  Int_t nbranches = fBranches.GetEntriesFast();
5298  for (Int_t i = 0; i < nbranches; ++i) {
5299  TBranch* abranch = (TBranch*) fBranches.UncheckedAt(i);
5300  // FIXME: This is a tail recursion!
5302  abranch->SetAddress(fObject + fBranchOffset[i]);
5303  abranch->SetBit(kAddressSet);
5304  } else {
5305  // When the member is missing, just leave the address alone
5306  // (since setting explicitly to 0 would trigger error/warning
5307  // messages).
5308  // abranch->SetAddress(0);
5309  abranch->SetBit(kAddressSet);
5310  }
5311  }
5312 }
5313 
5314 ////////////////////////////////////////////////////////////////////////////////
5315 /// Reset the basket size for all sub-branches of this branch element.
5316 
5318 {
5319  TBranch::SetBasketSize(buffsize);
5320  Int_t nbranches = fBranches.GetEntriesFast();
5321  for (Int_t i = 0; i < nbranches; ++i) {
5322  TBranch* branch = (TBranch*) fBranches[i];
5323  branch->SetBasketSize(fBasketSize);
5324  }
5325 }
5326 
5327 ////////////////////////////////////////////////////////////////////////////////
5328 /// Set the branch counter for this branch.
5329 
5331 {
5332  fBranchCount = brOfCounter;
5333  if (fBranchCount==0) return;
5334 
5335  TLeafElement* leafOfCounter = (TLeafElement*) brOfCounter->GetListOfLeaves()->At(0);
5336  TLeafElement* leaf = (TLeafElement*) GetListOfLeaves()->At(0);
5337  if (leafOfCounter && leaf) {
5338  leaf->SetLeafCount(leafOfCounter);
5339  } else {
5340  if (!leafOfCounter) {
5341  Warning("SetBranchCount", "Counter branch %s for branch %s has no leaves!", brOfCounter->GetName(), GetName());
5342  }
5343  if (!leaf) {
5344  Warning("SetBranchCount", "Branch %s has no leaves!", GetName());
5345  }
5346  }
5347 }
5348 
5349 ////////////////////////////////////////////////////////////////////////////////
5350 /// Set the branch in a mode where the object are decomposed
5351 /// (Also known as MakeClass mode).
5352 /// Return whether the setting was possible (it is not possible for
5353 /// TBranch and TBranchObject).
5354 
5356 {
5357  if (decomposeObj)
5358  SetBit(kDecomposedObj); // Same as SetBit(kMakeClass)
5359  else
5361 
5362  Int_t nbranches = fBranches.GetEntriesFast();
5363  for (Int_t i = 0; i < nbranches; ++i) {
5364  TBranchElement* branch = (TBranchElement*) fBranches[i];
5365  branch->SetMakeClass(decomposeObj);
5366  }
5367  SetReadLeavesPtr();
5368  SetFillLeavesPtr();
5369 
5370  return kTRUE;
5371 }
5372 
5373 ////////////////////////////////////////////////////////////////////////////////
5374 /// Set object this branch is pointing to.
5375 
5377 {
5378  if (TestBit(kDoNotProcess)) {
5379  return;
5380  }
5381  fObject = (char*)obj;
5382  SetAddress( &fObject );
5383 }
5384 
5385 ////////////////////////////////////////////////////////////////////////////////
5386 /// Set offset of the object (to which the data member represented by this
5387 /// branch belongs) inside its containing object (if any).
5388 
5390 {
5391  // We need to make sure that the Read and Write action's configuration
5392  // properly reflect this value.
5393 
5394  if (fReadActionSequence) {
5396  }
5397  if (fFillActionSequence) {
5399  }
5400  fOffset = offset;
5401 }
5402 
5403 
5404 ////////////////////////////////////////////////////////////////////////////////
5405 /// Set the sequence of actions needed to read the data out of the buffer.
5407 {
5408  // A 'split' node does not store data itself (it has not associated baskets)
5409  const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
5410 
5411  if (!isSplitNode) {
5412  fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
5413  }
5414 
5415  if (actionSequence) delete actionSequence;
5416  auto original = create(localInfo, GetCollectionProxy(), originalClass);
5417 
5418  actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
5419 
5420  if (!isSplitNode)
5421  fNewIDs.erase(fNewIDs.begin());
5422  else {
5423  // fObject has the address of the sub-object but the streamer action have
5424  // offset relative to the parent.
5425  TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
5426  if (fInitOffsets) {
5427  auto index = parent->fBranches.IndexOf(this);
5428  if (index >= 0) {
5429  fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
5430  }
5431  } // else it will be done by InitOffsets
5432  }
5433 }
5434 
5435 ////////////////////////////////////////////////////////////////////////////////
5436 /// Set the sequence of actions needed to read the data out of the buffer.
5438 {
5439  if (fInfo == 0) {
5440  // We are called too soon. We will be called again by InitInfo
5441  return;
5442  }
5443 
5445  TClass *originalClass = nullptr;
5446  TStreamerInfo *localInfo = fInfo;
5447  if (fType == 41) {
5450  } else {
5451  TVirtualStreamerInfo *info = GetInfoImp();
5452  if (GetParentClass() == info->GetClass()) {
5454  originalClass = fBranchClass;
5456  } else {
5458  }
5459  } else if (GetCollectionProxy()) {
5460  // Base class and embedded objects.
5462  }
5463  }
5464  } else if (fType == 31) {
5466  } else if (0<=fType && fType<=2) {
5467  // Note: this still requires the ObjectWise sequence to not be optimized!
5469  } else if ( fType == 4 && !fNewIDs.empty()) {
5470  localInfo = FindOnfileInfo(fClonesClass, fBranches);
5472  } else if ( fType == 3 && !fNewIDs.empty()) {
5473  localInfo = FindOnfileInfo(fClonesClass, fBranches);
5475  }
5476 
5477  if (create) {
5478  SetActionSequence(originalClass, localInfo, create, fReadActionSequence);
5479  }
5480 }
5481 
5482 ////////////////////////////////////////////////////////////////////////////////
5483 /// Set the ReadLeaves pointer to execute the expected operations.
5484 
5486 {
5487  if (TestBit(kDecomposedObj)) {
5489  } else if (fType == 4) {
5491  } else if (fType == 41) {
5495  } else {
5497  }
5498  } else {
5500  }
5501  } else if (fType == 3) {
5503  } else if (fType == 31) {
5505  } else if (fType < 0) {
5507  } else if (fType == 0 && fID == -1) {
5508  // top-level branch.
5510  if (hasCustomStreamer) {
5511  // We are in the case where the object did *not* have a custom
5512  // Streamer when the TTree was written but now *does* have a custom
5513  // Streamer thus we must use it.
5515  } else {
5517  }
5518  } else if (fType <= 2) {
5519  // split-class branch, base class branch or data member branch.
5520  if (fBranchCount) {
5524  } else {
5526  }
5527  } else {
5528  Fatal("SetReadLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5529  }
5530 
5532 }
5533 
5534 ////////////////////////////////////////////////////////////////////////////////
5535 /// Set the sequence of actions needed to write the data out from the buffer.
5536 
5538 {
5539  if (fInfo == 0) {
5540  // We are called too soon. We will be called again by InitInfo
5541  return;
5542  }
5543 
5545  TClass *originalClass = nullptr;
5546  TStreamerInfo *localInfo = fInfo;
5547  if (fType == 41) {
5550  } else {
5551  TVirtualStreamerInfo *info = GetInfoImp();
5552  if (GetParentClass() == info->GetClass()) {
5553  // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
5554  // originalClass = fBranchClass;
5555  // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter;
5556  // } else {
5558  // }
5559  } else if (GetCollectionProxy()) {
5560  // Base class and embedded objects.
5562  }
5563  }
5564  } else if (fType == 31) {
5566  } else if (0<=fType && fType<=2) {
5567  // Note: this still requires the ObjectWise sequence to not be optimized!
5569  } else if ( fType == 4 && !fNewIDs.empty()) {
5570  localInfo = FindOnfileInfo(fClonesClass, fBranches);
5572  } else if ( fType == 3 && !fNewIDs.empty()) {
5573  localInfo = FindOnfileInfo(fClonesClass, fBranches);
5575  }
5576 
5577  if (create) {
5578  SetActionSequence(originalClass, localInfo, create, fFillActionSequence);
5579  }
5580 }
5581 
5582 ////////////////////////////////////////////////////////////////////////////////
5583 /// Set the FillLeaves pointer to execute the expected operations.
5584 
5586 {
5587  if (TestBit(kDecomposedObj) && ((fType==3)||(fType==31))) {
5589  } else if (fType == 4) {
5591  } else if (fType == 41) {
5595  } else {
5597  }
5600  } else {
5602  }
5603  } else if (fType == 3) {
5605  } else if (fType == 31) {
5607  } else if (fType < 0) {
5609  } else if (fType <=2) {
5610  //split-class branch, base class branch, data member branch, or top-level branch.
5611  if (fBranchCount) {
5615  } else {
5617  }
5618  } else {
5619  Fatal("SetFillLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5620  }
5621 
5623 }
5624 
5625 ////////////////////////////////////////////////////////////////////////////////
5626 /// Set the name of the class of the in-memory object into which the data will
5627 /// loaded.
5628 
5630 {
5631  if (name == 0) return;
5632 
5633  if (strcmp(fTargetClass.GetClassName(),name) != 0 )
5634  {
5635  // We are changing target class, let's reset the meta information and
5636  // the sub-branches.
5637 
5638  ResetInitInfo(/*recurse=*/ kFALSE);
5639 
5640  Int_t nbranches = fBranches.GetEntriesFast();
5641  for (Int_t i = 0; i < nbranches; ++i) {
5643 
5644  if (sub->fTargetClass == fTargetClass ) {
5645  sub->SetTargetClass(name);
5646  } else {
5647  // Since the top level changes, the StreamerInfo (in particular for split collection)
5648  // may still need to change (and the info might be updated else (see for example SetAddress for the
5649  // the case fType 4/41)
5650  sub->ResetInitInfo(kTRUE);
5651  }
5652  if (sub->fParentClass == fTargetClass ) {
5653  sub->SetParentClass(TClass::GetClass(name));
5654  }
5655  }
5656  fTargetClass = name;
5657  }
5658 
5659 }
5660 
5661 ////////////////////////////////////////////////////////////////////////////////
5662 /// If the branch address is not set, we set all addresses starting with
5663 /// the top level parent branch. This is required to be done in order for
5664 /// GetOffset to be correct and for GetEntry to run.
5665 
5667 {
5668  // Check to see if the user changed the branch address on us.
5669  ValidateAddress();
5670 
5671  if (fAddress || TestBit(kDecomposedObj)) {
5672  // -- Do nothing if already setup or if we are a MakeClass branch.
5673  return;
5674  }
5676 }
5677 
5678 ////////////////////////////////////////////////////////////////////////////////
5679 /// If the branch address is not set, we set all addresses starting with
5680 /// the top level parent branch. This is required to be done in order for
5681 /// GetOffset to be correct and for GetEntry to run.
5682 
5684 {
5686  // -- Do nothing if we have been told not to.
5687  // Or the data member in this branch is not longer part of the
5688  // parent's layout.
5689  return;
5690  }
5691 
5692  //--------------------------------------------------------------------------
5693  // Check if we are splited STL collection of pointers
5694  /////////////////////////////////////////////////////////////////////////////
5695 
5697  {
5698  TBranchElement *parent = (TBranchElement *)GetMother()->GetSubBranch( this );
5699 
5700  // Make sure the StreamerInfo is loaded and initialized.
5701  GetInfoImp();
5702 
5703  if( !parent->GetAddress() )
5704  parent->SetAddress( 0 );
5705  return;
5706  }
5707 
5708  //--------------------------------------------------------------------------
5709  // Any other case
5710  /////////////////////////////////////////////////////////////////////////////
5711 
5712  TBranchElement* mother = (TBranchElement*) GetMother();
5713  if (!mother) {
5714  return;
5715  }
5716  TClass* cl = TClass::GetClass(mother->GetClassName());
5717 
5718  // Make sure the StreamerInfo is loaded and initialized.
5719  GetInfoImp();
5720 
5721  if (!cl) {
5722  return;
5723  }
5724 
5725  if (!mother->GetAddress()) {
5726  // -- Our top-level branch has no address.
5727  Bool_t motherStatus = mother->TestBit(kDoNotProcess);
5728  mother->ResetBit(kDoNotProcess);
5729  // Note: This will allocate an object.
5730  mother->SetAddress(0);
5731  mother->SetBit(kDoNotProcess, motherStatus);
5732  }
5733 }
5734 
5735 ////////////////////////////////////////////////////////////////////////////////
5736 /// Stream an object of class TBranchElement.
5737 
5738 void TBranchElement::Streamer(TBuffer& R__b)
5739 {
5740  if (R__b.IsReading()) {
5741  R__b.ReadClassBuffer(TBranchElement::Class(), this);
5746  // The fAddress and fObject data members are not persistent,
5747  // therefore we do not own anything.
5748  // Also clear the bit possibly set by the schema evolution.
5750  // Fixup a case where the TLeafElement was missing
5751  if ((fType == 0) && (fLeaves.GetEntriesFast() == 0)) {
5752  TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
5753  leaf->SetTitle(GetTitle());
5754  fNleaves = 1;
5755  fLeaves.Add(leaf);
5756  fTree->GetListOfLeaves()->Add(leaf);
5757  }
5758 
5759  // SetReadLeavesPtr();
5760  }
5761  else {
5762  TDirectory* dirsav = fDirectory;
5763  fDirectory = 0; // to avoid recursive calls
5764  {
5765  // Save class version.
5766  Int_t classVersion = fClassVersion;
5767  // Record only positive 'version number'
5768  if (fClassVersion < 0) {
5770  }
5771  // TODO: Should we clear the kDeleteObject bit before writing?
5772  // If we did we would have to remember the old value and
5773  // put it back, we wouldn't want to forget that we owned
5774  // something just because we got written to disk.
5776  // Restore class version.
5777  fClassVersion = classVersion;
5778  }
5779  //
5780  // Mark all streamer infos used by this branch element
5781  // to be written to our output file.
5782  //
5783  {
5784  R__b.ForceWriteInfo(GetInfoImp(), kTRUE);
5785  }
5786  //
5787  // If we are a clones array master branch, or an
5788  // STL container master branch, we must also mark
5789  // the streamer infos used by the value class to
5790  // be written to our output file.
5791  //
5792  if (fType == 3) {
5793  // -- TClonesArray, counter/master branch
5794  //
5795  // We must mark the streamer info for the
5796  // value class to be written to the file.
5797  //
5798  TClass* cl = fClonesClass;
5799  if (cl) {
5800  R__b.ForceWriteInfo(cl->GetStreamerInfo(), kTRUE);
5801  }
5802  }
5803  else if (fType == 4) {
5804  // -- STL container, counter/master branch
5805  //
5806  // We must mark the streamer info for the
5807  // value class to be written to the file.
5808  //
5810  if (cp) {
5811  TClass* cl = cp->GetValueClass();
5812  if (cl) {
5813  R__b.ForceWriteInfo(cl->GetStreamerInfo(), kTRUE);
5814  }
5815  }
5816  }
5817  // If we are in a separate file, then save
5818  // ourselves as an independent key.
5819  if (!dirsav) {
5820  // Note: No need to restore fDirectory, it was already zero.
5821  return;
5822  }
5823  if (!dirsav->IsWritable()) {
5824  fDirectory = dirsav;
5825  return;
5826  }
5827  TDirectory* pdirectory = fTree->GetDirectory();
5828  if (!pdirectory) {
5829  fDirectory = dirsav;
5830  return;
5831  }
5832  const char* treeFileName = pdirectory->GetFile()->GetName();
5833  TBranch* mother = GetMother();
5834  const char* motherFileName = treeFileName;
5835  if (mother && (mother != this)) {
5836  motherFileName = mother->GetFileName();
5837  }
5838  if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
5839  dirsav->WriteTObject(this);
5840  }
5841  fDirectory = dirsav;
5842  }
5843 }
5844 
5845 
5846 ////////////////////////////////////////////////////////////////////////////////
5847 /// Split class cl into sub-branches of this branch.
5848 ///
5849 /// This version of Unroll was formerly embedded in TTree::BronchExec
5850 /// It is moved here so we can make sure to call SetReadActionSequence.
5851 
5852 void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Int_t bufsize, Int_t splitlevel)
5853 {
5854  //
5855  // Do we have a final dot in our name?
5856  //
5857 
5858  // Note: The branch constructor which takes a folder as input
5859  // creates top-level branch names with dots in them to
5860  // indicate the folder hierarchy.
5861  char* dot = (char*) strchr(name, '.');
5862  Int_t nch = strlen(name);
5863  Bool_t dotlast = kFALSE;
5864  if (nch && (name[nch-1] == '.')) {
5865  dotlast = kTRUE;
5866  }
5867 
5868  // Loop on all public data members of the class and its base classes and create branches for each one.
5869  TObjArray* blist = this->GetListOfBranches();
5870  TIter next(sinfo->GetElements());
5871  TStreamerElement* element = 0;
5872  TString bname;
5873  for (Int_t id = 0; (element = (TStreamerElement*) next()); ++id) {
5874  if (element->IsA() == TStreamerArtificial::Class()) {
5875  continue;
5876  }
5877  if (element->TestBit(TStreamerElement::kRepeat)) {
5878  continue;
5879  }
5880  if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) {
5881  continue;
5882  }
5883  char* pointer = (char*) (objptr + element->GetOffset());
5884  // FIXME: This is not good enough, an STL container can be
5885  // a base, and the test will fail.
5886  // See TBranchElement::InitializeOffsets() for the
5887  // correct test.
5888  Bool_t isBase = (element->IsA() == TStreamerBase::Class());
5889  if (isBase) {
5890  TClass* clbase = element->GetClassPointer();
5891  if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) {
5892  // Note: TStreamerInfo::Compile() leaves this element
5893  // out of the optimized info, although it does
5894  // exists in the non-compiled and non-optimized info.
5895  // FIXME: The test that TStreamerInfo::Compile() uses
5896  // is element->GetType() < 0, so that is what
5897  // we should do as well.
5898  continue;
5899  }
5900  if (clbase->GetListOfRealData()->GetSize() == 0) {
5901  // Do not create a branch for empty bases.
5902  continue;
5903  }
5904  }
5905  if (dot) {
5906  if (dotlast) {
5907  bname.Form("%s%s", name, element->GetFullName());
5908  } else {
5909  // FIXME: We are in the case where we have a top-level
5910  // branch name that was created by the branch
5911  // constructor which takes a folder as input.
5912  // The internal dots in the name are in place of
5913  // of the original slashes and represent the
5914  // folder hierarchy.
5915  if (isBase) {
5916  // FIXME: This is very strange, this is the only case where
5917  // we create a branch for a base class that does
5918  // not have the base class name in the branch name.
5919  // FIXME: This is also quite bad since classes with two
5920  // or more base classes end up with sub-branches
5921  // that have the same name.
5922  bname = name;
5923  } else {
5924  bname.Form("%s.%s", name, element->GetFullName());
5925  }
5926  }
5927  } else {
5928  // Note: For a base class element, this results in the branchname
5929  // being the name of the base class.
5930  bname.Form("%s", element->GetFullName());
5931  }
5932 
5933  if( splitlevel > TTree::kSplitCollectionOfPointers && element->GetClass() &&
5934  element->GetClass()->GetCollectionProxy() &&
5935  element->GetClass()->GetCollectionProxy()->HasPointers() )
5936  {
5937  TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id );
5938  blist->Add(brSTL);
5939  }
5940  else
5941  {
5942  TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1);
5943  bre->SetParentClass(cl);
5944  blist->Add(bre);
5945  }
5946  }
5947  // Now that we know that this branch is split, let's redo the actions.
5950 }
5951 
5952 ////////////////////////////////////////////////////////////////////////////////
5953 /// Split class cl into sub-branches of this branch.
5954 ///
5955 /// Create a sub-branch of this branch for each non-empty,
5956 /// non-abstract base class of cl (unless we are a sub-branch
5957 /// of a TClonesArray or an STL container, in which case we
5958 /// do *not* create a sub-branch), and for each non-split data
5959 /// member of cl.
5960 ///
5961 /// Note: We do *not* create sub-branches for base classes of cl
5962 /// if we are a sub-branch of a TClonesArray or an STL container.
5963 ///
5964 /// Note: We do *not* create sub-branches for data members which
5965 /// have a class type and which we are splitting.
5966 ///
5967 /// Note: The above rules imply that the branch heirarchy increases
5968 /// in depth only for base classes of cl (unless we are inside
5969 /// of a TClonesArray or STL container, in which case the depth
5970 /// does *not* increase, the base class is elided) and for
5971 /// TClonesArray or STL container data members (which have one
5972 /// additional level of sub-branches). The only other way the
5973 /// depth increases is when the top-level branch has a split
5974 /// class data member, in that case the constructor will create
5975 /// a sub-branch for it. In other words, the interior nodes of
5976 /// the branch tree are all either: base class nodes; split
5977 /// class nodes which are direct sub-branches of top-level nodes
5978 /// (created by TClass::Bronch usually); or TClonesArray or STL
5979 /// container master nodes.
5980 ///
5981 /// Note: The exception to the above is for the top-level branches,
5982 /// Tree::Bronch creates nodes for everything in that case,
5983 /// except for a TObject base class of a class which has the
5984 /// can ignore tobject streamer flag set.
5985 
5986 Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype)
5987 {
5988  //----------------------------------------------------------------------------
5989  // Handling the case of STL collections of pointers
5990  /////////////////////////////////////////////////////////////////////////////
5991 
5992  Int_t splitSTLP = splitlevel - (splitlevel%TTree::kSplitCollectionOfPointers);
5993  splitlevel %= TTree::kSplitCollectionOfPointers;
5994 
5995  TString branchname;
5996 
5997  if ((cl == TObject::Class()) && clParent->CanIgnoreTObjectStreamer()) {
5998  return 0;
5999  }
6000 
6001  TStreamerInfo* sinfo = fTree->BuildStreamerInfo(cl);
6002 
6003  //
6004  // Do nothing if we couldn't build the streamer info for cl.
6005  //
6006 
6007  if (!sinfo) {
6008  return 0;
6009  }
6010 
6011  Int_t ndata = sinfo->GetNelement();
6012 
6013  if ((ndata == 1) && cl->GetCollectionProxy() && !strcmp(sinfo->GetElement(0)->GetName(), "This")) {
6014  // -- Class cl is an STL collection, refuse to split it.
6015  // Question: Why? We certainly could by switching to the value class.
6016  // Partial Answer: Only the branch element constructor can split STL containers.
6017  return 1;
6018  }
6019 
6020  for (Int_t elemID = 0; elemID < ndata; ++elemID) {
6021  // -- Loop over all the streamer elements and create sub-branches as needed.
6022  TStreamerElement* elem = sinfo->GetElement(elemID);
6023  if (elem->IsA() == TStreamerArtificial::Class()) {
6024  continue;
6025  }
6026  if (elem->TestBit(TStreamerElement::kRepeat)) {
6027  continue;
6028  }
6030  continue;
6031  }
6032  Int_t offset = elem->GetOffset();
6033  // FIXME: An STL container as a base class gets TStreamerSTL as its class, so this test is not enough.
6034  // See InitializeOffsets() for the proper test.
6035  if (elem->IsA() == TStreamerBase::Class()) {
6036  // -- This is a base class of cl.
6037  TClass* clOfBase = elem->GetClassPointer();
6038  if (!clOfBase || ((clOfBase->Property() & kIsAbstract) && cl->InheritsFrom(TCollection::Class()))) {
6039  // -- Do nothing if we are one of the abstract collection (we know they have no data).
6040  return -1;
6041  }
6042  if ((btype == 31) || (btype == 41)) {
6043  // -- Elide the base-class sub-branches of a split TClonesArray or STL container.
6044  //
6045  // Note: We are eliding the base class here, that is, we never
6046  // create a branch for it, so the branch heirarchy is not
6047  // complete.
6048  // Note: The clParent parameter is the value class of the
6049  // container which we are splitting. It does not
6050  // appear in the branch heirarchy either.
6051  // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6052  Int_t unroll = -1;
6053  if (!elem->CannotSplit() || clOfBase == TObject::Class()) {
6054  unroll = Unroll(name, clParent, clOfBase, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6055  }
6056  if (unroll < 0) {
6057  // FIXME: We could not split because we are abstract, should we be doing this?
6058  if (strlen(name)) {
6059  branchname.Form("%s.%s", name, elem->GetFullName());
6060  } else {
6061  branchname.Form("%s", elem->GetFullName());
6062  }
6063  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, 0, basketsize, 0, btype);
6064  branch->SetParentClass(clParent);
6065  fBranches.Add(branch);
6066  }
6067  } else if (clOfBase->GetListOfRealData()->GetSize()) {
6068  // -- Create a branch for a non-empty base class.
6069  if (strlen(name)) {
6070  branchname.Form("%s.%s", name, elem->GetFullName());
6071  // Elide the base class name when creating the sub-branches.
6072  // Note: The branch names for sub-branches of a base class branch
6073  // do not represent the full class heirarchy because we do
6074  // this, however it does keep the branch names for the
6075  // inherited data members simple.
6076  TBranchElement* branch = new TBranchElement(this, name, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6077  // Then reset it to the proper name.
6078  branch->SetName(branchname);
6079  branch->SetTitle(branchname);
6080  branch->SetParentClass(clParent);
6081  fBranches.Add(branch);
6082  } else {
6083  branchname.Form("%s", elem->GetFullName());
6084  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6085  branch->SetParentClass(clParent);
6086  fBranches.Add(branch);
6087  }
6088  }
6089  } else {
6090  // -- This is a data member of cl.
6091  if (strlen(name)) {
6092  branchname.Form("%s.%s", name, elem->GetFullName());
6093  } else {
6094  branchname.Form("%s", elem->GetFullName());
6095  }
6096  if ((splitlevel > 1) && ((elem->IsA() == TStreamerObject::Class()) || (elem->IsA() == TStreamerObjectAny::Class()))) {
6097  // -- We are splitting a non-TClonesArray (may inherit from TClonesArray though), non-STL container object.
6098  //
6099  // Ignore an abstract class.
6100  // FIXME: How could an abstract class get here?
6101  // Partial answer: It is a base class. But this is a data member!
6102  TClass* elemClass = elem->GetClassPointer();
6103  if (!elemClass || elemClass->Property() & kIsAbstract) {
6104  return -1;
6105  }
6106  if (elem->CannotSplit()) {
6107  // We are not splitting.
6108  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6109  branch->SetParentClass(clParent);
6110  fBranches.Add(branch);
6111  } else if (elemClass->InheritsFrom(TClonesArray::Class())) {
6112  // Splitting something derived from TClonesArray.
6113  Int_t subSplitlevel = splitlevel-1;
6114  if (btype == 31 || btype == 41 || elem->CannotSplit()) {
6115  // -- We split the sub-branches of a TClonesArray or an STL container only once.
6116  subSplitlevel = 0;
6117  }
6118  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel, btype);
6119  branch->SetParentClass(clParent);
6120  fBranches.Add(branch);
6121  } else {
6122  // Splitting a normal class.
6123  // FIXME: We are eliding the class we are splitting here,
6124  // i.e., we do not create a branch for it, so the
6125  // branch heirarchy does not match the class heirarchy.
6126  // Note: clParent is the class which contains a data member of
6127  // the class type which we are splitting.
6128  // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6129  Int_t unroll = Unroll(branchname, clParent, elemClass, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6130  if (unroll < 0) {
6131  // FIXME: We could not split because we are abstract, should we be doing this?
6132  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6133  branch->SetParentClass(clParent);
6134  fBranches.Add(branch);
6135  }
6136  }
6137  }
6138  else if( elem->GetClassPointer() &&
6139  elem->GetClassPointer()->GetCollectionProxy() &&
6141  splitSTLP && fType != 4 )
6142  {
6143 
6144  TBranchSTL* branch = new TBranchSTL( this, branchname,
6146  basketsize, splitlevel - 1+splitSTLP, sinfo, elemID );
6147  branch->SetAddress( ptr+offset );
6148  fBranches.Add( branch );
6149  }
6150  else if ((elem->IsA() == TStreamerSTL::Class()) && !elem->IsaPointer()) {
6151  // -- We have an STL container.
6152  // Question: What if splitlevel == 0 here?
6153  // Answer: then we should not be here.
6154  Int_t subSplitlevel = splitlevel - 1;
6155  if ((btype == 31) || (btype == 41) || elem->CannotSplit()) {
6156  // -- We split the sub-branches of a TClonesArray or an STL container only once.
6157  subSplitlevel = 0;
6158  }
6159  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel+splitSTLP, btype);
6160  branch->SetParentClass(clParent);
6161  fBranches.Add(branch);
6162  } else if (((btype != 31) && (btype != 41)) && ptr && ((elem->GetClassPointer() == TClonesArray::Class()) || ((elem->IsA() == TStreamerSTL::Class()) && !elem->CannotSplit()))) {
6163  // -- We have a TClonesArray.
6164  // FIXME: We could get a ptr to a TClonesArray here by mistake.
6165  // Question: What if splitlevel == 0 here?
6166  // Answer: then we should not be here.
6167  // Note: ptr may be null in case of a TClonesArray inside another
6168  // TClonesArray or STL container, see the else clause.
6169  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6170  branch->SetParentClass(clParent);
6171  fBranches.Add(branch);
6172  } else {
6173  // -- We are not going to split this element any farther.
6174  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, 0, basketsize, splitSTLP, btype);
6175  branch->SetType(btype);
6176  branch->SetParentClass(clParent);
6177  fBranches.Add(branch);
6178  }
6179  }
6180  }
6181 
6182  if (!fBranches.IsEmpty()) {
6183  // Refresh this branch's action now that we know whether it is split or not.
6186  }
6187  return 1;
6188 }
6189 
6190 ////////////////////////////////////////////////////////////////////////////////
6191 /// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
6192 /// with the current value of fTree->GetCurrentFile unless this branch has been
6193 /// redirected to a different file. Also update the sub-branches.
6194 
6196 {
6197  // The BranchCount and BranchCount2 are part of higher level branches' list of
6198  // branches.
6199  // if (fBranchCount) fBranchCount->UpdateFile();
6200  // if (fBranchCount2) fBranchCount2->UpdateFile();
6202 }
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is &#39;source&#39;.
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:43
TClassRef fTargetClass
! Reference to the target in-memory class
Int_t * GetEntryOffset()
Definition: TBasket.h:112
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Int_t GetDefaultEntryOffsetLen() const
Definition: TTree.h:378
virtual Bool_t IsTransient() const
Return kTRUE if the element represent an entity that is not written to the disk (transient members...
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:90
virtual Int_t GetCollectionType() const =0
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:32
Int_t Unroll(const char *name, TClass *cltop, TClass *cl, char *ptr, Int_t basketsize, Int_t splitlevel, Int_t btype)
Split class cl into sub-branches of this branch.
Bool_t IsReading() const
Definition: TBuffer.h:83
void FillLeavesAssociativeCollectionMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
virtual void WriteFloat16(Float_t *f, TStreamerElement *ele=0)=0
We are the owner of fOnfileObject.
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method). ...
Definition: TClass.cxx:5677
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition: TClass.cxx:2231
TStreamerInfo * BuildStreamerInfo(TClass *cl, void *pointer=0, Bool_t canOptimize=kTRUE)
Build StreamerInfo for class cl.
Definition: TTree.cxx:2509
An array of TObjects.
Definition: TObjArray.h:37
TBranchElement * fBranchCount2
pointer to secondary branchcount branch
TVirtualCollectionProxy * GetCollectionProxy()
Return the collection proxy describing the branch content, if any.
const char * GetTypeNameBasic() const
Return type name of this element in case the type name is not a standard basic type, return the basic type name known to CINT.
virtual Int_t FillImpl(ROOT::Internal::TBranchIMTHelper *)
Loop on all leaves of this branch to fill Basket buffer.
Definition: TBranch.cxx:815
TStreamerInfoActions::TIDs fNewIDs
! Nested List of the serial number of all the StreamerInfo to be used.
virtual void * Allocate(UInt_t n, Bool_t forceDelete)=0
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
T GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
Return value of element i in object at pointer.
virtual void UpdateFile()
Refresh the value of fDirectory (i.e.
Definition: TBranch.cxx:2854
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
TVirtualStreamerInfo * fInfo
TStreamerInfo form which the action is derived.
void PrintValue(Int_t i) const
Prints values of leaves.
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket...
Definition: TBufferFile.h:47
virtual void SetAddress(void *add)
Set address of this branch.
Definition: TBranch.cxx:2240
static SequencePtr WriteMemberWiseActionsCollectionCreator(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *)
virtual TLeaf * FindLeaf(const char *name)
Find the leaf corresponding to the name &#39;searchname&#39;.
Int_t fOffset
Offset of this branch.
Definition: TBranch.h:85
long long Long64_t
Definition: RtypesCore.h:69
virtual Int_t GetProperties() const
auto * m
Definition: textangle.C:8
Int_t GetType() const
virtual Int_t GetExpectedType(TClass *&clptr, EDataType &type)
Fill expectedClass and expectedType with information on the data type of the object/values contained ...
virtual TBranch * FindBranch(const char *name)
Find the immediate sub-branch with passed name.
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
virtual void ResetInitInfo(bool recurse)
Reset offset and StremerInfo information from this branch.
Int_t ApplySequence(const TStreamerInfoActions::TActionSequence &sequence, void *object)
Read one collection of objects from the buffer using the StreamerInfoLoopAction.
TStreamerElement * GetStreamerElement(const char *datamember, Int_t &offset) const
Return the StreamerElement of "datamember" inside our class or any of its base classes.
void CreateIterators(void *collection, TVirtualCollectionProxy *proxy)
std::vector< TIDNode > TIDs
virtual TClass * GetClass() const =0
Int_t GetNevBufSize() const
Definition: TBasket.h:118
Long64_t fEntries
Number of entries.
Definition: TBranch.h:95
float Float_t
Definition: RtypesCore.h:53
virtual void InitInfo()
Init the streamer info for the branch class, try to compensate for class code unload/reload and schem...
TVirtualStreamerInfo * GetConversionStreamerInfo(const char *onfile_classname, Int_t version) const
Return a Conversion StreamerInfo from the class &#39;classname&#39; for version number &#39;version&#39; to this clas...
Definition: TClass.cxx:6757
float Size_t
Definition: RtypesCore.h:83
const char Option_t
Definition: RtypesCore.h:62
Double_t GetValue(Int_t i, Int_t len, Bool_t subarr=kFALSE) const
virtual TClass * GetValueClass() const =0
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
double T(double x)
Definition: ChebyshevPol.h:34
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:40
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:638
TString fParentName
Name of parent class.
virtual void WriteDouble32(Double_t *d, TStreamerElement *ele=0)=0
ReadLeaves_t fReadLeaves
! Pointer to the ReadLeaves implementation to use.
Definition: TBranch.h:118
TStreamerElement * GetElement(Int_t id) const
const char * GetIconName() const
Return icon name depending on type of branch element.
T GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
virtual void SetLeafCount(TLeaf *leaf)
Set the leaf count of this leaf.
Definition: TLeafElement.h:59
virtual void Reset(Option_t *option="")
Reset a Branch.
unsigned short UShort_t
Definition: RtypesCore.h:36
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:140
TBranch * GetSubBranch(const TBranch *br) const
Find the parent branch of child.
Definition: TBranch.cxx:1730
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist...
Definition: TClass.cxx:4420
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:46
virtual Int_t GetEntries() const
Definition: TCollection.h:177
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
virtual void Commit(void *)=0
virtual TLeaf * FindLeaf(const char *name)
Find the leaf corresponding to the name &#39;searchname&#39;.
Definition: TBranch.cxx:1032
Int_t GetNdata() const
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
void FillLeavesCollectionMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
TClassStreamer * GetStreamer() const
Return the Streamer Class allowing streaming (if any).
Definition: TClass.cxx:2833
void SetName(const char *new_name)
Definition: TClassRef.h:66
Bool_t IsFolder() const
Return kTRUE if more than one leaf or browsables, kFALSE otherwise.
Definition: TBranch.cxx:1838
virtual TClass * GetCollectionClass() const
TStreamerInfo * GetInfo() const
Get streamer info for the branch class.
#define R__ASSERT(e)
Definition: TError.h:96
#define gROOT
Definition: TROOT.h:402
void FillLeavesCustomStreamer(TBuffer &b)
Write leaves into i/o buffers for this branch.
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3617
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:585
Long64_t GetDebugMin() const
Definition: TTree.h:380
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
virtual Int_t WriteTObject(const TObject *obj, const char *name=0, Option_t *="", Int_t=0)
See TDirectoryFile::WriteTObject for details.
Int_t GetOffset() const
Definition: TBranch.h:183
void PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids)
Print branch parameters.
UInt_t fElemId
Identifier of the TStreamerElement.
TObjArray fBaskets
-> List of baskets of this branch
Definition: TBranch.h:101
Basic string class.
Definition: TString.h:125
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2816
virtual void SetAddress(void *addobj)
Point this branch at an object.
static void R__CleanName(std::string &name)
Remove trailing dimensions and make sure there is a trailing dot.
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:168
virtual void SetTargetClass(const char *name)
Set the name of the class of the in-memory object into which the data will loaded.
Bool_t IsEmpty() const
Definition: TObjArray.h:70
static SequencePtr ReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *)
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const char * GetClassName()
Definition: TClassRef.h:70
virtual void Clear(const char *opt="")=0
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:57
virtual void * New() const
virtual void ForceWriteInfo(TVirtualStreamerInfo *info, Bool_t force)=0
void SetReadActionSequence()
Set the sequence of actions needed to read the data out of the buffer.
Int_t fNleaves
! Number of leaves
Definition: TBranch.h:89
Int_t GetNelement() const
void ReadLeavesCollectionSplitVectorPtrMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
TObjArray fLeaves
-> List of leaves of this branch
Definition: TBranch.h:100
void MapObject(const TObject *obj, UInt_t offset=1)
Add object to the fMap container.
TString & Prepend(const char *cs)
Definition: TString.h:607
Long64_t * fBasketSeek
[fMaxBaskets] Addresses of baskets on file
Definition: TBranch.h:104
TObject * At(Int_t idx) const
Definition: TObjArray.h:165
The addressing set have been called for this branch.
virtual Int_t FillImpl(ROOT::Internal::TBranchIMTHelper *)
Loop on all leaves of this branch to fill the basket buffer.
UInt_t fCheckSum
CheckSum of class.
void FillLeavesCollectionSplitVectorPtrMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
virtual EDataType GetType() const =0
void SetupAddressesImpl()
If the branch address is not set, we set all addresses starting with the top level parent branch...
virtual Int_t GetMaximum() const
Return maximum count value of the branchcount if any.
TObject ** GetObjectRef() const
Definition: TObjArray.h:68
TStreamerInfoActions::TActionSequence * fFillActionSequence
! Set of actions to be executed to write the data to the basket.
void CreateIterators(void *collection, TVirtualCollectionProxy *proxy)
void PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax=1000) const
print value of element i in object at pointer The function may be called in two ways: -method1 len < ...
Bool_t fInit
! Initialization flag for branch assignment
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual TStreamerElement * GetElement(Int_t id) const =0
TClass * GetClass() const
Definition: TClassRef.h:71
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
void ReadLeavesClones(TBuffer &b)
Read leaves into i/o buffers for this branch.
Int_t * fBasketBytes
[fMaxBaskets] Length of baskets on file
Definition: TBranch.h:102
virtual TList * GetBrowsables()
Returns (and, if 0, creates) browsable objects for this branch See TVirtualBranchBrowsable::FillListO...
Definition: TBranch.cxx:1254
TActionSequence * CreateSubSequence(const std::vector< Int_t > &element_ids, size_t offset)
Long64_t fEntryNumber
Current entry number (last one filled in this branch)
Definition: TBranch.h:83
virtual Bool_t CannotSplit() const
Returns true if the element cannot be split, false otherwise.
TStreamerInfo * FindOnfileInfo(TClass *valueClass, const TObjArray &branches) const
void ReadLeavesCustomStreamer(TBuffer &b)
Read leaves into i/o buffers for this branch.
Int_t Length() const
Definition: TBuffer.h:96
void FillLeavesCollection(TBuffer &b)
Write leaves into i/o buffers for this branch.
void ReadLeavesMemberBranchCount(TBuffer &b)
Read leaves into i/o buffers for this branch.
Int_t fWriteBasket
Last basket number written.
Definition: TBranch.h:82
Int_t fNdata
! Number of data in this branch
static SequencePtr ConversionReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass)
char * GetObjectAt(UInt_t ind) const
Definition: TVirtualArray.h:38
friend class TClonesArray
Definition: TObject.h:213
static SequencePtr WriteMemberWiseActionsCollectionGetter(TStreamerInfo *info, TVirtualCollectionProxy *, TClass *)
TVirtualArray * fOnfileObject
! Place holder for the onfile representation of data members.
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString...
Definition: TString.cxx:2365
void Class()
Definition: Class.C:29
void SetFillActionSequence()
Set the sequence of actions needed to write the data out from the buffer.
TStreamerInfoActions::TActionSequence * fReadActionSequence
! Set of actions to be executed to extract the data from the basket.
virtual void SetAddress(void *addr)
Set Address.
Definition: TBranchSTL.cxx:661
virtual Bool_t IsWritable() const
Definition: TDirectory.h:163
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:414
virtual Long64_t GetReadEntry() const
Definition: TTree.h:426
Int_t fMaximum
Maximum entries for a TClonesArray or variable array.
TVirtualStreamerInfo * GetStreamerInfoAbstractEmulated(Int_t version=0) const
For the case where the requestor class is emulated and this class is abstract, returns a pointer to t...
Definition: TClass.cxx:4523
void ReadLeavesCollectionSplitPtrMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process&#39;s memory.
Definition: TClass.cxx:5642
virtual TBranch * FindBranch(const char *name)
Find the immediate sub-branch with passed name.
Definition: TBranch.cxx:986
void BuildTitle(const char *name)
Set branch and leaf name and title in the case of a container sub-branch.
virtual void ResetDeleteObject()
Release ownership of any allocated objects.
void FillLeavesClones(TBuffer &b)
Write leaves into i/o buffers for this branch.
static SequencePtr WriteMemberWiseActionsGetter(TStreamerInfo *info, TVirtualCollectionProxy *, TClass *)
void FillLeavesClonesMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
virtual void SetBasketSize(Int_t buffsize)
Reset the basket size for all sub-branches of this branch element.
Bool_t IsAutoDelete() const
Return kTRUE if an existing object in a TBranchObject must be deleted.
Definition: TBranch.cxx:1830
void ReadLeavesMemberCounter(TBuffer &b)
Read leaves into i/o buffers for this branch.
TString & Append(const char *cs)
Definition: TString.h:495
Int_t * fBranchOffset
! Sub-Branch offsets with respect to current transient class
virtual void Destructor(void *p, Bool_t dtorOnly=kFALSE) const
Long_t GetThisOffset() const
Definition: TRealData.h:55
TVirtualCollectionProxy * fCollProxy
! collection interface (if any)
Int_t GetID() const
virtual Bool_t SetMakeClass(Bool_t decomposeObj=kTRUE)
Set the branch in a mode where the object are decomposed (Also known as MakeClass mode)...
virtual void Browse(TBrowser *b)
Browse the branch content.
Version_t fClassVersion
Version number of class.
TObjArray * GetListOfBranches()
Definition: TBranch.h:194
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:477
Int_t fMaxBaskets
Maximum number of Baskets so far.
Definition: TBranch.h:86
T GetTypedValue(Int_t i, Int_t len, Bool_t subarr=kFALSE) const
void FillLeavesMemberCounter(TBuffer &b)
Write leaves into i/o buffers for this branch.
XFontStruct * id
Definition: TGX11.cxx:108
void FillLeavesMemberBranchCount(TBuffer &b)
Write leaves into i/o buffers for this branch.
TString fClassName
Class name of referenced object.
virtual void ls(Option_t *option="") const
Print the content of the element.
virtual Int_t GetEntry(Long64_t entry=0, Int_t getall=0)
Read all branches of a BranchElement and return total number of bytes.
const TObjArray * GetStreamerInfos() const
Definition: TClass.h:457
virtual void SetAddress(void *add=0)
Definition: TLeaf.h:126
A branch containing and managing a TRefTable for TRef autoloading.
Definition: TBranchRef.h:29
void SetFillLeavesPtr()
Set the FillLeaves pointer to execute the expected operations.
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset a Branch after a Merge operation (drop data but keep customizations)
Bool_t IsMissingCollection() const
Detect a collection written using a zero pointer in old versions of root.
virtual TFile * GetFile() const
Definition: TDirectory.h:147
virtual const char * GetClonesName() const
Int_t fSplitLevel
Branch split level.
Definition: TBranch.h:88
static SequencePtr ReadMemberWiseActionsCollectionGetter(TStreamerInfo *info, TVirtualCollectionProxy *, TClass *)
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition: TObject.h:134
TString fClonesName
Name of class in TClonesArray (if any)
virtual void ResetAddress()
Set branch address to zero and free all allocated memory.
void ReadLeavesClonesMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
T GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
A doubly linked list.
Definition: TList.h:44
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset a Branch.
Definition: TBranch.cxx:2156
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition: TTree.cxx:4985
Int_t GetType() const
Definition: TDataType.h:68
Need to pushd/pop fOnfileObject.
void FillLeavesMakeClass(TBuffer &b)
Write leaves into i/o buffers for this branch.
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:1942
static SequencePtr ReadMemberWiseActionsGetter(TStreamerInfo *info, TVirtualCollectionProxy *, TClass *)
Int_t ApplySequenceVecPtr(const TStreamerInfoActions::TActionSequence &sequence, void *start_collection, void *end_collection)
Read one collection of objects from the buffer using the StreamerInfoLoopAction.
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:37
void(TBranch::* ReadLeaves_t)(TBuffer &b)
Definition: TBranch.h:117
Int_t fID
element serial number in fInfo
void SetupInfo()
Set the value of fInfo.
void SetParentClass(TClass *clparent)
void ValidateAddress() const
virtual char * GetAddress() const
Get the branch address.
virtual const char * GetTypeName() const
Return type name of element in the branch.
static SequencePtr WriteMemberWiseActionsViaProxyGetter(TStreamerInfo *, TVirtualCollectionProxy *collectionProxy, TClass *)
Small helper class to generically acquire and release iterators.
TClass * GetClass() const
Int_t fBasketSize
Initial Size of Basket Buffer.
Definition: TBranch.h:80
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition: TClass.cxx:6737
void ReadLeavesCollection(TBuffer &b)
Read leaves into i/o buffers for this branch.
friend class TLeafElement
virtual void SetupAddresses()
If the branch address is not set, we set all addresses starting with the top level parent branch...
Wrapper around an object and giving indirect access to its content even if the object is not of a cla...
Definition: TVirtualArray.h:26
UInt_t GetCheckSum() const
virtual void SetType(Int_t btype)
virtual Int_t ApplySequence(const TStreamerInfoActions::TActionSequence &sequence, void *object)=0
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
char * GetObject() const
Return a pointer to our object.
TClassRef fParentClass
! Reference to class definition in fParentName
virtual void UpdateFile()
Refresh the value of fDirectory (i.e.
Int_t GetLast() const
Definition: TBasket.h:119
virtual Bool_t HasPointers() const =0
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5149
TBranchElement * fBranchCount
pointer to primary branchcount branch
Int_t fStreamerType
branch streamer type
TClass * GetParentClass()
Return a pointer to the parent class of the branch element.
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2343
FillLeaves_t fFillLeaves
! Pointer to the FillLeaves implementation to use.
Definition: TBranch.h:120
virtual void * GetValuePointer() const
Returns pointer to first data element of this branch.
unsigned int UInt_t
Definition: RtypesCore.h:42
void SetActionSequence(TClass *originalClass, TStreamerInfo *localInfo, TStreamerInfoActions::TActionSequence::SequenceGetter_t create, TStreamerInfoActions::TActionSequence *&actionSequence)
Set the sequence of actions needed to read the data out of the buffer.
Int_t GetEntriesFast() const
Definition: TObjArray.h:64
void SetReadLeavesPtr()
Set the ReadLeaves pointer to execute the expected operations.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
const Handle_t kNone
Definition: GuiTypes.h:87
Int_t Debug() const
Definition: TTree.h:353
Ssiz_t Length() const
Definition: TString.h:386
TClass * GetCurrentClass()
Return a pointer to the current type of the data member corresponding to branch element.
void ReadLeavesImpl(TBuffer &b)
Unconfiguration Read Leave function.
Manages buffers for branches of a Tree.
Definition: TBasket.h:34
void Init(TTree *tree, TBranch *parent, const char *name, TStreamerInfo *sinfo, Int_t id, char *pointer, Int_t basketsize=32000, Int_t splitlevel=0, Int_t btype=0)
Init when the branch object is not a TClonesArray nor an STL container.
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1080
short Short_t
Definition: RtypesCore.h:35
TClassRef fCurrentClass
! Reference to current (transient) class definition
The TRealData class manages the effective list of all data members for a given class.
Definition: TRealData.h:30
virtual Int_t GetEntry(Long64_t entry=0, Int_t getall=0)
Read all leaves of entry and return total number of bytes read.
Definition: TBranch.cxx:1301
Bool_t CanIgnoreTObjectStreamer()
Definition: TClass.h:365
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
long double LongDouble_t
Definition: RtypesCore.h:57
TClassRef fBranchClass
! Reference to class definition in fClassName
Bool_t fInInitInfo
! True during the 2nd part of InitInfo (cut recursion).
ROOT::ESTLType GetCollectionType() const
Return the &#39;type&#39; of the STL the TClass is representing.
Definition: TClass.cxx:2805
virtual TBranchRef * GetBranchRef() const
Definition: TTree.h:369
const char * GetFileName() const
Definition: TBranch.h:182
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4688
static SequencePtr ReadMemberWiseActionsCollectionCreator(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *)
Long_t Property() const
Set TObject::fBits and fStreamerType to cache information about the class.
Definition: TClass.cxx:5768
TString fName
Definition: TNamed.h:32
virtual void ReadFastArray(Bool_t *b, Int_t n)=0
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=0) const
Definition: TClass.h:561
virtual void WriteFastArray(const Bool_t *b, Int_t n)=0
A TLeaf for the general case when using the branches created via a TStreamerInfo (i.e.
Definition: TLeafElement.h:30
virtual Int_t GetLenStatic() const
Definition: TLeaf.h:75
A Branch for the case of an object.
#define Printf
Definition: TGeoToOCC.h:18
virtual void SetRequestedEntry(Long64_t entry)
Definition: TBranchRef.h:50
const Bool_t kFALSE
Definition: RtypesCore.h:88
PyObject * fType
virtual void SetBasketSize(Int_t buffsize)
Set the basket size The function makes sure that the basket size is greater than fEntryOffsetlen.
Definition: TBranch.cxx:2287
T GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
static const Ssiz_t kNPOS
Definition: TString.h:246
virtual void ReadFloat16(Float_t *f, TStreamerElement *ele=0)=0
TString & Remove(Ssiz_t pos)
Definition: TString.h:619
long Long_t
Definition: RtypesCore.h:50
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=0)=0
int Ssiz_t
Definition: RtypesCore.h:63
void SetBranchCount(TBranchElement *bre)
Set the branch counter for this branch.
virtual Int_t ApplySequenceVecPtr(const TStreamerInfoActions::TActionSequence &sequence, void *start_collection, void *end_collection)=0
Int_t fSTLtype
! STL container type
Version_t GetClassVersion() const
Definition: TClass.h:391
virtual void MapObject(const TObject *obj, UInt_t offset=1)=0
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:89
virtual TVirtualArray * PopDataCache()
Pop and Return the &#39;current&#39; data cache area from the list of area to be used for temporarily store &#39;...
Definition: TBuffer.cxx:360
void Print(Option_t *="") const
This method must be overridden when a class wants to print itself.
virtual Int_t GetMaximum() const
Definition: TLeaf.h:77
#define ClassImp(name)
Definition: Rtypes.h:359
Int_t fReadBasket
! Current basket number when reading
Definition: TBranch.h:90
virtual void ResetAddress()
Reset the address of the branch.
Definition: TBranch.cxx:2209
double Double_t
Definition: RtypesCore.h:55
virtual TObjArray * GetElements() const =0
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:875
Bool_t IsFolder() const
Return kTRUE if more than one leaf, kFALSE otherwise.
void FillLeavesMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
Describe directory structure in memory.
Definition: TDirectory.h:34
TDirectory * GetDirectory() const
Definition: TTree.h:381
virtual Bool_t IsaPointer() const
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any. ...
virtual const char * GetFullName() const
Return element name including dimensions, if any Note that this function stores the name into a stati...
int type
Definition: TGX11.cxx:120
Int_t IndexOf(const TObject *obj) const
Definition: TObjArray.cxx:589
unsigned long long ULong64_t
Definition: RtypesCore.h:70
TList * GetListOfRealData() const
Definition: TClass.h:418
unsigned long ULong_t
Definition: RtypesCore.h:51
void SetBranchCount2(TBranchElement *bre)
TStreamerInfo * GetInfoImp() const
Get streamer info for the branch class.
virtual void Draw(Option_t *opt)
Default Draw method for all objects.
Definition: TTree.h:355
virtual Bool_t IsBase() const
Return kTRUE if the element represent a base class.
virtual void SetObject(void *objadd)
Set object this branch is pointing to.
const char * GetCountName() const
More explicit alias for kMakeClass.
Int_t fBranchID
! ID number assigned by a TRefTable.
EDataType
Definition: TDataType.h:28
TBranchElement()
Default and I/O constructor.
virtual void * At(UInt_t idx)=0
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:570
static constexpr double s
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
virtual Int_t SetParent(const TObject *obj, Int_t branchID)
Set the current parent branch.
Definition: TBranchRef.cxx:212
#define R__LOCKGUARD(mutex)
TTree * fTree
! Pointer to Tree header
Definition: TBranch.h:105
void Browse(TBrowser *b)
Browse this collection (called by TBrowser).
TObjArray * GetListOfLeaves()
Definition: TBranch.h:195
virtual void PushDataCache(TVirtualArray *)
Push a new data cache area onto the list of area to be used for temporarily store &#39;missing&#39; data memb...
Definition: TBuffer.cxx:341
TDirectory * fDirectory
! Pointer to directory where this branch buffers are stored
Definition: TBranch.h:109
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2887
TCanvas * slash()
Definition: slash.C:1
TClassRef fClonesClass
! Reference to class definition in fClonesName
UInt_t GetCheckSum()
virtual void SetOffset(Int_t offset)
Set offset of the object (to which the data member represented by this branch belongs) inside its con...
Bool_t IsPersistent() const
Definition: TDataMember.h:89
We are the owner of fObject.
TClass * GetClass() const
Definition: TClonesArray.h:56
void ReadLeavesMakeClass(TBuffer &b)
Read leaves into i/o buffers for this branch.
Mother of all ROOT objects.
Definition: TObject.h:37
TObjArray * GetElements() const
virtual void ReadDouble32(Double_t *d, TStreamerElement *ele=0)=0
A Branch handling STL collection of pointers (vectors, lists, queues, sets and multisets) while stori...
Definition: TBranchSTL.h:22
SequencePtr(*)(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass) SequenceGetter_t
Int_t GetNewType() const
virtual UInt_t Size() const =0
Bool_t fInitOffsets
! Initialization flag to not endlessly recalculate offsets
TClassRef is used to implement a permanent reference to a TClass object.
Definition: TClassRef.h:29
char Char_t
Definition: RtypesCore.h:29
Int_t GetClassVersion() const
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5668
Long64_t GetEntries() const
Definition: TBranch.h:199
virtual void Print(Option_t *option="") const
Print TBranch parameters.
An array of clone (identical) objects.
Definition: TClonesArray.h:32
Long64_t * fBasketEntry
[fMaxBaskets] Table of first entry in each basket
Definition: TBranch.h:103
virtual ~TBranchElement()
Destructor.
static void SwitchContainer(TObjArray *)
Modify the container type of the branches.
void FillLeavesCollectionSplitPtrMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
const char * GetTypeName() const
virtual void ExpandCreateFast(Int_t n)
Expand or shrink the array to n elements and create the clone objects by calling their default ctor...
virtual void Add(TObject *obj)
Definition: TList.h:87
#define R__unlikely(expr)
Definition: RConfig.h:554
Definition: file.py:1
const char * GetCountName() const
Int_t GetClassVersion()
TClass * GetNewClass() const
virtual void Reset(Option_t *option="")
Reset a Branch.
Definition: TBranch.cxx:2115
void FillLeavesImpl(TBuffer &b)
Unconfiguration Fill Leave function.
TVirtualCollectionIterators * fWriteIterators
! holds the read (non-staging) iterators when the branch is of fType==4 and associative containers...
Bool_t IsVersioned() const
Definition: TClass.h:484
void(TBranch::* FillLeaves_t)(TBuffer &b)
Definition: TBranch.h:119
Long64_t fReadEntry
! Current entry number when reading
Definition: TBranch.h:91
Int_t fType
branch type
Long64_t GetReadEntry() const
Definition: TBranch.h:185
virtual TClass * GetClass() const
TVirtualCollectionIterators * fIterators
! holds the iterators when the branch is of fType==4.
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
TBranch * fMother
! Pointer to top-level parent branch in the tree.
Definition: TBranch.h:106
TTree * GetTree() const
Definition: TBranch.h:200
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:522
#define gPad
Definition: TVirtualPad.h:285
R__EXTERN Int_t gDebug
Definition: Rtypes.h:86
Bool_t GetMakeClass() const
Return whether this branch is in a mode where the object are decomposed or not (Also known as MakeCla...
virtual const char * GetParentName() const
Definition: tree.py:1
void PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
void SetSize(UInt_t size)
Definition: TVirtualArray.h:40
void Add(TObject *obj)
Definition: TObjArray.h:73
char * fObject
! Pointer to object at *fAddress
A TTree object has a header with a name and a title.
Definition: TTree.h:70
Int_t fEntryOffsetLen
Initial Length of fEntryOffset table in the basket buffers.
Definition: TBranch.h:81
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3280
void ResetBit(UInt_t f)
Definition: TObject.h:171
unsigned char UChar_t
Definition: RtypesCore.h:34
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition: TClass.cxx:1843
#define R__LOCKGUARD_IMT2(mutex)
Definition: first.py:1
TObjArray fBranches
-> List of Branches of this branch
Definition: TBranch.h:99
Option_t * GetDrawOption() const
Get option used by the graphics system to draw this object.
Definition: TBrowser.h:104
UInt_t GetCheckSum(ECheckSum code=kCurrentCheckSum) const
Call GetCheckSum with validity check.
Definition: TClass.cxx:6185
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:908
virtual Int_t GetSize() const
Definition: TCollection.h:180
A TTree is a list of TBranches.
Definition: TBranch.h:59
Abstract Interface class describing Streamer information for one class.
Int_t fCompress
Compression level and algorithm.
Definition: TBranch.h:79
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:164
Int_t GetOffset() const
virtual void Print(Option_t *option="") const
Print TBranch parameters.
Definition: TBranch.cxx:1908
TString fFileName
Name of file where buffers are stored ("" if in same file as Tree header)
Definition: TBranch.h:110
Base class of the Configurations.
const Bool_t kTRUE
Definition: RtypesCore.h:87
TBranch * fParent
! Pointer to parent branch.
Definition: TBranch.h:107
TVirtualCollectionPtrIterators * fPtrIterators
! holds the iterators when the branch is of fType==4 and it is a split collection of pointers...
Int_t GetType() const
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Copy the argument.
Definition: TClass.cxx:2389
const Int_t n
Definition: legend1.C:16
Int_t GetStreamerType() const
TStreamerInfo * fInfo
! Pointer to StreamerInfo
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3334
void ReadLeavesMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition: TBranch.cxx:1709
char name[80]
Definition: TGX11.cxx:109
virtual void InitializeOffsets()
Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a containe...
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
virtual const char * GetName() const
Return name of this collection.
Int_t GetCompressionSettings() const
Definition: TFile.h:378
TRangeDynCast is an adaptater class that allows the typed iteration through a TCollection.
Definition: TCollection.h:409
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
TClass * GetClass() const
virtual TObjArray * GetListOfLeaves()
Definition: TTree.h:408
virtual TVirtualCollectionProxy * Generate() const =0
void ReadLeavesCollectionMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4792
void ReleaseObject()
Delete any object we may have allocated on a previous call to SetAddress.
const char * Data() const
Definition: TString.h:345
virtual void SetAutoDelete(Bool_t autodel=kTRUE)
Set the automatic delete bit.
Definition: TBranch.cxx:2274
char * fAddress
! Address of 1st leaf (variable or object)
Definition: TBranch.h:108