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