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