Logo ROOT   6.14/05
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  TString subprefix;
2019  if (prefix.Length() && nextel->IsA() == TStreamerBase::Class()) {
2020  // We skip the name of the base class if there is already a prefix.
2021  // See TBranchElement::Unroll
2022  subprefix = prefix;
2023  } else {
2024  subprefix = ename + ".";
2025  }
2026  GatherArtificialElements(branches, ids.back().fNestedIDs->fIDs, subprefix, nextinfo, offset + nextel->GetOffset());
2027  if (ids.back().fNestedIDs->fIDs.empty())
2028  ids.pop_back();
2029  }
2030  }
2031 };
2032 } // Anonymous namespace.
2033 
2034 
2035 ////////////////////////////////////////////////////////////////////////////////
2036 /// Set the value of fInfo. This is part one of InitInfo.
2037 /// To be used as:
2038 /// if (!fInfo)
2039 /// SetupInfo();
2040 /// It would only be used within InitInfo (and its callees)
2041 
2043 {
2044  // We did not already have streamer info, so now we must find it.
2045  TClass* cl = fBranchClass.GetClass();
2046 
2047  //------------------------------------------------------------------------
2048  // Check if we're dealing with the name change
2049  //////////////////////////////////////////////////////////////////////////
2050 
2051  TClass* targetClass = 0;
2052  if( fTargetClass.GetClassName()[0] ) {
2053  targetClass = fTargetClass;
2054  if (!targetClass && GetCollectionProxy()) {
2055  // We are in the case where the branch holds a custom collection
2056  // proxy but the dictionary is not loaded, calling
2057  // GetCollectionProxy had the side effect of creating the TClass
2058  // corresponding to this emulated collection.
2059  targetClass = fTargetClass;
2060  }
2061  if ( !targetClass ) {
2062  Error( "InitInfo", "The target class dictionary is not present!" );
2063  return;
2064  }
2065  } else {
2066  targetClass = cl;
2067  }
2068  if (cl) {
2069  //---------------------------------------------------------------------
2070  // Get the streamer info for given version
2071  ///////////////////////////////////////////////////////////////////////
2072 
2073  {
2074  if ( (cl->Property() & kIsAbstract) && cl == targetClass) {
2075  TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this);
2076  if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
2077  // Our parent's class is emulated and we represent an abstract class.
2078  // and the target class has not been set explicilty.
2079  TString target = cl->GetName();
2080  target += "@@emulated";
2081  fTargetClass.SetName(target);
2082 
2083  if (!fTargetClass) {
2085  }
2086  targetClass = fTargetClass;
2087  }
2088  }
2089  if( targetClass != cl ) {
2091  } else {
2093  }
2094  }
2095 
2096  // FIXME: Check that the found streamer info checksum matches our branch class checksum here.
2097  // Check to see if the class code was unloaded/reloaded
2098  // since we were created.
2100  if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) {
2101  // Try to compensate for a class that got unloaded on us.
2102  // Search through the streamer infos by checksum
2103  // and take the first match.
2104 
2105  TStreamerInfo* info;
2106  if( targetClass != cl )
2107  info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum );
2108  else {
2109  info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum );
2110  if (info) {
2111  // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
2112  info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion());
2113  }
2114  }
2115  if( info ) {
2116  fInfo = info;
2117  // We no longer reset the class version so that in case the user is passing us later
2118  // the address of a class that require (another) Conversion we can find the proper
2119  // StreamerInfo.
2120  // fClassVersion = fInfo->GetClassVersion();
2121  }
2122  }
2123  }
2124 }
2125 
2126 
2127 ////////////////////////////////////////////////////////////////////////////////
2128 /// Init the streamer info for the branch class, try to compensate for class
2129 /// code unload/reload and schema evolution.
2130 
2132 {
2133  if (!fInfo)
2134  SetupInfo();
2135 
2136  //
2137  // Fixup cached streamer info if necessary.
2138  //
2139  // FIXME: What if the class code was unloaded/reloaded since we were cached?
2140 
2141  if (fInfo) {
2142 
2143  if (!fInfo->IsCompiled()) {
2144  // Streamer info has not yet been compiled.
2145 
2146  Error("InitInfo","StreamerInfo is not compiled.");
2147  }
2148  // return immediately if we are called recursively.
2149  if (fInInitInfo)
2150  return;
2151  fInInitInfo = kTRUE;
2152  if (!fInit) {
2153  // We were read in from a file, figure out what our fID should be,
2154  // schema evolution must be considered.
2155  //
2156  // Force our fID to be the id of the first streamer element that matches our name.
2157  //
2158  auto SetOnfileObject = [this](TStreamerInfo *info) {
2159  Int_t arrlen = 1;
2160  if (fType==31 || fType==41) {
2161  TLeaf *leaf = (TLeaf*)fLeaves.At(0);
2162  if (leaf) {
2163  arrlen = leaf->GetMaximum();
2164  }
2165  }
2166  Bool_t toplevel = (fType == 3 || fType == 4 || (fType == 0 && fID == -2));
2167  Bool_t seenExisting = kFALSE;
2168 
2169  fOnfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), arrlen );
2170  // Propage this to all the other branch of this type.
2172  Int_t nbranches = branches->GetEntriesFast();
2173  TBranchElement *lastbranch = this;
2174 
2175  TClass *currentClass = fBranchClass;
2176  auto currentVersion = fClassVersion;
2177  if (toplevel) {
2178  // Note: Fragile/wrong when using conversion StreamerInfo?
2179  currentClass = info->GetClass();
2180  currentVersion = info->GetClassVersion();
2181  }
2182 
2183  for (Int_t i = 0; i < nbranches; ++i) {
2184  TBranchElement* subbranch = (TBranchElement*)branches->At(i);
2185  Bool_t match = kFALSE;
2186  if (this != subbranch) {
2187 
2188  if (!subbranch->fInfo)
2189  subbranch->SetupInfo();
2190 
2191  if (subbranch->fInfo == info)
2192  match = kTRUE;
2193  else if (subbranch->fInfo == nullptr && subbranch->fBranchClass == currentClass) {
2194  if (!toplevel) {
2195  if (subbranch->fCheckSum == fCheckSum)
2196  match = kTRUE;
2197  } else {
2198  if (!subbranch->fBranchClass->IsForeign() && subbranch->fClassVersion == currentVersion)
2199  match = kTRUE;
2200  else if (subbranch->fCheckSum == info->GetCheckSum()) {
2201  match = kTRUE;
2202  }
2203  }
2204  }
2205  }
2206  if (match) {
2207  if (subbranch->fOnfileObject && subbranch->fOnfileObject != fOnfileObject) {
2208  if (seenExisting) {
2209  Error("SetOnfileObject (lambda)", "2 distincts fOnfileObject are in the hierarchy of %s for type %s",
2210  toplevel ? GetName() : GetMother()->GetSubBranch(this)->GetName(), info->GetName());
2211  } else {
2212  delete fOnfileObject;
2213  fOnfileObject = subbranch->fOnfileObject;
2214  seenExisting = kTRUE;
2215  }
2216  }
2217  subbranch->fOnfileObject = fOnfileObject;
2218  lastbranch = subbranch;
2219  }
2220  }
2221  if (toplevel) {
2223  if (lastbranch != this)
2224  lastbranch->ResetBit(kOwnOnfileObj);
2225  } else {
2226  lastbranch->SetBit(kOwnOnfileObj);
2227  }
2228  };
2229  if (GetID() > -1) {
2230  // We are *not* a top-level branch.
2231  std::string s(GetName());
2232  size_t pos = s.rfind('.');
2233  if (pos != std::string::npos) {
2234  s = s.substr(pos+1);
2235  }
2236  while ((pos = s.rfind('[')) != std::string::npos) {
2237  s = s.substr(0, pos);
2238  }
2239  int offset = 0;
2240  TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
2241  if (elt && offset!=TStreamerInfo::kMissing) {
2242  size_t ndata = fInfo->GetNelement();
2243  fNewIDs.clear();
2244  for (size_t i = 0; i < ndata; ++i) {
2245  if (fInfo->GetElement(i) == elt) {
2247  && (i+1) < ndata
2248  && s == fInfo->GetElement(i)->GetName())
2249  {
2250  // If the TStreamerElement we found is storing the information in the
2251  // cache and is a repeater, we need to use the real one (the next one).
2252  // (At least until the cache/repeat mechanism is properly handle by
2253  // ReadLeaves).
2254  // fID = i+1;
2255  fID = i;
2256  if (fType != 2) {
2257  if (elt->TestBit(TStreamerElement::kRepeat)) {
2258  fNewIDs.push_back(fID+1);
2259  fNewIDs.back().fElement = fInfo->GetElement(i+1);
2260  fNewIDs.back().fInfo = fInfo;
2261  } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) {
2262  fNewIDs.push_back(fID+1);
2263  fNewIDs.back().fElement = fInfo->GetElement(i+1);
2264  fNewIDs.back().fInfo = fInfo;
2265  }
2266  }
2267  } else {
2268  fID = i;
2269  }
2270  if (elt->TestBit (TStreamerElement::kCache)) {
2272  }
2273  break;
2274  }
2275  }
2276  for (size_t i = fID+1+(fNewIDs.size()); i < ndata; ++i) {
2277  TStreamerElement *nextel = fInfo->GetElement(i);
2278 
2279  std::string ename = nextel->GetName();
2280  if (ename[0] == '*')
2281  ename = ename.substr(1);
2282 
2283  while ((pos = ename.rfind('[')) != std::string::npos) {
2284  ename = ename.substr(0, pos);
2285  }
2286 
2287  if (s != ename) {
2288  // We moved on to the next set
2289  break;
2290  }
2291  // Add all (and only) the Artificial Elements that follows this StreamerInfo.
2292  // fprintf(stderr,"%s/%d[%zu] passing trhough %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2293  if (fType==31||fType==41) {
2294  // The nested objects are unfolded and their branch can not be used to
2295  // execute StreamerElements of this StreamerInfo.
2296  if ((nextel->GetType() == TStreamerInfo::kObject
2297  || nextel->GetType() == TStreamerInfo::kAny)
2298  && nextel->GetClassPointer()->CanSplit())
2299  {
2300  continue;
2301  }
2302  }
2303  if (nextel->GetOffset() == TStreamerInfo::kMissing) {
2304  // This element will be 'skipped', it's TBranchElement's fObject will null
2305  // and thus can not be used to execute the artifical StreamerElements
2306  continue;
2307  }
2308  if (nextel->IsA() != TStreamerArtificial::Class()
2309  || nextel->GetType() == TStreamerInfo::kCacheDelete ) {
2310  continue;
2311  }
2312  // NOTE: We should verify that the rule's source are 'before'
2313  // or 'at' this branch.
2314  // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2315  fNewIDs.push_back(i);
2316  fNewIDs.back().fElement = nextel;
2317  fNewIDs.back().fInfo = fInfo;
2318  }
2319  } else if (elt && offset==TStreamerInfo::kMissing) {
2320  // Still re-assign fID properly.
2321  fNewIDs.clear();
2322  size_t ndata = fInfo->GetNelement();
2323  for (size_t i = 0; i < ndata; ++i) {
2324  if (fInfo->GetElement(i) == elt) {
2325  fID = i;
2326  break;
2327  }
2328  }
2329  } else {
2330  // We have not even found the element .. this is strange :(
2331  // fNewIDs.clear();
2332  // fID = -3;
2333  // SetBit(kDoNotProcess);
2334  }
2335  if (fOnfileObject==0 && (fType==31 || fType==41 || (0 <= fType && fType <=2) ) && fInfo->GetNelement()
2337  {
2338  SetOnfileObject(fInfo);
2339  }
2340  }
2341  if (fType == 3 || fType == 4 || (fType == 0 && fID == -2)) {
2342  // Need to add the rule targetting transient members.
2343  TStreamerInfo *localInfo = fInfo;
2344  if (fType == 3 || fType == 4) {
2345  // Don't we have real version information?
2346  // Not unless there is a subbranch with a non-split element of the class.
2347  // Search for the correct version.
2348  localInfo = FindOnfileInfo(fClonesClass, fBranches);
2349  }
2350 
2351  TString prefix(GetName());
2352  if (prefix[prefix.Length()-1] != '.') {
2353  if (fType == 3 || fType == 4) {
2354  prefix += ".";
2355  } else {
2356  prefix = "";
2357  }
2358  }
2359  fNewIDs.clear();
2360 
2361  GatherArtificialElements(fBranches, fNewIDs, prefix, localInfo, 0);
2362 
2363  if (!fNewIDs.empty() && fOnfileObject == nullptr && localInfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew)
2364  {
2365  SetOnfileObject(localInfo);
2366  }
2367 
2368  }
2369  fInit = kTRUE;
2370 
2371  // Get the action sequence we need to copy for reading.
2374  } else if (!fReadActionSequence) {
2375  // Get the action sequence we need to copy for reading.
2378  }
2379  SetReadLeavesPtr();
2380  SetFillLeavesPtr();
2381  fInInitInfo = kFALSE;
2382  }
2383 }
2384 
2385 ////////////////////////////////////////////////////////////////////////////////
2386 /// Return the collection proxy describing the branch content, if any.
2387 
2389 {
2390  if (fCollProxy) {
2391  return fCollProxy;
2392  }
2393  TBranchElement* thiscast = const_cast<TBranchElement*>(this);
2394  if (fType == 4) {
2395  // STL container top-level branch.
2396  const char* className = 0;
2397  TClass* cl = nullptr;
2398  if (fID < 0) {
2399  // We are a top-level branch.
2400  if (fBranchClass.GetClass()) {
2401  cl = fBranchClass.GetClass();
2402  }
2403  } else {
2404  // We are not a top-level branch.
2405  TVirtualStreamerInfo* si = thiscast->GetInfoImp();
2406  if (fCollProxy) {
2407  // The GetInfo set fProxy for us, let's not
2408  // redo it; the value of fCollProxy is possibly
2409  // used/recorded is the actions sequences, so
2410  // if we change it here, we would need to propagate
2411  // the change.
2412  return fCollProxy;
2413  }
2414  TStreamerElement* se = si->GetElement(fID);
2415  cl = se->GetClassPointer();
2416  }
2417  if (!cl) {
2418  // The TClass was not created but we do know (since it
2419  // is used as a collection) that it 'className' was a
2420  // class, so let's create it by hand!.
2421 
2422  if (fID < 0) {
2425  className = cl->GetName();
2426  } else {
2427  cl = new TClass(className, fClassVersion);
2429  className = cl->GetName();
2430  }
2431  }
2433  if (!proxy) {
2434  // humm, we must have an older file with a custom collection
2435  // let's try to work-around it.
2436  TString equiv;
2437  equiv.Form("vector<%s>",fClonesName.Data());
2438  TClass *clequiv = TClass::GetClass(equiv);
2439  proxy = clequiv->GetCollectionProxy();
2440  if (!proxy) {
2441  Fatal("GetCollectionProxy",
2442  "Can not create a Collection Proxy of any kind for the class \"%s\" needed by the branch \"%s\" of the TTree \"%s\"!",
2443  className, GetName(), GetTree()->GetName());
2444  }
2445  if (gDebug > 0) Info("GetCollectionProxy",
2446  "Fixing the collection proxy of the class \"%s\" \n"
2447  "\tneeded by the branch \"%s\" of the TTree \"%s\" to be similar to \"%s\".",
2448  className, GetName(), GetTree()->GetName(),equiv.Data());
2449  cl->CopyCollectionProxy( *proxy );
2450  }
2451  fCollProxy = proxy->Generate();
2452  fSTLtype = proxy->GetCollectionType();
2453  } else if (fType == 41) {
2454  // STL container sub-branch.
2456  }
2457  return fCollProxy;
2458 }
2459 
2460 ////////////////////////////////////////////////////////////////////////////////
2461 /// Return a pointer to the current type of the data member corresponding to branch element.
2462 
2464 {
2465  TClass* cl = fCurrentClass;
2466  if (cl) {
2467  return cl;
2468  }
2469 
2470  TStreamerInfo* brInfo = (TStreamerInfo*)GetInfoImp();
2471  if (!brInfo) {
2473  R__ASSERT(cl && cl->GetCollectionProxy());
2474  fCurrentClass = cl;
2475  return cl;
2476  }
2477  TClass* motherCl = brInfo->GetClass();
2478  if (motherCl->GetCollectionProxy()) {
2479  cl = motherCl->GetCollectionProxy()->GetCollectionClass();
2480  if (cl) {
2481  fCurrentClass = cl;
2482  }
2483  return cl;
2484  }
2485  if (GetID() < 0 || GetID()>=brInfo->GetNelement()) {
2486  return 0;
2487  }
2488  TStreamerElement* currentStreamerElement = brInfo->GetElement(GetID());
2489  TDataMember* dm = (TDataMember*) motherCl->GetListOfDataMembers()->FindObject(currentStreamerElement->GetName());
2490 
2491  TString newType;
2492  if (!dm) {
2493  // Either the class is not loaded or the data member is gone
2494  if (!motherCl->IsLoaded()) {
2495  TVirtualStreamerInfo* newInfo = motherCl->GetStreamerInfo();
2496  if (newInfo != brInfo) {
2497  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(currentStreamerElement->GetName());
2498  if (newElems) {
2499  if (newElems->GetClassPointer())
2500  newType = newElems->GetClassPointer()->GetName();
2501  else
2502  newType = newElems->GetTypeName();
2503  }
2504  }
2505  if (newType.Length()==0) {
2506  if (currentStreamerElement->GetClassPointer())
2507  newType = currentStreamerElement->GetClassPointer()->GetName();
2508  else
2509  newType = currentStreamerElement->GetTypeName();
2510  }
2511  }
2512  } else {
2513  newType = dm->GetTypeName();
2514  }
2515  cl = TClass::GetClass(newType);
2516  if (cl) {
2517  fCurrentClass = cl;
2518  }
2519  return cl;
2520 }
2521 
2522 ////////////////////////////////////////////////////////////////////////////////
2523 /// Read all branches of a BranchElement and return total number of bytes.
2524 ///
2525 /// - If entry = 0, then use current entry number + 1.
2526 /// - If entry < 0, then reset entry number to 0.
2527 ///
2528 /// Returns the number of bytes read from the input buffer.
2529 /// - If entry does not exist, then returns 0.
2530 /// - If an I/O error occurs, then returns -1.
2531 ///
2532 /// See IMPORTANT REMARKS in TTree::GetEntry.
2533 
2535 {
2536  // Remember which entry we are reading.
2537  fReadEntry = entry;
2538 
2539  // If our tree has a branch ref, make it remember the entry and
2540  // this branch. This allows a TRef::GetObject() call done during
2541  // the following I/O operation, for example in a custom streamer,
2542  // to search for the referenced object in the proper element of the
2543  // proper branch.
2544  TBranchRef* bref = fTree->GetBranchRef();
2545  if (R__unlikely(bref)) {
2546  R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2547  fBranchID = bref->SetParent(this, fBranchID);
2548  bref->SetRequestedEntry(entry);
2549  }
2550 
2551  Int_t nbytes = 0;
2552 
2553  if (R__unlikely(IsAutoDelete())) {
2556  } else {
2558  R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2560  }
2561  }
2562 
2563  Int_t nbranches = fBranches.GetEntriesFast();
2564  if (nbranches) {
2565  // -- Branch has daughters.
2566  // One must always read the branch counter.
2567  // In the case when one reads consecutively twice the same entry,
2568  // the user may have cleared the TClonesArray between the GetEntry calls.
2569  if ((fType == 3) || (fType == 4)) {
2570  Int_t nb = TBranch::GetEntry(entry, getall);
2571  if (nb < 0) {
2572  return nb;
2573  }
2574  nbytes += nb;
2575  }
2576  switch(fSTLtype) {
2577  case ROOT::kSTLset:
2578  case ROOT::kSTLmultiset:
2581  case ROOT::kSTLmap:
2582  case ROOT::kSTLmultimap:
2585  break;
2586  default:
2587  ValidateAddress(); // There is no ReadLeave for this node, so we need to do the validation here.
2588  for (Int_t i = 0; i < nbranches; ++i) {
2589  TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2590  Int_t nb = branch->GetEntry(entry, getall);
2591  if (nb < 0) {
2592  return nb;
2593  }
2594  nbytes += nb;
2595  }
2596  break;
2597  }
2599  if (fType == 3) {
2600  // Apply the unattached rules; by definition they do not need any
2601  // input from a buffer.
2603 
2604  auto ndata = GetNdata();
2605 
2606  TClonesArray* clones = (TClonesArray*) fObject;
2607  if (clones->IsZombie()) {
2608  return -1;
2609  }
2610  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2611 
2612  char **arr = (char **)clones->GetObjectRef();
2613  char **end = arr + fNdata;
2614 
2616  } else if (fType == 4) {
2617  // Apply the unattached rules; by definition they do not need any
2618  // input from a buffer.
2620 
2621  auto ndata = GetNdata();
2622 
2623  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2626 
2628  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
2629  } else {
2630  // Apply the unattached rules; by definition they do not need any
2631  // input from a buffer.
2633  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
2635  }
2636  }
2637  } else {
2638  // -- Terminal branch.
2639  if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
2640  Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
2641  if (nb < 0) {
2642  return nb;
2643  }
2644  nbytes += nb;
2645  }
2646  Int_t nb = TBranch::GetEntry(entry, getall);
2647  if (nb < 0) {
2648  return nb;
2649  }
2650  nbytes += nb;
2651  }
2652 
2653  if (R__unlikely(fTree->Debug() > 0)) {
2654  if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
2655  Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
2656  }
2657  }
2658  return nbytes;
2659 }
2660 
2661 ////////////////////////////////////////////////////////////////////////////////
2662 /// Fill expectedClass and expectedType with information on the data type of the
2663 /// object/values contained in this branch (and thus the type of pointers
2664 /// expected to be passed to Set[Branch]Address
2665 /// return 0 in case of success and > 0 in case of failure.
2666 
2668 {
2669  expectedClass = 0;
2670  expectedType = kOther_t;
2671 
2673  if ((type == -1) || (fID == -1)) {
2674  expectedClass = fBranchClass;
2675  } else {
2676  // Case of an object data member. Here we allow for the
2677  // variable name to be ommitted. Eg, for Event.root with split
2678  // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
2679  TStreamerElement* element = GetInfoImp()->GetElement(fID);
2680  if (element) {
2681  expectedClass = element->GetClassPointer();
2682  if (!expectedClass) {
2683  TDataType* data = gROOT->GetType(element->GetTypeNameBasic());
2684  if (!data) {
2685  Error("GetExpectedType", "Did not find the type number for %s", element->GetTypeNameBasic());
2686  return 1;
2687  } else {
2688  expectedType = (EDataType) data->GetType();
2689  }
2690  }
2691  } else {
2692  Error("GetExpectedType", "Did not find the type for %s",GetName());
2693  return 2;
2694  }
2695  }
2696  return 0;
2697 }
2698 
2699 ////////////////////////////////////////////////////////////////////////////////
2700 /// Return icon name depending on type of branch element.
2701 
2702 const char* TBranchElement::GetIconName() const
2703 {
2704  if (IsFolder()) {
2705  return "TBranchElement-folder";
2706  } else {
2707  return "TBranchElement-leaf";
2708  }
2709 }
2710 
2711 ////////////////////////////////////////////////////////////////////////////////
2712 /// Return whether this branch is in a mode where the object are decomposed
2713 /// or not (Also known as MakeClass mode).
2714 
2716 {
2717  return TestBit(kDecomposedObj); // Same as TestBit(kMakeClass)
2718 }
2719 
2720 ////////////////////////////////////////////////////////////////////////////////
2721 /// Return maximum count value of the branchcount if any.
2722 
2724 {
2725  if (fBranchCount) {
2726  return fBranchCount->GetMaximum();
2727  }
2728  return fMaximum;
2729 }
2730 
2731 ////////////////////////////////////////////////////////////////////////////////
2732 /// Return a pointer to our object.
2733 
2735 {
2736  ValidateAddress();
2737  return fObject;
2738 }
2739 
2740 ////////////////////////////////////////////////////////////////////////////////
2741 /// Return a pointer to the parent class of the branch element.
2742 
2744 {
2745  return fParentClass.GetClass();
2746 }
2747 
2748 ////////////////////////////////////////////////////////////////////////////////
2749 /// Return type name of element in the branch.
2750 
2751 const char* TBranchElement::GetTypeName() const
2752 {
2753  if (fType == 3 || fType == 4) {
2754  return "Int_t";
2755  }
2756  // FIXME: Use symbolic constants here.
2757  if ((fStreamerType < 1) || (fStreamerType > 59)) {
2758  if (fBranchClass.GetClass()) {
2759  if (fID>=0) {
2760  return GetInfoImp()->GetElement(fID)->GetTypeName();
2761  } else {
2762  return fBranchClass.GetClass()->GetName();
2763  }
2764  } else {
2765  return 0;
2766  }
2767  }
2768  const char *types[20] = {
2769  "",
2770  "Char_t",
2771  "Short_t",
2772  "Int_t",
2773  "Long_t",
2774  "Float_t",
2775  "Int_t",
2776  "char*",
2777  "Double_t",
2778  "Double32_t",
2779  "",
2780  "UChar_t",
2781  "UShort_t",
2782  "UInt_t",
2783  "ULong_t",
2784  "UInt_t",
2785  "Long64_t",
2786  "ULong64_t",
2787  "Bool_t",
2788  "Float16_t"
2789  };
2790  Int_t itype = fStreamerType % 20;
2791  return types[itype];
2792 }
2793 
2794 ////////////////////////////////////////////////////////////////////////////////
2795 
2796 template Double_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2797 template Long64_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2798 template LongDouble_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2799 
2800 template <typename T>
2802 {
2803  // -- Returns the branch value.
2804  //
2805  // If the leaf is an array, j is the index in the array.
2806  //
2807  // If leaf is an array inside a TClonesArray, len should be the length
2808  // of the array.
2809  //
2810  // If subarr is true, then len is actually the index within the sub-array.
2811  //
2812 
2813  ValidateAddress();
2814 
2815  Int_t prID = fID;
2816  char *object = fObject;
2817  if (TestBit(kCache)) {
2818  if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2819  prID = fID+1;
2820  } else if (fOnfileObject) {
2821  object = fOnfileObject->GetObjectAt(0);
2822  }
2823  }
2824 
2825  if (!j && fBranchCount) {
2826  Long64_t entry = fTree->GetReadEntry();
2827  // Since reloading the index, will reset the ClonesArray, let's
2828  // skip the load if we already read this entry.
2829  if (entry != fBranchCount->GetReadEntry()) {
2830  fBranchCount->TBranch::GetEntry(entry);
2831  }
2832  if (fBranchCount2 && entry != fBranchCount2->GetReadEntry()) {
2833  fBranchCount2->TBranch::GetEntry(entry);
2834  }
2835  }
2836 
2837  if (TestBit(kDecomposedObj)) {
2838  if (!fAddress) {
2839  return 0;
2840  }
2841  if ((fType == 3) || (fType == 4)) {
2842  // Top-level branch of a TClonesArray.
2843  return fNdata;
2844  } else if ((fType == 31) || (fType == 41)) {
2845  // sub branch of a TClonesArray
2846  Int_t atype = fStreamerType;
2847  if (atype < 20) {
2848  atype += 20;
2849  }
2850  return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
2851  } else if (fType <= 2) {
2852  // branch in split mode
2853  // FIXME: This should probably be < 60 instead!
2854  if ((fStreamerType > 40) && (fStreamerType < 55)) {
2855  Int_t atype = fStreamerType - 20;
2856  return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
2857  } else {
2858  return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
2859  }
2860  }
2861  }
2862 
2863  if (object == 0)
2864  {
2865  // We have nowhere to read the data from (probably because the data member was
2866  // 'dropped' from the current schema).
2867  return 0;
2868  }
2869 
2870  if (fType == 31) {
2871  TClonesArray* clones = (TClonesArray*) object;
2872  if (subarr) {
2873  return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j, len, fOffset);
2874  }
2875  return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j/len, j%len, fOffset);
2876  } else if (fType == 41) {
2879  {
2880  if (subarr)
2881  return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
2882 
2883  return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
2884  }
2885  else
2886  {
2887  if (subarr)
2888  return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
2889  return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
2890  }
2891  } else {
2892  if (GetInfoImp()) {
2893  return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
2894  }
2895  return 0;
2896  }
2897 }
2898 
2899 ////////////////////////////////////////////////////////////////////////////////
2900 /// Returns pointer to first data element of this branch.
2901 /// Currently used only for members of type character.
2902 
2904 {
2905  ValidateAddress();
2906 
2907  Int_t prID = fID;
2908  char *object = fObject;
2909  if (TestBit(kCache)) {
2910  if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2911  prID = fID+1;
2912  } else if (fOnfileObject) {
2913  object = fOnfileObject->GetObjectAt(0);
2914  }
2915  }
2916 
2917  if (fBranchCount) {
2918  Long64_t entry = fTree->GetReadEntry();
2919  fBranchCount->TBranch::GetEntry(entry);
2920  if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
2921  }
2922  if (TestBit(kDecomposedObj)) {
2923  if (!fAddress) {
2924  return 0;
2925  }
2926  if (fType == 3) { //top level branch of a TClonesArray
2927  //return &fNdata;
2928  return 0;
2929  } else if (fType == 4) { //top level branch of a TClonesArray
2930  //return &fNdata;
2931  return 0;
2932  } else if (fType == 31) { // sub branch of a TClonesArray
2933  //Int_t atype = fStreamerType;
2934  //if (atype < 20) atype += 20;
2935  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2936  return 0;
2937  } else if (fType == 41) { // sub branch of a TClonesArray
2938  //Int_t atype = fStreamerType;
2939  //if (atype < 20) atype += 20;
2940  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2941  return 0;
2942  } else if (fType <= 2) { // branch in split mode
2943  // FIXME: This should probably be < 60 instead!
2944  if (fStreamerType > 40 && fStreamerType < 55) {
2945  //Int_t atype = fStreamerType - 20;
2946  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2947  return 0;
2948  } else {
2949  //return GetInfoImp()->GetValue(object, fID, j, -1);
2950  return 0;
2951  }
2952  }
2953  }
2954 
2955  if (fType == 31) {
2956  return 0;
2957  } else if (fType == 41) {
2958  return 0;
2959  } else if (prID < 0) {
2960  return object;
2961  } else {
2962  //return GetInfoImp()->GetValue(object,fID,j,-1);
2963  if (!GetInfoImp() || !object) return 0;
2964  char **val = (char**)(object+GetInfoImp()->TStreamerInfo::GetElementOffset(prID));
2965  return *val;
2966  }
2967 }
2968 
2969 ////////////////////////////////////////////////////////////////////////////////
2970 /// Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a container sub-branch.
2971 ///
2972 /// Note: The offsets are zero for data members so that when
2973 /// SetAddress recursively sets their address, they will get the
2974 /// same address as their containing class because i/o is based
2975 /// on streamer info offsets from the addresss of the containing
2976 /// class.
2977 ///
2978 /// Offsets are non-zero for base-class sub-branches that are
2979 /// not the leftmost direct base class. They are laid out in
2980 /// memory sequentially and only the leftmost direct base class
2981 /// has the same address as the derived class. The streamer
2982 /// offsets need to be added to the address of the base class
2983 /// subobject which is not the same as the address of the
2984 /// derived class for the non-leftmost direct base classes.
2985 
2987 {
2988  Int_t nbranches = fBranches.GetEntriesFast();
2989 
2990  // See https://sft.its.cern.ch/jira/browse/ROOT-8742
2991  // and https://sft.its.cern.ch/jira/browse/ROOT-9253
2992  // As of commit e21b4f1a3b, removing this lock lead to a failure
2993  // in the test testSetAddress[Loop].
2994  // As of commit 4f8b237849, removing this lock does not lead to
2995  // a visible failure in test. This might be due to the underlying
2996  // problem (missing lock or ?) being solved somewhere else or some
2997  // other pertubation reducing the failure rate.
2998  // Having the lock here is not too costly as InitializeOffsets is
2999  // one called once in the lifetime of the TBranch.
3001 
3002  if (fID < 0) {
3003  // -- We are a top-level branch. Let's mark whether we need to use MapObject.
3004  if (CanSelfReference(fBranchClass)) {
3005  if (fBranchClass.GetClass()->IsTObject()) {
3007  } else {
3008  SetBit(kBranchAny);
3009  }
3010  }
3011  }
3012  if (nbranches) {
3013  // Allocate space for the new sub-branch offsets.
3014  delete[] fBranchOffset;
3015  fBranchOffset = 0;
3016  fBranchOffset = new Int_t[nbranches];
3017  // Make sure we can instantiate our class meta info.
3018  if (!fBranchClass.GetClass()) {
3019  Warning("InitializeOffsets", "No branch class set for branch: %s", GetName());
3020  fInitOffsets = kTRUE;
3021  return;
3022  }
3023  // Make sure we can instantiate our class streamer info.
3024  if (!GetInfoImp()) {
3025  Warning("InitializeOffsets", "No streamer info available for branch: %s of class: %s", GetName(), fBranchClass.GetClass()->GetName());
3026  fInitOffsets = kTRUE;
3027  return;
3028  }
3029 
3030  // Get the class we are a member of now (which is the
3031  // type of our containing subobject) and get our offset
3032  // inside of our containing subobject (our local offset).
3033  // Note: branchElem stays zero if we are a top-level branch,
3034  // we have to be careful about this later.
3035  TStreamerElement* branchElem = 0;
3036  Int_t localOffset = 0;
3037  TClass* branchClass = fBranchClass.GetClass();
3038  Bool_t renamed = kFALSE;
3039  if (fID > -1) {
3040  // -- Branch is *not* a top-level branch.
3041  // Instead of the streamer info class, we want the class of our
3042  // specific element in the streamer info. We could be a data
3043  // member of a base class or a split class, in which case our
3044  // streamer info will be for our containing sub-object, while
3045  // we are actually a different type.
3047  // Note: We tested to make sure the streamer info was available previously.
3048  if (!si->IsCompiled()) {
3049  Warning("InitializeOffsets", "Streamer info for branch: %s has no elements array!", GetName());
3050  fInitOffsets = kTRUE;
3051  return;
3052  }
3053  // FIXME: Check that fID is in range.
3054  branchElem = si->GetElement(fID);
3055  if (!branchElem) {
3056  Warning("InitializeOffsets", "Cannot get streamer element for branch: %s!", GetName());
3057  fInitOffsets = kTRUE;
3058  return;
3059  } else if (branchElem->TestBit(TStreamerElement::kRepeat)) {
3060  // If we have a repeating streamerElement, use the next
3061  // one as it actually hold the 'real' data member('s offset)
3062  if (si->GetElement(fID+1)) {
3063  branchElem = si->GetElement(fID+1);
3064  }
3065  }
3066  localOffset = branchElem->GetOffset();
3067  branchClass = branchElem->GetClassPointer();
3068  if (localOffset == TStreamerInfo::kMissing) {
3069  fObject = 0;
3070  } else {
3071  renamed = branchClass && branchElem->GetNewClass() && (branchClass != branchElem->GetNewClass());
3072  }
3073  } else {
3074  renamed = fTargetClass != fBranchClass;
3075  }
3076  if (!branchClass) {
3077  Error("InitializeOffsets", "Could not find class for branch: %s", GetName());
3078  fInitOffsets = kTRUE;
3079  return;
3080  }
3081 
3082  //------------------------------------------------------------------------
3083  // Extract the name of the STL branch in case it has been split.
3084  //////////////////////////////////////////////////////////////////////////
3085 
3086  TString stlParentName;
3087  Bool_t stlParentNameUpdated = kFALSE;
3088  if( fType == 4 )
3089  {
3090  TBranch *br = GetMother()->GetSubBranch( this );
3091  stlParentName = br->GetName();
3092  stlParentName.Strip( TString::kTrailing, '.' );
3093 
3094  // We may ourself contain the 'Mother' branch name.
3095  // To avoid code duplication, we delegate the removal
3096  // of the mother's name to the first sub-branch loop.
3097  }
3098 
3099  // Loop over our sub-branches and compute their offsets.
3100  for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
3101  bool alternateElement = false;
3102 
3103  fBranchOffset[subBranchIdx] = 0;
3104  TBranchElement* subBranch = dynamic_cast<TBranchElement*> (fBranches[subBranchIdx]);
3105  if (subBranch == 0) {
3106  // -- Skip sub-branches that are not TBranchElements.
3107  continue;
3108  }
3109 
3110  if (renamed) {
3111  if (subBranch->fBranchClass == branchClass) {
3112  if (branchElem) subBranch->SetTargetClass(branchElem->GetNewClass()->GetName());
3113  else subBranch->SetTargetClass(fTargetClass->GetName());
3114  }
3115  }
3116 
3117  TVirtualStreamerInfo* sinfo = subBranch->GetInfoImp();
3118  if (!sinfo) {
3119  Warning("InitializeOffsets", "No streamer info for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3120  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3121  continue;
3122  }
3123  if (!sinfo->IsCompiled()) {
3124  Warning("InitializeOffsets", "No elements array for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3125  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3126  continue;
3127  }
3128  // FIXME: Make sure subBranch->fID is in range.
3129  TStreamerElement* subBranchElement = sinfo->GetElement(subBranch->fID);
3130  if (!subBranchElement) {
3131  Warning("InitializeOffsets", "No streamer element for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3132  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3133  continue;
3134  } else if (subBranchElement->TestBit(TStreamerElement::kRepeat)) {
3135  // If we have a repeating streamerElement, use the next
3136  // one as it actually hold the 'real' data member('s offset)
3137  if (sinfo->GetElement(subBranch->fID+1)) {
3138  subBranchElement = sinfo->GetElement(subBranch->fID+1);
3139  }
3140  } else if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3141  // We have a cached item which is not a repeated but we might still
3142  // have some Actions triggered by a rule that affect real
3143  // data member(s).
3144  if (subBranch->fReadActionSequence && subBranch->fReadActionSequence->fActions.size() > 1) {
3145  typedef TStreamerInfoActions::ActionContainer_t::iterator iterator;
3146  iterator end = subBranch->fReadActionSequence->fActions.end();
3147  for(iterator iter = subBranch->fReadActionSequence->fActions.begin();
3148  iter != end; ++iter) {
3149  TStreamerInfoActions::TConfiguration *config = iter->fConfiguration;
3150  UInt_t id = config->fElemId;
3151  TStreamerElement *e = (TStreamerElement*)config->fInfo->GetElements()->At(id);
3152  if (e && !e->TestBit(TStreamerElement::kCache)) {
3153  subBranchElement = e;
3154  alternateElement = true;
3155  break;
3156  }
3157  }
3158  }
3159  }
3160 
3161  localOffset = subBranchElement->GetOffset();
3162  if (localOffset == TStreamerInfo::kMissing) {
3163  subBranch->fObject = 0;
3164  }
3165  {
3166  Int_t streamerType = subBranchElement->GetType();
3167  if (streamerType > TStreamerInfo::kObject
3168  && subBranch->GetListOfBranches()->GetEntries()==0
3169  && CanSelfReference(subBranchElement->GetClass()))
3170  {
3171  subBranch->SetBit(kBranchAny);
3172  } else {
3173  subBranch->ResetBit(kBranchAny);
3174  }
3175  }
3176 
3177  if (subBranchElement->GetNewType()<0) {
3178  subBranch->ResetBit(kBranchAny);
3179  subBranch->ResetBit(kBranchObject);
3180  }
3181 
3182  // Note: This call is expensive, do it only once.
3183  TBranch* mother = GetMother();
3184  if (!mother) {
3185  Warning("InitializeOffsets", "Branch '%s' has no mother!", GetName());
3186  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3187  continue;
3188  }
3189  TString motherName(mother->GetName());
3190  Bool_t motherDot = kFALSE;
3191  if (motherName.Length() && strchr(motherName.Data(), '.')) {
3192  motherDot = kTRUE;
3193  }
3194  Bool_t motherDotAtEnd = kFALSE;
3195  if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
3196  motherDotAtEnd = kTRUE;
3197  }
3198 
3199  Bool_t isBaseSubBranch = kFALSE;
3200  if ((subBranch->fType == 1) || (subBranchElement && subBranchElement->IsBase())) {
3201  // -- Base class sub-branch (1).
3202  //
3203  // Note: Our type will not be 1, even though we are
3204  // a base class branch, if we are not split (see the
3205  // constructor), or if we are an STL container master
3206  // branch and a base class branch at the same time
3207  // or an std::string.
3208  isBaseSubBranch = kTRUE;
3209  }
3210 
3211  Bool_t isContDataMember = kFALSE;
3212  if ((subBranch->fType == 31) || (subBranch->fType == 41)) {
3213  // -- Container data member sub-branch (31 or 41).
3214  isContDataMember = kTRUE;
3215  }
3216 
3217  // I am either a data member sub-branch (0), or a base class
3218  // sub-branch (1), or TClonesArray master sub-branch (3),
3219  // or an STL container master sub-branch (4), or TClonesArray
3220  // data member sub-branch (31), or an STL container data member
3221  // sub-branch (41).
3222  //
3223  // My parent branch is either a top-level branch ((0), fID==(-2,-1)),
3224  // or a base class sub-branch (1), or a split-class branch (2),
3225  // or a TClonesArray master branch (3), or an STL container
3226  // master branch (4).
3227  //
3228 
3229  //
3230  // We need to extract from our name the name
3231  // of the data member which contains us, so
3232  // that we may then do a by-name lookup in the
3233  // dictionary meta info of our parent class to
3234  // get our offset in our parent class.
3235  //
3236 
3237  // Get our name.
3238  TString dataName(subBranch->GetName());
3239  if (motherDotAtEnd) {
3240  // -- Remove the top-level branch name from our name.
3241  dataName.Remove(0, motherName.Length());
3242  // stlParentNameUpdated is false the first time in this loop.
3243  if (!stlParentNameUpdated && stlParentName.Length()) {
3244  stlParentName.Remove(0, motherName.Length());
3245  stlParentNameUpdated = kTRUE;
3246  }
3247  } else if (motherDot) {
3248  // -- Remove the top-level branch name from our name, folder case.
3249  //
3250  // Note: We are in the case where our mother was created
3251  // by the branch constructor which takes a folder
3252  // as an argument. The mother branch has internal
3253  // dots in its name to represent the folder heirarchy.
3254  // The TTree::Bronch() routine has handled us as a
3255  // special case, we must compensate.
3256  if ((fID < 0) && (subBranchElement->IsA() == TStreamerBase::Class())) {
3257  // -- Our name is the mother name, remove it.
3258  // Note: The test is our parent is a top-level branch
3259  // and our streamer is the base class streamer,
3260  // this matches the exact test in TTree::Bronch().
3261  if (dataName.Length() == motherName.Length()) {
3262  dataName.Remove(0, motherName.Length());
3263  // stlParentNameUpdated is false the first time in this loop.
3264  if (!stlParentNameUpdated && stlParentName.Length()) {
3265  stlParentName.Remove(0, motherName.Length());
3266  }
3267  }
3268  } else {
3269  // -- Remove the mother name and the dot.
3270  if (dataName.Length() > motherName.Length()) {
3271  dataName.Remove(0, motherName.Length() + 1);
3272  if (!stlParentNameUpdated && stlParentName.Length()) {
3273  stlParentName.Remove(0, motherName.Length());
3274  }
3275  }
3276  }
3277  }
3278  stlParentNameUpdated = kTRUE;
3279  if (isBaseSubBranch) {
3280  // -- Remove the base class name suffix from our name.
3281  // Note: The pattern is the name of the base class.
3282  TString pattern(subBranchElement->GetName());
3283  if (pattern.Length() <= dataName.Length()) {
3284  if (!strcmp(dataName.Data() + (dataName.Length() - pattern.Length()), pattern.Data())) {
3285  // The branch name contains the name of the base class in it.
3286  // This name is not reproduced in the sub-branches, so we need to
3287  // remove it.
3288  dataName.Remove(dataName.Length() - pattern.Length());
3289  }
3290  }
3291  // Remove any leading dot.
3292  if (dataName.Length()) {
3293  if (dataName[0] == '.') {
3294  dataName.Remove(0, 1);
3295  }
3296  }
3297  // Note: We intentionally leave any trailing dot
3298  // in our modified name here.
3299  }
3300 
3301  // Get our parent branch's name.
3302  TString parentName(GetName());
3303  if (motherDotAtEnd) {
3304  // -- Remove the top-level branch name from our parent's name.
3305  parentName.Remove(0, motherName.Length());
3306  } else if (motherDot) {
3307  // -- Remove the top-level branch name from our parent's name, folder case.
3308  //
3309  // Note: We are in the case where our mother was created
3310  // by the branch constructor which takes a folder
3311  // as an argument. The mother branch has internal
3312  // dots in its name to represent the folder heirarchy.
3313  // The TTree::Bronch() routine has handled us as a
3314  // special case, we must compensate.
3315  if ((fID > -1) && (mother == mother->GetSubBranch(this)) && (branchElem->IsA() == TStreamerBase::Class())) {
3316  // -- Our parent's name is the mother name, remove it.
3317  // Note: The test is our parent's parent is a top-level branch
3318  // and our parent's streamer is the base class streamer,
3319  // this matches the exact test in TTree::Bronch().
3320  if (parentName.Length() == motherName.Length()) {
3321  parentName.Remove(0, motherName.Length());
3322  }
3323  } else {
3324  // -- Remove the mother name and the dot.
3325  if (parentName.Length() > motherName.Length()) {
3326  parentName.Remove(0, motherName.Length() + 1);
3327  }
3328  }
3329  }
3330  // FIXME: Do we need to use the other tests for a base class here?
3331  if (fType == 1) {
3332  // -- Our parent is a base class sub-branch, remove the base class name suffix from its name.
3333  if (mother != mother->GetSubBranch(this)) {
3334  // -- My parent's parent is not a top-level branch.
3335  // Remove the base class name suffix from the parent name.
3336  // Note: The pattern is the name of the base class.
3337  // coverity[var_deref_model] branchElem is non zero here since fType==1 and thus fID > -1
3338  TString pattern(branchElem->GetName());
3339  if (pattern.Length() <= parentName.Length()) {
3340  if (!strcmp(parentName.Data() + (parentName.Length() - pattern.Length()), pattern.Data())) {
3341  // The branch name contains the name of the base class in it.
3342  // This name is not reproduced in the sub-branches, so we need to
3343  // remove it.
3344  parentName.Remove(parentName.Length() - pattern.Length());
3345  }
3346  }
3347  }
3348  // Note: We intentionally leave any trailing dots
3349  // in the modified parent name here.
3350  }
3351 
3352  // Remove the parent branch name part from our name,
3353  // but only if the parent branch is not a top-level branch.
3354  // FIXME: We should not assume parent name does not have length 0.
3355  if (fID > -1) {
3356  RemovePrefix(dataName, parentName);
3357  }
3358 
3359  // Remove any leading dot.
3360  if (dataName.Length()) {
3361  if (dataName[0] == '.') {
3362  dataName.Remove(0, 1);
3363  }
3364  }
3365 
3366  // Remove any trailing dot.
3367  if (dataName.Length()) {
3368  if (dataName[dataName.Length()-1] == '.') {
3369  dataName.Remove(dataName.Length() - 1, 1);
3370  }
3371  }
3372 
3373  //
3374  // Now that we have our data member name, find our offset
3375  // in our parent class.
3376  //
3377  // Note: Our data member name can have many dots in it
3378  // if branches were elided between our parent branch
3379  // and us by Unroll().
3380  //
3381  // FIXME: This may not work if our member name is ambiguous.
3382  //
3383 
3384  Int_t offset = 0;
3385  if (dataName.Length()) {
3386  // -- We have our data member name, do a lookup in the dictionary meta info of our parent class.
3387  // Get our parent class.
3388  TClass* pClass = 0;
3389  // First check whether this sub-branch is part of the 'cache' (because the data member it
3390  // represents is no longer in the current class layout.
3391  TStreamerInfo *subInfo = subBranch->GetInfoImp();
3392  //if (subInfo && subBranch->TestBit(kCache)) { // subInfo->GetElements()->At(subBranch->GetID())->TestBit(TStreamerElement::kCache)) {
3393  if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3394  pClass = ((TStreamerElement*)subInfo->GetElements()->At(0))->GetClassPointer();
3395  }
3396  // FIXME: Do we need the other base class tests here?
3397  if (!pClass) {
3398  if (fType == 1) {
3399  // -- Parent branch is a base class branch.
3400  // FIXME: Is using branchElem here the right thing?
3401  pClass = branchElem->GetClassPointer();
3402  if (pClass->Property() & kIsAbstract) {
3403  // the class is abstract, let see if the
3404 
3405  TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this);
3406  if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
3407  // Our parent's class is emulated and we represent an abstract class.
3408  // and the target class has not been set explicilty.
3409  TString target = pClass->GetName();
3410  target += "@@emulated";
3411 
3412  pClass = TClass::GetClass(target);
3413  }
3414  }
3415  } else {
3416  // -- Parent branch is *not* a base class branch.
3417  // FIXME: This sometimes returns a null pointer.
3418  pClass = subBranch->GetParentClass();
3419  }
3420  }
3421  if (!pClass) {
3422  // -- No parent class, fix it.
3423  // FIXME: This is probably wrong!
3424  // Assume parent class is our parent branch's clones class or value class.
3425  if (GetClonesName() && strlen(GetClonesName())) {
3426  pClass = fClonesClass;
3427  if (!pClass) {
3428  Warning("InitializeOffsets", "subBranch: '%s' has no parent class, and cannot get class for clones class: '%s'!", subBranch->GetName(), GetClonesName());
3429  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3430  continue;
3431  }
3432  Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3433  }
3435  pClass = fBranchCount->fCollProxy->GetValueClass();
3436  Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass ? pClass->GetName() : "unknowned class");
3437  }
3438  if (!pClass) {
3439  // -- Still no parent class, assume our parent class is our parent branch's class.
3440  // FIXME: This is probably wrong!
3441  pClass = branchClass;
3442  // FIXME: Enable this warning!
3443  //Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3444  }
3445  }
3446  if (renamed && pClass) {
3447  if (pClass == branchClass) {
3448  pClass = branchElem->GetNewClass();
3449  } else if (fCollProxy && pClass == branchClass->GetCollectionProxy()->GetValueClass()) {
3450  pClass = fCollProxy->GetValueClass();
3451  }
3452  }
3453 
3454  //------------------------------------------------------------------
3455  // If we have the are the sub-branch of the TBranchSTL, we need
3456  // to remove it's name to get the correct real data offsets
3457  ////////////////////////////////////////////////////////////////////
3458 
3459  if( dynamic_cast<TBranchSTL*>(fParent) && stlParentName.Length() )
3460  {
3461  if( !strncmp( stlParentName.Data(), dataName.Data(), stlParentName.Length()-1 )
3462  && dataName[ stlParentName.Length() ] == '.' )
3463  dataName.Remove( 0, stlParentName.Length()+1 );
3464  }
3465 
3466  // Find our offset in our parent class using
3467  // a lookup by name in the dictionary meta info
3468  // for our parent class.
3469 
3470  if (alternateElement) {
3471  Ssiz_t dotpos = dataName.Last('.');
3472  Ssiz_t endpos = dataName.Length();
3473  if (dotpos != kNPOS) ++dotpos; else dotpos = 0;
3474  dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
3475  }
3476  TRealData* rd = pClass->GetRealData(dataName);
3477  if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
3478  // -- Data member exists in the dictionary meta info, get the offset.
3479  // If we are using an alternateElement, it is the target of a rule
3480  // and might be indeed transient.
3481  offset = rd->GetThisOffset();
3482  } else if (subBranchElement->TestBit(TStreamerElement::kWholeObject)) {
3483  // We are a rule with no specific target, it applies to the whole
3484  // object, let's set the offset to zero
3485  offset = 0;
3486  } else {
3487  // -- No dictionary meta info for this data member, it must no
3488  // longer exist
3489  if (fEntries == 0) {
3490  // ... unless we creating the branch in which case
3491  // we have an internal error.
3492  if (pClass->GetListOfRealData()->GetEntries() == 0) {
3493  // We are probably missing the ShowMember, let's
3494  // just issue an error.
3495  Error("InitializeOffsets",
3496  "Could not find the real data member '%s' when constructing the branch '%s' [Likely missing ShowMember].",
3497  dataName.Data(),GetName());
3498  } else if (subInfo && subInfo->GetClassVersion()!=subInfo->GetClass()->GetClassVersion()) {
3499  // In the case where we are cloning a TTree that was created with an older version of the layout, we may not
3500  // able to find all the members
3501  Info("InitializeOffsets",
3502  "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'. ",
3503  dataName.Data(),GetName());
3504  } else {
3505  // Something really bad happen.
3506  Fatal("InitializeOffsets",
3507  "Could not find the real data member '%s' when constructing the branch '%s' [Likely an internal error, please report to the developers].",
3508  dataName.Data(),GetName());
3509  }
3510  }
3511  localOffset = TStreamerInfo::kMissing;
3512  }
3513  } else {
3514  // -- We have no data member name, ok for a base class, not good otherwise.
3515  if (isBaseSubBranch) {
3516  // I am a direct base class of my parent class, my local offset is enough.
3517  } else {
3518  Warning("InitializeOffsets", "Could not find the data member name for branch '%s' with parent branch '%s', assuming offset is zero!", subBranch->GetName(), GetName());
3519  }
3520  }
3521 
3522  //
3523  // Ok, do final calculations for fOffset and fBranchOffset.
3524  //
3525 
3526  if (isContDataMember) {
3527  // -- Container data members set fOffset instead of fBranchOffset.
3528  // The fOffset is what should be added to the start of the entry
3529  // in the collection (i.e., its current absolute address) to find
3530  // the beginning of the data member described by the current branch.
3531  //
3532  // Compensate for the i/o routines adding our local offset later.
3533  if (subBranch->fObject == 0 && localOffset == TStreamerInfo::kMissing) {
3534  subBranch->SetOffset(TStreamerInfo::kMissing);
3535  // We stil need to set fBranchOffset in the case of a missing
3536  // element so that SetAddress is (as expected) not called
3537  // recursively in this case.
3538  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3539  } else {
3540  if (isBaseSubBranch) {
3541  // The value of 'offset' for a base class does not include its
3542  // 'localOffset'.
3543  subBranch->SetOffset(offset);
3544  } else {
3545  // The value of 'offset' for a regular data member does include its
3546  // 'localOffset', we need to remove it explicitly.
3547  subBranch->SetOffset(offset - localOffset);
3548  }
3549  }
3550  } else {
3551  // -- Set fBranchOffset for sub-branch.
3552  Int_t isSplit = 0 != subBranch->GetListOfBranches()->GetEntriesFast();
3553  if (subBranch->fObject == 0 && localOffset == TStreamerInfo::kMissing) {
3554  // The branch is missing
3555  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3556 
3557  } else if (isSplit) {
3558  if (isBaseSubBranch) {
3559  // We are split, so we need to add in our local offset
3560  // to get our absolute address for our children.
3561  fBranchOffset[subBranchIdx] = offset + localOffset;
3562  } else {
3563  // We are split so our offset will never be
3564  // used in an i/o, so we do not have to subtract
3565  // off our local offset like below.
3566  fBranchOffset[subBranchIdx] = offset;
3567  }
3568  } else {
3569  if (isBaseSubBranch) {
3570  // We are not split, so our local offset will be
3571  // added later by the i/o routines.
3572  fBranchOffset[subBranchIdx] = offset;
3573  } else {
3574  // Compensate for the fact that the i/o routines
3575  // are going to add my local offset later.
3576  fBranchOffset[subBranchIdx] = offset - localOffset;
3577  }
3578  }
3579  }
3580  }
3581  }
3582  else {
3583  if (fID > -1) {
3584  // Branch is *not* a top-level branch.
3585  // Let's check if the target member is still present in memory
3587  fObject = 0;
3588  }
3589  }
3590  }
3591  const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
3592  if (fReadActionSequence && isSplitNode) {
3593  TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3594  auto index = parent->fBranches.IndexOf(this);
3595  if (index >= 0) {
3596  fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
3597  }
3598  }
3599 
3600  fInitOffsets = kTRUE;
3601 }
3602 
3603 ////////////////////////////////////////////////////////////////////////////////
3604 /// Return kTRUE if more than one leaf, kFALSE otherwise.
3605 
3607 {
3608  Int_t nbranches = fBranches.GetEntriesFast();
3609  if (nbranches >= 1) {
3610  return kTRUE;
3611  }
3612  TList* browsables = const_cast<TBranchElement*>(this)->GetBrowsables();
3613  return browsables && browsables->GetSize();
3614 }
3615 
3616 ////////////////////////////////////////////////////////////////////////////////
3617 /// Detect a collection written using a zero pointer in old versions of root.
3618 /// In versions of ROOT older than 4.00/03, if a collection (TClonesArray
3619 /// or STL container) was split but the pointer to the collection was zeroed
3620 /// out, nothing was saved. Hence there is no __easy__ way to detect the
3621 /// case. In newer versions, a zero is written so that a 'missing' collection
3622 /// appears to be an empty collection.
3623 
3625 {
3626  Bool_t ismissing = kFALSE;
3628  if (basket && fTree) {
3629  Long64_t entry = fTree->GetReadEntry();
3631  Long64_t last;
3632  if (fReadBasket == fWriteBasket) {
3633  last = fEntryNumber - 1;
3634  } else {
3635  last = fBasketEntry[fReadBasket+1] - 1;
3636  }
3637  Int_t* entryOffset = basket->GetEntryOffset();
3638  Int_t bufbegin;
3639  Int_t bufnext;
3640  if (entryOffset) {
3641  bufbegin = entryOffset[entry-first];
3642 
3643  if (entry < last) {
3644  bufnext = entryOffset[entry+1-first];
3645  } else {
3646  bufnext = basket->GetLast();
3647  }
3648  if (bufnext == bufbegin) {
3649  ismissing = kTRUE;
3650  } else {
3651  // fixed length buffer so this is not the case here.
3652  if (basket->GetNevBufSize() == 0) {
3653  ismissing = kTRUE;
3654  }
3655  }
3656  }
3657  }
3658  return ismissing;
3659 }
3660 
3661 ////////////////////////////////////////////////////////////////////////////////
3662 /// Print branch parameters.
3663 
3664 static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids)
3665 {
3666  for(auto &cursor : ids) {
3667  auto id = cursor.fElemID;
3668  if (id >= 0)
3669  info->GetElement(id)->ls();
3670  else if (cursor.fNestedIDs) {
3671  Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
3672  PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
3673  }
3674  }
3675 }
3676 
3677 void TBranchElement::Print(Option_t* option) const
3678 {
3679  Int_t nbranches = fBranches.GetEntriesFast();
3680  if (strncmp(option,"debugAddress",strlen("debugAddress"))==0) {
3681  if (strlen(option)==strlen("debugAddress")) {
3682  Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s\n",
3683  "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject");
3684  }
3685  if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3686  else Printf("%-24s ", GetName());
3687 
3688  TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3689  Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3690  TVirtualStreamerInfo *info = ((TBranchElement*)this)->GetInfoImp();
3691 
3692  Printf("%-16s %2d %4d %-16s %-16s %8x %8x %s\n",
3693  info ? info->GetName() : "StreamerInfo unvailable", GetID(), GetType(),
3695  (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3696  GetOffset(), GetObject());
3697  for (Int_t i = 0; i < nbranches; ++i) {
3698  TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3699  subbranch->Print("debugAddressSub");
3700  }
3701  return;
3702  }
3703  if (strncmp(option,"debugInfo",strlen("debugInfo"))==0) {
3704  Printf("Branch %s uses:",GetName());
3705  if (fID>=0) {
3706  // GetInfoImp()->GetElement(fID)->ls();
3707  // for(UInt_t i=0; i< fIDs.size(); ++i) {
3708  // GetInfoImp()->GetElement(fIDs[i])->ls();
3709  // }
3710  TStreamerInfo *localInfo = GetInfoImp();
3711  if (fType == 3 || fType == 4) {
3712  // Search for the correct version.
3713  localInfo = FindOnfileInfo(fClonesClass, fBranches);
3714  }
3715  Printf(" With elements:");
3716  if (fType != 3 && fType != 4)
3717  localInfo->GetElement(fID)->ls();
3718  PrintElements(localInfo, fNewIDs);
3719  Printf(" with read actions:");
3721  Printf(" with write actions:");
3723  } else if (!fNewIDs.empty() && GetInfoImp()) {
3724  TStreamerInfo *localInfo = GetInfoImp();
3725  if (fType == 3 || fType == 4) {
3726  localInfo = (TStreamerInfo *)fClonesClass->GetStreamerInfo();
3727  }
3728  PrintElements(localInfo, fNewIDs);
3729  Printf(" with read actions:");
3731  Printf(" with write actions:");
3733  }
3734  TString suboption = "debugInfoSub";
3735  suboption += (option+strlen("debugInfo"));
3736  for (Int_t i = 0; i < nbranches; ++i) {
3737  TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3738  subbranch->Print(suboption);
3739  }
3740  Printf(" ");
3741  return;
3742  }
3743  if (nbranches) {
3744  if (fID == -2) {
3745  if (strcmp(GetName(),GetTitle()) == 0) {
3746  Printf("*Branch :%-66s *",GetName());
3747  } else {
3748  Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3749  }
3750  Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3751  Printf("*............................................................................*");
3752  }
3753  if (fType >= 2) {
3754  TBranch::Print(option);
3755  }
3756  for (Int_t i=0;i<nbranches;i++) {
3757  TBranch *branch = (TBranch*)fBranches.At(i);
3758  branch->Print(option);
3759  }
3760  } else {
3761  TBranch::Print(option);
3762  }
3763 }
3764 
3765 ////////////////////////////////////////////////////////////////////////////////
3766 /// Prints values of leaves.
3767 
3769 {
3770  ValidateAddress();
3771 
3772  TStreamerInfo *info = GetInfoImp();
3773  Int_t prID = fID;
3774  char *object = fObject;
3775  if (TestBit(kCache)) {
3777  prID = fID+1;
3778  } else if (fOnfileObject) {
3779  object = fOnfileObject->GetObjectAt(0);
3780  }
3781  }
3782 
3783  if (TestBit(kDecomposedObj)) {
3784  if (!fAddress) {
3785  return;
3786  }
3787  if (fType == 3 || fType == 4) {
3788  // TClonesArray or STL container top-level branch.
3789  printf(" %-15s = %d\n", GetName(), fNdata);
3790  return;
3791  } else if (fType == 31 || fType == 41) {
3792  // TClonesArray or STL container sub-branch.
3793  Int_t n = TMath::Min(10, fNdata);
3796  // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
3797  // printed as a string and could print weird characters.
3798  // So we print an unsigned char instead (not perfect, but better).
3799  atype = TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kUChar;
3800  }
3801  if (atype > 54) {
3802  // FIXME: More logic required here (like in ReadLeaves)
3803  printf(" %-15s = %d\n", GetName(), fNdata);
3804  return;
3805  }
3806  if (fStreamerType > 20) {
3807  atype -= 20;
3809  n = n * leaf->GetLenStatic();
3810  }
3811  if (GetInfoImp()) {
3812  GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3813  }
3814  return;
3815  } else if (fType <= 2) {
3816  // Branch in split mode.
3817  // FIXME: This should probably be < 60 instead.
3818  if ((fStreamerType > 40) && (fStreamerType < 55)) {
3819  Int_t atype = fStreamerType - 20;
3820  TBranchElement* counterElement = (TBranchElement*) fBranchCount;
3821  Int_t n = (Int_t) counterElement->GetValue(0, 0);
3822  if (GetInfoImp()) {
3823  GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3824  }
3825  } else {
3826  if (GetInfoImp()) {
3827  GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3828  }
3829  }
3830  return;
3831  }
3832  } else if (fType == 3) {
3833  printf(" %-15s = %d\n", GetName(), fNdata);
3834  } else if (fType == 31) {
3835  TClonesArray* clones = (TClonesArray*) object;
3836  if (GetInfoImp()) {
3837  GetInfoImp()->PrintValueClones(GetName(), clones, prID, fOffset, lenmax);
3838  }
3839  } else if (fType == 41) {
3841  if (GetInfoImp()) {
3842  GetInfoImp()->PrintValueSTL(GetName(), ((TBranchElement*) this)->GetCollectionProxy(), prID, fOffset, lenmax);
3843  }
3844  } else {
3845  if (GetInfoImp()) {
3846  GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3847  }
3848  }
3849 }
3850 
3851 ////////////////////////////////////////////////////////////////////////////////
3852 /// Unconfiguration Read Leave function.
3853 
3855 {
3856  Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
3857 }
3858 
3859 ////////////////////////////////////////////////////////////////////////////////
3860 /// Read leaves into i/o buffers for this branch.
3861 /// For the case where the branch is set in MakeClass mode (decomposed object).
3862 
3864 {
3865  ValidateAddress();
3866 
3867  if (fType == 3 || fType == 4) {
3868  // Top level branch of a TClonesArray.
3869  Int_t *n = (Int_t*) fAddress;
3870  b >> n[0];
3871  if ((n[0] < 0) || (n[0] > fMaximum)) {
3872  if (IsMissingCollection()) {
3873  n[0] = 0;
3874  b.SetBufferOffset(b.Length() - sizeof(n));
3875  } else {
3876  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());
3877  n[0] = 0;
3878  }
3879  }
3880  fNdata = n[0];
3881  if (fType == 4) {
3882  Int_t nbranches = fBranches.GetEntriesFast();
3883  switch(fSTLtype) {
3884  case ROOT::kSTLset:
3885  case ROOT::kSTLmultiset:
3886  case ROOT::kSTLmap:
3887  case ROOT::kSTLmultimap:
3888  for (Int_t i=0; i<nbranches; i++) {
3889  TBranch *branch = (TBranch*)fBranches[i];
3890  Int_t nb = branch->GetEntry(GetReadEntry(), 1);
3891  if (nb < 0) {
3892  break;
3893  }
3894  }
3895  break;
3896  default:
3897  break;
3898  }
3899  }
3900  return;
3901  } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
3903  Int_t atype = fStreamerType;
3904  // FIXME: This should probably be > 59 instead.
3905  if (atype > 54) return;
3906  if (!fAddress) {
3907  return;
3908  }
3909  Int_t n = fNdata;
3910  if (atype>40) {
3911  atype -= 40;
3912  if (!fBranchCount2) return;
3913  const char *len_where = (char*)fBranchCount2->fAddress;
3914  if (!len_where) return;
3915  Int_t len_atype = fBranchCount2->fStreamerType;
3916  Int_t length;
3917  Int_t k;
3918  Char_t isArray;
3919  for( k=0; k<n; k++) {
3920  char **where = &(((char**)fAddress)[k]);
3921  delete [] *where;
3922  *where = 0;
3923  switch(len_atype) {
3924  case 1: {length = ((Char_t*) len_where)[k]; break;}
3925  case 2: {length = ((Short_t*) len_where)[k]; break;}
3926  case 3: {length = ((Int_t*) len_where)[k]; break;}
3927  case 4: {length = ((Long_t*) len_where)[k]; break;}
3928  //case 5: {length = ((Float_t*) len_where)[k]; break;}
3929  case 6: {length = ((Int_t*) len_where)[k]; break;}
3930  //case 8: {length = ((Double_t*)len_where)[k]; break;}
3931  case 11: {length = ((UChar_t*) len_where)[k]; break;}
3932  case 12: {length = ((UShort_t*) len_where)[k]; break;}
3933  case 13: {length = ((UInt_t*) len_where)[k]; break;}
3934  case 14: {length = ((ULong_t*) len_where)[k]; break;}
3935  case 15: {length = ((UInt_t*) len_where)[k]; break;}
3936  case 16: {length = ((Long64_t*) len_where)[k]; break;}
3937  case 17: {length = ((ULong64_t*)len_where)[k]; break;}
3938  case 18: {length = ((Bool_t*) len_where)[k]; break;}
3939  default: continue;
3940  }
3941  b >> isArray;
3942  if (length <= 0) continue;
3943  if (isArray == 0) continue;
3944  switch (atype) {
3945  case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
3946  case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
3947  case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
3948  case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
3949  case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
3950  case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
3951  case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
3952  case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
3953  case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
3954  case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
3955  case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
3956  case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
3957  case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
3958  case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
3959  case 18: {*where=new char[sizeof(Bool_t)*length]; b.ReadFastArray((Bool_t*) *where, length); break;}
3960  }
3961  }
3962  return;
3963  }
3964  if (atype > 20) {
3965  atype -= 20;
3967  n *= leaf->GetLenStatic();
3968  }
3969  switch (atype) {
3970  case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
3971  case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
3972  case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
3973  case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
3974  case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
3975  case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
3976  case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
3977  case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
3978  case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
3979  case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
3980  case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
3981  case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
3982  case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
3983  case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
3984  case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
3985  case 9: {
3988  Double_t *xx = (Double_t*) fAddress;
3989  for (Int_t ii=0;ii<n;ii++) {
3990  b.ReadDouble32(&(xx[ii]),se);
3991  }
3992  break;
3993  }
3994  case 19: {
3997  Float_t *xx = (Float_t*) fAddress;
3998  for (Int_t ii=0;ii<n;ii++) {
3999  b.ReadFloat16(&(xx[ii]),se);
4000  }
4001  break;
4002  }
4003  }
4004  return;
4005  } else if (fType <= 2) { // branch in split mode
4006  // FIXME: This should probably be < 60 instead.
4007  if (fStreamerType > 40 && fStreamerType < 55) {
4008  Int_t atype = fStreamerType - 40;
4009  Int_t n;
4010  if (fBranchCount==0) {
4011  // Missing fBranchCount. let's attempts to recover.
4012 
4013  TString countname( GetName() );
4014  Ssiz_t dot = countname.Last('.');
4015  if (dot>=0) {
4016  countname.Remove(dot+1);
4017  } else {
4018  countname = "";
4019  }
4020  TString counter( GetTitle() );
4021  Ssiz_t loc = counter.Last('[');
4022  if (loc>=0) {
4023  counter.Remove(0,loc+1);
4024  }
4025  loc = counter.Last(']');
4026  if (loc>=0) {
4027  counter.Remove(loc);
4028  }
4029  countname += counter;
4030  SetBranchCount((TBranchElement *)fTree->GetBranch(countname));
4031  }
4032  if (fBranchCount) {
4033  n = (Int_t)fBranchCount->GetValue(0,0);
4034  } else {
4035  Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4036  n = 0;
4037  }
4038  fNdata = n;
4039  Char_t isArray;
4040  b >> isArray;
4041  switch (atype) {
4042  case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4043  case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4044  case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4045  case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4046  case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4047  case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4048  case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4049  case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4050  case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4051  case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4052  case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4053  case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4054  case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
4055  case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4056  case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
4057  case 9: {
4060  Double_t *xx = (Double_t*) fAddress;
4061  for (Int_t ii=0;ii<n;ii++) {
4062  b.ReadDouble32(&(xx[ii]),se);
4063  }
4064  break;
4065  }
4066  case 19: {
4069  Float_t *xx = (Float_t*) fAddress;
4070  for (Int_t ii=0;ii<n;ii++) {
4071  b.ReadFloat16(&(xx[ii]),se);
4072  }
4073  break;
4074  }
4075  }
4076  } else {
4077  fNdata = 1;
4078  if (fAddress) {
4079  if (fType<0) {
4080  // Non TObject, Non collection classes with a custom streamer.
4081 
4082  // if (fObject)
4084  } else {
4085  TStreamerInfo *info = GetInfoImp();
4086  if (!info) {
4087  return;
4088  }
4089  // Since info is not null, fReadActionSequence is not null either.
4091  }
4093  fNdata = (Int_t) GetValue(0, 0);
4094  }
4095  } else {
4096  fNdata = 0;
4097  }
4098  }
4099  return;
4100  }
4101 }
4102 
4103 ////////////////////////////////////////////////////////////////////////////////
4104 /// Read leaves into i/o buffers for this branch.
4105 /// Case of a collection (fType == 4).
4106 
4108 {
4109  ValidateAddress();
4110  if (fObject == 0)
4111  {
4112  // We have nowhere to copy the data (probably because the data member was
4113  // 'dropped' from the current schema) so let's no copy it in a random place.
4114  return;
4115  }
4116 
4117  // STL container master branch (has only the number of elements).
4118  Int_t n;
4119  b >> n;
4120  if ((n < 0) || (n > fMaximum)) {
4121  if (IsMissingCollection()) {
4122  n = 0;
4123  b.SetBufferOffset(b.Length()-sizeof(n));
4124  } else {
4125  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());
4126  n = 0;
4127  }
4128  }
4129  fNdata = n;
4130 
4131  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4132 
4133  // Note: Proxy-helper needs to "embrace" the entire
4134  // streaming of this STL container if the container
4135  // is a set/multiset/map/multimap (what we do not
4136  // know here).
4137  // For vector/list/deque Allocate == Resize
4138  // and Commit == noop.
4139  // TODO: Exception safety a la TPushPop
4142  void* alternate = proxy->Allocate(fNdata, true);
4144  fPtrIterators->CreateIterators(alternate, proxy);
4145  } else {
4146  fIterators->CreateIterators(alternate, proxy);
4147  }
4148 
4149  Int_t nbranches = fBranches.GetEntriesFast();
4150  switch (fSTLtype) {
4151  case ROOT::kSTLset:
4154  case ROOT::kSTLmultiset:
4155  case ROOT::kSTLmap:
4156  case ROOT::kSTLmultimap:
4159  for (Int_t i = 0; i < nbranches; ++i) {
4160  TBranch *branch = (TBranch*) fBranches[i];
4161  Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4162  if (nb < 0) {
4163  // Give up on i/o failure.
4164  // FIXME: We need an error message here.
4165  break;
4166  }
4167  }
4168  break;
4169  default:
4170  break;
4171  }
4172  //------------------------------------------------------------------------
4173  // We have split this stuff, so we need to create the the pointers
4174  /////////////////////////////////////////////////////////////////////////////
4175 
4177  {
4178  TClass *elClass = proxy->GetValueClass();
4179 
4180  //--------------------------------------------------------------------
4181  // The allocation is done in this strange way because ReadLeaves
4182  // is being called many times by TTreeFormula!!!
4183  //////////////////////////////////////////////////////////////////////////
4184 
4185  Int_t i = 0;
4186  // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4187  if( !fNdata || *(void**)proxy->At( 0 ) != 0 )
4188  i = fNdata;
4189 
4190  for( ; i < fNdata; ++i )
4191  {
4192  void **el = (void**)proxy->At( i );
4193  // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4194  *el = elClass->New();
4195  }
4196  }
4197 
4198  proxy->Commit(alternate);
4199 }
4200 
4201 ////////////////////////////////////////////////////////////////////////////////
4202 /// Read leaves into i/o buffers for this branch.
4203 /// Case of a data member within a collection (fType == 41).
4204 
4206 {
4207  ValidateAddress();
4208  if (fObject == 0)
4209  {
4210  // We have nowhere to copy the data (probably because the data member was
4211  // 'dropped' from the current schema) so let's no copy it in a random place.
4212  return;
4213  }
4214 
4215  // STL container sub-branch (contains the elements).
4217  if (!fNdata) {
4218  return;
4219  }
4220 
4221  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4222 
4223  TStreamerInfo *info = GetInfoImp();
4224  if (info == 0) return;
4225 
4228 
4229  // R__ASSERT(0);
4231  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4232 }
4233 
4234 ////////////////////////////////////////////////////////////////////////////////
4235 /// Read leaves into i/o buffers for this branch.
4236 /// Case of a data member within a collection (fType == 41).
4237 
4239 {
4240  ValidateAddress();
4241  if (fObject == 0)
4242  {
4243  // We have nowhere to copy the data (probably because the data member was
4244  // 'dropped' from the current schema) so let's no copy it in a random place.
4245  return;
4246  }
4247 
4248  // STL container sub-branch (contains the elements).
4250  if (!fNdata) {
4251  return;
4252  }
4253  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4254 
4255  TStreamerInfo *info = GetInfoImp();
4256  if (info == 0) return;
4257 
4260 
4263 }
4264 
4265 ////////////////////////////////////////////////////////////////////////////////
4266 /// Read leaves into i/o buffers for this branch.
4267 /// Case of a data member within a collection (fType == 41).
4268 
4270 {
4271  ValidateAddress();
4272  if (fObject == 0)
4273  {
4274  // We have nowhere to copy the data (probably because the data member was
4275  // 'dropped' from the current schema) so let's no copy it in a random place.
4276  return;
4277  }
4278 
4279  // STL container sub-branch (contains the elements).
4281  if (!fNdata) {
4282  return;
4283  }
4284  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4285 
4286  TStreamerInfo *info = GetInfoImp();
4287  if (info == 0) return;
4288  // Since info is not null, fReadActionSequence is not null either.
4289 
4290  // Still calling PushPop for the legacy entries.
4293 
4295  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4296 }
4297 
4298 ////////////////////////////////////////////////////////////////////////////////
4299 /// Read leaves into i/o buffers for this branch.
4300 /// Case of a TClonesArray (fType == 3).
4301 
4303 {
4304  ValidateAddress();
4305  if (fObject == 0)
4306  {
4307  // We have nowhere to copy the data (probably because the data member was
4308  // 'dropped' from the current schema) so let's no copy it in a random place.
4309  return;
4310  }
4311 
4312  // TClonesArray master branch (has only the number of elements).
4313  Int_t n;
4314  b >> n;
4315  if ((n < 0) || (n > fMaximum)) {
4316  if (IsMissingCollection()) {
4317  n = 0;
4318  b.SetBufferOffset(b.Length()-sizeof(n));
4319  } else {
4320  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());
4321  n = 0;
4322  }
4323  }
4324  fNdata = n;
4325  TClonesArray* clones = (TClonesArray*) fObject;
4326  if (clones->IsZombie()) {
4327  return;
4328  }
4329  // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4330  // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4331  // clones->Clear();
4332  clones->ExpandCreateFast(fNdata);
4333 }
4334 
4335 ////////////////////////////////////////////////////////////////////////////////
4336 /// Read leaves into i/o buffers for this branch.
4337 /// Case of a data member within a TClonesArray (fType == 31).
4338 
4340 {
4341  // No need to validate the address here, if we are a member of a split ClonesArray,
4342  // fID is positive
4343  // ValidateAddress();
4344 
4345  if (fObject == 0)
4346  {
4347  // We have nowhere to copy the data (probably because the data member was
4348  // 'dropped' from the current schema) so let's no copy it in a random place.
4349  return;
4350  }
4351 
4352  // TClonesArray sub-branch (contains the elements).
4354  TClonesArray* clones = (TClonesArray*) fObject;
4355  if (clones->IsZombie()) {
4356  return;
4357  }
4358  TStreamerInfo *info = GetInfoImp();
4359  if (info==0) return;
4360  // Since info is not null, fReadActionSequence is not null either.
4361 
4362  // Note, we could (possibly) save some more, by configuring the action
4363  // based on the value of fOnfileObject rather than pushing in on a stack.
4364  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4365 
4366  char **arr = (char **)clones->GetObjectRef();
4367  char **end = arr + fNdata;
4369 }
4370 
4371 ////////////////////////////////////////////////////////////////////////////////
4372 /// Read leaves into i/o buffers for this branch.
4373 /// For split-class branch, base class branch, data member branch, or top-level branch.
4374 /// which do not have a branch count and are not a counter.
4375 
4377 {
4378  R__ASSERT(fBranchCount==0);
4380 
4381  ValidateAddress();
4382  if (fObject == 0)
4383  {
4384  // We have nowhere to copy the data (probably because the data member was
4385  // 'dropped' from the current schema) so let's no copy it in a random place.
4386  return;
4387  }
4388 
4389  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4390  // If not a TClonesArray or STL container master branch
4391  // or sub-branch and branch inherits from tobject,
4392  // then register with the buffer so that pointers are
4393  // handled properly.
4394  if (TestBit(kBranchObject)) {
4395  b.MapObject((TObject*) fObject);
4396  } else if (TestBit(kBranchAny)) {
4398  }
4399 
4400  fNdata = 1;
4401  TStreamerInfo *info = GetInfoImp();
4402  if (!info) {
4403  return;
4404  }
4405  // Since info is not null, fReadActionSequence is not null either.
4407 }
4408 
4409 ////////////////////////////////////////////////////////////////////////////////
4410 /// Read leaves into i/o buffers for this branch.
4411 /// For split-class branch, base class branch, data member branch, or top-level branch.
4412 /// which do have a branch count and are not a counter.
4413 
4415 {
4417 
4418  ValidateAddress();
4419  if (fObject == 0)
4420  {
4421  // We have nowhere to copy the data (probably because the data member was
4422  // 'dropped' from the current schema) so let's no copy it in a random place.
4423  return;
4424  }
4425 
4426  // If not a TClonesArray or STL container master branch
4427  // or sub-branch and branch inherits from tobject,
4428  // then register with the buffer so that pointers are
4429  // handled properly.
4430  if (TestBit(kBranchObject)) {
4431  b.MapObject((TObject*) fObject);
4432  } else if (TestBit(kBranchAny)) {
4434  }
4435 
4436  fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4437  TStreamerInfo *info = GetInfoImp();
4438  if (!info) {
4439  return;
4440  }
4441  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1); // Here we have a single object that contains a variable size C-style array.
4442  // Since info is not null, fReadActionSequence is not null either.
4444 }
4445 
4446 ////////////////////////////////////////////////////////////////////////////////
4447 /// Read leaves into i/o buffers for this branch.
4448 /// For split-class branch, base class branch, data member branch, or top-level branch.
4449 /// which do not have a branch count and are a counter.
4450 
4452 {
4453  ValidateAddress();
4454  if (fObject == 0)
4455  {
4456  // We have nowhere to copy the data (probably because the data member was
4457  // 'dropped' from the current schema) so let's no copy it in a random place.
4458  return;
4459  }
4460 
4461  // If not a TClonesArray or STL container master branch
4462  // or sub-branch and branch inherits from tobject,
4463  // then register with the buffer so that pointers are
4464  // handled properly.
4465  if (TestBit(kBranchObject)) {
4466  b.MapObject((TObject*) fObject);
4467  } else if (TestBit(kBranchAny)) {
4469  }
4470 
4471  TStreamerInfo *info = GetInfoImp();
4472  if (!info) {
4473  return;
4474  }
4475 
4476  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4477 
4478  // Since info is not null, fReadActionSequence is not null either.
4480  fNdata = (Int_t) GetValue(0, 0);
4481 }
4482 
4483 ////////////////////////////////////////////////////////////////////////////////
4484 /// Read leaves into i/o buffers for this branch.
4485 /// Non TObject, Non collection classes with a custom streamer.
4486 
4488 {
4489  ValidateAddress();
4490  if (fObject == 0)
4491  {
4492  // We have nowhere to copy the data (probably because the data member was
4493  // 'dropped' from the current schema) so let's no copy it in a random place.
4494  return;
4495  }
4496 
4497  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4499 }
4500 
4501 ////////////////////////////////////////////////////////////////////////////////
4502 /// Unconfiguration Fill Leave function.
4503 
4505 {
4506  Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4507 }
4508 
4509 ////////////////////////////////////////////////////////////////////////////////
4510 /// Delete any object we may have allocated on a previous call to SetAddress.
4511 
4513 {
4514  if (fObject && TestBit(kDeleteObject)) {
4515  if (IsAutoDelete() && fAddress != (char*)&fObject) {
4516  *((char**) fAddress) = 0;
4517  }
4519  if (fType == 3) {
4520  // -- We are a TClonesArray master branch.
4521  TClonesArray::Class()->Destructor(fObject);
4522  fObject = 0;
4525  // -- We are a pointer to a TClonesArray.
4526  // We must zero the pointer in the object.
4527  *((char**) fAddress) = 0;
4528  }
4529  } else if (fType == 4) {
4530  // -- We are an STL container master branch.
4532 
4533  if (!proxy) {
4534  Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4535  fObject = 0;
4536  } else {
4538  if (needDelete && fID >= 0) {
4541  needDelete = !se->TestBit(TStreamerElement::kDoNotDelete);
4542  }
4543  if (needDelete) {
4544  TVirtualCollectionProxy::TPushPop helper(proxy,fObject);
4545  proxy->Clear("force");
4546  }
4547  proxy->Destructor(fObject);
4548  fObject = 0;
4549  }
4551  // -- We are a pointer to an STL container.
4552  // We must zero the pointer in the object.
4553  *((char**) fAddress) = 0;
4554  }
4555  } else {
4556  // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4557  TClass* cl = fBranchClass.GetClass();
4558  if (!cl) {
4559  Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4560  fObject = 0;
4561  } else {
4563 
4564  if (proxy) {
4565  if (fID >= 0) {
4567  TStreamerElement* se = si->GetElement(fID);
4569  TVirtualCollectionProxy::TPushPop helper(proxy,fObject);
4570  proxy->Clear("force");
4571  }
4573  TVirtualCollectionProxy::TPushPop helper(proxy,fObject);
4574  proxy->Clear("force");
4575  }
4576 
4577  }
4578  cl->Destructor(fObject);
4579  fObject = 0;
4580  }
4581  }
4582  }
4583 }
4584 
4585 ////////////////////////////////////////////////////////////////////////////////
4586 /// Reset a Branch.
4587 ///
4588 /// Existing i/o buffers are deleted.
4589 /// Entries, max and min are reset.
4590 ///
4591 
4593 {
4594  Int_t nbranches = fBranches.GetEntriesFast();
4595  for (Int_t i = 0; i < nbranches; ++i) {
4596  TBranch* branch = (TBranch*) fBranches[i];
4597  branch->Reset(option);
4598  }
4599  fBranchID = -1;
4600  TBranch::Reset(option);
4601 }
4602 
4603 ////////////////////////////////////////////////////////////////////////////////
4604 /// Reset a Branch after a Merge operation (drop data but keep customizations)
4605 ///
4606 
4608 {
4609  Int_t nbranches = fBranches.GetEntriesFast();
4610  for (Int_t i = 0; i < nbranches; ++i) {
4611  TBranch* branch = (TBranch*) fBranches[i];
4612  branch->ResetAfterMerge(info);
4613  }
4615 }
4616 
4617 ////////////////////////////////////////////////////////////////////////////////
4618 /// Set branch address to zero and free all allocated memory.
4619 
4621 {
4622  for (Int_t i = 0; i < fNleaves; ++i) {
4623  TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
4624  //if (leaf) leaf->SetAddress(0);
4625  leaf->SetAddress(0);
4626  }
4627 
4628  // Note: We *must* do the sub-branches first, otherwise
4629  // we may delete the object containing the sub-branches
4630  // before giving them a chance to cleanup.
4631  Int_t nbranches = fBranches.GetEntriesFast();
4632  for (Int_t i = 0; i < nbranches; ++i) {
4633  TBranch* br = (TBranch*) fBranches[i];
4634  if (br) br->ResetAddress();
4635  }
4636 
4637  //
4638  // SetAddress may have allocated an object.
4639  //
4640 
4641  ReleaseObject();
4642 
4644  fAddress = 0;
4645  fObject = 0;
4646 }
4647 
4648 ////////////////////////////////////////////////////////////////////////////////
4649 /// Release ownership of any allocated objects.
4650 ///
4651 /// Note: This interface was added so that clone trees could
4652 /// be told they do not own the allocated objects.
4653 
4655 {
4658  for (Int_t i = 0; i < nb; ++i) {
4659  TBranch* br = (TBranch*) fBranches[i];
4660  if (br->InheritsFrom(TBranchElement::Class())) {
4661  ((TBranchElement*) br)->ResetDeleteObject();
4662  }
4663  }
4664 }
4665 
4666 ////////////////////////////////////////////////////////////////////////////////
4667 /// \brief Reset offset and StremerInfo information from this branch.
4668 /// \param[in] recurse When true call ResetInitInfo on all subbranches.
4669 ///
4670 
4672 {
4673  fInfo = nullptr;
4674  fInit = kFALSE;
4675  fInitOffsets = kFALSE;
4676  fCurrentClass = nullptr;
4677  delete fReadActionSequence;
4678  fReadActionSequence = nullptr;
4679  delete fFillActionSequence;
4680  fFillActionSequence = nullptr;
4681 
4682  if (recurse) {
4683  Int_t nbranches = fBranches.GetEntriesFast();
4684  for (Int_t i = 0; i < nbranches; ++i) {
4686  sub->ResetInitInfo(kTRUE);
4687  }
4688  }
4689 }
4690 
4691 ////////////////////////////////////////////////////////////////////////////////
4692 /// Point this branch at an object.
4693 ///
4694 /// For a sub-branch, addr is a pointer to the branch object.
4695 ///
4696 /// For a top-level branch the meaning of addr is as follows:
4697 ///
4698 /// If addr is zero, then we allocate a branch object
4699 /// internally and the branch is the owner of the allocated
4700 /// object, not the caller. However the caller may obtain
4701 /// a pointer to the branch object with GetObject().
4702 ///
4703 /// Example:
4704 /// ~~~ {.cpp}
4705 /// branch->SetAddress(0);
4706 /// Event* event = branch->GetObject();
4707 /// ... Do some work.
4708 /// ~~~
4709 /// If addr is not zero, but the pointer addr points at is
4710 /// zero, then we allocate a branch object and set the passed
4711 /// pointer to point at the allocated object. The caller
4712 /// owns the allocated object and is responsible for deleting
4713 /// it when it is no longer needed.
4714 ///
4715 /// Example:
4716 /// ~~~ {.cpp}
4717 /// Event* event = 0;
4718 /// branch->SetAddress(&event);
4719 /// ... Do some work.
4720 /// delete event;
4721 /// event = 0;
4722 /// ~~~
4723 /// If addr is not zero and the pointer addr points at is
4724 /// also not zero, then the caller has allocated a branch
4725 /// object and is asking us to use it. The caller owns it
4726 /// and must delete it when it is no longer needed.
4727 ///
4728 /// Example:
4729 /// ~~~ {.cpp}
4730 /// Event* event = new Event();
4731 /// branch->SetAddress(&event);
4732 /// ... Do some work.
4733 /// delete event;
4734 /// event = 0;
4735 /// ~~~
4736 /// These rules affect users of TTree::Branch(),
4737 /// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4738 /// as well because those routines call this one.
4739 ///
4740 /// An example of a tree with branches with objects allocated
4741 /// and owned by us:
4742 /// ~~~ {.cpp}
4743 /// TFile* f1 = new TFile("myfile_original.root");
4744 /// TTree* t1 = (TTree*) f->Get("MyTree");
4745 /// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4746 /// TTree* t2 = t1->Clone(0);
4747 /// for (Int_t i = 0; i < 10; ++i) {
4748 /// t1->GetEntry(i);
4749 /// t2->Fill();
4750 /// }
4751 /// t2->Write()
4752 /// delete f2;
4753 /// f2 = 0;
4754 /// delete f1;
4755 /// f1 = 0;
4756 /// ~~~
4757 /// An example of a branch with an object allocated by us,
4758 /// but owned by the caller:
4759 /// ~~~ {.cpp}
4760 /// TFile* f = new TFile("myfile.root", "recreate");
4761 /// TTree* t = new TTree("t", "A test tree.")
4762 /// Event* event = 0;
4763 /// TBranchElement* br = t->Branch("event.", &event);
4764 /// for (Int_t i = 0; i < 10; ++i) {
4765 /// ... Fill event with meaningful data in some way.
4766 /// t->Fill();
4767 /// }
4768 /// t->Write();
4769 /// delete event;
4770 /// event = 0;
4771 /// delete f;
4772 /// f = 0;
4773 /// ~~~
4774 /// Notice that the only difference between this example
4775 /// and the following example is that the event pointer
4776 /// is zero when the branch is created.
4777 ///
4778 /// An example of a branch with an object allocated and
4779 /// owned by the caller:
4780 /// ~~~ {.cpp}
4781 /// TFile* f = new TFile("myfile.root", "recreate");
4782 /// TTree* t = new TTree("t", "A test tree.")
4783 /// Event* event = new Event();
4784 /// TBranchElement* br = t->Branch("event.", &event);
4785 /// for (Int_t i = 0; i < 10; ++i) {
4786 /// ... Fill event with meaningful data in some way.
4787 /// t->Fill();
4788 /// }
4789 /// t->Write();
4790 /// delete event;
4791 /// event = 0;
4792 /// delete f;
4793 /// f = 0;
4794 /// ~~~
4795 /// If AutoDelete is on (see TBranch::SetAutoDelete),
4796 /// the top level objet will be deleted and recreate
4797 /// each time an entry is read, whether or not the
4798 /// TTree owns the object.
4799 
4801 {
4802  //
4803  // Don't bother if we are disabled.
4804  //
4805 
4806  if (TestBit(kDoNotProcess)) {
4807  return;
4808  }
4809 
4810  //
4811  // FIXME: When would this happen?
4812  //
4813 
4814  if (fType < -1) {
4815  return;
4816  }
4817 
4818  //
4819  // Special case when called from code generated by TTree::MakeClass.
4820  //
4821 
4822  if (Long_t(addr) == -1) {
4823  // FIXME: Do we have to release an object here?
4824  // ReleaseObject();
4825  fAddress = (char*) -1;
4826  fObject = (char*) -1;
4828  return;
4829  }
4830 
4831  //
4832  // Reset last read entry number, we have a new user object now.
4833  //
4834 
4835  fReadEntry = -1;
4836 
4837  //
4838  // Make sure our branch class is instantiated.
4839  //
4840  TClass* clOfBranch = fBranchClass.GetClass();
4841  if( fTargetClass.GetClassName()[0] ) {
4842  clOfBranch = fTargetClass;
4843  }
4844 
4845  //
4846  // Try to build the streamer info.
4847  //
4848 
4849  TStreamerInfo *info = GetInfoImp();
4850 
4851  // FIXME: Warn about failure to get the streamer info here?
4852 
4853  //
4854  // We may have allocated an object last time we were called.
4855  //
4856 
4857  if (fObject && TestBit(kDeleteObject)){
4858  ReleaseObject();
4859  }
4860 
4861  //
4862  // Remember the pointer to the pointer to our object.
4863  //
4864 
4865  fAddress = (char*) addr;
4866  if (fAddress != (char*)(&fObject)) {
4867  fObject = 0;
4868  }
4870 
4871  //
4872  // Do special stuff if we got called from a MakeClass class.
4873  // Allow sub-branches to have independently set addresses.
4874  //
4875 
4876  if (TestBit(kDecomposedObj)) {
4877  if (fID > -1) {
4878  // We are *not* a top-level branch.
4879  if (!info) {
4880  // No streamer info, give up.
4881  // FIXME: We should have an error message here.
4882  fObject = fAddress;
4883  } else {
4884  // Compensate for the fact that the i/o routines
4885  // will add the streamer offset to the address.
4886  fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
4887  }
4888  return;
4889  }
4890  }
4891 
4892  //
4893  // Check whether the container type is still the same
4894  // to support schema evolution; what is written on the file
4895  // may no longer match the class code which is loaded.
4896  //
4897 
4898  if (fType == 3) {
4899  // split TClonesArray, counter/master branch.
4900  TClass* clm = fClonesClass;
4901  if (clm) {
4902  // In case clm derives from an abstract class.
4903  clm->BuildRealData();
4904  clm->GetStreamerInfo();
4905  }
4906  TClass* newType = GetCurrentClass();
4907  if (newType && (newType != TClonesArray::Class())) {
4908  // The data type of the container has changed.
4909  //
4910  // Let's check if it is a compatible type:
4911  Bool_t matched = kFALSE;
4912  if (newType->GetCollectionProxy()) {
4913  TClass *content = newType->GetCollectionProxy()->GetValueClass();
4914  if (clm == content) {
4915  matched = kTRUE;
4916  } else {
4917  Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
4918  }
4919  } else {
4920  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());
4921  }
4922  if (matched) {
4923  // Change from 3/31 to 4/41
4924  SetType(4);
4925  // Set the proxy.
4926  fSTLtype = newType->GetCollectionType();
4927  fCollProxy = newType->GetCollectionProxy()->Generate();
4928 
4930  SetReadLeavesPtr();
4931  SetFillLeavesPtr();
4932 
4938  } else {
4940  }
4941  } else {
4942  // FIXME: Must maintain fObject here as well.
4943  fAddress = 0;
4944  }
4945  }
4946  } else if (fType == 4) {
4947  // split STL container, counter/master branch.
4948  TClass* newType = GetCurrentClass();
4949  if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
4950  // Let's check if it is a compatible type:
4951  TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
4953  if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
4954  delete fCollProxy;
4955  Int_t nbranches = GetListOfBranches()->GetEntries();
4956  fCollProxy = newType->GetCollectionProxy()->Generate();
4958  for (Int_t i = 0; i < nbranches; ++i) {
4960  br->fCollProxy = 0;
4961  if (br->fReadActionSequence) {
4962  br->SetReadActionSequence();
4963  }
4964  if (br->fFillActionSequence) {
4965  br->SetFillActionSequence();
4966  }
4967  }
4970  SetReadLeavesPtr();
4971  SetFillLeavesPtr();
4972  delete fIterators;
4973  delete fPtrIterators;
4979  } else {
4981  }
4982  }
4983  else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=0) && (newProxy->GetValueClass()!=0)) {
4984  // Let see if there is a rule to convert the content of the collection into each other.
4985  if (newType->GetSchemaRules()->HasRuleWithSourceClass( oldProxy->GetCollectionClass()->GetName())) {
4986  TClass *oldValueClass = oldProxy->GetValueClass();
4987  delete fCollProxy;
4988  Int_t nbranches = GetListOfBranches()->GetEntries();
4989  fCollProxy = newType->GetCollectionProxy()->Generate();
4991  for (Int_t i = 0; i < nbranches; ++i) {
4993  br->fCollProxy = 0;
4994  if (br->fBranchClass == oldValueClass) {
4996  }
4997  if (br->fReadActionSequence) {
4998  br->SetReadActionSequence();
4999  }
5000  if (br->fFillActionSequence) {
5001  br->SetFillActionSequence();
5002  }
5003  }
5006  SetReadLeavesPtr();
5007  SetFillLeavesPtr();
5008  delete fIterators;
5009  delete fPtrIterators;
5015  } else {
5017  }
5018  } else {
5019  Error("SetAddress","For %s, we can not convert %s into %s\n",
5020  GetName(),oldProxy->GetCollectionClass()->GetName(),newType->GetName());
5021  fAddress = 0;
5022  fObject = 0;
5023  return;
5024  }
5025  }
5026  else if ((newType == TClonesArray::Class()) && (oldProxy->GetValueClass() && !oldProxy->HasPointers() && oldProxy->GetValueClass()->IsTObject()))
5027  {
5028  // The new collection and the old collection are not compatible,
5029  // we cannot use the new collection to read the data.
5030  // Actually we could check if the new collection is a
5031  // compatible ROOT collection.
5032 
5033  // We cannot insure that the TClonesArray is set for the
5034  // proper class (oldProxy->GetValueClass()), so we assume that
5035  // the transformation was done properly by the class designer.
5036 
5037  // Change from 4/41 to 3/31
5038  SetType(3);
5039  // Reset the proxy.
5040  fSTLtype = kNone;
5041  switch(fStreamerType) {
5045  break;
5049  break;
5052  break;
5053  }
5054  fClonesClass = oldProxy->GetValueClass();
5056  delete fCollProxy;
5057  fCollProxy = 0;
5058  TClass* clm = fClonesClass;
5059  if (clm) {
5060  clm->BuildRealData(); //just in case clm derives from an abstract class
5061  clm->GetStreamerInfo();
5062  }
5064  SetReadLeavesPtr();
5065  SetFillLeavesPtr();
5066  delete fIterators;
5067  fIterators = 0;
5068  delete fPtrIterators;
5069  fPtrIterators =0;
5070  } else {
5071  // FIXME: We must maintain fObject here as well.
5072  Error("SetAddress","For %s can not convert %s into %s\n",GetName(),GetCurrentClass()->GetName(),newType->GetName());
5073  fAddress = 0;
5074  return;
5075  }
5076  } else {
5077  if (!fIterators && !fPtrIterators) {
5083  } else {
5085  }
5086  }
5087  }
5088  }
5089 
5090  //
5091  // Establish the semantics of fObject and fAddress.
5092  //
5093  // Top-level branch:
5094  // fObject is a ptr to the object,
5095  // fAddress is a ptr to a pointer to the object.
5096  //
5097  // Sub-branch:
5098  // fObject is a ptr to the object,
5099  // fAddress is the same as fObject.
5100  //
5101  //
5102  // There are special cases for TClonesArray and STL containers.
5103  // If there is no user-provided object, we allocate one. We must
5104  // also initialize any STL container proxy.
5105  //
5106 
5107  if (fType == 3) {
5108  // -- We are a TClonesArray master branch.
5109  if (fAddress) {
5110  // -- We have been given a non-zero address, allocate if necessary.
5112  // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5113  // Case of an embedded TClonesArray.
5114  fObject = fAddress;
5115  // Check if it has already been properly built.
5116  TClonesArray* clones = (TClonesArray*) fObject;
5117  if (!clones->GetClass()) {
5119  }
5120  } else {
5121  // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5122  // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5123  if ((fStreamerType != -1) &&
5126  Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5127  } else if (fStreamerType == -1) {
5128  // -- We are a top-level branch.
5129  TClonesArray** pp = (TClonesArray**) fAddress;
5130  if (!*pp) {
5131  // -- Caller wants us to allocate the clones array, but they will own it.
5132  *pp = new TClonesArray(fClonesClass);
5133  }
5134  fObject = (char*) *pp;
5135  } else {
5136  // -- We are a pointer to a TClonesArray.
5137  // Note: We do this so that the default constructor,
5138  // or the i/o constructor can be lazy.
5139  TClonesArray** pp = (TClonesArray**) fAddress;
5140  if (!*pp) {
5141  // -- Caller wants us to allocate the clones array, but they will own it.
5142  *pp = new TClonesArray(fClonesClass);
5143  }
5144  fObject = (char*) *pp;
5145  }
5146  }
5147  } else {
5148  // -- We have been given a zero address, allocate for top-level only.
5150  // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5151  // Case of an embedded TClonesArray.
5152  Error("SetAddress", "Embedded TClonesArray given a zero address for branch '%s'", GetName());
5153  } else {
5154  // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5155  // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5156  if ((fStreamerType != -1) &&
5159  Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5160  } else if (fStreamerType == -1) {
5161  // -- We are a top-level branch.
5162  // Idea: Consider making a zero address not allocate.
5164  fObject = (char*) new TClonesArray(fClonesClass);
5165  fAddress = (char*) &fObject;
5166  } else {
5167  // -- We are a sub-branch which is a pointer to a TClonesArray.
5168  Error("SetAddress", "Embedded pointer to a TClonesArray given a zero address for branch '%s'", GetName());
5169  }
5170  }
5171  }
5172  } else if (fType == 4) {
5173  // -- We are an STL container master branch.
5174  //
5175  // Initialize fCollProxy.
5177  if (fAddress) {
5178  // -- We have been given a non-zero address, allocate if necessary.
5182  // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5183  // Case of an embedded STL container.
5184  // Note: We test for the kObject and kAny types to support
5185  // the (unwise) choice of inheriting from an STL container.
5186  fObject = fAddress;
5187  } else {
5188  // We are either a top-level branch or subbranch which is a pointer to an STL container.
5189  // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5191  Error("SetAddress", "STL container with fStreamerType: %d", fStreamerType);
5192  } else if (fStreamerType == -1) {
5193  // -- We are a top-level branch.
5194  void** pp = (void**) fAddress;
5195  if (!*pp) {
5196  // -- Caller wants us to allocate the STL container, but they will own it.
5197  *pp = proxy->New();
5198  if (!(*pp)) {
5199  Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5200  // FIXME: Should we do this? Lots of other code wants
5201  // fAddress to be zero if no fObject, but is
5202  // that a good thing?
5203  fAddress = 0;
5204  }
5205  }
5206  fObject = (char*) *pp;
5207  } else {
5208  // -- We are a pointer to an STL container.
5209  // Note: We do this so that the default constructor,
5210  // or the i/o constructor can be lazy.
5211  void** pp = (void**) fAddress;
5212  if (!*pp) {
5213  // -- Caller wants us to allocate the STL container, but they will own it.
5214  *pp = proxy->New();
5215  if (!(*pp)) {
5216  Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5217  // FIXME: Should we do this? Lots of other code wants
5218  // fAddress to be zero if no fObject, but is
5219  // that a good thing?
5220  fAddress = 0;
5221  }
5222  }
5223  fObject = (char*) *pp;
5224  }
5225  }
5226  } else {
5227  // -- We have been given a zero address, allocate for top-level only.
5231  // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5232  // Case of an embedded STL container.
5233  // Note: We test for the kObject and kAny types to support
5234  // the (unwise) choice of inheriting from an STL container.
5235  Error("SetAddress", "Embedded STL container given a zero address for branch '%s'", GetName());
5236  } else {
5237  // We are either a top-level branch or sub-branch which is a pointer to an STL container.
5238  // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5240  Error("SetAddress", "STL container with fStreamerType: %d", fStreamerType);
5241  } else if (fStreamerType == -1) {
5242  // -- We are a top-level branch, allocate.
5244  fObject = (char*) proxy->New();
5245  if (fObject) {
5246  fAddress = (char*) &fObject;
5247  } else {
5248  Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5249  // FIXME: Should we do this? Lots of other code wants
5250  // fAddress to be zero if no fObject, but is
5251  // that a good thing?
5252  fAddress = 0;
5253  }
5254  } else {
5255  // -- We are a sub-branch which is a pointer to an STL container.
5256  Error("SetAddress", "Embedded pointer to an STL container given a zero address for branch '%s'", GetName());
5257  }
5258  }
5259  }
5260  } else if (fType == 41) {
5261  // -- We are an STL container sub-branch.
5262  // Initialize fCollProxy.
5264  // We are not at top-level branch.
5265  fObject = fAddress;
5266  } else if (fID < 0) {
5267  // -- We are a top-level branch.
5268  char** pp = (char**) fAddress;
5269  if (pp && *pp) {
5270  // -- Caller provided an i/o buffer for us to use.
5271  fObject = *pp;
5272  } else {
5273  // -- Caller did not provide an i/o buffer for us to use, we must make one for ourselves.
5274  if (clOfBranch) {
5275  if (!pp) {
5276  // -- Caller wants us to own the object.
5278  }
5279  fObject = (char*) clOfBranch->New();
5280  if (pp) {
5281  *pp = fObject;
5282  } else {
5283  fAddress = (char*) &fObject;
5284  }
5285  } else {
5286  Error("SetAddress", "I have no TClass for branch %s, so I cannot allocate an I/O buffer!", GetName());
5287  if (pp) {
5288  fObject = 0;
5289  *pp = 0;
5290  }
5291  }
5292  }
5293  } else {
5294  // -- We are *not* a top-level branch.
5295  fObject = fAddress;
5296  }
5297 
5298  if (!info) {
5299  // FIXME: We need and error message here, no streamer info, so cannot set offsets.
5300  return;
5301  }
5302 
5303  // We do this only once because it depends only on
5304  // the type of our object, not on its address.
5305  if (!fInitOffsets) {
5307  }
5308 
5309  // We are split, recurse down to our sub-branches.
5310  //
5311  // FIXME: This is a tail recursion, we burn stack.
5312  Int_t nbranches = fBranches.GetEntriesFast();
5313  for (Int_t i = 0; i < nbranches; ++i) {
5314  TBranch* abranch = (TBranch*) fBranches.UncheckedAt(i);
5315  // FIXME: This is a tail recursion!
5317  abranch->SetAddress(fObject + fBranchOffset[i]);
5318  abranch->SetBit(kAddressSet);
5319  } else {
5320  // When the member is missing, just leave the address alone
5321  // (since setting explicitly to 0 would trigger error/warning
5322  // messages).
5323  // abranch->SetAddress(0);
5324  abranch->SetBit(kAddressSet);
5325  }
5326  }
5327 }
5328 
5329 ////////////////////////////////////////////////////////////////////////////////
5330 /// Reset the basket size for all sub-branches of this branch element.
5331 
5333 {
5334  TBranch::SetBasketSize(buffsize);
5335  Int_t nbranches = fBranches.GetEntriesFast();
5336  for (Int_t i = 0; i < nbranches; ++i) {
5337  TBranch* branch = (TBranch*) fBranches[i];
5338  branch->SetBasketSize(fBasketSize);
5339  }
5340 }
5341 
5342 ////////////////////////////////////////////////////////////////////////////////
5343 /// Set the branch counter for this branch.
5344 
5346 {
5347  fBranchCount = brOfCounter;
5348  if (fBranchCount==0) return;
5349 
5350  TLeafElement* leafOfCounter = (TLeafElement*) brOfCounter->GetListOfLeaves()->At(0);
5351  TLeafElement* leaf = (TLeafElement*) GetListOfLeaves()->At(0);
5352  if (leafOfCounter && leaf) {
5353  leaf->SetLeafCount(leafOfCounter);
5354  } else {
5355  if (!leafOfCounter) {
5356  Warning("SetBranchCount", "Counter branch %s for branch %s has no leaves!", brOfCounter->GetName(), GetName());
5357  }
5358  if (!leaf) {
5359  Warning("SetBranchCount", "Branch %s has no leaves!", GetName());
5360  }
5361  }
5362 }
5363 
5364 ////////////////////////////////////////////////////////////////////////////////
5365 /// Set the branch in a mode where the object are decomposed
5366 /// (Also known as MakeClass mode).
5367 /// Return whether the setting was possible (it is not possible for
5368 /// TBranch and TBranchObject).
5369 
5371 {
5372  if (decomposeObj)
5373  SetBit(kDecomposedObj); // Same as SetBit(kMakeClass)
5374  else
5376 
5377  Int_t nbranches = fBranches.GetEntriesFast();
5378  for (Int_t i = 0; i < nbranches; ++i) {
5379  TBranchElement* branch = (TBranchElement*) fBranches[i];
5380  branch->SetMakeClass(decomposeObj);
5381  }
5382  SetReadLeavesPtr();
5383  SetFillLeavesPtr();
5384 
5385  return kTRUE;
5386 }
5387 
5388 ////////////////////////////////////////////////////////////////////////////////
5389 /// Set object this branch is pointing to.
5390 
5392 {
5393  if (TestBit(kDoNotProcess)) {
5394  return;
5395  }
5396  fObject = (char*)obj;
5397  SetAddress( &fObject );
5398 }
5399 
5400 ////////////////////////////////////////////////////////////////////////////////
5401 /// Set offset of the object (to which the data member represented by this
5402 /// branch belongs) inside its containing object (if any).
5403 
5405 {
5406  // We need to make sure that the Read and Write action's configuration
5407  // properly reflect this value.
5408 
5409  if (fReadActionSequence) {
5411  }
5412  if (fFillActionSequence) {
5414  }
5415  fOffset = offset;
5416 }
5417 
5418 
5419 ////////////////////////////////////////////////////////////////////////////////
5420 /// Set the sequence of actions needed to read the data out of the buffer.
5422 {
5423  // A 'split' node does not store data itself (it has not associated baskets)
5424  const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
5425 
5426  if (!isSplitNode) {
5427  fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
5428  }
5429 
5430  if (actionSequence) delete actionSequence;
5431  auto original = create(localInfo, GetCollectionProxy(), originalClass);
5432 
5433  actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
5434 
5435  if (!isSplitNode)
5436  fNewIDs.erase(fNewIDs.begin());
5437  else {
5438  // fObject has the address of the sub-object but the streamer action have
5439  // offset relative to the parent.
5440  TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
5441  if (fInitOffsets) {
5442  auto index = parent->fBranches.IndexOf(this);
5443  if (index >= 0) {
5444  fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
5445  }
5446  } // else it will be done by InitOffsets
5447  }
5448 }
5449 
5450 ////////////////////////////////////////////////////////////////////////////////
5451 /// Set the sequence of actions needed to read the data out of the buffer.
5453 {
5454  if (fInfo == 0) {
5455  // We are called too soon. We will be called again by InitInfo
5456  return;
5457  }
5458 
5460  TClass *originalClass = nullptr;
5461  TStreamerInfo *localInfo = fInfo;
5462  if (fType == 41) {
5465  } else {
5466  TVirtualStreamerInfo *info = GetInfoImp();
5467  if (GetParentClass() == info->GetClass()) {
5469  originalClass = fBranchClass;
5471  } else {
5473  }
5474  } else if (GetCollectionProxy()) {
5475  // Base class and embedded objects.
5477  }
5478  }
5479  } else if (fType == 31) {
5481  } else if (0<=fType && fType<=2) {
5482  // Note: this still requires the ObjectWise sequence to not be optimized!
5484  } else if ( fType == 4 && !fNewIDs.empty()) {
5485  localInfo = FindOnfileInfo(fClonesClass, fBranches);
5487  } else if ( fType == 3 && !fNewIDs.empty()) {
5488  localInfo = FindOnfileInfo(fClonesClass, fBranches);
5490  }
5491 
5492  if (create) {
5493  SetActionSequence(originalClass, localInfo, create, fReadActionSequence);
5494  }
5495 }
5496 
5497 ////////////////////////////////////////////////////////////////////////////////
5498 /// Set the ReadLeaves pointer to execute the expected operations.
5499 
5501 {
5502  if (TestBit(kDecomposedObj)) {
5504  } else if (fType == 4) {
5506  } else if (fType == 41) {
5510  } else {
5512  }
5513  } else {
5515  }
5516  } else if (fType == 3) {
5518  } else if (fType == 31) {
5520  } else if (fType < 0) {
5522  } else if (fType == 0 && fID == -1) {
5523  // top-level branch.
5525  if (hasCustomStreamer) {
5526  // We are in the case where the object did *not* have a custom
5527  // Streamer when the TTree was written but now *does* have a custom
5528  // Streamer thus we must use it.
5530  } else {
5532  }
5533  } else if (fType <= 2) {
5534  // split-class branch, base class branch or data member branch.
5535  if (fBranchCount) {
5539  } else {
5541  }
5542  } else {
5543  Fatal("SetReadLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5544  }
5545 
5547 }
5548 
5549 ////////////////////////////////////////////////////////////////////////////////
5550 /// Set the sequence of actions needed to write the data out from the buffer.
5551 
5553 {
5554  if (fInfo == 0) {
5555  // We are called too soon. We will be called again by InitInfo
5556  return;
5557  }
5558 
5560  TClass *originalClass = nullptr;
5561  TStreamerInfo *localInfo = fInfo;
5562  if (fType == 41) {
5565  } else {
5566  TVirtualStreamerInfo *info = GetInfoImp();
5567  if (GetParentClass() == info->GetClass()) {
5568  // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
5569  // originalClass = fBranchClass;
5570  // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter;
5571  // } else {
5573  // }
5574  } else if (GetCollectionProxy()) {
5575  // Base class and embedded objects.
5577  }
5578  }
5579  } else if (fType == 31) {
5581  } else if (0<=fType && fType<=2) {
5582  // Note: this still requires the ObjectWise sequence to not be optimized!
5584  } else if ( fType == 4 && !fNewIDs.empty()) {
5585  localInfo = FindOnfileInfo(fClonesClass, fBranches);
5587  } else if ( fType == 3 && !fNewIDs.empty()) {
5588  localInfo = FindOnfileInfo(fClonesClass, fBranches);
5590  }
5591 
5592  if (create) {
5593  SetActionSequence(originalClass, localInfo, create, fFillActionSequence);
5594  }
5595 }
5596 
5597 ////////////////////////////////////////////////////////////////////////////////
5598 /// Set the FillLeaves pointer to execute the expected operations.
5599 
5601 {
5602  if (TestBit(kDecomposedObj) && ((fType==3)||(fType==31))) {
5604  } else if (fType == 4) {
5606  } else if (fType == 41) {
5610  } else {
5612  }
5615  } else {
5617  }
5618  } else if (fType == 3) {
5620  } else if (fType == 31) {
5622  } else if (fType < 0) {
5624  } else if (fType <=2) {
5625  //split-class branch, base class branch, data member branch, or top-level branch.
5626  if (fBranchCount) {
5630  } else {
5632  }
5633  } else {
5634  Fatal("SetFillLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5635  }
5636 
5638 }
5639 
5640 ////////////////////////////////////////////////////////////////////////////////
5641 /// Set the name of the class of the in-memory object into which the data will
5642 /// loaded.
5643 
5645 {
5646  if (name == 0) return;
5647 
5648  if (strcmp(fTargetClass.GetClassName(),name) != 0 )
5649  {
5650  // We are changing target class, let's reset the meta information and
5651  // the sub-branches.
5652 
5653  ResetInitInfo(/*recurse=*/ kFALSE);
5654 
5655  Int_t nbranches = fBranches.GetEntriesFast();
5656  for (Int_t i = 0; i < nbranches; ++i) {
5658 
5659  if (sub->fTargetClass == fTargetClass ) {
5660  sub->SetTargetClass(name);
5661  } else {
5662  // Since the top level changes, the StreamerInfo (in particular for split collection)
5663  // may still need to change (and the info might be updated else (see for example SetAddress for the
5664  // the case fType 4/41)
5665  sub->ResetInitInfo(kTRUE);
5666  }
5667  if (sub->fParentClass == fTargetClass ) {
5668  sub->SetParentClass(TClass::GetClass(name));
5669  }
5670  }
5671  fTargetClass = name;
5672  }
5673 
5674 }
5675 
5676 ////////////////////////////////////////////////////////////////////////////////
5677 /// If the branch address is not set, we set all addresses starting with
5678 /// the top level parent branch. This is required to be done in order for
5679 /// GetOffset to be correct and for GetEntry to run.
5680 
5682 {
5683  // Check to see if the user changed the branch address on us.
5684  ValidateAddress();
5685 
5686  if (fAddress || TestBit(kDecomposedObj)) {
5687  // -- Do nothing if already setup or if we are a MakeClass branch.
5688  return;
5689  }
5691 }
5692 
5693 ////////////////////////////////////////////////////////////////////////////////
5694 /// If the branch address is not set, we set all addresses starting with
5695 /// the top level parent branch. This is required to be done in order for
5696 /// GetOffset to be correct and for GetEntry to run.
5697 
5699 {
5701  // -- Do nothing if we have been told not to.
5702  // Or the data member in this branch is not longer part of the
5703  // parent's layout.
5704  return;
5705  }
5706 
5707  //--------------------------------------------------------------------------
5708  // Check if we are splited STL collection of pointers
5709  /////////////////////////////////////////////////////////////////////////////
5710 
5712  {
5713  TBranchElement *parent = (TBranchElement *)GetMother()->GetSubBranch( this );
5714 
5715  // Make sure the StreamerInfo is loaded and initialized.
5716  GetInfoImp();
5717 
5718  if( !parent->GetAddress() )
5719  parent->SetAddress( 0 );
5720  return;
5721  }
5722 
5723  //--------------------------------------------------------------------------
5724  // Any other case
5725  /////////////////////////////////////////////////////////////////////////////
5726 
5727  TBranchElement* mother = (TBranchElement*) GetMother();
5728  if (!mother) {
5729  return;
5730  }
5731  TClass* cl = TClass::GetClass(mother->GetClassName());
5732 
5733  // Make sure the StreamerInfo is loaded and initialized.
5734  GetInfoImp();
5735 
5736  if (!cl) {
5737  return;
5738  }
5739 
5740  if (!mother->GetAddress()) {
5741  // -- Our top-level branch has no address.
5742  Bool_t motherStatus = mother->TestBit(kDoNotProcess);
5743  mother->ResetBit(kDoNotProcess);
5744  // Note: This will allocate an object.
5745  mother->SetAddress(0);
5746  mother->SetBit(kDoNotProcess, motherStatus);
5747  }
5748 }
5749 
5750 ////////////////////////////////////////////////////////////////////////////////
5751 /// Stream an object of class TBranchElement.
5752 
5753 void TBranchElement::Streamer(TBuffer& R__b)
5754 {
5755  if (R__b.IsReading()) {
5756  R__b.ReadClassBuffer(TBranchElement::Class(), this);
5761  // The fAddress and fObject data members are not persistent,
5762  // therefore we do not own anything.
5763  // Also clear the bit possibly set by the schema evolution.
5765  // Fixup a case where the TLeafElement was missing
5766  if ((fType == 0) && (fLeaves.GetEntriesFast() == 0)) {
5767  TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
5768  leaf->SetTitle(GetTitle());
5769  fNleaves = 1;
5770  fLeaves.Add(leaf);
5771  fTree->GetListOfLeaves()->Add(leaf);
5772  }
5773 
5774  // SetReadLeavesPtr();
5775  }
5776  else {
5777  TDirectory* dirsav = fDirectory;
5778  fDirectory = 0; // to avoid recursive calls
5779  {
5780  // Save class version.
5781  Int_t classVersion = fClassVersion;
5782  // Record only positive 'version number'
5783  if (fClassVersion < 0) {
5785  }
5786  // TODO: Should we clear the kDeleteObject bit before writing?
5787  // If we did we would have to remember the old value and
5788  // put it back, we wouldn't want to forget that we owned
5789  // something just because we got written to disk.
5791  // Restore class version.
5792  fClassVersion = classVersion;
5793  }
5794  //
5795  // Mark all streamer infos used by this branch element
5796  // to be written to our output file.
5797  //
5798  {
5799  R__b.ForceWriteInfo(GetInfoImp(), kTRUE);
5800  }
5801  //
5802  // If we are a clones array master branch, or an
5803  // STL container master branch, we must also mark
5804  // the streamer infos used by the value class to
5805  // be written to our output file.
5806  //
5807  if (fType == 3) {
5808  // -- TClonesArray, counter/master branch
5809  //
5810  // We must mark the streamer info for the
5811  // value class to be written to the file.
5812  //
5813  TClass* cl = fClonesClass;
5814  if (cl) {
5815  R__b.ForceWriteInfo(cl->GetStreamerInfo(), kTRUE);
5816  }
5817  }
5818  else if (fType == 4) {
5819  // -- STL container, counter/master branch
5820  //
5821  // We must mark the streamer info for the
5822  // value class to be written to the file.
5823  //
5825  if (cp) {
5826  TClass* cl = cp->GetValueClass();
5827  if (cl) {
5828  R__b.ForceWriteInfo(cl->GetStreamerInfo(), kTRUE);
5829  }
5830  }
5831  }
5832  // If we are in a separate file, then save
5833  // ourselves as an independent key.
5834  if (!dirsav) {
5835  // Note: No need to restore fDirectory, it was already zero.
5836  return;
5837  }
5838  if (!dirsav->IsWritable()) {
5839  fDirectory = dirsav;
5840  return;
5841  }
5842  TDirectory* pdirectory = fTree->GetDirectory();
5843  if (!pdirectory) {
5844  fDirectory = dirsav;
5845  return;
5846  }
5847  const char* treeFileName = pdirectory->GetFile()->GetName();
5848  TBranch* mother = GetMother();
5849  const char* motherFileName = treeFileName;
5850  if (mother && (mother != this)) {
5851  motherFileName = mother->GetFileName();
5852  }
5853  if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
5854  dirsav->WriteTObject(this);
5855  }
5856  fDirectory = dirsav;
5857  }
5858 }
5859 
5860 
5861 ////////////////////////////////////////////////////////////////////////////////
5862 /// Split class cl into sub-branches of this branch.
5863 ///
5864 /// This version of Unroll was formerly embedded in TTree::BronchExec
5865 /// It is moved here so we can make sure to call SetReadActionSequence.
5866 
5867 void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Int_t bufsize, Int_t splitlevel)
5868 {
5869  //
5870  // Do we have a final dot in our name?
5871  //
5872 
5873  // Note: The branch constructor which takes a folder as input
5874  // creates top-level branch names with dots in them to
5875  // indicate the folder hierarchy.
5876  char* dot = (char*) strchr(name, '.');
5877  Int_t nch = strlen(name);
5878  Bool_t dotlast = kFALSE;
5879  if (nch && (name[nch-1] == '.')) {
5880  dotlast = kTRUE;
5881  }
5882 
5883  // Loop on all public data members of the class and its base classes and create branches for each one.
5884  TObjArray* blist = this->GetListOfBranches();
5885  TIter next(sinfo->GetElements());
5886  TStreamerElement* element = 0;
5887  TString bname;
5888  for (Int_t id = 0; (element = (TStreamerElement*) next()); ++id) {
5889  if (element->IsA() == TStreamerArtificial::Class()) {
5890  continue;
5891  }
5892  if (element->TestBit(TStreamerElement::kRepeat)) {
5893  continue;
5894  }
5895  if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) {
5896  continue;
5897  }
5898  char* pointer = (char*) (objptr + element->GetOffset());
5899  // FIXME: This is not good enough, an STL container can be
5900  // a base, and the test will fail.
5901  // See TBranchElement::InitializeOffsets() for the
5902  // correct test.
5903  Bool_t isBase = (element->IsA() == TStreamerBase::Class());
5904  if (isBase) {
5905  TClass* clbase = element->GetClassPointer();
5906  if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) {
5907  // Note: TStreamerInfo::Compile() leaves this element
5908  // out of the optimized info, although it does
5909  // exists in the non-compiled and non-optimized info.
5910  // FIXME: The test that TStreamerInfo::Compile() uses
5911  // is element->GetType() < 0, so that is what
5912  // we should do as well.
5913  continue;
5914  }
5915  if (clbase->GetListOfRealData()->GetSize() == 0) {
5916  // Do not create a branch for empty bases.
5917  continue;
5918  }
5919  }
5920  if (dot) {
5921  if (dotlast) {
5922  bname.Form("%s%s", name, element->GetFullName());
5923  } else {
5924  // FIXME: We are in the case where we have a top-level
5925  // branch name that was created by the branch
5926  // constructor which takes a folder as input.
5927  // The internal dots in the name are in place of
5928  // of the original slashes and represent the
5929  // folder hierarchy.
5930  if (isBase) {
5931  // FIXME: This is very strange, this is the only case where
5932  // we create a branch for a base class that does
5933  // not have the base class name in the branch name.
5934  // FIXME: This is also quite bad since classes with two
5935  // or more base classes end up with sub-branches
5936  // that have the same name.
5937  bname = name;
5938  } else {
5939  bname.Form("%s.%s", name, element->GetFullName());
5940  }
5941  }
5942  } else {
5943  // Note: For a base class element, this results in the branchname
5944  // being the name of the base class.
5945  bname.Form("%s", element->GetFullName());
5946  }
5947 
5948  if( splitlevel > TTree::kSplitCollectionOfPointers && element->GetClass() &&
5949  element->GetClass()->GetCollectionProxy() &&
5950  element->GetClass()->GetCollectionProxy()->HasPointers() )
5951  {
5952  TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id );
5953  blist->Add(brSTL);
5954  }
5955  else
5956  {
5957  TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1);
5958  bre->SetParentClass(cl);
5959  blist->Add(bre);
5960  }
5961  }
5962  // Now that we know that this branch is split, let's redo the actions.
5965 }
5966 
5967 ////////////////////////////////////////////////////////////////////////////////
5968 /// Split class cl into sub-branches of this branch.
5969 ///
5970 /// Create a sub-branch of this branch for each non-empty,
5971 /// non-abstract base class of cl (unless we are a sub-branch
5972 /// of a TClonesArray or an STL container, in which case we
5973 /// do *not* create a sub-branch), and for each non-split data
5974 /// member of cl.
5975 ///
5976 /// Note: We do *not* create sub-branches for base classes of cl
5977 /// if we are a sub-branch of a TClonesArray or an STL container.
5978 ///
5979 /// Note: We do *not* create sub-branches for data members which
5980 /// have a class type and which we are splitting.
5981 ///
5982 /// Note: The above rules imply that the branch heirarchy increases
5983 /// in depth only for base classes of cl (unless we are inside
5984 /// of a TClonesArray or STL container, in which case the depth
5985 /// does *not* increase, the base class is elided) and for
5986 /// TClonesArray or STL container data members (which have one
5987 /// additional level of sub-branches). The only other way the
5988 /// depth increases is when the top-level branch has a split
5989 /// class data member, in that case the constructor will create
5990 /// a sub-branch for it. In other words, the interior nodes of
5991 /// the branch tree are all either: base class nodes; split
5992 /// class nodes which are direct sub-branches of top-level nodes
5993 /// (created by TClass::Bronch usually); or TClonesArray or STL
5994 /// container master nodes.
5995 ///
5996 /// Note: The exception to the above is for the top-level branches,
5997 /// Tree::Bronch creates nodes for everything in that case,
5998 /// except for a TObject base class of a class which has the
5999 /// can ignore tobject streamer flag set.
6000 
6001 Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype)
6002 {
6003  //----------------------------------------------------------------------------
6004  // Handling the case of STL collections of pointers
6005  /////////////////////////////////////////////////////////////////////////////
6006 
6007  Int_t splitSTLP = splitlevel - (splitlevel%TTree::kSplitCollectionOfPointers);
6008  splitlevel %= TTree::kSplitCollectionOfPointers;
6009 
6010  TString branchname;
6011 
6012  if ((cl == TObject::Class()) && clParent->CanIgnoreTObjectStreamer()) {
6013  return 0;
6014  }
6015 
6016  TStreamerInfo* sinfo = fTree->BuildStreamerInfo(cl);
6017 
6018  //
6019  // Do nothing if we couldn't build the streamer info for cl.
6020  //
6021 
6022  if (!sinfo) {
6023  return 0;
6024  }
6025 
6026  Int_t ndata = sinfo->GetNelement();
6027 
6028  if ((ndata == 1) && cl->GetCollectionProxy() && !strcmp(sinfo->GetElement(0)->GetName(), "This")) {
6029  // -- Class cl is an STL collection, refuse to split it.
6030  // Question: Why? We certainly could by switching to the value class.
6031  // Partial Answer: Only the branch element constructor can split STL containers.
6032  return 1;
6033  }
6034 
6035  for (Int_t elemID = 0; elemID < ndata; ++elemID) {
6036  // -- Loop over all the streamer elements and create sub-branches as needed.
6037  TStreamerElement* elem = sinfo->GetElement(elemID);
6038  if (elem->IsA() == TStreamerArtificial::Class()) {
6039  continue;
6040  }
6041  if (elem->TestBit(TStreamerElement::kRepeat)) {
6042  continue;
6043  }
6045  continue;
6046  }
6047  Int_t offset = elem->GetOffset();
6048  // FIXME: An STL container as a base class gets TStreamerSTL as its class, so this test is not enough.
6049  // See InitializeOffsets() for the proper test.
6050  if (elem->IsA() == TStreamerBase::Class()) {
6051  // -- This is a base class of cl.
6052  TClass* clOfBase = elem->GetClassPointer();
6053  if (!clOfBase || ((clOfBase->Property() & kIsAbstract) && cl->InheritsFrom(TCollection::Class()))) {
6054  // -- Do nothing if we are one of the abstract collection (we know they have no data).
6055  return -1;
6056  }
6057  if ((btype == 31) || (btype == 41)) {
6058  // -- Elide the base-class sub-branches of a split TClonesArray or STL container.
6059  //
6060  // Note: We are eliding the base class here, that is, we never
6061  // create a branch for it, so the branch heirarchy is not
6062  // complete.
6063  // Note: The clParent parameter is the value class of the
6064  // container which we are splitting. It does not
6065  // appear in the branch heirarchy either.
6066  // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6067  Int_t unroll = -1;
6068  if (!elem->CannotSplit() || clOfBase == TObject::Class()) {
6069  unroll = Unroll(name, clParent, clOfBase, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6070  }
6071  if (unroll < 0) {
6072  // FIXME: We could not split because we are abstract, should we be doing this?
6073  if (strlen(name)) {
6074  branchname.Form("%s.%s", name, elem->GetFullName());
6075  } else {
6076  branchname.Form("%s", elem->GetFullName());
6077  }
6078  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, 0, basketsize, 0, btype);
6079  branch->SetParentClass(clParent);
6080  fBranches.Add(branch);
6081  }
6082  } else if (clOfBase->GetListOfRealData()->GetSize()) {
6083  // -- Create a branch for a non-empty base class.
6084  if (strlen(name)) {
6085  branchname.Form("%s.%s", name, elem->GetFullName());
6086  // Elide the base class name when creating the sub-branches.
6087  // Note: The branch names for sub-branches of a base class branch
6088  // do not represent the full class heirarchy because we do
6089  // this, however it does keep the branch names for the
6090  // inherited data members simple.
6091  TBranchElement* branch = new TBranchElement(this, name, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6092  // Then reset it to the proper name.
6093  branch->SetName(branchname);
6094  branch->SetTitle(branchname);
6095  branch->SetParentClass(clParent);
6096  fBranches.Add(branch);
6097  } else {
6098  branchname.Form("%s", elem->GetFullName());
6099  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6100  branch->SetParentClass(clParent);
6101  fBranches.Add(branch);
6102  }
6103  }
6104  } else {
6105  // -- This is a data member of cl.
6106  if (strlen(name)) {
6107  branchname.Form("%s.%s", name, elem->GetFullName());
6108  } else {
6109  branchname.Form("%s", elem->GetFullName());
6110  }
6111  if ((splitlevel > 1) && ((elem->IsA() == TStreamerObject::Class()) || (elem->IsA() == TStreamerObjectAny::Class()))) {
6112  // -- We are splitting a non-TClonesArray (may inherit from TClonesArray though), non-STL container object.
6113  //
6114  // Ignore an abstract class.
6115  // FIXME: How could an abstract class get here?
6116  // Partial answer: It is a base class. But this is a data member!
6117  TClass* elemClass = elem->GetClassPointer();
6118  if (!elemClass || elemClass->Property() & kIsAbstract) {
6119  return -1;
6120  }
6121  if (elem->CannotSplit()) {
6122  // We are not splitting.
6123  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6124  branch->SetParentClass(clParent);
6125  fBranches.Add(branch);
6126  } else if (elemClass->InheritsFrom(TClonesArray::Class())) {
6127  // Splitting something derived from TClonesArray.
6128  Int_t subSplitlevel = splitlevel-1;
6129  if (btype == 31 || btype == 41 || elem->CannotSplit()) {
6130  // -- We split the sub-branches of a TClonesArray or an STL container only once.
6131  subSplitlevel = 0;
6132  }
6133  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel, btype);
6134  branch->SetParentClass(clParent);
6135  fBranches.Add(branch);
6136  } else {
6137  // Splitting a normal class.
6138  // FIXME: We are eliding the class we are splitting here,
6139  // i.e., we do not create a branch for it, so the
6140  // branch heirarchy does not match the class heirarchy.
6141  // Note: clParent is the class which contains a data member of
6142  // the class type which we are splitting.
6143  // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6144  Int_t unroll = Unroll(branchname, clParent, elemClass, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6145  if (unroll < 0) {
6146  // FIXME: We could not split because we are abstract, should we be doing this?
6147  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6148  branch->SetParentClass(clParent);
6149  fBranches.Add(branch);
6150  }
6151  }
6152  }
6153  else if( elem->GetClassPointer() &&
6154  elem->GetClassPointer()->GetCollectionProxy() &&
6156  splitSTLP && fType != 4 )
6157  {
6158 
6159  TBranchSTL* branch = new TBranchSTL( this, branchname,
6161  basketsize, splitlevel - 1+splitSTLP, sinfo, elemID );
6162  branch->SetAddress( ptr+offset );
6163  fBranches.Add( branch );
6164  }
6165  else if ((elem->IsA() == TStreamerSTL::Class()) && !elem->IsaPointer()) {
6166  // -- We have an STL container.
6167  // Question: What if splitlevel == 0 here?
6168  // Answer: then we should not be here.
6169  Int_t subSplitlevel = splitlevel - 1;
6170  if ((btype == 31) || (btype == 41) || elem->CannotSplit()) {
6171  // -- We split the sub-branches of a TClonesArray or an STL container only once.
6172  subSplitlevel = 0;
6173  }
6174  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel+splitSTLP, btype);
6175  branch->SetParentClass(clParent);
6176  fBranches.Add(branch);
6177  } else if (((btype != 31) && (btype != 41)) && ptr && ((elem->GetClassPointer() == TClonesArray::Class()) || ((elem->IsA() == TStreamerSTL::Class()) && !elem->CannotSplit()))) {
6178  // -- We have a TClonesArray.
6179  // FIXME: We could get a ptr to a TClonesArray here by mistake.
6180  // Question: What if splitlevel == 0 here?
6181  // Answer: then we should not be here.
6182  // Note: ptr may be null in case of a TClonesArray inside another
6183  // TClonesArray or STL container, see the else clause.
6184  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6185  branch->SetParentClass(clParent);
6186  fBranches.Add(branch);
6187  } else {
6188  // -- We are not going to split this element any farther.
6189  TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, 0, basketsize, splitSTLP, btype);
6190  branch->SetType(btype);
6191  branch->SetParentClass(clParent);
6192  fBranches.Add(branch);
6193  }
6194  }
6195  }
6196 
6197  if (!fBranches.IsEmpty()) {
6198  // Refresh this branch's action now that we know whether it is split or not.
6201  }
6202  return 1;
6203 }
6204 
6205 ////////////////////////////////////////////////////////////////////////////////
6206 /// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
6207 /// with the current value of fTree->GetCurrentFile unless this branch has been
6208 /// redirected to a different file. Also update the sub-branches.
6209 
6211 {
6212  // The BranchCount and BranchCount2 are part of higher level branches' list of
6213  // branches.
6214  // if (fBranchCount) fBranchCount->UpdateFile();
6215  // if (fBranchCount2) fBranchCount2->UpdateFile();
6217 }
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:380
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:2519
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:818
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:2872
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:46
virtual void SetAddress(void *add)
Set address of this branch.
Definition: TBranch.cxx:2258
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:89
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)
#define R__unlikely(expr)
Definition: RConfig.h:578
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:99
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:687
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:125
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:1739
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:47
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:1035
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:1847
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:410
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:634
Long64_t GetDebugMin() const
Definition: TTree.h:382
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:190
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:105
Basic string class.
Definition: TString.h:131
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:93
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:104
TString & Prepend(const char *cs)
Definition: TString.h:656
Long64_t * fBasketSeek
[fMaxBaskets] Addresses of baskets on file
Definition: TBranch.h:108
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:106
virtual TList * GetBrowsables()
Returns (and, if 0, creates) browsable objects for this branch See TVirtualBranchBrowsable::FillListO...
Definition: TBranch.cxx:1263
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:87
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.
#define R__LOCKGUARD_IMT(mutex)
void ReadLeavesMemberBranchCount(TBuffer &b)
Read leaves into i/o buffers for this branch.
Int_t fWriteBasket
Last basket number written.
Definition: TBranch.h:86
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:2286
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:430
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:989
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:1839
void ReadLeavesMemberCounter(TBuffer &b)
Read leaves into i/o buffers for this branch.
TString & Append(const char *cs)
Definition: TString.h:559
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:201
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:487
Int_t fMaxBaskets
Maximum number of Baskets so far.
Definition: TBranch.h:90
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:133
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:92
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:2174
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition: TTree.cxx:5017
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:124
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:84
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 void MapObject(const TObject *obj, UInt_t offset=1)
Add object to the fMap container.
Definition: TBufferIO.cxx:163
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:2264
FillLeaves_t fFillLeaves
! Pointer to the FillLeaves implementation to use.
Definition: TBranch.h:127
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:355
Ssiz_t Length() const
Definition: TString.h:405
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:1081
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:1310
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:371
const char * GetFileName() const
Definition: TBranch.h:189
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
Return the fixed length of this leaf.
Definition: TLeaf.h:82
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:2305
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:264
virtual void ReadFloat16(Float_t *f, TStreamerElement *ele=0)=0
TString & Remove(Ssiz_t pos)
Definition: TString.h:668
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:84
#define ClassImp(name)
Definition: Rtypes.h:359
Int_t fReadBasket
! Current basket number when reading
Definition: TBranch.h:94
virtual void ResetAddress()
Reset the address of the branch.
Definition: TBranch.cxx:2227
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:876
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:383
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:357
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:619
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:109
void Browse(TBrowser *b)
Browse this collection (called by TBrowser).
TObjArray * GetListOfLeaves()
Definition: TBranch.h:202
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:113
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:206
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:107
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
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:2133
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:126
Long64_t fReadEntry
! Current entry number when reading
Definition: TBranch.h:95
Int_t fType
branch type
Long64_t GetReadEntry() const
Definition: TBranch.h:192
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:110
TTree * GetTree() const
Definition: TBranch.h:207
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:85
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
Definition: first.py:1
TObjArray fBranches
-> List of Branches of this branch
Definition: TBranch.h:103
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
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
A TTree is a list of TBranches.
Definition: TBranch.h:62
Abstract Interface class describing Streamer information for one class.
Int_t fCompress
Compression level and algorithm.
Definition: TBranch.h:83
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:1917
TString fFileName
Name of file where buffers are stored ("" if in same file as Tree header)
Definition: TBranch.h:114
Base class of the Configurations.
const Bool_t kTRUE
Definition: RtypesCore.h:87
TBranch * fParent
! Pointer to parent branch.
Definition: TBranch.h:111
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:1718
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:390
TRangeDynCast is an adaptater class that allows the typed iteration through a TCollection.
Definition: TCollection.h:411
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
TClass * GetClass() const
virtual TObjArray * GetListOfLeaves()
Definition: TTree.h:410
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:364
virtual void SetAutoDelete(Bool_t autodel=kTRUE)
Set the automatic delete bit.
Definition: TBranch.cxx:2292
char * fAddress
! Address of 1st leaf (variable or object)
Definition: TBranch.h:112