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