Logo ROOT  
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 {
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.
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())
183 , fClassVersion(sinfo->GetClass()->GetClassVersion())
184 , fID(id)
185 , fType(0)
186 , fStreamerType(-1)
187 , fMaximum(0)
188 , fSTLtype(ROOT::kNotSTL)
189 , fNdata(1)
190 , fBranchCount(0)
191 , fBranchCount2(0)
192 , fInfo(sinfo)
193 , fObject(0)
194 , fOnfileObject(0)
195 , fInit(kTRUE)
196 , fInInitInfo(kFALSE)
197 , fInitOffsets(kFALSE)
198 , fTargetClass(fClassName)
199 , fCurrentClass()
200 , fParentClass()
201 , fBranchClass(sinfo->GetClass())
202 , fClonesClass()
203 , fBranchOffset(0)
204 , fBranchID(-1)
205 , fReadActionSequence(0)
206 , fFillActionSequence(0)
207 , fIterators(0)
208 , fWriteIterators(0)
209 , fPtrIterators(0)
210 {
211  if (tree) {
212  ROOT::TIOFeatures features = tree->GetIOFeatures();
213  SetIOFeatures(features);
214  }
215  Init(tree, 0, bname,sinfo,id,pointer,basketsize,splitlevel,btype);
216 }
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 /// Constructor when the branch object is not a TClonesArray nor an STL container.
220 ///
221 /// If splitlevel > 0 this branch in turn is split into sub-branches.
222 
223 TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
224 : TBranch()
225 , fClassName(sinfo->GetName())
226 , fParentName()
227 , fClonesName()
228 , fCollProxy(0)
229 , fCheckSum(sinfo->GetCheckSum())
230 , fClassVersion(sinfo->GetClass()->GetClassVersion())
231 , fID(id)
232 , fType(0)
233 , fStreamerType(-1)
234 , fMaximum(0)
235 , fSTLtype(ROOT::kNotSTL)
236 , fNdata(1)
237 , fBranchCount(0)
238 , fBranchCount2(0)
239 , fInfo(sinfo)
240 , fObject(0)
241 , fOnfileObject(0)
242 , fInit(kTRUE)
243 , fInInitInfo(kFALSE)
244 , fInitOffsets(kFALSE)
245 , fTargetClass( fClassName )
246 , fCurrentClass()
247 , fParentClass()
248 , fBranchClass(sinfo->GetClass())
249 , fClonesClass()
250 , fBranchOffset(0)
251 , fBranchID(-1)
252 , fReadActionSequence(0)
253 , fFillActionSequence(0)
254 , fIterators(0)
255 , fWriteIterators(0)
256 , fPtrIterators(0)
257 {
258  ROOT::TIOFeatures features = parent->GetIOFeatures();
259  SetIOFeatures(features);
260  Init(parent ? parent->GetTree() : 0, parent, bname,sinfo,id,pointer,basketsize,splitlevel,btype);
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Init when the branch object is not a TClonesArray nor an STL container.
265 ///
266 /// If splitlevel > 0 this branch in turn is split into sub-branches.
267 
268 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)
269 {
270  TString name(bname);
271 
272  // Set our TNamed attributes.
273  SetName(name);
274  SetTitle(name);
275 
276  // Set our TBranch attributes.
277  fSplitLevel = splitlevel;
278  fTree = tree;
279  if (fTree == 0) return;
280  fMother = parent ? parent->GetMother() : this;
281  fParent = parent;
283  fFileName = "";
284 
285  // Clear the bit kAutoDelete to specify that when reading
286  // the object should not be deleted before calling Streamer.
287 
289 
292 
293  //---------------------------------------------------------------------------
294  // Handling the splitting of the STL collections of pointers
295  /////////////////////////////////////////////////////////////////////////////
296 
297  Int_t splitSTLP = splitlevel - (splitlevel%TTree::kSplitCollectionOfPointers);
298  splitlevel %= TTree::kSplitCollectionOfPointers;
299 
300  fCompress = -1;
301  if (fTree->GetDirectory()) {
302  TFile* bfile = fTree->GetDirectory()->GetFile();
303  if (bfile) {
305  }
306  }
307 
308  //
309  // Initialize streamer type and element.
310  //
311 
312  if (id > -1) {
313  // We are *not* a top-level branch.
314  TStreamerElement* element = sinfo->GetElement(id);
315  fStreamerType = element->GetType();
316  }
317 
318  //
319  // Handle varying-length datatypes by allocating an offsets array.
320  //
321  // The fBits part of a TObject is of varying length because the pidf
322  // is streamed only when the TObject is referenced by a TRef.
323  //
324 
325  fEntryOffsetLen = 0;
328  }
329 
330  //
331  // Make sure the basket is big enough to contain the
332  // entry offset array plus 100 bytes of data.
333  //
334 
335  if (basketsize < (100 + fEntryOffsetLen)) {
336  basketsize = 100 + fEntryOffsetLen;
337  }
338  fBasketSize = basketsize;
339 
340  //
341  // Allocate and initialize the basket control arrays.
342  //
343 
347 
348  for (Int_t i = 0; i < fMaxBaskets; ++i) {
349  fBasketBytes[i] = 0;
350  fBasketEntry[i] = 0;
351  fBasketSeek[i] = 0;
352  }
353 
354  // We need to keep track of the counter branch if we have
355  // one, since we cannot set it until we have created our
356  // leaf, which we do last.
357  TBranchElement* brOfCounter = 0;
358 
359  if (id < 0) {
360  // -- We are a top-level branch. Don't split a top-level branch, TTree::Bronch will do that work.
361  if (fBranchClass.GetClass()) {
362  Bool_t hasCustomStreamer = kFALSE;
363  Bool_t canSelfReference = CanSelfReference(fBranchClass);
364  if (fBranchClass.GetClass()->IsTObject()) {
365  if (canSelfReference) SetBit(kBranchObject);
367  } else {
368  if (canSelfReference) SetBit(kBranchAny);
370  }
371  if (hasCustomStreamer) {
372  fType = -1;
373  }
374  }
375  } else {
376  // -- We are a sub-branch of a split object.
377  TStreamerElement* element = sinfo->GetElement(id);
379  // -- If we are an object data member which inherits from TObject,
380  // flag it so that later during i/o we will register the object
381  // with the buffer so that pointers are handled correctly.
382  if (CanSelfReference(fBranchClass)) {
383  if (fBranchClass.GetClass()->IsTObject()) {
385  } else {
387  }
388  }
389  }
390  if (element->IsA() == TStreamerBasicPointer::Class()) {
391  // -- Fixup title with counter if we are a varying length array data member.
393  TString countname;
394  countname = bname;
395  Ssiz_t dot = countname.Last('.');
396  if (dot>=0) {
397  countname.Remove(dot+1);
398  } else {
399  countname = "";
400  }
401  countname += bp->GetCountName();
402  brOfCounter = (TBranchElement *)fTree->GetBranch(countname);
403  countname.Form("%s[%s]",name.Data(),bp->GetCountName());
404  SetTitle(countname);
405 
406  } else if (element->IsA() == TStreamerLoop::Class()) {
407  // -- Fixup title with counter if we are a varying length array data member.
408  TStreamerLoop *bp = (TStreamerLoop *)element;
409  TString countname;
410  countname = bname;
411  Ssiz_t dot = countname.Last('.');
412  if (dot>=0) {
413  countname.Remove(dot+1);
414  } else {
415  countname = "";
416  }
417  countname += bp->GetCountName();
418  brOfCounter = (TBranchElement *)fTree->GetBranch(countname);
419  countname.Form("%s[%s]",name.Data(),bp->GetCountName());
420  SetTitle(countname);
421 
422  }
423 
424  if (splitlevel > 0) {
425  // -- Create sub branches if requested by splitlevel.
426  const char* elemType = element->GetTypeName();
427  TClass *elementClass = element->GetClassPointer();
428  fSTLtype = elementClass ? elementClass->GetCollectionType() : ROOT::kNotSTL;
429  if (element->CannotSplit()) {
430  fSplitLevel = 0;
431  } else if (element->IsA() == TStreamerBase::Class()) {
432  // -- We are a base class element.
433  // Note: This does not include an STL container class which is
434  // being used as a base class because the streamer element
435  // in that case is not the base streamer element it is the
436  // STL streamer element.
437  fType = 1;
438  TClass* clOfElement = element->GetClassPointer();
439  Int_t nbranches = fBranches.GetEntriesFast();
440  // Note: The following code results in base class branches
441  // having two different cases for what their parent
442  // class will be, this is very annoying. It is also
443  // very annoying that the naming conventions for the
444  // sub-branch names are different as well.
445  if (!strcmp(name, clOfElement->GetName())) {
446  // -- If the branch's name is the same as the base class name,
447  // which happens when we are a child branch of a top-level
448  // branch whose name does not end in a dot and also has no
449  // internal dots, elide the branch name, and keep the branch
450  // heirarchy rooted at the ultimate parent, this keeps the base
451  // class part of the branch name from propagating downwards.
452  // FIXME: We are eliding the base class here, creating a break in the branch hierarchy.
453  // Note: We can use parent class (cltop) != branch class (elemClass) to detection elision.
454  Unroll("", fBranchClass.GetClass(), clOfElement, pointer, basketsize, splitlevel+splitSTLP, 0);
457  return;
458  }
459  // If the branch's name is not the same as the base class name,
460  // keep the branch name as a prefix (i.e., continue the branch
461  // heirarchy), but start a new class heirarchy at the base class.
462  //
463  // Note: If the parent branch was created by the branch constructor
464  // which takes a folder as a parameter, then this case will
465  // be used, because the branch name will be the same as the
466  // parent branch name.
467  // Note: This means that the sub-branches of a base class branch
468  // created by TTree::Bronch() have the base class name as
469  // as part of the branch name, while those created by
470  // Unroll() do not, ouch!!!
471  //
472  Unroll(name, clOfElement, clOfElement, pointer, basketsize, splitlevel+splitSTLP, 0);
473  if (strchr(bname, '.')) {
474  // Note: How can this happen?
475  // Answer: This is the case when using the new branch
476  // naming convention where the top-level branch ends in dot.
477  // Note: Well actually not entirely, we could also be a sub-branch
478  // of a split class, even when the top-level branch does not
479  // end in a dot.
480  // Note: Or the top-level branch could have been created by the
481  // branch constructor which takes a folder as input, in which
482  // case the top-level branch name will have internal dots
483  // representing the folder hierarchy.
486  return;
487  }
488  if (nbranches == fBranches.GetEntriesFast()) {
489  // -- 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.
490  if (strlen(bname)) {
491  name.Form("%s.%s", bname, clOfElement->GetName());
492  } else {
493  name.Form("%s", clOfElement->GetName());
494  }
495  SetName(name);
496  SetTitle(name);
497  }
500  return;
501  } else if (element->GetClassPointer() == TClonesArray::Class()) {
502  // -- We are a TClonesArray element.
503  Bool_t ispointer = element->IsaPointer();
504  TClonesArray *clones;
505  if (ispointer) {
506  char **ppointer = (char**)(pointer);
507  clones = (TClonesArray*)(*ppointer);
508  } else {
509  clones = (TClonesArray*)pointer;
510  }
511  // basket->DeleteEntryOffset(); //entryoffset not required for the clonesarray counter
512  fEntryOffsetLen = 0;
513  // ===> Create a leafcount
514  TLeaf* leaf = new TLeafElement(this, name, fID, fStreamerType);
515  fNleaves = 1;
516  fLeaves.Add(leaf);
517  fTree->GetListOfLeaves()->Add(leaf);
518  if (!clones) {
520  return;
521  }
522  TClass* clOfClones = clones->GetClass();
523  if (!clOfClones) {
526  return;
527  }
528  fType = 3;
529  // ===> create sub branches for each data member of a TClonesArray
530  //check that the contained objects class name is part of the element title
531  //This name is mandatory when reading the Tree later on and
532  //the parent class with the pointer to the TClonesArray is not available.
533  fClonesName = clOfClones->GetName();
534  fClonesClass = clOfClones;
535  TString aname;
536  aname.Form(" (%s)", clOfClones->GetName());
537  TString atitle = element->GetTitle();
538  if (!atitle.Contains(aname)) {
539  atitle += aname;
540  element->SetTitle(atitle.Data());
541  }
542  TString branchname( name );
543  branchname += "_";
544  SetTitle(branchname);
545  leaf->SetName(branchname);
546  leaf->SetTitle(branchname);
547  leaf->SetRange(kTRUE);
548  Unroll(name, clOfClones, clOfClones, pointer, basketsize, splitlevel+splitSTLP, 31);
549  BuildTitle(name);
552  return;
553  } else if (((fSTLtype >= ROOT::kSTLvector) && (fSTLtype < ROOT::kSTLend)) || ((fSTLtype > -ROOT::kSTLend) && (fSTLtype <= -ROOT::kSTLvector))) {
554  // -- We are an STL container element.
555  TClass* contCl = elementClass;
556  fCollProxy = contCl->GetCollectionProxy()->Generate();
557  TClass* valueClass = GetCollectionProxy()->GetValueClass();
558  // Check to see if we can split the container.
559  Bool_t cansplit = kTRUE;
560  if (!valueClass) {
561  cansplit = kFALSE;
562  } else if ((valueClass == TString::Class()) || (valueClass == TClass::GetClass("string"))) {
563  cansplit = kFALSE;
564  } else if (GetCollectionProxy()->HasPointers() && !splitSTLP ) {
565  cansplit = kFALSE;
566  } else if (!valueClass->CanSplit() && !(GetCollectionProxy()->HasPointers() && splitSTLP)) {
567  cansplit = kFALSE;
568  } else if (valueClass->GetCollectionProxy()) {
569  // -- A collection was stored in a collection, we choose not to split it.
570  // Note: Splitting it would require extending TTreeFormula
571  // to understand how to access it.
572  cansplit = kFALSE;
573  }
574  if (cansplit) {
575  // -- Do the splitting work if we are allowed to.
576  fType = 4;
577  // Create a leaf for the master branch (the counter).
578  TLeaf *leaf = new TLeafElement(this, name, fID, fStreamerType);
579  fNleaves = 1;
580  fLeaves.Add(leaf);
581  fTree->GetListOfLeaves()->Add(leaf);
582  // Check that the contained objects class name is part of the element title.
583  // This name is mandatory when reading the tree later on and
584  // the parent class with the pointer to the STL container is not available.
585  fClonesName = valueClass->GetName();
586  fClonesClass = valueClass;
587  TString aname;
588  aname.Form(" (%s)", valueClass->GetName());
589  TString atitle = element->GetTitle();
590  if (!atitle.Contains(aname)) {
591  atitle += aname;
592  element->SetTitle(atitle.Data());
593  }
594  TString branchname (name);
595  branchname += "_";
596  SetTitle(branchname);
597  leaf->SetName(branchname);
598  leaf->SetTitle(branchname);
599  leaf->SetRange(kTRUE);
600  // Create sub branches for each data member of an STL container.
601  Unroll(name, valueClass, valueClass, pointer, basketsize, splitlevel+splitSTLP, 41);
602  BuildTitle(name);
605  return;
606  }
607  } else if (!strchr(elemType, '*') && ((fStreamerType == TVirtualStreamerInfo::kObject) || (fStreamerType == TVirtualStreamerInfo::kAny))) {
608  // -- Create sub-branches for members that are classes.
609  //
610  // Note: This can only happen if we were called directly
611  // (usually by TClass::Bronch) because Unroll never
612  // calls us for an element of this type.
613  fType = 2;
614  TClass* clm = elementClass;
615  Int_t err = Unroll(name, clm, clm, pointer, basketsize, splitlevel+splitSTLP, 0);
616  if (err >= 0) {
617  // Return on success.
618  // FIXME: Why not on error too?
621  return;
622  }
623  }
624  }
625  }
626 
627  //
628  // Create a leaf to represent this branch.
629  //
630 
631  TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
632  leaf->SetTitle(GetTitle());
633  fNleaves = 1;
634  fLeaves.Add(leaf);
635  fTree->GetListOfLeaves()->Add(leaf);
636 
637  //
638  // If we have a counter branch set it now that we have
639  // created our leaf, we cannot do it before then.
640  //
641 
642  if (brOfCounter) {
643  SetBranchCount(brOfCounter);
644  }
645 
648 }
649 
650 ////////////////////////////////////////////////////////////////////////////////
651 /// Constructor when the branch object is a TClonesArray.
652 ///
653 /// If splitlevel > 0 this branch in turn is split into sub branches.
654 
655 TBranchElement::TBranchElement(TTree *tree, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress)
656 : TBranch()
657 , fClassName("TClonesArray")
658 , fParentName()
659 , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo())
660 , fInit(kTRUE)
661 , fInInitInfo(kFALSE)
662 , fInitOffsets(kFALSE)
663 , fTargetClass( fClassName )
664 , fCurrentClass()
665 , fParentClass()
666 , fBranchClass(TClonesArray::Class())
667 , fBranchID(-1)
668 , fReadActionSequence(0)
669 , fFillActionSequence(0)
670 , fIterators(0)
671 , fWriteIterators(0)
672 , fPtrIterators(0)
673 {
674  Init(tree, 0, bname, clones, basketsize, splitlevel, compress);
675 }
676 
677 ////////////////////////////////////////////////////////////////////////////////
678 /// Constructor when the branch object is a TClonesArray.
679 ///
680 /// If splitlevel > 0 this branch in turn is split into sub branches.
681 
682 TBranchElement::TBranchElement(TBranch *parent, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress)
683 : TBranch()
684 , fClassName("TClonesArray")
685 , fParentName()
686 , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo())
687 , fInit(kTRUE)
688 , fInInitInfo(kFALSE)
689 , fInitOffsets(kFALSE)
690 , fTargetClass( fClassName )
691 , fCurrentClass()
692 , fParentClass()
693 , fBranchClass(TClonesArray::Class())
694 , fBranchID(-1)
695 , fReadActionSequence(0)
696 , fFillActionSequence(0)
697 , fIterators(0)
698 , fWriteIterators(0)
699 , fPtrIterators(0)
700 {
701  Init(parent ? parent->GetTree() : 0, parent, bname, clones, basketsize, splitlevel, compress);
702 }
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Init when the branch object is a TClonesArray.
706 ///
707 /// If splitlevel > 0 this branch in turn is split into sub branches.
708 
709 void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress)
710 {
711  fCollProxy = 0;
712  fSplitLevel = splitlevel;
713  fID = 0;
714  fInit = kTRUE;
715  fStreamerType = -1;
716  fType = 0;
717  fClassVersion = TClonesArray::Class()->GetClassVersion();
719  fBranchCount = 0;
720  fBranchCount2 = 0;
721  fObject = 0;
722  fOnfileObject = 0;
723  fMaximum = 0;
724  fBranchOffset = 0;
727 
728  fTree = tree;
729  fMother = parent ? parent->GetMother() : this;
730  fParent = parent;
732  fFileName = "";
733 
734  SetName(bname);
735  const char* name = GetName();
736  SetTitle(name);
737  //fClassName = fInfo->GetName();
738  fCompress = compress;
739  if (compress == -1 && fTree->GetDirectory()) {
740  TFile *bfile = fTree->GetDirectory()->GetFile();
741  if (bfile) fCompress = bfile->GetCompressionSettings();
742  }
743 
744  if (basketsize < 100) basketsize = 100;
745  fBasketSize = basketsize;
749 
750  for (Int_t i=0;i<fMaxBaskets;i++) {
751  fBasketBytes[i] = 0;
752  fBasketEntry[i] = 0;
753  fBasketSeek[i] = 0;
754  }
755 
756  // Reset the bit kAutoDelete to specify that when reading
757  // the object should not be deleted before calling the streamer.
759 
760  // create sub branches if requested by splitlevel
761  if (splitlevel%TTree::kSplitCollectionOfPointers > 0) {
762  TClass* clonesClass = clones->GetClass();
763  if (!clonesClass) {
764  Error("Init","Missing class object of the TClonesArray %s\n",clones->GetName());
765  return;
766  }
767  fType = 3;
768  // ===> Create a leafcount
769  TLeaf* leaf = new TLeafElement(this, name, fID, fStreamerType);
770  fNleaves = 1;
771  fLeaves.Add(leaf);
772  fTree->GetListOfLeaves()->Add(leaf);
773  // ===> create sub branches for each data member of a TClonesArray
774  fClonesName = clonesClass->GetName();
775  fClonesClass = clonesClass;
776  std::string branchname = name + std::string("_");
777  SetTitle(branchname.c_str());
778  leaf->SetName(branchname.c_str());
779  leaf->SetTitle(branchname.c_str());
780  Unroll(name, clonesClass, clonesClass, 0, basketsize, splitlevel, 31);
781  BuildTitle(name);
784  return;
785  }
786 
787  if (!clones->GetClass() || CanSelfReference(clones->GetClass())) {
789  }
790  TLeaf *leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
791  leaf->SetTitle(GetTitle());
792  fNleaves = 1;
793  fLeaves.Add(leaf);
794  fTree->GetListOfLeaves()->Add(leaf);
795 
798 }
799 
800 ////////////////////////////////////////////////////////////////////////////////
801 /// Constructor when the branch object is an STL collection.
802 ///
803 /// If splitlevel > 0 this branch in turn is split into sub branches.
804 
805 TBranchElement::TBranchElement(TTree *tree, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress)
806 : TBranch()
807 , fClassName(cont->GetCollectionClass()->GetName())
808 , fParentName()
809 , fInit(kTRUE)
810 , fInInitInfo(kFALSE)
811 , fInitOffsets(kFALSE)
812 , fTargetClass( fClassName )
813 , fCurrentClass()
814 , fParentClass()
815 , fBranchClass(cont->GetCollectionClass())
816 , fBranchID(-1)
817 , fReadActionSequence(0)
818 , fFillActionSequence(0)
819 , fIterators(0)
820 , fWriteIterators(0)
821 , fPtrIterators(0)
822 {
823  Init(tree, 0, bname, cont, basketsize, splitlevel, compress);
824 }
825 
826 ////////////////////////////////////////////////////////////////////////////////
827 /// Constructor when the branch object is an STL collection.
828 ///
829 /// If splitlevel > 0 this branch in turn is split into sub branches.
830 
831 TBranchElement::TBranchElement(TBranch *parent, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress)
832 : TBranch()
833 , fClassName(cont->GetCollectionClass()->GetName())
834 , fParentName()
835 , fInit(kTRUE)
836 , fInInitInfo(kFALSE)
837 , fInitOffsets(kFALSE)
838 , fTargetClass( fClassName )
839 , fCurrentClass()
840 , fParentClass()
841 , fBranchClass(cont->GetCollectionClass())
842 , fBranchID(-1)
843 , fReadActionSequence(0)
844 , fFillActionSequence(0)
845 , fIterators(0)
846 , fWriteIterators(0)
847 , fPtrIterators(0)
848 {
849  Init(parent ? parent->GetTree() : 0, parent, bname, cont, basketsize, splitlevel, compress);
850 }
851 
852 ////////////////////////////////////////////////////////////////////////////////
853 /// Init when the branch object is an STL collection.
854 ///
855 /// If splitlevel > 0 this branch in turn is split into sub branches.
856 
857 void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress)
858 {
859  fCollProxy = cont->Generate();
860  TString name( bname );
861  if (name[name.Length()-1]=='.') {
862  name.Remove(name.Length()-1);
863  }
865  fSplitLevel = splitlevel;
866  fInfo = 0;
867  fID = -1;
868  fInit = kTRUE;
869  fStreamerType = -1; // TVirtualStreamerInfo::kSTLp;
870  fType = 0;
873  fBranchCount = 0;
874  fBranchCount2 = 0;
875  fObject = 0;
876  fOnfileObject = 0;
877  fMaximum = 0;
878  fBranchOffset = 0;
879 
880  //Must be set here so that write actions will be properly matched to the ReadLeavesPtr
881  fSTLtype = cont->GetCollectionType();
882  if (fSTLtype < 0) {
883  fSTLtype = -fSTLtype;
884  }
885 
886  fTree = tree;
887  fMother = parent ? parent->GetMother() : this;
888  fParent = parent;
890  fFileName = "";
891 
892  SetName(name);
893  SetTitle(name);
894  //fClassName = fBranchClass.GetClass()->GetName();
895  fCompress = compress;
896  if ((compress == -1) && fTree->GetDirectory()) {
897  TFile* bfile = fTree->GetDirectory()->GetFile();
898  if (bfile) {
900  }
901  }
902 
903  if (basketsize < 100) {
904  basketsize = 100;
905  }
906  fBasketSize = basketsize;
907 
911 
912  for (Int_t i = 0; i < fMaxBaskets; ++i) {
913  fBasketBytes[i] = 0;
914  fBasketEntry[i] = 0;
915  fBasketSeek[i] = 0;
916  }
917 
918  // Reset the bit kAutoDelete to specify that, when reading,
919  // the object should not be deleted before calling the streamer.
921 
922  // create sub branches if requested by splitlevel
924  (cont->HasPointers() && splitlevel > TTree::kSplitCollectionOfPointers && cont->GetValueClass() && cont->GetValueClass()->CanSplit() ) )
925  {
926  fType = 4;
927  // ===> Create a leafcount
928  TLeaf* leaf = new TLeafElement(this, name, fID, fStreamerType);
929  fNleaves = 1;
930  fLeaves.Add(leaf);
931  fTree->GetListOfLeaves()->Add(leaf);
932  // ===> create sub branches for each data member of an STL container value class
933  TClass* valueClass = cont->GetValueClass();
934  if (!valueClass) {
935  return;
936  }
937  fClonesName = valueClass->GetName();
938  fClonesClass = valueClass;
939  TString branchname( name );
940  branchname += "_";
941  SetTitle(branchname);
942  leaf->SetName(branchname);
943  leaf->SetTitle(branchname);
944  Unroll(name, valueClass, valueClass, 0, basketsize, splitlevel, 41);
945  BuildTitle(name);
948  return;
949  }
950 
951  TLeaf *leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
952  leaf->SetTitle(GetTitle());
953  fNleaves = 1;
954  fLeaves.Add(leaf);
955  fTree->GetListOfLeaves()->Add(leaf);
958 }
959 
960 ////////////////////////////////////////////////////////////////////////////////
961 /// Destructor.
962 
964 {
965  // Release any allocated I/O buffers.
967  delete fOnfileObject;
968  fOnfileObject = 0;
969  }
970  ResetAddress();
971 
972  delete[] fBranchOffset;
973  fBranchOffset = 0;
974 
975  fInfo = 0;
976  fBranchCount2 = 0;
977  fBranchCount = 0;
978 
979  if (fType == 4 || fType == 0) {
980  // Only the top level TBranchElement containing an STL container,
981  // owns the collectionproxy.
982  delete fCollProxy;
983  }
984  fCollProxy = 0;
985 
986  delete fReadActionSequence;
987  delete fFillActionSequence;
988  delete fIterators;
989  delete fWriteIterators;
990  delete fPtrIterators;
991 }
992 
993 //
994 // This function is located here to allow inlining by the optimizer.
995 //
996 ////////////////////////////////////////////////////////////////////////////////
997 /// Get streamer info for the branch class.
998 
1000 {
1001  // Note: we need to find a way to reduce the complexity of
1002  // this often executed condition.
1003  if (!fInfo || (fInfo && (!fInit || !fInfo->IsCompiled()))) {
1004  const_cast<TBranchElement*>(this)->InitInfo();
1005  }
1006  return fInfo;
1007 }
1008 
1009 ////////////////////////////////////////////////////////////////////////////////
1010 /// Get streamer info for the branch class.
1011 
1013 {
1014  return GetInfoImp();
1015 }
1016 
1017 ////////////////////////////////////////////////////////////////////////////////
1018 /// Browse the branch content.
1019 
1021 {
1022  Int_t nbranches = fBranches.GetEntriesFast();
1023  if (nbranches > 0) {
1024  TList persistentBranches;
1025  TBranch* branch=0;
1026  TIter iB(&fBranches);
1027  while((branch=(TBranch*)iB())) {
1028  if (branch->IsFolder()) persistentBranches.Add(branch);
1029  else {
1030  // only show branches corresponding to persistent members
1031  TClass* cl=0;
1032  if (strlen(GetClonesName()))
1033  // this works both for top level branches and for sub-branches,
1034  // as GetClonesName() is properly updated for sub-branches
1035  cl=fClonesClass;
1036  else {
1038 
1039  // check if we're in a sub-branch of this class
1040  // we can only find out asking the streamer given our ID
1041  TStreamerElement *element=0;
1042  TClass* clsub=0;
1043  if (fID>=0 && GetInfoImp()
1044  && GetInfoImp()->IsCompiled()
1045  && ((element=GetInfoImp()->GetElement(fID)))
1046  && ((clsub=element->GetClassPointer())))
1047  cl=clsub;
1048  }
1049  if (cl) {
1050  TString strMember=branch->GetName();
1051  Size_t mempos=strMember.Last('.');
1052  if (mempos!=kNPOS)
1053  strMember.Remove(0, (Int_t)mempos+1);
1054  mempos=strMember.First('[');
1055  if (mempos!=kNPOS)
1056  strMember.Remove((Int_t)mempos);
1057  TDataMember* m=cl->GetDataMember(strMember);
1058  if (!m || m->IsPersistent()) persistentBranches.Add(branch);
1059  } else persistentBranches.Add(branch);
1060  } // branch if not a folder
1061  }
1062  persistentBranches.Browse(b);
1063  // add all public const methods without params
1064  if (GetBrowsables() && GetBrowsables()->GetSize())
1065  GetBrowsables()->Browse(b);
1066  } else {
1067  if (GetBrowsables() && GetBrowsables()->GetSize()) {
1068  GetBrowsables()->Browse(b);
1069  return;
1070  }
1071  // Get the name and strip any extra brackets
1072  // in order to get the full arrays.
1073  TString slash("/");
1074  TString escapedSlash("\\/");
1075  TString name = GetName();
1076  Int_t pos = name.First('[');
1077  if (pos != kNPOS) {
1078  name.Remove(pos);
1079  }
1080  TString mothername;
1081  if (GetMother()) {
1082  mothername = GetMother()->GetName();
1083  pos = mothername.First('[');
1084  if (pos != kNPOS) {
1085  mothername.Remove(pos);
1086  }
1087  Int_t len = mothername.Length();
1088  if (len) {
1089  if (mothername(len-1) != '.') {
1090  // We do not know for sure whether the mother's name is
1091  // already preprended. So we need to check:
1092  // a) it is prepended
1093  // b) it is NOT the name of a daugher (i.e. mothername.mothername exist)
1094  TString doublename = mothername;
1095  doublename.Append(".");
1096  Int_t isthere = (name.Index(doublename) == 0);
1097  if (!isthere) {
1098  name.Prepend(doublename);
1099  } else {
1100  if (GetMother()->FindBranch(mothername)) {
1101  doublename.Append(mothername);
1102  isthere = (name.Index(doublename) == 0);
1103  if (!isthere) {
1104  mothername.Append(".");
1105  name.Prepend(mothername);
1106  }
1107  } else {
1108  // Nothing to do because the mother's name is
1109  // already in the name.
1110  }
1111  }
1112  } else {
1113  // If the mother's name end with a dot then
1114  // the daughter probably already contains the mother's name
1115  if (name.Index(mothername) == kNPOS) {
1116  name.Prepend(mothername);
1117  }
1118  }
1119  }
1120  }
1121  name.ReplaceAll(slash, escapedSlash);
1122  GetTree()->Draw(name, "", b ? b->GetDrawOption() : "");
1123  if (gPad) {
1124  gPad->Update();
1125  }
1126  }
1127 }
1128 
1129 ////////////////////////////////////////////////////////////////////////////////
1130 /// Set branch and leaf name and title in the case of a container sub-branch.
1131 
1133 {
1134  TString branchname;
1135 
1136  Int_t nbranches = fBranches.GetEntries();
1137 
1138  for (Int_t i = 0; i < nbranches; ++i) {
1140  if (fType == 3) {
1141  bre->SetType(31);
1142  } else if (fType == 4) {
1143  bre->SetType(41);
1144  } else {
1145  Error("BuildTitle", "This cannot happen, fType of parent is not 3 or 4!");
1146  }
1147  bre->fCollProxy = GetCollectionProxy();
1148  bre->BuildTitle(name);
1149  const char* fin = strrchr(bre->GetTitle(), '.');
1150  if (fin == 0) {
1151  continue;
1152  }
1153  // The branch counter for a sub-branch of a container is the container master branch.
1154  bre->SetBranchCount(this);
1155  TLeafElement* lf = (TLeafElement*) bre->GetListOfLeaves()->At(0);
1156  // If branch name is of the form fTracks.fCovar[3][4], then
1157  // set the title to fCovar[fTracks_].
1158  branchname = fin+1;
1159  Ssiz_t dim = branchname.First('[');
1160  if (dim>=0) {
1161  branchname.Remove(dim);
1162  }
1163  branchname += TString::Format("[%s_]",name);
1164  bre->SetTitle(branchname);
1165  if (lf) {
1166  lf->SetTitle(branchname);
1167  }
1168  // Is there a secondary branchcount?
1169  //
1170  // fBranchCount2 points to the secondary branchcount
1171  // in case a TClonesArray element itself has a branchcount.
1172  //
1173  // Example: In Event class with TClonesArray fTracks of Track objects.
1174  // if the Track object has two members
1175  // Int_t fNpoint;
1176  // Float_t *fPoints; //[fNpoint]
1177  // In this case the TBranchElement fTracks.fPoints has
1178  // -its primary branchcount pointing to the branch fTracks
1179  // -its secondary branchcount pointing to fTracks.fNpoint
1180  Int_t stype = bre->GetStreamerType();
1181  // FIXME: Should 60 be included here?
1182  if ((stype > 40) && (stype < 61)) {
1183  TString name2 (bre->GetName());
1184  Ssiz_t bn = name2.Last('.');
1185  if (bn<0) {
1186  continue;
1187  }
1189  name2.Remove(bn+1);
1190  if (el) name2 += el->GetCountName();
1192  bre->SetBranchCount2(bc2);
1193  }
1194  bre->SetReadLeavesPtr();
1195  bre->SetFillLeavesPtr();
1196  }
1197 }
1198 
1199 ////////////////////////////////////////////////////////////////////////////////
1200 /// Loop on all leaves of this branch to fill the basket buffer.
1201 ///
1202 /// The function returns the number of bytes committed to the
1203 /// individual branches. If a write error occurs, the number of
1204 /// bytes returned is -1. If no data are written, because, e.g.,
1205 /// the branch is disabled, the number of bytes returned is 0.
1206 ///
1207 /// Note: We not not use any member functions from TLeafElement!
1208 
1210 {
1211  Int_t nbytes = 0;
1212  Int_t nwrite = 0;
1213  Int_t nerror = 0;
1214  Int_t nbranches = fBranches.GetEntriesFast();
1215 
1216  ValidateAddress();
1217 
1218  //
1219  // If we are a top-level branch, update addresses.
1220  //
1221 
1222  if (fID < 0) {
1223  if (!fObject) {
1224  Error("Fill", "attempt to fill branch %s while addresss is not set", GetName());
1225  return 0;
1226  }
1227  }
1228 
1229  //
1230  // If the tree has a TRefTable, set the current branch if
1231  // branch is not a basic type.
1232  //
1233 
1234  // FIXME: This test probably needs to be extended past 10.
1235  if ((fType >= -1) && (fType < 10)) {
1236  TBranchRef* bref = fTree->GetBranchRef();
1237  if (bref) {
1238  fBranchID = bref->SetParent(this, fBranchID);
1239  }
1240  }
1241 
1242  if (!nbranches) {
1243  // No sub-branches.
1244  if (!TestBit(kDoNotProcess)) {
1245  nwrite = TBranch::FillImpl(imtHelper);
1246  if (nwrite < 0) {
1247  Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1248  ++nerror;
1249  } else {
1250  nbytes += nwrite;
1251  }
1252  }
1253  } else {
1254  // We have sub-branches.
1255  if (fType == 3 || fType == 4) {
1256  // TClonesArray or STL container counter
1257  nwrite = TBranch::FillImpl(imtHelper);
1258  if (nwrite < 0) {
1259  Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1260  ++nerror;
1261  } else {
1262  nbytes += nwrite;
1263  }
1264  } else {
1265  ++fEntries;
1266  }
1267  for (Int_t i = 0; i < nbranches; ++i) {
1268  TBranchElement* branch = (TBranchElement*) fBranches[i];
1269  if (!branch->TestBit(kDoNotProcess)) {
1270  nwrite = branch->FillImpl(imtHelper);
1271  if (nwrite < 0) {
1272  Error("Fill", "Failed filling branch:%s.%s, nbytes=%d", GetName(), branch->GetName(), nwrite);
1273  nerror++;
1274  } else {
1275  nbytes += nwrite;
1276  }
1277  }
1278  }
1279  }
1280 
1281  if (fTree->Debug() > 0) {
1282  // Debugging.
1283  Long64_t entry = fEntries;
1284  if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
1285  printf("Fill: %lld, branch=%s, nbytes=%d\n", entry, GetName(), nbytes);
1286  }
1287  }
1288 
1289  if (nerror != 0) {
1290  return -1;
1291  }
1292 
1293  return nbytes;
1294 }
1295 
1296 ////////////////////////////////////////////////////////////////////////////////
1297 /// Write leaves into i/o buffers for this branch.
1298 /// For the case where the branch is set in MakeClass mode (decomposed object).
1299 
1301 {
1302  ValidateAddress();
1303 
1304  //
1305  // Silently do nothing if we have no user i/o buffer.
1306  //
1307 
1308  if (!fObject) {
1309  return;
1310  }
1311 
1312  // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1313  if(fType == 3) {
1314  // fClonesClass can not be zero since we are of type 3, see TBranchElement::Init
1316  if (!si) {
1317  Error("FillLeaves", "Cannot get streamer info for branch '%s' class '%s'", GetName(), fClonesClass->GetName());
1318  return;
1319  }
1320  b.ForceWriteInfo(si,kFALSE);
1321  Int_t* nptr = (Int_t*) fAddress;
1322  b << *nptr;
1323  } else if (fType == 31) {
1324  // -- TClonesArray sub-branch. Write out the entries in the TClonesArray.
1325  // -- A MakeClass() tree, we must use fAddress instead of fObject.
1326  if (!fAddress) {
1327  // FIXME: Enable this message.
1328  //Error("FillLeaves", "Branch address not set for branch '%s'!", GetName());
1329  return;
1330  }
1331  Int_t atype = fStreamerType;
1332  if (atype > 54) {
1333  // Note: We are not supporting kObjectp, kAny, kObjectp,
1334  // kObjectP, kTString, kTObject, kTNamed, kAnyp,
1335  // kAnyP, kSTLp, kSTL, kSTLstring, kStreamer,
1336  // kStreamLoop here, nor pointers to varying length
1337  // arrays of them either.
1338  // Nor do we support pointers to varying length
1339  // arrays of kBits, kLong64, kULong64, nor kBool.
1340  return;
1341  }
1342  Int_t* nn = (Int_t*) fBranchCount->GetAddress();
1343  if (!nn) {
1344  Error("FillLeaves", "The branch counter address was zero!");
1345  return;
1346  }
1347  Int_t n = *nn;
1348  if (atype > 40) {
1349  // Note: We are not supporting pointer to varying length array.
1350  Error("FillLeaves", "Clonesa: %s, n=%d, sorry not supported yet", GetName(), n);
1351  return;
1352  }
1353  if (atype > 20) {
1354  atype -= 20;
1356  n = n * leaf->GetLenStatic();
1357  }
1358  switch (atype) {
1359  // Note: Type 0 is a base class and cannot happen here, see Unroll().
1360  case TVirtualStreamerInfo::kChar /* 1 */: { b.WriteFastArray((Char_t*) fAddress, n); break; }
1361  case TVirtualStreamerInfo::kShort /* 2 */: { b.WriteFastArray((Short_t*) fAddress, n); break; }
1362  case TVirtualStreamerInfo::kInt /* 3 */: { b.WriteFastArray((Int_t*) fAddress, n); break; }
1363  case TVirtualStreamerInfo::kLong /* 4 */: { b.WriteFastArray((Long_t*) fAddress, n); break; }
1364  case TVirtualStreamerInfo::kFloat /* 5 */: { b.WriteFastArray((Float_t*) fAddress, n); break; }
1365  case TVirtualStreamerInfo::kCounter /* 6 */: { b.WriteFastArray((Int_t*) fAddress, n); break; }
1366  // FIXME: We do nothing with type 7 (TVirtualStreamerInfo::kCharStar, char*) here!
1367  case TVirtualStreamerInfo::kDouble /* 8 */: { b.WriteFastArray((Double_t*) fAddress, n); break; }
1368  case TVirtualStreamerInfo::kDouble32 /* 9 */: {
1370  // coverity[returned_null] structurally si->fComp (used in GetElem) can not be null.
1371  TStreamerElement* se = si->GetElement(fID);
1372  Double_t* xx = (Double_t*) fAddress;
1373  for (Int_t ii = 0; ii < n; ++ii) {
1374  b.WriteDouble32(&(xx[ii]),se);
1375  }
1376  break;
1377  }
1378  case TVirtualStreamerInfo::kFloat16 /* 19 */: {
1380  // coverity[dereference] structurally si can not be null.
1382  Float_t* xx = (Float_t*) fAddress;
1383  for (Int_t ii = 0; ii < n; ++ii) {
1384  b.WriteFloat16(&(xx[ii]),se);
1385  }
1386  break;
1387  }
1388  // Note: Type 10 is unused for now.
1389  case TVirtualStreamerInfo::kUChar /* 11 */: { b.WriteFastArray((UChar_t*) fAddress, n); break; }
1390  case TVirtualStreamerInfo::kUShort /* 12 */: { b.WriteFastArray((UShort_t*) fAddress, n); break; }
1391  case TVirtualStreamerInfo::kUInt /* 13 */: { b.WriteFastArray((UInt_t*) fAddress, n); break; }
1392  case TVirtualStreamerInfo::kULong /* 14 */: { b.WriteFastArray((ULong_t*) fAddress, n); break; }
1393  // FIXME: This is wrong!!! TVirtualStreamerInfo::kBits is a variable length type.
1394  case TVirtualStreamerInfo::kBits /* 15 */: { b.WriteFastArray((UInt_t*) fAddress, n); break; }
1395  case TVirtualStreamerInfo::kLong64 /* 16 */: { b.WriteFastArray((Long64_t*) fAddress, n); break; }
1396  case TVirtualStreamerInfo::kULong64 /* 17 */: { b.WriteFastArray((ULong64_t*) fAddress, n); break; }
1397  case TVirtualStreamerInfo::kBool /* 18 */: { b.WriteFastArray((Bool_t*) fAddress, n); break; }
1398  }
1399  }
1400 }
1401 
1402 ////////////////////////////////////////////////////////////////////////////////
1403 /// Write leaves into i/o buffers for this branch.
1404 /// Case of a collection (fType == 4).
1405 
1407 {
1408  // -- STL container top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1409  ValidateAddress();
1410 
1411  //
1412  // Silently do nothing if we have no user i/o buffer.
1413  //
1414 
1415  if (!fObject) {
1416  return;
1417  }
1418 
1420  Int_t n = 0;
1421  // We are in a block so the helper pops as soon as possible.
1423  n = proxy->Size();
1424 
1425  if (n > fMaximum) {
1426  fMaximum = n;
1427  }
1428  b << n;
1429 
1432  } else {
1433  //NOTE: this does not work for not vectors since the CreateIterators expects a TGenCollectionProxy::TStaging as its argument!
1434  //NOTE: and those not work in general yet, since the TStaging object is neither created nor passed.
1435  // We need to review how to avoid the need for a TStaging during the writing.
1438  } else {
1440  }
1441  }
1442 
1443 }
1444 
1445 ////////////////////////////////////////////////////////////////////////////////
1446 /// Write leaves into i/o buffers for this branch.
1447 /// Case of a data member within a collection (fType == 41).
1448 
1450 {
1451  ValidateAddress();
1452 
1453  //
1454  // Silently do nothing if we have no user i/o buffer.
1455  //
1456 
1457  if (!fObject) {
1458  return;
1459  }
1460 
1461  // FIXME: This wont work if a pointer to vector is split!
1463  // Note: We cannot pop the proxy here because we need it for the i/o.
1465  if (!si) {
1466  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1467  return;
1468  }
1469 
1471  R__ASSERT(0!=iter);
1472  b.ApplySequenceVecPtr(*fFillActionSequence,iter->fBegin,iter->fEnd);
1473 }
1474 
1475 ////////////////////////////////////////////////////////////////////////////////
1476 /// Write leaves into i/o buffers for this branch.
1477 /// Case of a data member within a collection (fType == 41).
1478 
1480 {
1481  ValidateAddress();
1482 
1483  //
1484  // Silently do nothing if we have no user i/o buffer.
1485  //
1486 
1487  if (!fObject) {
1488  return;
1489  }
1490 
1491  // FIXME: This wont work if a pointer to vector is split!
1493 
1494  // Note: We cannot pop the proxy here because we need it for the i/o.
1496  if (!si) {
1497  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1498  return;
1499  }
1500 
1502  b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1503 
1504 }
1505 
1506 ////////////////////////////////////////////////////////////////////////////////
1507 /// Write leaves into i/o buffers for this branch.
1508 /// Case of a data member within a collection (fType == 41).
1509 
1511 {
1512  ValidateAddress();
1513 
1514  //
1515  // Silently do nothing if we have no user i/o buffer.
1516  //
1517 
1518  if (!fObject) {
1519  return;
1520  }
1521 
1522  // FIXME: This wont work if a pointer to vector is split!
1524  // Note: We cannot pop the proxy here because we need it for the i/o.
1526  if (!si) {
1527  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1528  return;
1529  }
1530 
1532  R__ASSERT(0!=iter);
1533  b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1534 
1535 }
1536 
1537 ////////////////////////////////////////////////////////////////////////////////
1538 /// Write leaves into i/o buffers for this branch.
1539 /// Case of a data member within a collection (fType == 41).
1540 
1542 {
1543  ValidateAddress();
1544 
1545  //
1546  // Silently do nothing if we have no user i/o buffer.
1547  //
1548 
1549  if (!fObject) {
1550  return;
1551  }
1552 
1553  // FIXME: This wont work if a pointer to vector is split!
1555  // Note: We cannot pop the proxy here because we need it for the i/o.
1557  if (!si) {
1558  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1559  return;
1560  }
1561 
1563  R__ASSERT(0!=iter);
1564  b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1565 
1566 }
1567 
1568 ////////////////////////////////////////////////////////////////////////////////
1569 /// Write leaves into i/o buffers for this branch.
1570 /// Case of a TClonesArray (fType == 3).
1571 
1573 {
1574  // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1575  ValidateAddress();
1576 
1577  //
1578  // Silently do nothing if we have no user i/o buffer.
1579  //
1580 
1581  if (!fObject) {
1582  return;
1583  }
1584 
1585  TClonesArray* clones = (TClonesArray*) fObject;
1586  Int_t n = clones->GetEntriesFast();
1587  if (n > fMaximum) {
1588  fMaximum = n;
1589  }
1590  b << n;
1591 }
1592 
1593 ////////////////////////////////////////////////////////////////////////////////
1594 /// Write leaves into i/o buffers for this branch.
1595 /// Case of a data member within a TClonesArray (fType == 31).
1596 
1598 {
1599  ValidateAddress();
1600 
1601  //
1602  // Silently do nothing if we have no user i/o buffer.
1603  //
1604 
1605  if (!fObject) {
1606  return;
1607  }
1608 
1609  TClonesArray* clones = (TClonesArray*) fObject;
1610  Int_t n = clones->GetEntriesFast();
1612  if (!si) {
1613  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1614  return;
1615  }
1616 
1617  char **arr = (char **)clones->GetObjectRef(0);
1618  char **end = arr + n;
1619  b.ApplySequenceVecPtr(*fFillActionSequence,arr,end);
1620 }
1621 
1622 ////////////////////////////////////////////////////////////////////////////////
1623 /// Write leaves into i/o buffers for this branch.
1624 /// Case of a non TObject, non collection class with a custom streamer
1625 
1627 {
1628  ValidateAddress();
1629 
1630  //
1631  // Silently do nothing if we have no user i/o buffer.
1632  //
1633 
1634  if (!fObject) {
1635  return;
1636  }
1637 
1638  //
1639  // Remember tobjects written to the buffer so that
1640  // pointers are handled correctly later.
1641 
1642  if (TestBit(kBranchObject)) {
1643  b.MapObject((TObject*) fObject);
1644  } else if (TestBit(kBranchAny)) {
1645  b.MapObject(fObject, fBranchClass);
1646  }
1647 
1649 }
1650 
1651 ////////////////////////////////////////////////////////////////////////////////
1652 /// Write leaves into i/o buffers for this branch.
1653 /// For split-class branch, base class branch, data member branch, or top-level branch.
1654 /// which do have a branch count and are not a counter.
1655 
1657 {
1659  /*
1660  ValidateAddress();
1661 
1662  //
1663  // Silently do nothing if we have no user i/o buffer.
1664  //
1665 
1666  if (!fObject) {
1667  return;
1668  }
1669  */
1670 }
1671 
1672 ////////////////////////////////////////////////////////////////////////////////
1673 /// Write leaves into i/o buffers for this branch.
1674 /// For split-class branch, base class branch, data member branch, or top-level branch.
1675 /// which do not have a branch count and are a counter.
1676 
1678 {
1679  ValidateAddress();
1680 
1681  //
1682  // Silently do nothing if we have no user i/o buffer.
1683  //
1684 
1685  if (!fObject) {
1686  return;
1687  }
1688  // -- Top-level, data member, base class, or split class branch.
1689  // 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.
1690  // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1691  // FIXME: What happens with a split base class branch,
1692  // or a split class branch???
1693  TStreamerInfo* si = GetInfoImp();
1694  if (!si) {
1695  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1696  return;
1697  }
1698  // Since info is not null, fFillActionSequence is not null either.
1699  b.ApplySequence(*fFillActionSequence, fObject);
1700  // Int_t n = si->WriteBufferAux(b, &fObject, fID, 1, 0, 0);
1701 
1702  Int_t n = *(Int_t*)(fObject + si->TStreamerInfo::GetElementOffset(fID)); // or GetInfoImp()->GetTypedValue<Int_t>(&fObject, fID, j, -1);
1703  if (n > fMaximum) {
1704  fMaximum = n;
1705  }
1706 
1707 }
1708 
1709 ////////////////////////////////////////////////////////////////////////////////
1710 /// Write leaves into i/o buffers for this branch.
1711 /// For split-class branch, base class branch, data member branch, or top-level branch.
1712 /// which do not have a branch count and are not a counter.
1713 
1715 {
1716  ValidateAddress();
1717 
1718  //
1719  // Silently do nothing if we have no user i/o buffer.
1720  //
1721 
1722  if (!fObject) {
1723  return;
1724  }
1725 
1726  if (TestBit(kBranchObject)) {
1727  b.MapObject((TObject*) fObject);
1728  } else if (TestBit(kBranchAny)) {
1729  b.MapObject(fObject, fBranchClass);
1730  }
1731 
1732  // -- Top-level, data member, base class, or split class branch.
1733  // 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.
1734  // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1735  // FIXME: What happens with a split base class branch,
1736  // or a split class branch???
1737  TStreamerInfo* si = GetInfoImp();
1738  if (!si) {
1739  Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1740  return;
1741  }
1742  // Since info is not null, fFillActionSequence is not null either.
1743  b.ApplySequence(*fFillActionSequence, fObject);
1744 
1745 }
1746 
1747 ////////////////////////////////////////////////////////////////////////////////
1748 /// Remove trailing dimensions and make sure
1749 /// there is a trailing dot.
1750 
1751 static void R__CleanName(std::string &name)
1752 {
1753  if (name[name.length()-1]==']') {
1754  std::size_t dim = name.find_first_of("[");
1755  if (dim != std::string::npos) {
1756  name.erase(dim);
1757  }
1758  }
1759  if (name[name.size()-1] != '.') {
1760  name += '.';
1761  }
1762 }
1763 
1764 ////////////////////////////////////////////////////////////////////////////////
1765 /// Find the immediate sub-branch with passed name.
1766 
1768 {
1769  // The default behavior of TBranch::FindBranch is sometimes
1770  // incorrect if this branch represent a base class, since
1771  // the base class name might or might not be in the name
1772  // of the sub-branches and might or might not be in the
1773  // name being passed.
1774 
1775  if (fID >= 0) {
1777  TStreamerElement* se = si->GetElement(fID);
1778  if (se && se->IsBase()) {
1779  // We allow the user to pass only the last dotted component of the name.
1780  UInt_t len = strlen(name);
1781  std::string longnm;
1782  longnm.reserve(fName.Length()+len+3); // Enough space of fName + name + dots
1783  longnm = fName.Data();
1784  R__CleanName(longnm);
1785  longnm += name;
1786  std::string longnm_parent;
1787  longnm_parent.reserve(fName.Length()+len+3);
1788  longnm_parent = (GetMother()->GetSubBranch(this)->GetName());
1789  R__CleanName(longnm_parent);
1790  longnm_parent += name; // Name without the base class name
1791 
1792  UInt_t namelen = strlen(name);
1793 
1794  TBranch* branch = 0;
1795  Int_t nbranches = fBranches.GetEntries();
1796  for(Int_t i = 0; i < nbranches; ++i) {
1797  branch = (TBranch*) fBranches.UncheckedAt(i);
1798 
1799  const char *brname = branch->GetName();
1800  UInt_t brlen = strlen(brname);
1801  if (brname[brlen-1]==']') {
1802  const char *dim = strchr(brname,'[');
1803  if (dim) {
1804  brlen = dim - brname;
1805  }
1806  }
1807  if (namelen == brlen /* same effective size */
1808  && strncmp(name,brname,brlen) == 0) {
1809  return branch;
1810  }
1811  if (brlen == longnm.length()
1812  && strncmp(longnm.c_str(),brname,brlen) == 0) {
1813  return branch;
1814  }
1815  // This check is specific to base class
1816  if (brlen == longnm_parent.length()
1817  && strncmp(longnm_parent.c_str(),brname,brlen) == 0) {
1818  return branch;
1819  }
1820 
1821  if (namelen>brlen && name[brlen]=='.' && strncmp(name,brname,brlen)==0) {
1822  // The prefix subbranch name match the branch name.
1823  return branch->FindBranch(name+brlen+1);
1824  }
1825  }
1826  }
1827  }
1828  TBranch *result = TBranch::FindBranch(name);
1829  if (!result) {
1830  // Look in base classes if any
1831  Int_t nbranches = fBranches.GetEntries();
1832  for(Int_t i = 0; i < nbranches; ++i) {
1833  TObject *obj = fBranches.UncheckedAt(i);
1834  if(obj->IsA() != TBranchElement :: Class() )
1835  continue;
1836  TBranchElement *br = (TBranchElement*)obj;
1837  TVirtualStreamerInfo* si = br->GetInfoImp();
1838  if (si && br->GetID() >= 0) {
1839  TStreamerElement* se = si->GetElement(br->GetID());
1840  if (se && se->IsBase()) {
1841  result = br->FindBranch(name);
1842  }
1843  }
1844  }
1845  }
1846  return result;
1847 }
1848 
1849 ////////////////////////////////////////////////////////////////////////////////
1850 /// Find the leaf corresponding to the name 'searchname'.
1851 
1853 {
1854  TLeaf *leaf = TBranch::FindLeaf(name);
1855 
1856  if (leaf==0 && GetListOfLeaves()->GetEntries()==1) {
1857  TBranch *br = GetMother()->GetSubBranch( this );
1858  if( br->IsA() != TBranchElement::Class() )
1859  return 0;
1860 
1861  TBranchElement *parent = (TBranchElement*)br;
1862  if (parent==this || parent->GetID()<0 ) return 0;
1863 
1864  TVirtualStreamerInfo* si = parent->GetInfoImp();
1865  TStreamerElement* se = si->GetElement(parent->GetID());
1866 
1867  if (! se->IsBase() ) return 0;
1868 
1869  br = GetMother()->GetSubBranch( parent );
1870  if( br->IsA() != TBranchElement::Class() )
1871  return 0;
1872 
1873  TBranchElement *grand_parent = (TBranchElement*)br;
1874 
1875  std::string longname( grand_parent->GetName() );
1876  R__CleanName(longname);
1877  longname += name;
1878 
1879  std::string leafname( GetListOfLeaves()->At(0)->GetName() );
1880 
1881  if ( longname == leafname ) {
1882  return (TLeaf*)GetListOfLeaves()->At(0);
1883  }
1884  }
1885  return leaf;
1886 }
1887 
1888 ////////////////////////////////////////////////////////////////////////////////
1889 /// Get the branch address.
1890 ///
1891 /// If we are *not* owned by a MakeClass() tree:
1892 ///
1893 /// - If we are a top-level branch, return a pointer
1894 /// - to the pointer to our object.
1895 ///
1896 /// If we are *not* a top-level branch, return a pointer
1897 /// to our object.
1898 ///
1899 /// If we are owned by a MakeClass() tree:
1900 ///
1901 /// - Return a pointer to our object.
1902 
1904 {
1905  ValidateAddress();
1906  return fAddress;
1907 }
1908 
1909 
1910 // For a mother branch of type 3 or 4, find the 'correct' StreamerInfo for the
1911 // content of the collection by find a sub-branch corresponding to a direct data member
1912 // of the containee class (valueClass)
1913 // Default to the current StreamerInfo if none are found.
1914 TStreamerInfo *TBranchElement::FindOnfileInfo(TClass *valueClass, const TObjArray &branches) const
1915 {
1916  TStreamerInfo *localInfo = nullptr;
1917 
1918  // Search for the correct version.
1919  for(auto subbe : TRangeDynCast<TBranchElement>( branches )) {
1920  if (!subbe->fInfo)
1921  subbe->SetupInfo();
1922  if (valueClass == subbe->fInfo->GetClass()) { // Use GetInfo to provoke its creation.
1923  localInfo = subbe->fInfo;
1924  break;
1925  }
1926  }
1927  if (!localInfo) {
1928  // This is likely sub-optimal as we really should call GetFile but it is non-const.
1929  auto file = fDirectory ? fDirectory->GetFile() : nullptr;
1930  if (file && file->GetSeekInfo()) {
1931  localInfo = (TStreamerInfo*)file->GetStreamerInfoCache()->FindObject(valueClass->GetName());
1932  if (localInfo) {
1933  if (valueClass->IsVersioned()) {
1934  localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1935  } else {
1936  localInfo = (TStreamerInfo*)valueClass->FindStreamerInfo(localInfo->GetCheckSum());
1937  if (localInfo) {
1938  // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
1939  localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1940  }
1941  }
1942  }
1943  }
1944  }
1945  if (!localInfo)
1946  localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo();
1947 
1948  if (localInfo) {
1949  // See if we need any conversion.
1950  TClass *targetValueClass = fInfo->GetClass()->GetCollectionProxy()
1952  : nullptr;
1953  // For TClonesArray, the rest of the code probably does not support change in
1954  // value class, but if it does, we would have to look up the target value class
1955  // in the TClonesArray instance.
1956  // if (type == 3 && instance) targetValueClass = ((TClonesArray*)instance)->GetClass();
1957 
1958  if (targetValueClass && localInfo->GetClass() != targetValueClass) {
1959  localInfo = (TStreamerInfo*)targetValueClass->GetConversionStreamerInfo(localInfo->GetClass(),
1960  localInfo->GetClassVersion());
1961  }
1962  }
1963  return localInfo;
1964 }
1965 
1966 namespace {
1967 static void GatherArtificialElements(const TObjArray &branches, TStreamerInfoActions::TIDs &ids, TString prefix, TStreamerInfo *info, Int_t offset) {
1968  size_t ndata = info->GetNelement();
1969  for (size_t i =0; i < ndata; ++i) {
1970  TStreamerElement *nextel = info->GetElement(i);
1971 
1972  if (nextel->GetType() == TStreamerInfo::kCacheDelete
1973  || nextel->GetType() == TStreamerInfo::kCacheNew) {
1974  continue;
1975  }
1976 
1977  TString ename = prefix + nextel->GetName();
1978 
1979  if (ename[0]=='*')
1980  ename.Remove(0,1);
1981 
1982  Ssiz_t pos;
1983  while ((pos = ename.Last('[')) != TString::kNPOS) {
1984  ename = ename.Remove(pos);
1985  }
1986 
1987  TBranchElement *be = (TBranchElement*)branches.FindObject(ename);
1988  if (nextel->IsA() == TStreamerArtificial::Class()
1989  && be == nullptr) {
1990 
1991  ids.push_back(i);
1992  ids.back().fElement = nextel;
1993  ids.back().fInfo = info;
1994  }
1995 
1996  if (nextel->CannotSplit() || nextel->IsTransient() || nextel->GetOffset() == TStreamerInfo::kMissing)
1997  continue;
1998 
1999  if (!be && nextel->IsBase()) {
2000  // We could be in the case of a branch created from a Folder or
2001  // a top level branch with a non-trailing dot in its name (case inadvertently confused with the folder case).
2002  // In those case, the name of the base class is *not* used to create the corresponding branch.
2003  TString subprefix(prefix);
2004  if (subprefix.Length() && subprefix[subprefix.Length()-1] == '.')
2005  subprefix.Remove(subprefix.Length()-1);
2006 
2007  be = (TBranchElement*)branches.FindObject(subprefix);
2008  if (be) {
2009  // There is at least 'one' base class branch all with the same name, so let's find the
2010  // right one.
2011  TClass *expectedClass = nullptr;
2012  EDataType expectedType;
2013  if (0 != be->GetExpectedType(expectedClass,expectedType)
2014  || expectedClass != nextel->GetClassPointer())
2015  {
2016  be = nullptr;
2017  Int_t nbranches = branches.GetEntriesFast();
2018  for (Int_t bi = 0; bi < nbranches; ++bi) {
2019  TBranchElement* branch = (TBranchElement*) branches[bi];
2020  if (subprefix != branch->GetName())
2021  continue;
2022  if (0 == branch->GetExpectedType(expectedClass,expectedType)
2023  && expectedClass == nextel->GetClassPointer())
2024  {
2025  be = branch;
2026  break;
2027  }
2028  }
2029  } // else we have already found the right branch.
2030  }
2031  }
2032 
2033  TClass *elementClass = nextel->GetClassPointer();
2034  if (elementClass && (!be || be->GetType() == -2)) {
2035  // Recurse on sub-objects.
2036  TStreamerInfo *nextinfo = nullptr;
2037 
2038  // nextinfo_version = ....
2039  auto search = be ? be->GetListOfBranches() : &branches;
2040  TVirtualArray *onfileObject = nullptr;
2041  for(auto subbe : TRangeDynCast<TBranchElement>( *search )) {
2042 
2043  if (elementClass == subbe->GetInfo()->GetClass()) { // Use GetInfo to provoke its creation.
2044  nextinfo = subbe->GetInfo();
2045  onfileObject = subbe->GetOnfileObject();
2046  break;
2047  }
2048  }
2049  if (!nextinfo) {
2050  nextinfo = (TStreamerInfo *)elementClass->GetStreamerInfo();
2051  if (elementClass->GetCollectionProxy() && elementClass->GetCollectionProxy()->GetValueClass()) {
2052  nextinfo = (TStreamerInfo *)elementClass->GetCollectionProxy()->GetValueClass()->GetStreamerInfo(); // NOTE: need to find the right version
2053  }
2054  }
2055  ids.emplace_back(nextinfo, offset + nextel->GetOffset());
2056  if (!onfileObject && nextinfo && nextinfo->GetNelement() && nextinfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew) {
2057  onfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), 1 /* is that always right? */ );
2058  ids.back().fNestedIDs->fOwnOnfileObject = kTRUE;
2059  }
2060  ids.back().fNestedIDs->fOnfileObject = onfileObject;
2061  TString subprefix;
2062  if (prefix.Length() && nextel->IsA() == TStreamerBase::Class()) {
2063  // We skip the name of the base class if there is already a prefix.
2064  // See TBranchElement::Unroll
2065  subprefix = prefix;
2066  } else {
2067  subprefix = ename + ".";
2068  }
2069  GatherArtificialElements(branches, ids.back().fNestedIDs->fIDs, subprefix, nextinfo, offset + nextel->GetOffset());
2070  if (ids.back().fNestedIDs->fIDs.empty())
2071  ids.pop_back();
2072  }
2073  }
2074 };
2075 } // Anonymous namespace.
2076 
2077 
2078 ////////////////////////////////////////////////////////////////////////////////
2079 /// Set the value of fInfo. This is part one of InitInfo.
2080 /// To be used as:
2081 /// if (!fInfo)
2082 /// SetupInfo();
2083 /// It would only be used within InitInfo (and its callees)
2084 
2086 {
2087  // We did not already have streamer info, so now we must find it.
2088  TClass* cl = fBranchClass.GetClass();
2089 
2090  //------------------------------------------------------------------------
2091  // Check if we're dealing with the name change
2092  //////////////////////////////////////////////////////////////////////////
2093 
2094  TClass* targetClass = 0;
2095  if( fTargetClass.GetClassName()[0] ) {
2096  targetClass = fTargetClass;
2097  if (!targetClass && GetCollectionProxy()) {
2098  // We are in the case where the branch holds a custom collection
2099  // proxy but the dictionary is not loaded, calling
2100  // GetCollectionProxy had the side effect of creating the TClass
2101  // corresponding to this emulated collection.
2102  targetClass = fTargetClass;
2103  }
2104  if ( !targetClass ) {
2105  Error( "InitInfo", "The target class dictionary is not present!" );
2106  return;
2107  }
2108  } else {
2109  targetClass = cl;
2110  }
2111  if (cl) {
2112  //---------------------------------------------------------------------
2113  // Get the streamer info for given version
2114  ///////////////////////////////////////////////////////////////////////
2115 
2116  {
2117  if ( (cl->Property() & kIsAbstract) && cl == targetClass) {
2118  TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this);
2119  if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
2120  // Our parent's class is emulated and we represent an abstract class.
2121  // and the target class has not been set explicilty.
2122  TString target = cl->GetName();
2123  target += "@@emulated";
2124  fTargetClass.SetName(target);
2125 
2126  if (!fTargetClass) {
2128  }
2129  targetClass = fTargetClass;
2130  }
2131  }
2132  if( targetClass != cl ) {
2134  } else {
2136  }
2137  }
2138 
2139  // FIXME: Check that the found streamer info checksum matches our branch class checksum here.
2140  // Check to see if the class code was unloaded/reloaded
2141  // since we were created.
2143  if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) {
2144  // Try to compensate for a class that got unloaded on us.
2145  // Search through the streamer infos by checksum
2146  // and take the first match.
2147 
2148  TStreamerInfo* info;
2149  if( targetClass != cl )
2150  info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum );
2151  else {
2152  info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum );
2153  if (info) {
2154  // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
2155  info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion());
2156  }
2157  }
2158  if( info ) {
2159  fInfo = info;
2160  // We no longer reset the class version so that in case the user is passing us later
2161  // the address of a class that require (another) Conversion we can find the proper
2162  // StreamerInfo.
2163  // fClassVersion = fInfo->GetClassVersion();
2164  }
2165  }
2166  }
2167 }
2168 
2169 
2170 ////////////////////////////////////////////////////////////////////////////////
2171 /// Init the streamer info for the branch class, try to compensate for class
2172 /// code unload/reload and schema evolution.
2173 
2175 {
2176  if (!fInfo)
2177  SetupInfo();
2178 
2179  //
2180  // Fixup cached streamer info if necessary.
2181  //
2182  // FIXME: What if the class code was unloaded/reloaded since we were cached?
2183 
2184  if (fInfo) {
2185 
2186  if (!fInfo->IsCompiled()) {
2187  // Streamer info has not yet been compiled.
2188 
2189  Error("InitInfo","StreamerInfo is not compiled.");
2190  }
2191  // return immediately if we are called recursively.
2192  if (fInInitInfo)
2193  return;
2194  fInInitInfo = kTRUE;
2195  if (!fInit) {
2196  // We were read in from a file, figure out what our fID should be,
2197  // schema evolution must be considered.
2198  //
2199  // Force our fID to be the id of the first streamer element that matches our name.
2200  //
2201  auto SetOnfileObject = [this](TStreamerInfo *info) {
2202  Int_t arrlen = 1;
2203  if (fType==31 || fType==41) {
2204  TLeaf *leaf = (TLeaf*)fLeaves.At(0);
2205  if (leaf) {
2206  arrlen = leaf->GetMaximum();
2207  }
2208  }
2209  Bool_t toplevel = (fType == 3 || fType == 4 || (fType == 0 && fID == -2));
2210  Bool_t seenExisting = kFALSE;
2211 
2212  fOnfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), arrlen );
2213  // Propage this to all the other branch of this type.
2214  TObjArray *branches = toplevel ? GetListOfBranches() : GetMother()->GetSubBranch(this)->GetListOfBranches();
2215  Int_t nbranches = branches->GetEntriesFast();
2216  TBranchElement *lastbranch = this;
2217 
2218  TClass *currentClass = fBranchClass;
2219  auto currentVersion = fClassVersion;
2220  if (toplevel) {
2221  // Note: Fragile/wrong when using conversion StreamerInfo?
2222  currentClass = info->GetClass();
2223  currentVersion = info->GetClassVersion();
2224  }
2225 
2226  for (Int_t i = 0; i < nbranches; ++i) {
2227  TBranchElement* subbranch = (TBranchElement*)branches->At(i);
2228  Bool_t match = kFALSE;
2229  if (this != subbranch) {
2230 
2231  if (!subbranch->fInfo)
2232  subbranch->SetupInfo();
2233 
2234  if (subbranch->fInfo == info)
2235  match = kTRUE;
2236  else if (subbranch->fInfo == nullptr && subbranch->fBranchClass == currentClass) {
2237  if (!toplevel) {
2238  if (subbranch->fCheckSum == fCheckSum)
2239  match = kTRUE;
2240  } else {
2241  if (!subbranch->fBranchClass->IsForeign() && subbranch->fClassVersion == currentVersion)
2242  match = kTRUE;
2243  else if (subbranch->fCheckSum == info->GetCheckSum()) {
2244  match = kTRUE;
2245  }
2246  }
2247  }
2248  }
2249  if (match) {
2250  if (subbranch->fOnfileObject && subbranch->fOnfileObject != fOnfileObject) {
2251  if (seenExisting) {
2252  Error("SetOnfileObject (lambda)", "2 distincts fOnfileObject are in the hierarchy of %s for type %s",
2253  toplevel ? GetName() : GetMother()->GetSubBranch(this)->GetName(), info->GetName());
2254  } else {
2255  delete fOnfileObject;
2256  fOnfileObject = subbranch->fOnfileObject;
2257  seenExisting = kTRUE;
2258  }
2259  }
2260  subbranch->fOnfileObject = fOnfileObject;
2261  lastbranch = subbranch;
2262  }
2263  }
2264  if (toplevel) {
2266  if (lastbranch != this)
2267  lastbranch->ResetBit(kOwnOnfileObj);
2268  } else {
2269  lastbranch->SetBit(kOwnOnfileObj);
2270  }
2271  };
2272  if (GetID() > -1) {
2273  // We are *not* a top-level branch.
2274  std::string s(GetName());
2275  size_t pos = s.rfind('.');
2276  if (pos != std::string::npos) {
2277  s = s.substr(pos+1);
2278  }
2279  while ((pos = s.rfind('[')) != std::string::npos) {
2280  s = s.substr(0, pos);
2281  }
2282  int offset = 0;
2283  TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
2284  if (elt && offset!=TStreamerInfo::kMissing) {
2285  size_t ndata = fInfo->GetNelement();
2286  fNewIDs.clear();
2287  for (size_t i = 0; i < ndata; ++i) {
2288  if (fInfo->GetElement(i) == elt) {
2290  && (i+1) < ndata
2291  && s == fInfo->GetElement(i)->GetName())
2292  {
2293  // If the TStreamerElement we found is storing the information in the
2294  // cache and is a repeater, we need to use the real one (the next one).
2295  // (At least until the cache/repeat mechanism is properly handle by
2296  // ReadLeaves).
2297  // fID = i+1;
2298  fID = i;
2299  if (fType != 2) {
2300  if (elt->TestBit(TStreamerElement::kRepeat)) {
2301  fNewIDs.push_back(fID+1);
2302  fNewIDs.back().fElement = fInfo->GetElement(i+1);
2303  fNewIDs.back().fInfo = fInfo;
2304  } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) {
2305  fNewIDs.push_back(fID+1);
2306  fNewIDs.back().fElement = fInfo->GetElement(i+1);
2307  fNewIDs.back().fInfo = fInfo;
2308  }
2309  }
2310  } else {
2311  fID = i;
2312  }
2313  if (elt->TestBit (TStreamerElement::kCache)) {
2315  }
2316  break;
2317  }
2318  }
2319  for (size_t i = fID+1+(fNewIDs.size()); i < ndata; ++i) {
2320  TStreamerElement *nextel = fInfo->GetElement(i);
2321 
2322  std::string ename = nextel->GetName();
2323  if (ename[0] == '*')
2324  ename = ename.substr(1);
2325 
2326  while ((pos = ename.rfind('[')) != std::string::npos) {
2327  ename = ename.substr(0, pos);
2328  }
2329 
2330  if (s != ename) {
2331  // We moved on to the next set
2332  break;
2333  }
2334  // Add all (and only) the Artificial Elements that follows this StreamerInfo.
2335  // fprintf(stderr,"%s/%d[%zu] passing trhough %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2336  if (fType==31||fType==41) {
2337  // The nested objects are unfolded and their branch can not be used to
2338  // execute StreamerElements of this StreamerInfo.
2339  if ((nextel->GetType() == TStreamerInfo::kObject
2340  || nextel->GetType() == TStreamerInfo::kAny)
2341  && nextel->GetClassPointer()->CanSplit())
2342  {
2343  continue;
2344  }
2345  }
2346  if (nextel->GetOffset() == TStreamerInfo::kMissing) {
2347  // This element will be 'skipped', it's TBranchElement's fObject will null
2348  // and thus can not be used to execute the artifical StreamerElements
2349  continue;
2350  }
2351  if (nextel->IsA() != TStreamerArtificial::Class()
2352  || nextel->GetType() == TStreamerInfo::kCacheDelete ) {
2353  continue;
2354  }
2355  // NOTE: We should verify that the rule's source are 'before'
2356  // or 'at' this branch.
2357  // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2358  fNewIDs.push_back(i);
2359  fNewIDs.back().fElement = nextel;
2360  fNewIDs.back().fInfo = fInfo;
2361  }
2362  } else if (elt && offset==TStreamerInfo::kMissing) {
2363  // Still re-assign fID properly.
2364  fNewIDs.clear();
2365  size_t ndata = fInfo->GetNelement();
2366  for (size_t i = 0; i < ndata; ++i) {
2367  if (fInfo->GetElement(i) == elt) {
2368  fID = i;
2369  break;
2370  }
2371  }
2372  } else {
2373  // We have not even found the element .. this is strange :(
2374  // fNewIDs.clear();
2375  // fID = -3;
2376  // SetBit(kDoNotProcess);
2377  }
2378  if (fOnfileObject==0 && (fType==31 || fType==41 || (0 <= fType && fType <=2) ) && fInfo->GetNelement()
2380  {
2381  SetOnfileObject(fInfo);
2382  }
2383  }
2384  if (fType == 3 || fType == 4 || (fType == 0 && fID == -2)) {
2385  // Need to add the rule targetting transient members.
2386  TStreamerInfo *localInfo = fInfo;
2387  if (fType == 3 || fType == 4) {
2388  // Don't we have real version information?
2389  // Not unless there is a subbranch with a non-split element of the class.
2390  // Search for the correct version.
2391  localInfo = FindOnfileInfo(fClonesClass, fBranches);
2392  }
2393 
2394  TString prefix(GetName());
2395  if (prefix[prefix.Length()-1] != '.') {
2396  if (fType == 3 || fType == 4 || prefix.Index('.') != TString::kNPOS) {
2397  prefix += ".";
2398  } else {
2399  prefix = "";
2400  }
2401  }
2402  fNewIDs.clear();
2403 
2404  GatherArtificialElements(fBranches, fNewIDs, prefix, localInfo, 0);
2405 
2406  if (!fNewIDs.empty() && fOnfileObject == nullptr && localInfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew)
2407  {
2408  SetOnfileObject(localInfo);
2409  }
2410 
2411  }
2412  fInit = kTRUE;
2413 
2414  // Get the action sequence we need to copy for reading.
2417  } else if (!fReadActionSequence) {
2418  // Get the action sequence we need to copy for reading.
2421  }
2422  SetReadLeavesPtr();
2423  SetFillLeavesPtr();
2424  fInInitInfo = kFALSE;
2425  }
2426 }
2427 
2428 ////////////////////////////////////////////////////////////////////////////////
2429 /// Return the collection proxy describing the branch content, if any.
2430 
2432 {
2433  if (fCollProxy) {
2434  return fCollProxy;
2435  }
2436  TBranchElement* thiscast = const_cast<TBranchElement*>(this);
2437  if (fType == 4) {
2438  // STL container top-level branch.
2439  const char* className = 0;
2440  TClass* cl = nullptr;
2441  if (fID < 0) {
2442  // We are a top-level branch.
2443  if (fBranchClass.GetClass()) {
2444  cl = fBranchClass.GetClass();
2445  }
2446  } else {
2447  // We are not a top-level branch.
2448  TVirtualStreamerInfo* si = thiscast->GetInfoImp();
2449  if (fCollProxy) {
2450  // The GetInfo set fProxy for us, let's not
2451  // redo it; the value of fCollProxy is possibly
2452  // used/recorded is the actions sequences, so
2453  // if we change it here, we would need to propagate
2454  // the change.
2455  return fCollProxy;
2456  }
2457  TStreamerElement* se = si->GetElement(fID);
2458  cl = se->GetClassPointer();
2459  }
2460  if (!cl) {
2461  // The TClass was not created but we do know (since it
2462  // is used as a collection) that it 'className' was a
2463  // class, so let's create it by hand!.
2464 
2465  if (fID < 0) {
2468  className = cl->GetName();
2469  } else {
2470  cl = new TClass(className, fClassVersion);
2472  className = cl->GetName();
2473  }
2474  }
2476  if (!proxy) {
2477  // humm, we must have an older file with a custom collection
2478  // let's try to work-around it.
2479  TString equiv;
2480  equiv.Form("vector<%s>",fClonesName.Data());
2481  TClass *clequiv = TClass::GetClass(equiv);
2482  proxy = clequiv->GetCollectionProxy();
2483  if (!proxy) {
2484  Fatal("GetCollectionProxy",
2485  "Can not create a Collection Proxy of any kind for the class \"%s\" needed by the branch \"%s\" of the TTree \"%s\"!",
2486  className, GetName(), GetTree()->GetName());
2487  }
2488  if (gDebug > 0) Info("GetCollectionProxy",
2489  "Fixing the collection proxy of the class \"%s\" \n"
2490  "\tneeded by the branch \"%s\" of the TTree \"%s\" to be similar to \"%s\".",
2491  className, GetName(), GetTree()->GetName(),equiv.Data());
2492  cl->CopyCollectionProxy( *proxy );
2493  }
2494  fCollProxy = proxy->Generate();
2495  fSTLtype = proxy->GetCollectionType();
2496  } else if (fType == 41) {
2497  // STL container sub-branch.
2499  }
2500  return fCollProxy;
2501 }
2502 
2503 ////////////////////////////////////////////////////////////////////////////////
2504 /// Return a pointer to the current type of the data member corresponding to branch element.
2505 
2507 {
2508  TClass* cl = fCurrentClass;
2509  if (cl) {
2510  return cl;
2511  }
2512 
2513  TStreamerInfo* brInfo = (TStreamerInfo*)GetInfoImp();
2514  if (!brInfo) {
2516  R__ASSERT(cl && cl->GetCollectionProxy());
2517  fCurrentClass = cl;
2518  return cl;
2519  }
2520  TClass* motherCl = brInfo->GetClass();
2521  if (motherCl->GetCollectionProxy()) {
2522  cl = motherCl->GetCollectionProxy()->GetCollectionClass();
2523  if (cl) {
2524  fCurrentClass = cl;
2525  }
2526  return cl;
2527  }
2528  if (GetID() < 0 || GetID()>=brInfo->GetNelement()) {
2529  return 0;
2530  }
2531  TStreamerElement* currentStreamerElement = brInfo->GetElement(GetID());
2532  TDataMember* dm = (TDataMember*) motherCl->GetListOfDataMembers()->FindObject(currentStreamerElement->GetName());
2533 
2534  TString newType;
2535  if (!dm) {
2536  // Either the class is not loaded or the data member is gone
2537  if (!motherCl->IsLoaded()) {
2538  TVirtualStreamerInfo* newInfo = motherCl->GetStreamerInfo();
2539  if (newInfo != brInfo) {
2540  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(currentStreamerElement->GetName());
2541  if (newElems) {
2542  if (newElems->GetClassPointer())
2543  newType = newElems->GetClassPointer()->GetName();
2544  else
2545  newType = newElems->GetTypeName();
2546  }
2547  }
2548  if (newType.Length()==0) {
2549  if (currentStreamerElement->GetClassPointer())
2550  newType = currentStreamerElement->GetClassPointer()->GetName();
2551  else
2552  newType = currentStreamerElement->GetTypeName();
2553  }
2554  }
2555  } else {
2556  newType = dm->GetTypeName();
2557  }
2558  cl = TClass::GetClass(newType);
2559  if (cl) {
2560  fCurrentClass = cl;
2561  }
2562  return cl;
2563 }
2564 
2565 ////////////////////////////////////////////////////////////////////////////////
2566 /// Read all branches of a BranchElement and return total number of bytes.
2567 ///
2568 /// - If entry = 0, then use current entry number + 1.
2569 /// - If entry < 0, then reset entry number to 0.
2570 ///
2571 /// Returns the number of bytes read from the input buffer.
2572 /// - If entry does not exist, then returns 0.
2573 /// - If an I/O error occurs, then returns -1.
2574 ///
2575 /// See IMPORTANT REMARKS in TTree::GetEntry.
2576 
2578 {
2579  // Remember which entry we are reading.
2580  fReadEntry = entry;
2581 
2582  // If our tree has a branch ref, make it remember the entry and
2583  // this branch. This allows a TRef::GetObject() call done during
2584  // the following I/O operation, for example in a custom streamer,
2585  // to search for the referenced object in the proper element of the
2586  // proper branch.
2587  TBranchRef* bref = fTree->GetBranchRef();
2588  if (R__unlikely(bref)) {
2589  R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2590  fBranchID = bref->SetParent(this, fBranchID);
2591  bref->SetRequestedEntry(entry);
2592  }
2593 
2594  Int_t nbytes = 0;
2595 
2596  if (R__unlikely(IsAutoDelete())) {
2599  } else {
2601  R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2603  }
2604  }
2605 
2606  Int_t nbranches = fBranches.GetEntriesFast();
2607  if (nbranches) {
2608  // -- Branch has daughters.
2609  // One must always read the branch counter.
2610  // In the case when one reads consecutively twice the same entry,
2611  // the user may have cleared the TClonesArray between the GetEntry calls.
2612  if ((fType == 3) || (fType == 4)) {
2613  Int_t nb = TBranch::GetEntry(entry, getall);
2614  if (nb < 0) {
2615  return nb;
2616  }
2617  nbytes += nb;
2618  }
2619  switch(fSTLtype) {
2620  case ROOT::kSTLset:
2621  case ROOT::kSTLmultiset:
2624  case ROOT::kSTLmap:
2625  case ROOT::kSTLmultimap:
2628  break;
2629  default:
2630  ValidateAddress(); // There is no ReadLeave for this node, so we need to do the validation here.
2631  for (Int_t i = 0; i < nbranches; ++i) {
2632  TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2633  Int_t nb = branch->GetEntry(entry, getall);
2634  if (nb < 0) {
2635  return nb;
2636  }
2637  nbytes += nb;
2638  }
2639  break;
2640  }
2642  if (fType == 3) {
2643  // Apply the unattached rules; by definition they do not need any
2644  // input from a buffer.
2646 
2647  auto ndata = GetNdata();
2648 
2649  TClonesArray* clones = (TClonesArray*) fObject;
2650  if (clones->IsZombie()) {
2651  return -1;
2652  }
2653  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2654 
2655  char **arr = (char **)clones->GetObjectRef();
2656  char **end = arr + fNdata;
2657 
2658  b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
2659  } else if (fType == 4) {
2660  // Apply the unattached rules; by definition they do not need any
2661  // input from a buffer.
2663 
2664  auto ndata = GetNdata();
2665 
2666  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2669 
2671  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
2672  } else {
2673  // Apply the unattached rules; by definition they do not need any
2674  // input from a buffer.
2676  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
2677  b.ApplySequence(*fReadActionSequence, fObject);
2678  }
2679  }
2680  } else {
2681  // -- Terminal branch.
2682  if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
2683  Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
2684  if (nb < 0) {
2685  return nb;
2686  }
2687  nbytes += nb;
2688  }
2689  Int_t nb = TBranch::GetEntry(entry, getall);
2690  if (nb < 0) {
2691  return nb;
2692  }
2693  nbytes += nb;
2694  }
2695 
2696  if (R__unlikely(fTree->Debug() > 0)) {
2697  if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
2698  Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
2699  }
2700  }
2701  return nbytes;
2702 }
2703 
2704 ////////////////////////////////////////////////////////////////////////////////
2705 /// Fill expectedClass and expectedType with information on the data type of the
2706 /// object/values contained in this branch (and thus the type of pointers
2707 /// expected to be passed to Set[Branch]Address
2708 /// return 0 in case of success and > 0 in case of failure.
2709 
2711 {
2712  expectedClass = 0;
2713  expectedType = kOther_t;
2714 
2716  if ((type == -1) || (fID == -1)) {
2717  expectedClass = fBranchClass;
2718  } else {
2719  // Case of an object data member. Here we allow for the
2720  // variable name to be ommitted. Eg, for Event.root with split
2721  // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
2722  TStreamerElement* element = GetInfoImp()->GetElement(fID);
2723  if (element) {
2724  expectedClass = element->GetClassPointer();
2725  if (!expectedClass) {
2726  TDataType* data = gROOT->GetType(element->GetTypeNameBasic());
2727  if (!data) {
2728  Error("GetExpectedType", "Did not find the type number for %s", element->GetTypeNameBasic());
2729  return 1;
2730  } else {
2731  expectedType = (EDataType) data->GetType();
2732  }
2733  }
2734  } else {
2735  Error("GetExpectedType", "Did not find the type for %s",GetName());
2736  return 2;
2737  }
2738  }
2739  return 0;
2740 }
2741 
2742 ////////////////////////////////////////////////////////////////////////////////
2743 /// Return icon name depending on type of branch element.
2744 
2745 const char* TBranchElement::GetIconName() const
2746 {
2747  if (IsFolder()) {
2748  return "TBranchElement-folder";
2749  } else {
2750  return "TBranchElement-leaf";
2751  }
2752 }
2753 
2754 ////////////////////////////////////////////////////////////////////////////////
2755 /// Return whether this branch is in a mode where the object are decomposed
2756 /// or not (Also known as MakeClass mode).
2757 
2759 {
2760  return TestBit(kDecomposedObj); // Same as TestBit(kMakeClass)
2761 }
2762 
2763 ////////////////////////////////////////////////////////////////////////////////
2764 /// Return maximum count value of the branchcount if any.
2765 
2767 {
2768  if (fBranchCount) {
2769  return fBranchCount->GetMaximum();
2770  }
2771  return fMaximum;
2772 }
2773 
2774 ////////////////////////////////////////////////////////////////////////////////
2775 /// Return a pointer to our object.
2776 
2778 {
2779  ValidateAddress();
2780  return fObject;
2781 }
2782 
2783 ////////////////////////////////////////////////////////////////////////////////
2784 /// Return a pointer to the parent class of the branch element.
2785 
2787 {
2788  return fParentClass.GetClass();
2789 }
2790 
2791 ////////////////////////////////////////////////////////////////////////////////
2792 /// Return type name of element in the branch.
2793 
2794 const char* TBranchElement::GetTypeName() const
2795 {
2796  if (fType == 3 || fType == 4) {
2797  return "Int_t";
2798  }
2799  // FIXME: Use symbolic constants here.
2800  if ((fStreamerType < 1) || (fStreamerType > 59)) {
2801  if (fBranchClass.GetClass()) {
2802  if (fID>=0) {
2803  return GetInfoImp()->GetElement(fID)->GetTypeName();
2804  } else {
2805  return fBranchClass.GetClass()->GetName();
2806  }
2807  } else {
2808  return 0;
2809  }
2810  }
2811  const char *types[20] = {
2812  "",
2813  "Char_t",
2814  "Short_t",
2815  "Int_t",
2816  "Long_t",
2817  "Float_t",
2818  "Int_t",
2819  "char*",
2820  "Double_t",
2821  "Double32_t",
2822  "",
2823  "UChar_t",
2824  "UShort_t",
2825  "UInt_t",
2826  "ULong_t",
2827  "UInt_t",
2828  "Long64_t",
2829  "ULong64_t",
2830  "Bool_t",
2831  "Float16_t"
2832  };
2833  Int_t itype = fStreamerType % 20;
2834  return types[itype];
2835 }
2836 
2837 ////////////////////////////////////////////////////////////////////////////////
2838 
2839 template Double_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2840 template Long64_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2841 template LongDouble_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2842 
2843 template <typename T>
2845 {
2846  // -- Returns the branch value.
2847  //
2848  // If the leaf is an array, j is the index in the array.
2849  //
2850  // If leaf is an array inside a TClonesArray, len should be the length
2851  // of the array.
2852  //
2853  // If subarr is true, then len is actually the index within the sub-array.
2854  //
2855 
2856  ValidateAddress();
2857 
2858  Int_t prID = fID;
2859  char *object = fObject;
2860  if (TestBit(kCache)) {
2861  if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2862  prID = fID+1;
2863  } else if (fOnfileObject) {
2864  object = fOnfileObject->GetObjectAt(0);
2865  }
2866  }
2867 
2868  if (!j && fBranchCount) {
2869  Long64_t entry = fTree->GetReadEntry();
2870  // Since reloading the index, will reset the ClonesArray, let's
2871  // skip the load if we already read this entry.
2872  if (entry != fBranchCount->GetReadEntry()) {
2873  fBranchCount->TBranch::GetEntry(entry);
2874  }
2875  if (fBranchCount2 && entry != fBranchCount2->GetReadEntry()) {
2876  fBranchCount2->TBranch::GetEntry(entry);
2877  }
2878  }
2879 
2880  if (TestBit(kDecomposedObj)) {
2881  if (!fAddress) {
2882  return 0;
2883  }
2884  if ((fType == 3) || (fType == 4)) {
2885  // Top-level branch of a TClonesArray.
2886  return fNdata;
2887  } else if ((fType == 31) || (fType == 41)) {
2888  // sub branch of a TClonesArray
2889  Int_t atype = fStreamerType;
2890  if (atype < 20) {
2891  atype += 20;
2892  }
2893  return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
2894  } else if (fType <= 2) {
2895  // branch in split mode
2896  // FIXME: This should probably be < 60 instead!
2897  if ((fStreamerType > 40) && (fStreamerType < 55)) {
2898  Int_t atype = fStreamerType - 20;
2899  return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
2900  } else {
2901  return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
2902  }
2903  }
2904  }
2905 
2906  if (object == 0)
2907  {
2908  // We have nowhere to read the data from (probably because the data member was
2909  // 'dropped' from the current schema).
2910  return 0;
2911  }
2912 
2913  if (fType == 31) {
2914  TClonesArray* clones = (TClonesArray*) object;
2915  if (subarr) {
2916  return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j, len, fOffset);
2917  }
2918  return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j/len, j%len, fOffset);
2919  } else if (fType == 41) {
2922  {
2923  if (subarr)
2924  return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
2925 
2926  return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
2927  }
2928  else
2929  {
2930  if (subarr)
2931  return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
2932  return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
2933  }
2934  } else {
2935  if (GetInfoImp()) {
2936  return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
2937  }
2938  return 0;
2939  }
2940 }
2941 
2942 ////////////////////////////////////////////////////////////////////////////////
2943 /// Returns pointer to first data element of this branch.
2944 /// Currently used only for members of type character.
2945 
2947 {
2948  ValidateAddress();
2949 
2950  Int_t prID = fID;
2951  char *object = fObject;
2952  if (TestBit(kCache)) {
2953  if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2954  prID = fID+1;
2955  } else if (fOnfileObject) {
2956  object = fOnfileObject->GetObjectAt(0);
2957  }
2958  }
2959 
2960  if (fBranchCount) {
2961  Long64_t entry = fTree->GetReadEntry();
2962  fBranchCount->TBranch::GetEntry(entry);
2963  if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
2964  }
2965  if (TestBit(kDecomposedObj)) {
2966  if (!fAddress) {
2967  return 0;
2968  }
2969  if (fType == 3) { //top level branch of a TClonesArray
2970  //return &fNdata;
2971  return 0;
2972  } else if (fType == 4) { //top level branch of a TClonesArray
2973  //return &fNdata;
2974  return 0;
2975  } else if (fType == 31) { // sub branch of a TClonesArray
2976  //Int_t atype = fStreamerType;
2977  //if (atype < 20) atype += 20;
2978  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2979  return 0;
2980  } else if (fType == 41) { // sub branch of a TClonesArray
2981  //Int_t atype = fStreamerType;
2982  //if (atype < 20) atype += 20;
2983  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2984  return 0;
2985  } else if (fType <= 2) { // branch in split mode
2986  // FIXME: This should probably be < 60 instead!
2987  if (fStreamerType > 40 && fStreamerType < 55) {
2988  //Int_t atype = fStreamerType - 20;
2989  //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
2990  return 0;
2991  } else {
2992  //return GetInfoImp()->GetValue(object, fID, j, -1);
2993  return 0;
2994  }
2995  }
2996  }
2997 
2998  if (fType == 31) {
2999  return 0;
3000  } else if (fType == 41) {
3001  return 0;
3002  } else if (prID < 0) {
3003  return object;
3004  } else {
3005  //return GetInfoImp()->GetValue(object,fID,j,-1);
3006  if (!GetInfoImp() || !object) return 0;
3007  char **val = (char**)(object+GetInfoImp()->TStreamerInfo::GetElementOffset(prID));
3008  return *val;
3009  }
3010 }
3011 
3012 ////////////////////////////////////////////////////////////////////////////////
3013 /// Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a container sub-branch.
3014 ///
3015 /// Note: The offsets are zero for data members so that when
3016 /// SetAddress recursively sets their address, they will get the
3017 /// same address as their containing class because i/o is based
3018 /// on streamer info offsets from the addresss of the containing
3019 /// class.
3020 ///
3021 /// Offsets are non-zero for base-class sub-branches that are
3022 /// not the leftmost direct base class. They are laid out in
3023 /// memory sequentially and only the leftmost direct base class
3024 /// has the same address as the derived class. The streamer
3025 /// offsets need to be added to the address of the base class
3026 /// subobject which is not the same as the address of the
3027 /// derived class for the non-leftmost direct base classes.
3028 
3030 {
3031  Int_t nbranches = fBranches.GetEntriesFast();
3032 
3033  // See https://sft.its.cern.ch/jira/browse/ROOT-8742
3034  // and https://sft.its.cern.ch/jira/browse/ROOT-9253
3035  // As of commit e21b4f1a3b, removing this lock lead to a failure
3036  // in the test testSetAddress[Loop].
3037  // As of commit 4f8b237849, removing this lock does not lead to
3038  // a visible failure in test. This might be due to the underlying
3039  // problem (missing lock or ?) being solved somewhere else or some
3040  // other pertubation reducing the failure rate.
3041  // Having the lock here is not too costly as InitializeOffsets is
3042  // one called once in the lifetime of the TBranch.
3044 
3045  if (fID < 0) {
3046  // -- We are a top-level branch. Let's mark whether we need to use MapObject.
3047  if (CanSelfReference(fBranchClass)) {
3048  if (fBranchClass.GetClass()->IsTObject()) {
3050  } else {
3051  SetBit(kBranchAny);
3052  }
3053  }
3054  }
3055  if (nbranches) {
3056  // Allocate space for the new sub-branch offsets.
3057  delete[] fBranchOffset;
3058  fBranchOffset = 0;
3059  fBranchOffset = new Int_t[nbranches];
3060  // Make sure we can instantiate our class meta info.
3061  if (!fBranchClass.GetClass()) {
3062  Warning("InitializeOffsets", "No branch class set for branch: %s", GetName());
3063  fInitOffsets = kTRUE;
3064  return;
3065  }
3066  // Make sure we can instantiate our class streamer info.
3067  if (!GetInfoImp()) {
3068  Warning("InitializeOffsets", "No streamer info available for branch: %s of class: %s", GetName(), fBranchClass.GetClass()->GetName());
3069  fInitOffsets = kTRUE;
3070  return;
3071  }
3072 
3073  // Get the class we are a member of now (which is the
3074  // type of our containing subobject) and get our offset
3075  // inside of our containing subobject (our local offset).
3076  // Note: branchElem stays zero if we are a top-level branch,
3077  // we have to be careful about this later.
3078  TStreamerElement* branchElem = 0;
3079  Int_t localOffset = 0;
3080  TClass* branchClass = fBranchClass.GetClass();
3081  Bool_t renamed = kFALSE;
3082  if (fID > -1) {
3083  // -- Branch is *not* a top-level branch.
3084  // Instead of the streamer info class, we want the class of our
3085  // specific element in the streamer info. We could be a data
3086  // member of a base class or a split class, in which case our
3087  // streamer info will be for our containing sub-object, while
3088  // we are actually a different type.
3090  // Note: We tested to make sure the streamer info was available previously.
3091  if (!si->IsCompiled()) {
3092  Warning("InitializeOffsets", "Streamer info for branch: %s has no elements array!", GetName());
3093  fInitOffsets = kTRUE;
3094  return;
3095  }
3096  // FIXME: Check that fID is in range.
3097  branchElem = si->GetElement(fID);
3098  if (!branchElem) {
3099  Warning("InitializeOffsets", "Cannot get streamer element for branch: %s!", GetName());
3100  fInitOffsets = kTRUE;
3101  return;
3102  } else if (branchElem->TestBit(TStreamerElement::kRepeat)) {
3103  // If we have a repeating streamerElement, use the next
3104  // one as it actually hold the 'real' data member('s offset)
3105  if (si->GetElement(fID+1)) {
3106  branchElem = si->GetElement(fID+1);
3107  }
3108  }
3109  localOffset = branchElem->GetOffset();
3110  branchClass = branchElem->GetClassPointer();
3111  if (localOffset == TStreamerInfo::kMissing) {
3112  fObject = 0;
3113  } else {
3114  renamed = branchClass && branchElem->GetNewClass() && (branchClass != branchElem->GetNewClass());
3115  }
3116  } else {
3117  renamed = fTargetClass != fBranchClass;
3118  }
3119  if (!branchClass) {
3120  Error("InitializeOffsets", "Could not find class for branch: %s", GetName());
3121  fInitOffsets = kTRUE;
3122  return;
3123  }
3124 
3125  //------------------------------------------------------------------------
3126  // Extract the name of the STL branch in case it has been split.
3127  //////////////////////////////////////////////////////////////////////////
3128 
3129  TString stlParentName;
3130  Bool_t stlParentNameUpdated = kFALSE;
3131  if( fType == 4 )
3132  {
3133  TBranch *br = GetMother()->GetSubBranch( this );
3134  stlParentName = br->GetName();
3135  stlParentName.Strip( TString::kTrailing, '.' );
3136 
3137  // We may ourself contain the 'Mother' branch name.
3138  // To avoid code duplication, we delegate the removal
3139  // of the mother's name to the first sub-branch loop.
3140  }
3141 
3142  // Loop over our sub-branches and compute their offsets.
3143  for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
3144  bool alternateElement = false;
3145 
3146  fBranchOffset[subBranchIdx] = 0;
3147  TBranchElement* subBranch = dynamic_cast<TBranchElement*> (fBranches[subBranchIdx]);
3148  if (subBranch == 0) {
3149  // -- Skip sub-branches that are not TBranchElements.
3150  continue;
3151  }
3152 
3153  if (renamed) {
3154  if (subBranch->fBranchClass == branchClass) {
3155  if (branchElem) subBranch->SetTargetClass(branchElem->GetNewClass()->GetName());
3156  else subBranch->SetTargetClass(fTargetClass->GetName());
3157  }
3158  }
3159 
3160  TVirtualStreamerInfo* sinfo = subBranch->GetInfoImp();
3161  if (!sinfo) {
3162  Warning("InitializeOffsets", "No streamer info for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3163  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3164  continue;
3165  }
3166  if (!sinfo->IsCompiled()) {
3167  Warning("InitializeOffsets", "No elements array for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3168  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3169  continue;
3170  }
3171  // FIXME: Make sure subBranch->fID is in range.
3172  TStreamerElement* subBranchElement = sinfo->GetElement(subBranch->fID);
3173  if (!subBranchElement) {
3174  Warning("InitializeOffsets", "No streamer element for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3175  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3176  continue;
3177  } else if (subBranchElement->TestBit(TStreamerElement::kRepeat)) {
3178  // If we have a repeating streamerElement, use the next
3179  // one as it actually hold the 'real' data member('s offset)
3180  if (sinfo->GetElement(subBranch->fID+1)) {
3181  subBranchElement = sinfo->GetElement(subBranch->fID+1);
3182  }
3183  } else if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3184  // We have a cached item which is not a repeated but we might still
3185  // have some Actions triggered by a rule that affect real
3186  // data member(s).
3187  if (subBranch->fReadActionSequence && subBranch->fReadActionSequence->fActions.size() > 1) {
3188  typedef TStreamerInfoActions::ActionContainer_t::iterator iterator;
3189  iterator end = subBranch->fReadActionSequence->fActions.end();
3190  for(iterator iter = subBranch->fReadActionSequence->fActions.begin();
3191  iter != end; ++iter) {
3192  TStreamerInfoActions::TConfiguration *config = iter->fConfiguration;
3193  UInt_t id = config->fElemId;
3194  TStreamerElement *e = (TStreamerElement*)config->fInfo->GetElements()->At(id);
3195  if (e && !e->TestBit(TStreamerElement::kCache)) {
3196  subBranchElement = e;
3197  alternateElement = true;
3198  break;
3199  }
3200  }
3201  }
3202  }
3203 
3204  localOffset = subBranchElement->GetOffset();
3205  if (localOffset == TStreamerInfo::kMissing) {
3206  subBranch->fObject = 0;
3207  }
3208  {
3209  Int_t streamerType = subBranchElement->GetType();
3210  if (streamerType > TStreamerInfo::kObject
3211  && subBranch->GetListOfBranches()->GetEntries()==0
3212  && CanSelfReference(subBranchElement->GetClass()))
3213  {
3214  subBranch->SetBit(kBranchAny);
3215  } else {
3216  subBranch->ResetBit(kBranchAny);
3217  }
3218  }
3219 
3220  if (subBranchElement->GetNewType()<0) {
3221  subBranch->ResetBit(kBranchAny);
3222  subBranch->ResetBit(kBranchObject);
3223  }
3224 
3225  // Note: This call is expensive, do it only once.
3226  TBranch* mother = GetMother();
3227  if (!mother) {
3228  Warning("InitializeOffsets", "Branch '%s' has no mother!", GetName());
3229  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3230  continue;
3231  }
3232  TString motherName(mother->GetName());
3233  Bool_t motherDot = kFALSE;
3234  if (motherName.Length() && strchr(motherName.Data(), '.')) {
3235  motherDot = kTRUE;
3236  }
3237  Bool_t motherDotAtEnd = kFALSE;
3238  if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
3239  motherDotAtEnd = kTRUE;
3240  }
3241 
3242  Bool_t isBaseSubBranch = kFALSE;
3243  if ((subBranch->fType == 1) || (subBranchElement && subBranchElement->IsBase())) {
3244  // -- Base class sub-branch (1).
3245  //
3246  // Note: Our type will not be 1, even though we are
3247  // a base class branch, if we are not split (see the
3248  // constructor), or if we are an STL container master
3249  // branch and a base class branch at the same time
3250  // or an std::string.
3251  isBaseSubBranch = kTRUE;
3252  }
3253 
3254  Bool_t isContDataMember = kFALSE;
3255  if ((subBranch->fType == 31) || (subBranch->fType == 41)) {
3256  // -- Container data member sub-branch (31 or 41).
3257  isContDataMember = kTRUE;
3258  }
3259 
3260  // I am either a data member sub-branch (0), or a base class
3261  // sub-branch (1), or TClonesArray master sub-branch (3),
3262  // or an STL container master sub-branch (4), or TClonesArray
3263  // data member sub-branch (31), or an STL container data member
3264  // sub-branch (41).
3265  //
3266  // My parent branch is either a top-level branch ((0), fID==(-2,-1)),
3267  // or a base class sub-branch (1), or a split-class branch (2),
3268  // or a TClonesArray master branch (3), or an STL container
3269  // master branch (4).
3270  //
3271 
3272  //
3273  // We need to extract from our name the name
3274  // of the data member which contains us, so
3275  // that we may then do a by-name lookup in the
3276  // dictionary meta info of our parent class to
3277  // get our offset in our parent class.
3278  //
3279 
3280  // Get our name.
3281  TString dataName(subBranch->GetName());
3282  if (motherDotAtEnd) {
3283  // -- Remove the top-level branch name from our name.
3284  dataName.Remove(0, motherName.Length());
3285  // stlParentNameUpdated is false the first time in this loop.
3286  if (!stlParentNameUpdated && stlParentName.Length()) {
3287  stlParentName.Remove(0, motherName.Length());
3288  stlParentNameUpdated = kTRUE;
3289  }
3290  } else if (motherDot) {
3291  // -- Remove the top-level branch name from our name, folder case.
3292  //
3293  // Note: We are in the case where our mother was created
3294  // by the branch constructor which takes a folder
3295  // as an argument. The mother branch has internal
3296  // dots in its name to represent the folder heirarchy.
3297  // The TTree::Bronch() routine has handled us as a
3298  // special case, we must compensate.
3299  if ((fID < 0) && (subBranchElement->IsA() == TStreamerBase::Class())) {
3300  // -- Our name is the mother name, remove it.
3301  // Note: The test is our parent is a top-level branch
3302  // and our streamer is the base class streamer,
3303  // this matches the exact test in TTree::Bronch().
3304  if (dataName.Length() == motherName.Length()) {
3305  dataName.Remove(0, motherName.Length());
3306  // stlParentNameUpdated is false the first time in this loop.
3307  if (!stlParentNameUpdated && stlParentName.Length()) {
3308  stlParentName.Remove(0, motherName.Length());
3309  }
3310  }
3311  } else {
3312  // -- Remove the mother name and the dot.
3313  if (dataName.Length() > motherName.Length()) {
3314  dataName.Remove(0, motherName.Length() + 1);
3315  if (!stlParentNameUpdated && stlParentName.Length()) {
3316  stlParentName.Remove(0, motherName.Length());
3317  }
3318  }
3319  }
3320  }
3321  stlParentNameUpdated = kTRUE;
3322  if (isBaseSubBranch) {
3323  // -- Remove the base class name suffix from our name.
3324  // Note: The pattern is the name of the base class.
3325  TString pattern(subBranchElement->GetName());
3326  if (pattern.Length() <= dataName.Length()) {
3327  if (!strcmp(dataName.Data() + (dataName.Length() - pattern.Length()), pattern.Data())) {
3328  // The branch name contains the name of the base class in it.
3329  // This name is not reproduced in the sub-branches, so we need to
3330  // remove it.
3331  dataName.Remove(dataName.Length() - pattern.Length());
3332  }
3333  }
3334  // Remove any leading dot.
3335  if (dataName.Length()) {
3336  if (dataName[0] == '.') {
3337  dataName.Remove(0, 1);
3338  }
3339  }
3340  // Note: We intentionally leave any trailing dot
3341  // in our modified name here.
3342  }
3343 
3344  // Get our parent branch's name.
3345  TString parentName(GetName());
3346  if (motherDotAtEnd) {
3347  // -- Remove the top-level branch name from our parent's name.
3348  parentName.Remove(0, motherName.Length());
3349  } else if (motherDot) {
3350  // -- Remove the top-level branch name from our parent's name, folder case.
3351  //
3352  // Note: We are in the case where our mother was created
3353  // by the branch constructor which takes a folder
3354  // as an argument. The mother branch has internal
3355  // dots in its name to represent the folder heirarchy.
3356  // The TTree::Bronch() routine has handled us as a
3357  // special case, we must compensate.
3358  if ((fID > -1) && (mother == mother->GetSubBranch(this)) && (branchElem->IsA() == TStreamerBase::Class())) {
3359  // -- Our parent's name is the mother name, remove it.
3360  // Note: The test is our parent's parent is a top-level branch
3361  // and our parent's streamer is the base class streamer,
3362  // this matches the exact test in TTree::Bronch().
3363  if (parentName.Length() == motherName.Length()) {
3364  parentName.Remove(0, motherName.Length());
3365  }
3366  } else {
3367  // -- Remove the mother name and the dot.
3368  if (parentName.Length() > motherName.Length()) {
3369  parentName.Remove(0, motherName.Length() + 1);
3370  }
3371  }
3372  }
3373  // FIXME: Do we need to use the other tests for a base class here?
3374  if (fType == 1) {
3375  // -- Our parent is a base class sub-branch, remove the base class name suffix from its name.
3376  if (mother != mother->GetSubBranch(this)) {
3377  // -- My parent's parent is not a top-level branch.
3378  // Remove the base class name suffix from the parent name.
3379  // Note: The pattern is the name of the base class.
3380  // coverity[var_deref_model] branchElem is non zero here since fType==1 and thus fID > -1
3381  TString pattern(branchElem->GetName());
3382  if (pattern.Length() <= parentName.Length()) {
3383  if (!strcmp(parentName.Data() + (parentName.Length() - pattern.Length()), pattern.Data())) {
3384  // The branch name contains the name of the base class in it.
3385  // This name is not reproduced in the sub-branches, so we need to
3386  // remove it.
3387  parentName.Remove(parentName.Length() - pattern.Length());
3388  }
3389  }
3390  }
3391  // Note: We intentionally leave any trailing dots
3392  // in the modified parent name here.
3393  }
3394 
3395  // Remove the parent branch name part from our name,
3396  // but only if the parent branch is not a top-level branch.
3397  // FIXME: We should not assume parent name does not have length 0.
3398  if (fID > -1) {
3399  RemovePrefix(dataName, parentName);
3400  }
3401 
3402  // Remove any leading dot.
3403  if (dataName.Length()) {
3404  if (dataName[0] == '.') {
3405  dataName.Remove(0, 1);
3406  }
3407  }
3408 
3409  // Remove any trailing dot.
3410  if (dataName.Length()) {
3411  if (dataName[dataName.Length()-1] == '.') {
3412  dataName.Remove(dataName.Length() - 1, 1);
3413  }
3414  }
3415 
3416  //
3417  // Now that we have our data member name, find our offset
3418  // in our parent class.
3419  //
3420  // Note: Our data member name can have many dots in it
3421  // if branches were elided between our parent branch
3422  // and us by Unroll().
3423  //
3424  // FIXME: This may not work if our member name is ambiguous.
3425  //
3426 
3427  Int_t offset = 0;
3428  if (dataName.Length()) {
3429  // -- We have our data member name, do a lookup in the dictionary meta info of our parent class.
3430  // Get our parent class.
3431  TClass* pClass = 0;
3432  // First check whether this sub-branch is part of the 'cache' (because the data member it
3433  // represents is no longer in the current class layout.
3434  TStreamerInfo *subInfo = subBranch->GetInfoImp();
3435  //if (subInfo && subBranch->TestBit(kCache)) { // subInfo->GetElements()->At(subBranch->GetID())->TestBit(TStreamerElement::kCache)) {
3436  if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3437  pClass = ((TStreamerElement*)subInfo->GetElements()->At(0))->GetClassPointer();
3438  }
3439  // FIXME: Do we need the other base class tests here?
3440  if (!pClass) {
3441  if (fType == 1) {
3442  // -- Parent branch is a base class branch.
3443  // FIXME: Is using branchElem here the right thing?
3444  pClass = branchElem->GetClassPointer();
3445  if (pClass->Property() & kIsAbstract) {
3446  // the class is abstract, let see if the
3447 
3448  TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this);
3449  if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
3450  // Our parent's class is emulated and we represent an abstract class.
3451  // and the target class has not been set explicilty.
3452  TString target = pClass->GetName();
3453  target += "@@emulated";
3454 
3455  pClass = TClass::GetClass(target);
3456  }
3457  }
3458  } else {
3459  // -- Parent branch is *not* a base class branch.
3460  // FIXME: This sometimes returns a null pointer.
3461  pClass = subBranch->GetParentClass();
3462  }
3463  }
3464  if (!pClass) {
3465  // -- No parent class, fix it.
3466  // FIXME: This is probably wrong!
3467  // Assume parent class is our parent branch's clones class or value class.
3468  if (GetClonesName() && strlen(GetClonesName())) {
3469  pClass = fClonesClass;
3470  if (!pClass) {
3471  Warning("InitializeOffsets", "subBranch: '%s' has no parent class, and cannot get class for clones class: '%s'!", subBranch->GetName(), GetClonesName());
3472  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3473  continue;
3474  }
3475  Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3476  }
3478  pClass = fBranchCount->fCollProxy->GetValueClass();
3479  Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass ? pClass->GetName() : "unknowned class");
3480  }
3481  if (!pClass) {
3482  // -- Still no parent class, assume our parent class is our parent branch's class.
3483  // FIXME: This is probably wrong!
3484  pClass = branchClass;
3485  // FIXME: Enable this warning!
3486  //Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3487  }
3488  }
3489  if (renamed && pClass) {
3490  if (pClass == branchClass) {
3491  pClass = branchElem->GetNewClass();
3492  } else if (fCollProxy && pClass == branchClass->GetCollectionProxy()->GetValueClass()) {
3493  pClass = fCollProxy->GetValueClass();
3494  }
3495  }
3496 
3497  //------------------------------------------------------------------
3498  // If we have the are the sub-branch of the TBranchSTL, we need
3499  // to remove it's name to get the correct real data offsets
3500  ////////////////////////////////////////////////////////////////////
3501 
3502  if( dynamic_cast<TBranchSTL*>(fParent) && stlParentName.Length() )
3503  {
3504  if( !strncmp( stlParentName.Data(), dataName.Data(), stlParentName.Length()-1 )
3505  && dataName[ stlParentName.Length() ] == '.' )
3506  dataName.Remove( 0, stlParentName.Length()+1 );
3507  }
3508 
3509  // Find our offset in our parent class using
3510  // a lookup by name in the dictionary meta info
3511  // for our parent class.
3512 
3513  if (alternateElement) {
3514  Ssiz_t dotpos = dataName.Last('.');
3515  Ssiz_t endpos = dataName.Length();
3516  if (dotpos != kNPOS) ++dotpos; else dotpos = 0;
3517  dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
3518  }
3519  TRealData* rd = pClass->GetRealData(dataName);
3520  if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
3521  // -- Data member exists in the dictionary meta info, get the offset.
3522  // If we are using an alternateElement, it is the target of a rule
3523  // and might be indeed transient.
3524  offset = rd->GetThisOffset();
3525  } else if (subBranchElement->TestBit(TStreamerElement::kWholeObject)) {
3526  // We are a rule with no specific target, it applies to the whole
3527  // object, let's set the offset to zero
3528  offset = 0;
3529  } else {
3530  // -- No dictionary meta info for this data member, it must no
3531  // longer exist
3532  if (fEntries == 0) {
3533  // ... unless we creating the branch in which case
3534  // we have an internal error.
3535  if (pClass->GetListOfRealData()->GetEntries() == 0) {
3536  // We are probably missing the ShowMember, let's
3537  // just issue an error.
3538  Error("InitializeOffsets",
3539  "Could not find the real data member '%s' when constructing the branch '%s' [Likely missing ShowMember].",
3540  dataName.Data(),GetName());
3541  } else if (subInfo && subInfo->GetClassVersion()!=subInfo->GetClass()->GetClassVersion()) {
3542  // In the case where we are cloning a TTree that was created with an older version of the layout, we may not
3543  // able to find all the members
3544  Info("InitializeOffsets",
3545  "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'. ",
3546  dataName.Data(),GetName());
3547  } else {
3548  // Something really bad happen.
3549  Fatal("InitializeOffsets",
3550  "Could not find the real data member '%s' when constructing the branch '%s' [Likely an internal error, please report to the developers].",
3551  dataName.Data(),GetName());
3552  }
3553  }
3554  localOffset = TStreamerInfo::kMissing;
3555  }
3556  } else {
3557  // -- We have no data member name, ok for a base class, not good otherwise.
3558  if (isBaseSubBranch) {
3559  // I am a direct base class of my parent class, my local offset is enough.
3560  } else {
3561  Warning("InitializeOffsets", "Could not find the data member name for branch '%s' with parent branch '%s', assuming offset is zero!", subBranch->GetName(), GetName());
3562  }
3563  }
3564 
3565  //
3566  // Ok, do final calculations for fOffset and fBranchOffset.
3567  //
3568 
3569  if (isContDataMember) {
3570  // -- Container data members set fOffset instead of fBranchOffset.
3571  // The fOffset is what should be added to the start of the entry
3572  // in the collection (i.e., its current absolute address) to find
3573  // the beginning of the data member described by the current branch.
3574  //
3575  // Compensate for the i/o routines adding our local offset later.
3576  if (subBranch->fObject == 0 && localOffset == TStreamerInfo::kMissing) {
3577  subBranch->SetMissing();
3578  // We stil need to set fBranchOffset in the case of a missing
3579  // element so that SetAddress is (as expected) not called
3580  // recursively in this case.
3581  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3582  } else {
3583  if (isBaseSubBranch) {
3584  // The value of 'offset' for a base class does not include its
3585  // 'localOffset'.
3586  subBranch->SetOffset(offset);
3587  } else {
3588  // The value of 'offset' for a regular data member does include its
3589  // 'localOffset', we need to remove it explicitly.
3590  subBranch->SetOffset(offset - localOffset);
3591  }
3592  }
3593  } else {
3594  // -- Set fBranchOffset for sub-branch.
3595  Int_t isSplit = 0 != subBranch->GetListOfBranches()->GetEntriesFast();
3596  if (subBranch->fObject == 0 && localOffset == TStreamerInfo::kMissing) {
3597  // The branch is missing
3598  fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3599 
3600  } else if (isSplit) {
3601  if (isBaseSubBranch) {
3602  // We are split, so we need to add in our local offset
3603  // to get our absolute address for our children.
3604  fBranchOffset[subBranchIdx] = offset + localOffset;
3605  } else {
3606  // We are split so our offset will never be
3607  // used in an i/o, so we do not have to subtract
3608  // off our local offset like below.
3609  fBranchOffset[subBranchIdx] = offset;
3610  }
3611  } else {
3612  if (isBaseSubBranch) {
3613  // We are not split, so our local offset will be
3614  // added later by the i/o routines.
3615  fBranchOffset[subBranchIdx] = offset;
3616  } else {
3617  // Compensate for the fact that the i/o routines
3618  // are going to add my local offset later.
3619  fBranchOffset[subBranchIdx] = offset - localOffset;
3620  }
3621  }
3622  }
3623  }
3624  }
3625  else {
3626  if (fID > -1) {
3627  // Branch is *not* a top-level branch.
3628  // Let's check if the target member is still present in memory
3630  fObject = 0;
3631  }
3632  }
3633  }
3634  const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
3635  if (fReadActionSequence && isSplitNode) {
3636  TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3637  auto index = parent->fBranches.IndexOf(this);
3638  if (index >= 0) {
3639  fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
3640  }
3641  }
3642 
3643  fInitOffsets = kTRUE;
3644 }
3645 
3646 ////////////////////////////////////////////////////////////////////////////////
3647 /// Return kTRUE if more than one leaf, kFALSE otherwise.
3648 
3650 {
3651  Int_t nbranches = fBranches.GetEntriesFast();
3652  if (nbranches >= 1) {
3653  return kTRUE;
3654  }
3655  TList* browsables = const_cast<TBranchElement*>(this)->GetBrowsables();
3656  return browsables && browsables->GetSize();
3657 }
3658 
3659 ////////////////////////////////////////////////////////////////////////////////
3660 /// Detect a collection written using a zero pointer in old versions of root.
3661 /// In versions of ROOT older than 4.00/03, if a collection (TClonesArray
3662 /// or STL container) was split but the pointer to the collection was zeroed
3663 /// out, nothing was saved. Hence there is no __easy__ way to detect the
3664 /// case. In newer versions, a zero is written so that a 'missing' collection
3665 /// appears to be an empty collection.
3666 
3668 {
3669  Bool_t ismissing = kFALSE;
3671  if (basket && fTree) {
3672  Long64_t entry = fTree->GetReadEntry();
3674  Long64_t last;
3675  if (fReadBasket == fWriteBasket) {
3676  last = fEntryNumber - 1;
3677  } else {
3678  last = fBasketEntry[fReadBasket+1] - 1;
3679  }
3680  Int_t* entryOffset = basket->GetEntryOffset();
3681  Int_t bufbegin;
3682  Int_t bufnext;
3683  if (entryOffset) {
3684  bufbegin = entryOffset[entry-first];
3685 
3686  if (entry < last) {
3687  bufnext = entryOffset[entry+1-first];
3688  } else {
3689  bufnext = basket->GetLast();
3690  }
3691  if (bufnext == bufbegin) {
3692  ismissing = kTRUE;
3693  } else {
3694  // fixed length buffer so this is not the case here.
3695  if (basket->GetNevBufSize() == 0) {
3696  ismissing = kTRUE;
3697  }
3698  }
3699  }
3700  }
3701  return ismissing;
3702 }
3703 
3704 ////////////////////////////////////////////////////////////////////////////////
3705 /// Print branch parameters.
3706 
3707 static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids)
3708 {
3709  for(auto &cursor : ids) {
3710  auto id = cursor.fElemID;
3711  if (id >= 0) {
3712  auto el = info->GetElement(id);
3713  if (el)
3714  el->ls();
3715  else {
3716  Error("TBranchElement::Print", "Element for id #%d not found in StreamerInfo for %s",
3717  id, info->GetName());
3718  info->ls();
3719  TClass::GetClass("PFTauWith")->GetStreamerInfos()->ls();
3720  }
3721  } else if (cursor.fNestedIDs) {
3722  Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
3723  PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
3724  }
3725  }
3726 }
3727 
3728 void TBranchElement::Print(Option_t* option) const
3729 {
3730  Int_t nbranches = fBranches.GetEntriesFast();
3731  if (strncmp(option,"debugAddress",strlen("debugAddress"))==0) {
3732  if (strlen(option)==strlen("debugAddress")) {
3733  Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s\n",
3734  "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject");
3735  }
3736  if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3737  else Printf("%-24s ", GetName());
3738 
3739  TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3740  Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3741  TVirtualStreamerInfo *info = ((TBranchElement*)this)->GetInfoImp();
3742 
3743  Printf("%-16s %2d %4d %-16s %-16s %8x %8x %p\n",
3744  info ? info->GetName() : "StreamerInfo unvailable", GetID(), GetType(),
3746  (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3747  GetOffset(), GetObject());
3748  for (Int_t i = 0; i < nbranches; ++i) {
3749  TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3750  subbranch->Print("debugAddressSub");
3751  }
3752  return;
3753  }
3754  if (strncmp(option,"debugInfo",strlen("debugInfo"))==0) {
3755  Printf("Branch %s uses:",GetName());
3756  if (fID>=0) {
3757  // GetInfoImp()->GetElement(fID)->ls();
3758  // for(UInt_t i=0; i< fIDs.size(); ++i) {
3759  // GetInfoImp()->GetElement(fIDs[i])->ls();
3760  // }
3761  TStreamerInfo *localInfo = GetInfoImp();
3762  if (fType == 3 || fType == 4) {
3763  // Search for the correct version.
3764  localInfo = FindOnfileInfo(fClonesClass, fBranches);
3765  }
3766  Printf(" With elements:");
3767  if (fType != 3 && fType != 4)
3768  localInfo->GetElement(fID)->ls();
3769  PrintElements(localInfo, fNewIDs);
3770  Printf(" with read actions:");
3772  Printf(" with write actions:");
3774  } else if (!fNewIDs.empty() && GetInfoImp()) {
3775  TStreamerInfo *localInfo = GetInfoImp();
3776  if (fType == 3 || fType == 4) {
3777  // Search for the correct version.
3778  localInfo = FindOnfileInfo(fClonesClass, fBranches);
3779  }
3780  PrintElements(localInfo, fNewIDs);
3781  Printf(" with read actions:");
3783  Printf(" with write actions:");
3785  }
3786  TString suboption = "debugInfoSub";
3787  suboption += (option+strlen("debugInfo"));
3788  for (Int_t i = 0; i < nbranches; ++i) {
3789  TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3790  subbranch->Print(suboption);
3791  }
3792  Printf(" ");
3793  return;
3794  }
3795  if (nbranches) {
3796  if (fID == -2) {
3797  if (strcmp(GetName(),GetTitle()) == 0) {
3798  Printf("*Branch :%-66s *",GetName());
3799  } else {
3800  Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3801  }
3802  Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3803  Printf("*............................................................................*");
3804  }
3805  if (fType >= 2) {
3806  TBranch::Print(option);
3807  }
3808  for (Int_t i=0;i<nbranches;i++) {
3809  TBranch *branch = (TBranch*)fBranches.At(i);
3810  branch->Print(option);
3811  }
3812  } else {
3813  TBranch::Print(option);
3814  }
3815 }
3816 
3817 ////////////////////////////////////////////////////////////////////////////////
3818 /// Prints values of leaves.
3819 
3821 {
3822  ValidateAddress();
3823 
3824  TStreamerInfo *info = GetInfoImp();
3825  Int_t prID = fID;
3826  char *object = fObject;
3827  if (TestBit(kCache)) {
3829  prID = fID+1;
3830  } else if (fOnfileObject) {
3831  object = fOnfileObject->GetObjectAt(0);
3832  }
3833  }
3834 
3835  if (TestBit(kDecomposedObj)) {
3836  if (!fAddress) {
3837  return;
3838  }
3839  if (fType == 3 || fType == 4) {
3840  // TClonesArray or STL container top-level branch.
3841  printf(" %-15s = %d\n", GetName(), fNdata);
3842  return;
3843  } else if (fType == 31 || fType == 41) {
3844  // TClonesArray or STL container sub-branch.
3845  Int_t n = TMath::Min(10, fNdata);
3848  // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
3849  // printed as a string and could print weird characters.
3850  // So we print an unsigned char instead (not perfect, but better).
3852  }
3853  if (atype > 54) {
3854  // FIXME: More logic required here (like in ReadLeaves)
3855  printf(" %-15s = %d\n", GetName(), fNdata);
3856  return;
3857  }
3858  if (fStreamerType > 20) {
3859  atype -= 20;
3861  n = n * leaf->GetLenStatic();
3862  }
3863  if (GetInfoImp()) {
3864  GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3865  }
3866  return;
3867  } else if (fType <= 2) {
3868  // Branch in split mode.
3869  // FIXME: This should probably be < 60 instead.
3870  if ((fStreamerType > 40) && (fStreamerType < 55)) {
3871  Int_t atype = fStreamerType - 20;
3872  TBranchElement* counterElement = (TBranchElement*) fBranchCount;
3873  Int_t n = (Int_t) counterElement->GetValue(0, 0);
3874  if (GetInfoImp()) {
3875  GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3876  }
3877  } else {
3878  if (GetInfoImp()) {
3879  GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3880  }
3881  }
3882  return;
3883  }
3884  } else if (fType == 3) {
3885  printf(" %-15s = %d\n", GetName(), fNdata);
3886  } else if (fType == 31) {
3887  TClonesArray* clones = (TClonesArray*) object;
3888  if (GetInfoImp()) {
3889  GetInfoImp()->PrintValueClones(GetName(), clones, prID, fOffset, lenmax);
3890  }
3891  } else if (fType == 41) {
3893  if (GetInfoImp()) {
3894  GetInfoImp()->PrintValueSTL(GetName(), ((TBranchElement*) this)->GetCollectionProxy(), prID, fOffset, lenmax);
3895  }
3896  } else {
3897  if (GetInfoImp()) {
3898  GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3899  }
3900  }
3901 }
3902 
3903 ////////////////////////////////////////////////////////////////////////////////
3904 /// Unconfiguration Read Leave function.
3905 
3907 {
3908  Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
3909 }
3910 
3911 ////////////////////////////////////////////////////////////////////////////////
3912 /// Read leaves into i/o buffers for this branch.
3913 /// For the case where the branch is set in MakeClass mode (decomposed object).
3914 
3916 {
3917  ValidateAddress();
3918 
3919  if (fType == 3 || fType == 4) {
3920  // Top level branch of a TClonesArray.
3921  Int_t *n = (Int_t*) fAddress;
3922  b >> n[0];
3923  if ((n[0] < 0) || (n[0] > fMaximum)) {
3924  if (IsMissingCollection()) {
3925  n[0] = 0;
3926  b.SetBufferOffset(b.Length() - sizeof(n));
3927  } else {
3928  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());
3929  n[0] = 0;
3930  }
3931  }
3932  fNdata = n[0];
3933  if (fType == 4) {
3934  Int_t nbranches = fBranches.GetEntriesFast();
3935  switch(fSTLtype) {
3936  case ROOT::kSTLset:
3937  case ROOT::kSTLmultiset:
3938  case ROOT::kSTLmap:
3939  case ROOT::kSTLmultimap:
3940  for (Int_t i=0; i<nbranches; i++) {
3941  TBranch *branch = (TBranch*)fBranches[i];
3942  Int_t nb = branch->GetEntry(GetReadEntry(), 1);
3943  if (nb < 0) {
3944  break;
3945  }
3946  }
3947  break;
3948  default:
3949  break;
3950  }
3951  }
3952  return;
3953  } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
3955  Int_t atype = fStreamerType;
3956  // FIXME: This should probably be > 59 instead.
3957  if (atype > 54) return;
3958  if (!fAddress) {
3959  return;
3960  }
3961  Int_t n = fNdata;
3962  if (atype>40) {
3963  atype -= 40;
3964  if (!fBranchCount2) return;
3965  const char *len_where = (char*)fBranchCount2->fAddress;
3966  if (!len_where) return;
3967  Int_t len_atype = fBranchCount2->fStreamerType;
3968  Int_t length;
3969  Int_t k;
3970  Char_t isArray;
3971  for( k=0; k<n; k++) {
3972  char **where = &(((char**)fAddress)[k]);
3973  delete [] *where;
3974  *where = 0;
3975  switch(len_atype) {
3976  case 1: {length = ((Char_t*) len_where)[k]; break;}
3977  case 2: {length = ((Short_t*) len_where)[k]; break;}
3978  case 3: {length = ((Int_t*) len_where)[k]; break;}
3979  case 4: {length = ((Long_t*) len_where)[k]; break;}
3980  //case 5: {length = ((Float_t*) len_where)[k]; break;}
3981  case 6: {length = ((Int_t*) len_where)[k]; break;}
3982  //case 8: {length = ((Double_t*)len_where)[k]; break;}
3983  case 11: {length = ((UChar_t*) len_where)[k]; break;}
3984  case 12: {length = ((UShort_t*) len_where)[k]; break;}
3985  case 13: {length = ((UInt_t*) len_where)[k]; break;}
3986  case 14: {length = ((ULong_t*) len_where)[k]; break;}
3987  case 15: {length = ((UInt_t*) len_where)[k]; break;}
3988  case 16: {length = ((Long64_t*) len_where)[k]; break;}
3989  case 17: {length = ((ULong64_t*)len_where)[k]; break;}
3990  case 18: {length = ((Bool_t*) len_where)[k]; break;}
3991  default: continue;
3992  }
3993  b >> isArray;
3994  if (length <= 0) continue;
3995  if (isArray == 0) continue;
3996  switch (atype) {
3997  case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
3998  case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
3999  case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4000  case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
4001  case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
4002  case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4003  case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
4004  case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
4005  case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
4006  case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4007  case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
4008  case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4009  case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
4010  case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
4011  case 18: {*where=new char[sizeof(Bool_t)*length]; b.ReadFastArray((Bool_t*) *where, length); break;}
4012  }
4013  }
4014  return;
4015  }
4016  if (atype > 20) {
4017  atype -= 20;
4019  n *= leaf->GetLenStatic();
4020  }
4021  switch (atype) {
4022  case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4023  case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4024  case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4025  case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4026  case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4027  case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4028  case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4029  case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4030  case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4031  case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4032  case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4033  case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4034  case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
4035  case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4036  case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
4037  case 9: {
4040  Double_t *xx = (Double_t*) fAddress;
4041  for (Int_t ii=0;ii<n;ii++) {
4042  b.ReadDouble32(&(xx[ii]),se);
4043  }
4044  break;
4045  }
4046  case 19: {
4049  Float_t *xx = (Float_t*) fAddress;
4050  for (Int_t ii=0;ii<n;ii++) {
4051  b.ReadFloat16(&(xx[ii]),se);
4052  }
4053  break;
4054  }
4055  }
4056  return;
4057  } else if (fType <= 2) { // branch in split mode
4058  // FIXME: This should probably be < 60 instead.
4059  if (fStreamerType > 40 && fStreamerType < 55) {
4060  Int_t atype = fStreamerType - 40;
4061  Int_t n;
4062  if (fBranchCount==0) {
4063  // Missing fBranchCount. let's attempts to recover.
4064 
4065  TString countname( GetName() );
4066  Ssiz_t dot = countname.Last('.');
4067  if (dot>=0) {
4068  countname.Remove(dot+1);
4069  } else {
4070  countname = "";
4071  }
4072  TString counter( GetTitle() );
4073  Ssiz_t loc = counter.Last('[');
4074  if (loc>=0) {
4075  counter.Remove(0,loc+1);
4076  }
4077  loc = counter.Last(']');
4078  if (loc>=0) {
4079  counter.Remove(loc);
4080  }
4081  countname += counter;
4082  SetBranchCount((TBranchElement *)fTree->GetBranch(countname));
4083  }
4084  if (fBranchCount) {
4085  n = (Int_t)fBranchCount->GetValue(0,0);
4086  } else {
4087  Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4088  n = 0;
4089  }
4090  fNdata = n;
4091  Char_t isArray;
4092  b >> isArray;
4093  switch (atype) {
4094  case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4095  case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4096  case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4097  case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4098  case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4099  case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4100  case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4101  case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4102  case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4103  case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4104  case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4105  case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4106  case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
4107  case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4108  case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
4109  case 9: {
4112  Double_t *xx = (Double_t*) fAddress;
4113  for (Int_t ii=0;ii<n;ii++) {
4114  b.ReadDouble32(&(xx[ii]),se);
4115  }
4116  break;
4117  }
4118  case 19: {
4121  Float_t *xx = (Float_t*) fAddress;
4122  for (Int_t ii=0;ii<n;ii++) {
4123  b.ReadFloat16(&(xx[ii]),se);
4124  }
4125  break;
4126  }
4127  }
4128  } else {
4129  fNdata = 1;
4130  if (fAddress) {
4131  if (fType<0) {
4132  // Non TObject, Non collection classes with a custom streamer.
4133 
4134  // if (fObject)
4136  } else {
4137  TStreamerInfo *info = GetInfoImp();
4138  if (!info) {
4139  return;
4140  }
4141  // Since info is not null, fReadActionSequence is not null either.
4142  b.ApplySequence(*fReadActionSequence, fObject);
4143  }
4145  fNdata = (Int_t) GetValue(0, 0);
4146  }
4147  } else {
4148  fNdata = 0;
4149  }
4150  }
4151  return;
4152  }
4153 }
4154 
4155 ////////////////////////////////////////////////////////////////////////////////
4156 /// Read leaves into i/o buffers for this branch.
4157 /// Case of a collection (fType == 4).
4158 
4160 {
4161  ValidateAddress();
4162  if (fObject == 0)
4163  {
4164  // We have nowhere to copy the data (probably because the data member was
4165  // 'dropped' from the current schema) so let's no copy it in a random place.
4166  return;
4167  }
4168 
4169  // STL container master branch (has only the number of elements).
4170  Int_t n;
4171  b >> n;
4172  if ((n < 0) || (n > fMaximum)) {
4173  if (IsMissingCollection()) {
4174  n = 0;
4175  b.SetBufferOffset(b.Length()-sizeof(n));
4176  } else {
4177  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());
4178  n = 0;
4179  }
4180  }
4181  fNdata = n;
4182 
4183  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4184 
4185  // Note: Proxy-helper needs to "embrace" the entire
4186  // streaming of this STL container if the container
4187  // is a set/multiset/map/multimap (what we do not
4188  // know here).
4189  // For vector/list/deque Allocate == Resize
4190  // and Commit == noop.
4191  // TODO: Exception safety a la TPushPop
4194  void* alternate = proxy->Allocate(fNdata, true);
4196  fPtrIterators->CreateIterators(alternate, proxy);
4197  } else {
4198  fIterators->CreateIterators(alternate, proxy);
4199  }
4200 
4201  Int_t nbranches = fBranches.GetEntriesFast();
4202  switch (fSTLtype) {
4203  case ROOT::kSTLset:
4206  case ROOT::kSTLmultiset:
4207  case ROOT::kSTLmap:
4208  case ROOT::kSTLmultimap:
4211  for (Int_t i = 0; i < nbranches; ++i) {
4212  TBranch *branch = (TBranch*) fBranches[i];
4213  Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4214  if (nb < 0) {
4215  // Give up on i/o failure.
4216  // FIXME: We need an error message here.
4217  break;
4218  }
4219  }
4220  break;
4221  default:
4222  break;
4223  }
4224  //------------------------------------------------------------------------
4225  // We have split this stuff, so we need to create the the pointers
4226  /////////////////////////////////////////////////////////////////////////////
4227 
4229  {
4230  TClass *elClass = proxy->GetValueClass();
4231 
4232  //--------------------------------------------------------------------
4233  // The allocation is done in this strange way because ReadLeaves
4234  // is being called many times by TTreeFormula!!!
4235  //////////////////////////////////////////////////////////////////////////
4236 
4237  Int_t i = 0;
4238  // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4239  if( !fNdata || *(void**)proxy->At( 0 ) != 0 )
4240  i = fNdata;
4241 
4242  for( ; i < fNdata; ++i )
4243  {
4244  void **el = (void**)proxy->At( i );
4245  // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4246  *el = elClass->New();
4247  }
4248  }
4249 
4250  proxy->Commit(alternate);
4251 }
4252 
4253 ////////////////////////////////////////////////////////////////////////////////
4254 /// Read leaves into i/o buffers for this branch.
4255 /// Case of a data member within a collection (fType == 41).
4256 
4258 {
4259  ValidateAddress();
4260  if (fObject == 0)
4261  {
4262  // We have nowhere to copy the data (probably because the data member was
4263  // 'dropped' from the current schema) so let's no copy it in a random place.
4264  return;
4265  }
4266 
4267  // STL container sub-branch (contains the elements).
4269  if (!fNdata) {
4270  return;
4271  }
4272 
4273  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4274 
4275  TStreamerInfo *info = GetInfoImp();
4276  if (info == 0) return;
4277 
4280 
4281  // R__ASSERT(0);
4283  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4284 }
4285 
4286 ////////////////////////////////////////////////////////////////////////////////
4287 /// Read leaves into i/o buffers for this branch.
4288 /// Case of a data member within a collection (fType == 41).
4289 
4291 {
4292  ValidateAddress();
4293  if (fObject == 0)
4294  {
4295  // We have nowhere to copy the data (probably because the data member was
4296  // 'dropped' from the current schema) so let's no copy it in a random place.
4297  return;
4298  }
4299 
4300  // STL container sub-branch (contains the elements).
4302  if (!fNdata) {
4303  return;
4304  }
4305  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4306 
4307  TStreamerInfo *info = GetInfoImp();
4308  if (info == 0) return;
4309 
4312 
4314  b.ApplySequenceVecPtr(*fReadActionSequence,iter->fBegin,iter->fEnd);
4315 }
4316 
4317 ////////////////////////////////////////////////////////////////////////////////
4318 /// Read leaves into i/o buffers for this branch.
4319 /// Case of a data member within a collection (fType == 41).
4320 
4322 {
4323  ValidateAddress();
4324  if (fObject == 0)
4325  {
4326  // We have nowhere to copy the data (probably because the data member was
4327  // 'dropped' from the current schema) so let's no copy it in a random place.
4328  return;
4329  }
4330 
4331  // STL container sub-branch (contains the elements).
4333  if (!fNdata) {
4334  return;
4335  }
4336  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4337 
4338  TStreamerInfo *info = GetInfoImp();
4339  if (info == 0) return;
4340  // Since info is not null, fReadActionSequence is not null either.
4341 
4342  // Still calling PushPop for the legacy entries.
4345 
4347  b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4348 }
4349 
4350 ////////////////////////////////////////////////////////////////////////////////
4351 /// Read leaves into i/o buffers for this branch.
4352 /// Case of a TClonesArray (fType == 3).
4353 
4355 {
4356  ValidateAddress();
4357  if (fObject == 0)
4358  {
4359  // We have nowhere to copy the data (probably because the data member was
4360  // 'dropped' from the current schema) so let's no copy it in a random place.
4361  return;
4362  }
4363 
4364  // TClonesArray master branch (has only the number of elements).
4365  Int_t n;
4366  b >> n;
4367  if ((n < 0) || (n > fMaximum)) {
4368  if (IsMissingCollection()) {
4369  n = 0;
4370  b.SetBufferOffset(b.Length()-sizeof(n));
4371  } else {
4372  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());
4373  n = 0;
4374  }
4375  }
4376  fNdata = n;
4377  TClonesArray* clones = (TClonesArray*) fObject;
4378  if (clones->IsZombie()) {
4379  return;
4380  }
4381  // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4382  // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4383  // clones->Clear();
4384  clones->ExpandCreateFast(fNdata);
4385 }
4386 
4387 ////////////////////////////////////////////////////////////////////////////////
4388 /// Read leaves into i/o buffers for this branch.
4389 /// Case of a data member within a TClonesArray (fType == 31).
4390 
4392 {
4393  // No need to validate the address here, if we are a member of a split ClonesArray,
4394  // fID is positive
4395  // ValidateAddress();
4396 
4397  if (fObject == 0)
4398  {
4399  // We have nowhere to copy the data (probably because the data member was
4400  // 'dropped' from the current schema) so let's no copy it in a random place.
4401  return;
4402  }
4403 
4404  // TClonesArray sub-branch (contains the elements).
4406  TClonesArray* clones = (TClonesArray*) fObject;
4407  if (clones->IsZombie()) {
4408  return;
4409  }
4410  TStreamerInfo *info = GetInfoImp();
4411  if (info==0) return;
4412  // Since info is not null, fReadActionSequence is not null either.
4413 
4414  // Note, we could (possibly) save some more, by configuring the action
4415  // based on the value of fOnfileObject rather than pushing in on a stack.
4416  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4417 
4418  char **arr = (char **)clones->GetObjectRef();
4419  char **end = arr + fNdata;
4420  b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
4421 }
4422 
4423 ////////////////////////////////////////////////////////////////////////////////
4424 /// Read leaves into i/o buffers for this branch.
4425 /// For split-class branch, base class branch, data member branch, or top-level branch.
4426 /// which do not have a branch count and are not a counter.
4427 
4429 {
4430  R__ASSERT(fBranchCount==0);
4432 
4433  ValidateAddress();
4434  if (fObject == 0)
4435  {
4436  // We have nowhere to copy the data (probably because the data member was
4437  // 'dropped' from the current schema) so let's no copy it in a random place.
4438  return;
4439  }
4440 
4441  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4442  // If not a TClonesArray or STL container master branch
4443  // or sub-branch and branch inherits from tobject,
4444  // then register with the buffer so that pointers are
4445  // handled properly.
4446  if (TestBit(kBranchObject)) {
4447  b.MapObject((TObject*) fObject);
4448  } else if (TestBit(kBranchAny)) {
4449  b.MapObject(fObject, fBranchClass);
4450  }
4451 
4452  fNdata = 1;
4453  TStreamerInfo *info = GetInfoImp();
4454  if (!info) {
4455  return;
4456  }
4457  // Since info is not null, fReadActionSequence is not null either.
4458  b.ApplySequence(*fReadActionSequence, fObject);
4459 }
4460 
4461 ////////////////////////////////////////////////////////////////////////////////
4462 /// Read leaves into i/o buffers for this branch.
4463 /// For split-class branch, base class branch, data member branch, or top-level branch.
4464 /// which do have a branch count and are not a counter.
4465 
4467 {
4469 
4470  ValidateAddress();
4471  if (fObject == 0)
4472  {
4473  // We have nowhere to copy the data (probably because the data member was
4474  // 'dropped' from the current schema) so let's no copy it in a random place.
4475  return;
4476  }
4477 
4478  // If not a TClonesArray or STL container master branch
4479  // or sub-branch and branch inherits from tobject,
4480  // then register with the buffer so that pointers are
4481  // handled properly.
4482  if (TestBit(kBranchObject)) {
4483  b.MapObject((TObject*) fObject);
4484  } else if (TestBit(kBranchAny)) {
4485  b.MapObject(fObject, fBranchClass);
4486  }
4487 
4488  fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4489  TStreamerInfo *info = GetInfoImp();
4490  if (!info) {
4491  return;
4492  }
4493  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1); // Here we have a single object that contains a variable size C-style array.
4494  // Since info is not null, fReadActionSequence is not null either.
4495  b.ApplySequence(*fReadActionSequence, fObject);
4496 }
4497 
4498 ////////////////////////////////////////////////////////////////////////////////
4499 /// Read leaves into i/o buffers for this branch.
4500 /// For split-class branch, base class branch, data member branch, or top-level branch.
4501 /// which do not have a branch count and are a counter.
4502 
4504 {
4505  ValidateAddress();
4506  if (fObject == 0)
4507  {
4508  // We have nowhere to copy the data (probably because the data member was
4509  // 'dropped' from the current schema) so let's no copy it in a random place.
4510  return;
4511  }
4512 
4513  // If not a TClonesArray or STL container master branch
4514  // or sub-branch and branch inherits from tobject,
4515  // then register with the buffer so that pointers are
4516  // handled properly.
4517  if (TestBit(kBranchObject)) {
4518  b.MapObject((TObject*) fObject);
4519  } else if (TestBit(kBranchAny)) {
4520  b.MapObject(fObject, fBranchClass);
4521  }
4522 
4523  TStreamerInfo *info = GetInfoImp();
4524  if (!info) {
4525  return;
4526  }
4527 
4528  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4529 
4530  // Since info is not null, fReadActionSequence is not null either.
4531  b.ApplySequence(*fReadActionSequence, fObject);
4532  fNdata = (Int_t) GetValue(0, 0);
4533 }
4534 
4535 ////////////////////////////////////////////////////////////////////////////////
4536 /// Read leaves into i/o buffers for this branch.
4537 /// Non TObject, Non collection classes with a custom streamer.
4538 
4540 {
4541  ValidateAddress();
4542  if (fObject == 0)
4543  {
4544  // We have nowhere to copy the data (probably because the data member was
4545  // 'dropped' from the current schema) so let's no copy it in a random place.
4546  return;
4547  }
4548 
4549  R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4551 }
4552 
4553 ////////////////////////////////////////////////////////////////////////////////
4554 /// Unconfiguration Fill Leave function.
4555 
4557 {
4558  Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4559 }
4560 
4561 ////////////////////////////////////////////////////////////////////////////////
4562 /// Delete any object we may have allocated on a previous call to SetAddress.
4563 
4565 {
4566  if (fObject && TestBit(kDeleteObject)) {
4567  if (IsAutoDelete() && fAddress != (char*)&fObject) {
4568  *((char**) fAddress) = 0;
4569  }
4571  if (fType == 3) {
4572  // -- We are a TClonesArray master branch.
4573  TClonesArray::Class()->Destructor(fObject);
4574  fObject = 0;
4577  // -- We are a pointer to a TClonesArray.
4578  // We must zero the pointer in the object.
4579  *((char**) fAddress) = 0;
4580  }
4581  } else if (fType == 4) {
4582  // -- We are an STL container master branch.
4584 
4585  if (!proxy) {
4586  Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4587  fObject = 0;
4588  } else {
4590  if (needDelete && fID >= 0) {
4593  needDelete = !se->TestBit(TStreamerElement::kDoNotDelete);
4594  }
4595  if (needDelete) {
4597  proxy->Clear("force");
4598  }
4599  proxy->Destructor(fObject);
4600  fObject = 0;
4601  }
4603  // -- We are a pointer to an STL container.
4604  // We must zero the pointer in the object.
4605  *((char**) fAddress) = 0;
4606  }
4607  } else {
4608  // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4609  TClass* cl = fBranchClass.GetClass();
4610  if (!cl) {
4611  Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4612  fObject = 0;
4613  } else {
4615 
4616  if (proxy) {
4617  if (fID >= 0) {
4619  TStreamerElement* se = si->GetElement(fID);
4622  proxy->Clear("force");
4623  }
4626  proxy->Clear("force");
4627  }
4628 
4629  }
4630  cl->Destructor(fObject);
4631  fObject = 0;
4632  }
4633  }
4634  }
4635 }
4636 
4637 ////////////////////////////////////////////////////////////////////////////////
4638 /// Reset a Branch.
4639 ///
4640 /// Existing i/o buffers are deleted.
4641 /// Entries, max and min are reset.
4642 ///
4643 
4645 {
4646  Int_t nbranches = fBranches.GetEntriesFast();
4647  for (Int_t i = 0; i < nbranches; ++i) {
4648  TBranch* branch = (TBranch*) fBranches[i];
4649  branch->Reset(option);
4650  }
4651  fBranchID = -1;
4652  TBranch::Reset(option);
4653 }
4654 
4655 ////////////////////////////////////////////////////////////////////////////////
4656 /// Reset a Branch after a Merge operation (drop data but keep customizations)
4657 ///
4658 
4660 {
4661  Int_t nbranches = fBranches.GetEntriesFast();
4662  for (Int_t i = 0; i < nbranches; ++i) {
4663  TBranch* branch = (TBranch*) fBranches[i];
4664  branch->ResetAfterMerge(info);
4665  }
4667 }
4668 
4669 ////////////////////////////////////////////////////////////////////////////////
4670 /// Set branch address to zero and free all allocated memory.
4671 
4673 {
4674  for (Int_t i = 0; i < fNleaves; ++i) {
4675  TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
4676  //if (leaf) leaf->SetAddress(0);
4677  leaf->SetAddress(0);
4678  }
4679 
4680  // Note: We *must* do the sub-branches first, otherwise
4681  // we may delete the object containing the sub-branches
4682  // before giving them a chance to cleanup.
4683  Int_t nbranches = fBranches.GetEntriesFast();
4684  for (Int_t i = 0; i < nbranches; ++i) {
4685  TBranch* br = (TBranch*) fBranches[i];
4686  if (br) br->ResetAddress();
4687  }
4688 
4689  //
4690  // SetAddress may have allocated an object.
4691  //
4692 
4693  ReleaseObject();
4694 
4696  fAddress = 0;
4697  fObject = 0;
4698 }
4699 
4700 ////////////////////////////////////////////////////////////////////////////////
4701 /// Release ownership of any allocated objects.
4702 ///
4703 /// Note: This interface was added so that clone trees could
4704 /// be told they do not own the allocated objects.
4705 
4707 {
4710  for (Int_t i = 0; i < nb; ++i) {
4711  TBranch* br = (TBranch*) fBranches[i];
4712  if (br->InheritsFrom(TBranchElement::Class())) {
4713  ((TBranchElement*) br)->ResetDeleteObject();
4714  }
4715  }
4716 }
4717 
4718 ////////////////////////////////////////////////////////////////////////////////
4719 /// \brief Reset offset and StremerInfo information from this branch.
4720 /// \param[in] recurse When true call ResetInitInfo on all subbranches.
4721 ///
4722 
4724 {
4725  fInfo = nullptr;
4726  fInit = kFALSE;
4727  fInitOffsets = kFALSE;
4728  fCurrentClass = nullptr;
4729  delete fReadActionSequence;
4730  fReadActionSequence = nullptr;
4731  delete fFillActionSequence;
4732  fFillActionSequence = nullptr;
4733 
4734  if (recurse) {
4735  Int_t nbranches = fBranches.GetEntriesFast();
4736  for (Int_t i = 0; i < nbranches; ++i) {
4738  sub->ResetInitInfo(kTRUE);
4739  }
4740  }
4741 }
4742 
4743 ////////////////////////////////////////////////////////////////////////////////
4744 /// Point this branch at an object.
4745 ///
4746 /// For a sub-branch, addr is a pointer to the branch object.
4747 ///
4748 /// For a top-level branch the meaning of addr is as follows:
4749 ///
4750 /// If addr is zero, then we allocate a branch object
4751 /// internally and the branch is the owner of the allocated
4752 /// object, not the caller. However the caller may obtain
4753 /// a pointer to the branch object with GetObject().
4754 /// The pointer is reset to zero (nullptr) when the relevant
4755 /// branch object is destroyed.
4756 ///
4757 /// Example:
4758 /// ~~~ {.cpp}
4759 /// branch->SetAddress(0);
4760 /// Event* event = branch->GetObject();
4761 /// ... Do some work.
4762 /// ~~~
4763 /// If addr is not zero, but the pointer addr points at is
4764 /// zero, then we allocate a branch object and set the passed
4765 /// pointer to point at the allocated object. The caller
4766 /// owns the allocated object and is responsible for deleting
4767 /// it when it is no longer needed.
4768 ///
4769 /// Example:
4770 /// ~~~ {.cpp}
4771 /// Event* event = 0;
4772 /// branch->SetAddress(&event);
4773 /// ... Do some work.
4774 /// delete event;
4775 /// event = 0;
4776 /// ~~~
4777 /// If addr is not zero and the pointer addr points at is
4778 /// also not zero, then the caller has allocated a branch
4779 /// object and is asking us to use it. The caller owns it
4780 /// and must delete it when it is no longer needed.
4781 ///
4782 /// Example:
4783 /// ~~~ {.cpp}
4784 /// Event* event = new Event();
4785 /// branch->SetAddress(&event);
4786 /// ... Do some work.
4787 /// delete event;
4788 /// event = 0;
4789 /// ~~~
4790 /// These rules affect users of TTree::Branch(),
4791 /// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4792 /// as well because those routines call this one.
4793 ///
4794 /// An example of a tree with branches with objects allocated
4795 /// and owned by us:
4796 /// ~~~ {.cpp}
4797 /// TFile* f1 = new TFile("myfile_original.root");
4798 /// TTree* t1 = (TTree*) f->Get("MyTree");
4799 /// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4800 /// TTree* t2 = t1->Clone(0);
4801 /// for (Int_t i = 0; i < 10; ++i) {
4802 /// t1->GetEntry(i);
4803 /// t2->Fill();
4804 /// }
4805 /// t2->Write()
4806 /// delete f2;
4807 /// f2 = 0;
4808 /// delete f1;
4809 /// f1 = 0;
4810 /// ~~~
4811 /// An example of a branch with an object allocated by us,
4812 /// but owned by the caller:
4813 /// ~~~ {.cpp}
4814 /// TFile* f = new TFile("myfile.root", "recreate");
4815 /// TTree* t = new TTree("t", "A test tree.")
4816 /// Event* event = 0;
4817 /// TBranchElement* br = t->Branch("event.", &event);
4818 /// for (Int_t i = 0; i < 10; ++i) {
4819 /// ... Fill event with meaningful data in some way.
4820 /// t->Fill();
4821 /// }
4822 /// t->Write();
4823 /// delete event;
4824 /// event = 0;
4825 /// delete f;
4826 /// f = 0;
4827 /// ~~~
4828 /// Notice that the only difference between this example
4829 /// and the following example is that the event pointer
4830 /// is zero when the branch is created.
4831 ///
4832 /// An example of a branch with an object allocated and
4833 /// owned by the caller:
4834 /// ~~~ {.cpp}
4835 /// TFile* f = new TFile("myfile.root", "recreate");
4836 /// TTree* t = new TTree("t", "A test tree.")
4837 /// Event* event = new Event();
4838 /// TBranchElement* br = t->Branch("event.", &event);
4839 /// for (Int_t i = 0; i < 10; ++i) {
4840 /// ... Fill event with meaningful data in some way.
4841 /// t->Fill();
4842 /// }
4843 /// t->Write();
4844 /// delete event;
4845 /// event = 0;
4846 /// delete f;
4847 /// f = 0;
4848 /// ~~~
4849 /// If AutoDelete is on (see TBranch::SetAutoDelete),
4850 /// the top level objet will be deleted and recreate
4851 /// each time an entry is read, whether or not the
4852 /// TTree owns the object.
4853 
4855 {
4856  SetAddressImpl(addr, (addr == nullptr));
4857 }
4858 
4859 /// See TBranchElement::SetAddress.
4860 /// If implied is true, we do not over-ride existing address for
4861 /// sub-branches.
4862 void TBranchElement::SetAddressImpl(void* addr, bool implied)
4863 {
4864  //
4865  // Don't bother if we are disabled.
4866  //
4867 
4868  if (TestBit(kDoNotProcess)) {
4869  return;
4870  }
4871 
4872  //
4873  // FIXME: When would this happen?
4874  //
4875 
4876  if (fType < -1) {
4877  return;
4878  }
4879 
4880  //
4881  // Special case when called from code generated by TTree::MakeClass.
4882  //
4883 
4884  if (Long_t(addr) == -1) {
4885  // FIXME: Do we have to release an object here?
4886  // ReleaseObject();
4887  fAddress = (char*) -1;
4888  fObject = (char*) -1;
4891  return;
4892  }
4893 
4894  //
4895  // Reset last read entry number, we have a new user object now.
4896  //
4897 
4898  fReadEntry = -1;
4899 
4900  //
4901  // Make sure our branch class is instantiated.
4902  //
4903  TClass* clOfBranch = fBranchClass.GetClass();
4904  if( fTargetClass.GetClassName()[0] ) {
4905  clOfBranch = fTargetClass;
4906  }
4907 
4908  //
4909  // Try to build the streamer info.
4910  //
4911 
4912  TStreamerInfo *info = GetInfoImp();
4913 
4914  // FIXME: Warn about failure to get the streamer info here?
4915 
4916  //
4917  // We may have allocated an object last time we were called.
4918  //
4919 
4920  if (fObject && TestBit(kDeleteObject)){
4921  ReleaseObject();
4922  }
4923 
4924  //
4925  // Remember the pointer to the pointer to our object.
4926  //
4927 
4928  fAddress = (char*) addr;
4929  if (fAddress != (char*)(&fObject)) {
4930  fObject = 0;
4931  }
4934 
4935  //
4936  // Do special stuff if we got called from a MakeClass class.
4937  // Allow sub-branches to have independently set addresses.
4938  //
4939 
4940  if (TestBit(kDecomposedObj)) {
4941  if (fID > -1) {
4942  // We are *not* a top-level branch.
4943  if (!info) {
4944  // No streamer info, give up.
4945  // FIXME: We should have an error message here.
4946  fObject = fAddress;
4947  } else {
4948  // Compensate for the fact that the i/o routines
4949  // will add the streamer offset to the address.
4950  fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
4951  }
4952  return;
4953  }
4954  }
4955 
4956  //
4957  // Check whether the container type is still the same
4958  // to support schema evolution; what is written on the file
4959  // may no longer match the class code which is loaded.
4960  //
4961 
4962  if (fType == 3) {
4963  // split TClonesArray, counter/master branch.
4964  TClass* clm = fClonesClass;
4965  if (clm) {
4966  // In case clm derives from an abstract class.
4967  clm->BuildRealData();
4968  clm->GetStreamerInfo();
4969  }
4970  TClass* newType = GetCurrentClass();
4971  if (newType && (newType != TClonesArray::Class())) {
4972  // The data type of the container has changed.
4973  //
4974  // Let's check if it is a compatible type:
4975  Bool_t matched = kFALSE;
4976  if (newType->GetCollectionProxy()) {
4977  TClass *content = newType->GetCollectionProxy()->GetValueClass();
4978  if (clm == content) {
4979  matched = kTRUE;
4980  } else {
4981  Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
4982  }
4983  } else {
4984  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());
4985  }
4986  if (matched) {
4987  // Change from 3/31 to 4/41
4988  SetType(4);
4989  // Set the proxy.
4990  fSTLtype = newType->GetCollectionType();
4991  fCollProxy = newType->GetCollectionProxy()->Generate();
4992 
4994  SetReadLeavesPtr();
4995  SetFillLeavesPtr();
4996 
5002  } else {
5004  }
5005  } else {
5006  // FIXME: Must maintain fObject here as well.
5007  fAddress = 0;
5009  }
5010  }
5011  } else if (fType == 4) {
5012  // split STL container, counter/master branch.
5013  TClass* newType = GetCurrentClass();
5014  if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
5015  // Let's check if it is a compatible type:
5016  TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
5018  if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
5019  delete fCollProxy;
5020  Int_t nbranches = GetListOfBranches()->GetEntries();
5021  fCollProxy = newType->GetCollectionProxy()->Generate();
5023  for (Int_t i = 0; i < nbranches; ++i) {
5025  br->fCollProxy = 0;
5026  if (br->fReadActionSequence) {
5027  br->SetReadActionSequence();
5028  }
5029  if (br->fFillActionSequence) {
5030  br->SetFillActionSequence();
5031  }
5032  }
5035  SetReadLeavesPtr();
5036  SetFillLeavesPtr();
5037  delete fIterators;
5038  delete fPtrIterators;
5044  } else {
5046  }
5047  }
5048  else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=0) && (newProxy->GetValueClass()!=0)) {
5049  // Let see if there is a rule to convert the content of the collection into each other.
5050  if (newType->GetSchemaRules()->HasRuleWithSour