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 {
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.GetEntriesFast();
1145
1146 for (Int_t i = 0; i < nbranches; ++i) {
1148 if (!bre)
1149 continue;
1150 if (fType == 3) {
1151 bre->SetType(31);
1152 } else if (fType == 4) {
1153 bre->SetType(41);
1154 } else {
1155 Error("BuildTitle", "This cannot happen, fType of parent is not 3 or 4!");
1156 }
1158 bre->BuildTitle(name);
1159 const char* fin = strrchr(bre->GetTitle(), '.');
1160 if (fin == 0) {
1161 continue;
1162 }
1163 // The branch counter for a sub-branch of a container is the container master branch.
1164 bre->SetBranchCount(this);
1165 TLeafElement* lf = (TLeafElement*) bre->GetListOfLeaves()->At(0);
1166 // If branch name is of the form fTracks.fCovar[3][4], then
1167 // set the title to fCovar[fTracks_].
1168 branchname = fin+1;
1169 Ssiz_t dim = branchname.First('[');
1170 if (dim>=0) {
1171 branchname.Remove(dim);
1172 }
1173 branchname += TString::Format("[%s_]",name);
1174 bre->SetTitle(branchname);
1175 if (lf) {
1176 lf->SetTitle(branchname);
1177 }
1178 // Is there a secondary branchcount?
1179 //
1180 // fBranchCount2 points to the secondary branchcount
1181 // in case a TClonesArray element itself has a branchcount.
1182 //
1183 // Example: In Event class with TClonesArray fTracks of Track objects.
1184 // if the Track object has two members
1185 // Int_t fNpoint;
1186 // Float_t *fPoints; //[fNpoint]
1187 // In this case the TBranchElement fTracks.fPoints has
1188 // -its primary branchcount pointing to the branch fTracks
1189 // -its secondary branchcount pointing to fTracks.fNpoint
1190 Int_t stype = bre->GetStreamerType();
1191 // FIXME: Should 60 be included here?
1192 if ((stype > 40) && (stype < 61)) {
1193 TString name2 (bre->GetName());
1194 Ssiz_t bn = name2.Last('.');
1195 if (bn<0) {
1196 continue;
1197 }
1199 name2.Remove(bn+1);
1200 if (el) name2 += el->GetCountName();
1202 bre->SetBranchCount2(bc2);
1203 }
1204 bre->SetReadLeavesPtr();
1205 bre->SetFillLeavesPtr();
1206 }
1207}
1208
1209////////////////////////////////////////////////////////////////////////////////
1210/// Loop on all leaves of this branch to fill the basket buffer.
1211///
1212/// The function returns the number of bytes committed to the
1213/// individual branches. If a write error occurs, the number of
1214/// bytes returned is -1. If no data are written, because, e.g.,
1215/// the branch is disabled, the number of bytes returned is 0.
1216///
1217/// Note: We not not use any member functions from TLeafElement!
1218
1220{
1221 Int_t nbytes = 0;
1222 Int_t nwrite = 0;
1223 Int_t nerror = 0;
1224 Int_t nbranches = fBranches.GetEntriesFast();
1225
1227
1228 //
1229 // If we are a top-level branch, update addresses.
1230 //
1231
1232 if (fID < 0) {
1233 if (!fObject) {
1234 Error("Fill", "attempt to fill branch %s while addresss is not set", GetName());
1235 return 0;
1236 }
1237 }
1238
1239 //
1240 // If the tree has a TRefTable, set the current branch if
1241 // branch is not a basic type.
1242 //
1243
1244 // FIXME: This test probably needs to be extended past 10.
1245 if ((fType >= -1) && (fType < 10)) {
1246 TBranchRef* bref = fTree->GetBranchRef();
1247 if (bref) {
1248 fBranchID = bref->SetParent(this, fBranchID);
1249 }
1250 }
1251
1252 if (!nbranches) {
1253 // No sub-branches.
1254 if (!TestBit(kDoNotProcess)) {
1255 nwrite = TBranch::FillImpl(imtHelper);
1256 if (nwrite < 0) {
1257 Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1258 ++nerror;
1259 } else {
1260 nbytes += nwrite;
1261 }
1262 }
1263 } else {
1264 // We have sub-branches.
1265 if (fType == 3 || fType == 4) {
1266 // TClonesArray or STL container counter
1267 nwrite = TBranch::FillImpl(imtHelper);
1268 if (nwrite < 0) {
1269 Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1270 ++nerror;
1271 } else {
1272 nbytes += nwrite;
1273 }
1274 } else {
1275 ++fEntries;
1276 }
1277 for (Int_t i = 0; i < nbranches; ++i) {
1278 TBranchElement* branch = (TBranchElement*) fBranches[i];
1279 if (!branch->TestBit(kDoNotProcess)) {
1280 nwrite = branch->FillImpl(imtHelper);
1281 if (nwrite < 0) {
1282 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d", GetName(), branch->GetName(), nwrite);
1283 nerror++;
1284 } else {
1285 nbytes += nwrite;
1286 }
1287 }
1288 }
1289 }
1290
1291 if (fTree->Debug() > 0) {
1292 // Debugging.
1293 Long64_t entry = fEntries;
1294 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
1295 printf("Fill: %lld, branch=%s, nbytes=%d\n", entry, GetName(), nbytes);
1296 }
1297 }
1298
1299 if (nerror != 0) {
1300 return -1;
1301 }
1302
1303 return nbytes;
1304}
1305
1306////////////////////////////////////////////////////////////////////////////////
1307/// Write leaves into i/o buffers for this branch.
1308/// For the case where the branch is set in MakeClass mode (decomposed object).
1309
1311{
1313
1314 //
1315 // Silently do nothing if we have no user i/o buffer.
1316 //
1317
1318 if (!fObject) {
1319 return;
1320 }
1321
1322 // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1323 if(fType == 3) {
1324 // fClonesClass can not be zero since we are of type 3, see TBranchElement::Init
1326 if (!si) {
1327 Error("FillLeaves", "Cannot get streamer info for branch '%s' class '%s'", GetName(), fClonesClass->GetName());
1328 return;
1329 }
1330 b.ForceWriteInfo(si,kFALSE);
1331 Int_t* nptr = (Int_t*) fAddress;
1332 b << *nptr;
1333 } else if (fType == 31) {
1334 // -- TClonesArray sub-branch. Write out the entries in the TClonesArray.
1335 // -- A MakeClass() tree, we must use fAddress instead of fObject.
1336 if (!fAddress) {
1337 // FIXME: Enable this message.
1338 //Error("FillLeaves", "Branch address not set for branch '%s'!", GetName());
1339 return;
1340 }
1341 Int_t atype = fStreamerType;
1342 if (atype > 54) {
1343 // Note: We are not supporting kObjectp, kAny, kObjectp,
1344 // kObjectP, kTString, kTObject, kTNamed, kAnyp,
1345 // kAnyP, kSTLp, kSTL, kSTLstring, kStreamer,
1346 // kStreamLoop here, nor pointers to varying length
1347 // arrays of them either.
1348 // Nor do we support pointers to varying length
1349 // arrays of kBits, kLong64, kULong64, nor kBool.
1350 return;
1351 }
1352 Int_t* nn = (Int_t*) fBranchCount->GetAddress();
1353 if (!nn) {
1354 Error("FillLeaves", "The branch counter address was zero!");
1355 return;
1356 }
1357 Int_t n = *nn;
1358 if (atype > 40) {
1359 // Note: We are not supporting pointer to varying length array.
1360 Error("FillLeaves", "Clonesa: %s, n=%d, sorry not supported yet", GetName(), n);
1361 return;
1362 }
1363 if (atype > 20) {
1364 atype -= 20;
1366 n = n * leaf->GetLenStatic();
1367 }
1368 switch (atype) {
1369 // Note: Type 0 is a base class and cannot happen here, see Unroll().
1370 case TVirtualStreamerInfo::kChar /* 1 */: { b.WriteFastArray((Char_t*) fAddress, n); break; }
1371 case TVirtualStreamerInfo::kShort /* 2 */: { b.WriteFastArray((Short_t*) fAddress, n); break; }
1372 case TVirtualStreamerInfo::kInt /* 3 */: { b.WriteFastArray((Int_t*) fAddress, n); break; }
1373 case TVirtualStreamerInfo::kLong /* 4 */: { b.WriteFastArray((Long_t*) fAddress, n); break; }
1374 case TVirtualStreamerInfo::kFloat /* 5 */: { b.WriteFastArray((Float_t*) fAddress, n); break; }
1375 case TVirtualStreamerInfo::kCounter /* 6 */: { b.WriteFastArray((Int_t*) fAddress, n); break; }
1376 // FIXME: We do nothing with type 7 (TVirtualStreamerInfo::kCharStar, char*) here!
1377 case TVirtualStreamerInfo::kDouble /* 8 */: { b.WriteFastArray((Double_t*) fAddress, n); break; }
1378 case TVirtualStreamerInfo::kDouble32 /* 9 */: {
1380 // coverity[returned_null] structurally si->fComp (used in GetElem) can not be null.
1381 TStreamerElement* se = si->GetElement(fID);
1382 Double_t* xx = (Double_t*) fAddress;
1383 for (Int_t ii = 0; ii < n; ++ii) {
1384 b.WriteDouble32(&(xx[ii]),se);
1385 }
1386 break;
1387 }
1388 case TVirtualStreamerInfo::kFloat16 /* 19 */: {
1390 // coverity[dereference] structurally si can not be null.
1392 Float_t* xx = (Float_t*) fAddress;
1393 for (Int_t ii = 0; ii < n; ++ii) {
1394 b.WriteFloat16(&(xx[ii]),se);
1395 }
1396 break;
1397 }
1398 // Note: Type 10 is unused for now.
1399 case TVirtualStreamerInfo::kUChar /* 11 */: { b.WriteFastArray((UChar_t*) fAddress, n); break; }
1400 case TVirtualStreamerInfo::kUShort /* 12 */: { b.WriteFastArray((UShort_t*) fAddress, n); break; }
1401 case TVirtualStreamerInfo::kUInt /* 13 */: { b.WriteFastArray((UInt_t*) fAddress, n); break; }
1402 case TVirtualStreamerInfo::kULong /* 14 */: { b.WriteFastArray((ULong_t*) fAddress, n); break; }
1403 // FIXME: This is wrong!!! TVirtualStreamerInfo::kBits is a variable length type.
1404 case TVirtualStreamerInfo::kBits /* 15 */: { b.WriteFastArray((UInt_t*) fAddress, n); break; }
1405 case TVirtualStreamerInfo::kLong64 /* 16 */: { b.WriteFastArray((Long64_t*) fAddress, n); break; }
1406 case TVirtualStreamerInfo::kULong64 /* 17 */: { b.WriteFastArray((ULong64_t*) fAddress, n); break; }
1407 case TVirtualStreamerInfo::kBool /* 18 */: { b.WriteFastArray((Bool_t*) fAddress, n); break; }
1408 }
1409 }
1410}
1411
1412////////////////////////////////////////////////////////////////////////////////
1413/// Write leaves into i/o buffers for this branch.
1414/// Case of a collection (fType == 4).
1415
1417{
1418 // -- STL container top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1420
1421 //
1422 // Silently do nothing if we have no user i/o buffer.
1423 //
1424
1425 if (!fObject) {
1426 return;
1427 }
1428
1430 Int_t n = 0;
1431 // We are in a block so the helper pops as soon as possible.
1433 n = proxy->Size();
1434
1435 if (n > fMaximum) {
1436 fMaximum = n;
1437 }
1438 b << n;
1439
1442 } else {
1443 //NOTE: this does not work for not vectors since the CreateIterators expects a TGenCollectionProxy::TStaging as its argument!
1444 //NOTE: and those not work in general yet, since the TStaging object is neither created nor passed.
1445 // We need to review how to avoid the need for a TStaging during the writing.
1448 } else {
1450 }
1451 }
1452
1453}
1454
1455////////////////////////////////////////////////////////////////////////////////
1456/// Write leaves into i/o buffers for this branch.
1457/// Case of a data member within a collection (fType == 41).
1458
1460{
1462
1463 //
1464 // Silently do nothing if we have no user i/o buffer.
1465 //
1466
1467 if (!fObject) {
1468 return;
1469 }
1470
1471 // FIXME: This wont work if a pointer to vector is split!
1473 // Note: We cannot pop the proxy here because we need it for the i/o.
1475 if (!si) {
1476 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1477 return;
1478 }
1479
1481 R__ASSERT(0!=iter);
1482 b.ApplySequenceVecPtr(*fFillActionSequence,iter->fBegin,iter->fEnd);
1483}
1484
1485////////////////////////////////////////////////////////////////////////////////
1486/// Write leaves into i/o buffers for this branch.
1487/// Case of a data member within a collection (fType == 41).
1488
1490{
1492
1493 //
1494 // Silently do nothing if we have no user i/o buffer.
1495 //
1496
1497 if (!fObject) {
1498 return;
1499 }
1500
1501 // FIXME: This wont work if a pointer to vector is split!
1503
1504 // Note: We cannot pop the proxy here because we need it for the i/o.
1506 if (!si) {
1507 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1508 return;
1509 }
1510
1512 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1513
1514}
1515
1516////////////////////////////////////////////////////////////////////////////////
1517/// Write leaves into i/o buffers for this branch.
1518/// Case of a data member within a collection (fType == 41).
1519
1521{
1523
1524 //
1525 // Silently do nothing if we have no user i/o buffer.
1526 //
1527
1528 if (!fObject) {
1529 return;
1530 }
1531
1532 // FIXME: This wont work if a pointer to vector is split!
1534 // Note: We cannot pop the proxy here because we need it for the i/o.
1536 if (!si) {
1537 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1538 return;
1539 }
1540
1542 R__ASSERT(0!=iter);
1543 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1544
1545}
1546
1547////////////////////////////////////////////////////////////////////////////////
1548/// Write leaves into i/o buffers for this branch.
1549/// Case of a data member within a collection (fType == 41).
1550
1552{
1554
1555 //
1556 // Silently do nothing if we have no user i/o buffer.
1557 //
1558
1559 if (!fObject) {
1560 return;
1561 }
1562
1563 // FIXME: This wont work if a pointer to vector is split!
1565 // Note: We cannot pop the proxy here because we need it for the i/o.
1567 if (!si) {
1568 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1569 return;
1570 }
1571
1573 R__ASSERT(0!=iter);
1574 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1575
1576}
1577
1578////////////////////////////////////////////////////////////////////////////////
1579/// Write leaves into i/o buffers for this branch.
1580/// Case of a TClonesArray (fType == 3).
1581
1583{
1584 // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1586
1587 //
1588 // Silently do nothing if we have no user i/o buffer.
1589 //
1590
1591 if (!fObject) {
1592 return;
1593 }
1594
1595 TClonesArray* clones = (TClonesArray*) fObject;
1596 Int_t n = clones->GetEntriesFast();
1597 if (n > fMaximum) {
1598 fMaximum = n;
1599 }
1600 b << n;
1601}
1602
1603////////////////////////////////////////////////////////////////////////////////
1604/// Write leaves into i/o buffers for this branch.
1605/// Case of a data member within a TClonesArray (fType == 31).
1606
1608{
1610
1611 //
1612 // Silently do nothing if we have no user i/o buffer.
1613 //
1614
1615 if (!fObject) {
1616 return;
1617 }
1618
1619 TClonesArray* clones = (TClonesArray*) fObject;
1620 Int_t n = clones->GetEntriesFast();
1622 if (!si) {
1623 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1624 return;
1625 }
1626
1627 char **arr = (char **)clones->GetObjectRef(0);
1628 char **end = arr + n;
1629 b.ApplySequenceVecPtr(*fFillActionSequence,arr,end);
1630}
1631
1632////////////////////////////////////////////////////////////////////////////////
1633/// Write leaves into i/o buffers for this branch.
1634/// Case of a non TObject, non collection class with a custom streamer
1635
1637{
1639
1640 //
1641 // Silently do nothing if we have no user i/o buffer.
1642 //
1643
1644 if (!fObject) {
1645 return;
1646 }
1647
1648 //
1649 // Remember tobjects written to the buffer so that
1650 // pointers are handled correctly later.
1651
1652 if (TestBit(kBranchObject)) {
1653 b.MapObject((TObject*) fObject);
1654 } else if (TestBit(kBranchAny)) {
1655 b.MapObject(fObject, fBranchClass);
1656 }
1657
1659}
1660
1661////////////////////////////////////////////////////////////////////////////////
1662/// Write leaves into i/o buffers for this branch.
1663/// For split-class branch, base class branch, data member branch, or top-level branch.
1664/// which do have a branch count and are not a counter.
1665
1667{
1669 /*
1670 ValidateAddress();
1671
1672 //
1673 // Silently do nothing if we have no user i/o buffer.
1674 //
1675
1676 if (!fObject) {
1677 return;
1678 }
1679 */
1680}
1681
1682////////////////////////////////////////////////////////////////////////////////
1683/// Write leaves into i/o buffers for this branch.
1684/// For split-class branch, base class branch, data member branch, or top-level branch.
1685/// which do not have a branch count and are a counter.
1686
1688{
1690
1691 //
1692 // Silently do nothing if we have no user i/o buffer.
1693 //
1694
1695 if (!fObject) {
1696 return;
1697 }
1698 // -- Top-level, data member, base class, or split class branch.
1699 // 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.
1700 // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1701 // FIXME: What happens with a split base class branch,
1702 // or a split class branch???
1703 TStreamerInfo* si = GetInfoImp();
1704 if (!si) {
1705 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1706 return;
1707 }
1708 // Since info is not null, fFillActionSequence is not null either.
1709 b.ApplySequence(*fFillActionSequence, fObject);
1710 // Int_t n = si->WriteBufferAux(b, &fObject, fID, 1, 0, 0);
1711
1712 Int_t n = *(Int_t*)(fObject + si->TStreamerInfo::GetElementOffset(fID)); // or GetInfoImp()->GetTypedValue<Int_t>(&fObject, fID, j, -1);
1713 if (n > fMaximum) {
1714 fMaximum = n;
1715 }
1716
1717}
1718
1719////////////////////////////////////////////////////////////////////////////////
1720/// Write leaves into i/o buffers for this branch.
1721/// For split-class branch, base class branch, data member branch, or top-level branch.
1722/// which do not have a branch count and are not a counter.
1723
1725{
1727
1728 //
1729 // Silently do nothing if we have no user i/o buffer.
1730 //
1731
1732 if (!fObject) {
1733 return;
1734 }
1735
1736 if (TestBit(kBranchObject)) {
1737 b.MapObject((TObject*) fObject);
1738 } else if (TestBit(kBranchAny)) {
1739 b.MapObject(fObject, fBranchClass);
1740 }
1741
1742 // -- Top-level, data member, base class, or split class branch.
1743 // 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.
1744 // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1745 // FIXME: What happens with a split base class branch,
1746 // or a split class branch???
1747 TStreamerInfo* si = GetInfoImp();
1748 if (!si) {
1749 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1750 return;
1751 }
1752 // Since info is not null, fFillActionSequence is not null either.
1753 b.ApplySequence(*fFillActionSequence, fObject);
1754
1755}
1756
1757////////////////////////////////////////////////////////////////////////////////
1758/// Remove trailing dimensions and make sure
1759/// there is a trailing dot.
1760
1761static void R__CleanName(std::string &name)
1762{
1763 if (name[name.length()-1]==']') {
1764 std::size_t dim = name.find_first_of("[");
1765 if (dim != std::string::npos) {
1766 name.erase(dim);
1767 }
1768 }
1769 if (name[name.size()-1] != '.') {
1770 name += '.';
1771 }
1772}
1773
1774////////////////////////////////////////////////////////////////////////////////
1775/// Find the immediate sub-branch with passed name.
1776
1778{
1779 // The default behavior of TBranch::FindBranch is sometimes
1780 // incorrect if this branch represent a base class, since
1781 // the base class name might or might not be in the name
1782 // of the sub-branches and might or might not be in the
1783 // name being passed.
1784
1785 if (fID >= 0) {
1787 TStreamerElement* se = si->GetElement(fID);
1788 if (se && se->IsBase()) {
1789 // We allow the user to pass only the last dotted component of the name.
1790 UInt_t len = strlen(name);
1791 std::string longnm;
1792 longnm.reserve(fName.Length()+len+3); // Enough space of fName + name + dots
1793 longnm = fName.Data();
1794 R__CleanName(longnm);
1795 longnm += name;
1796 std::string longnm_parent;
1797 longnm_parent.reserve(fName.Length()+len+3);
1798 longnm_parent = (GetMother()->GetSubBranch(this)->GetName());
1799 R__CleanName(longnm_parent);
1800 longnm_parent += name; // Name without the base class name
1801
1802 UInt_t namelen = strlen(name);
1803
1804 TBranch* branch = 0;
1805 Int_t nbranches = fBranches.GetEntries();
1806 for(Int_t i = 0; i < nbranches; ++i) {
1807 branch = (TBranch*) fBranches.UncheckedAt(i);
1808
1809 const char *brname = branch->GetName();
1810 UInt_t brlen = strlen(brname);
1811 if (brname[brlen-1]==']') {
1812 const char *dim = strchr(brname,'[');
1813 if (dim) {
1814 brlen = dim - brname;
1815 }
1816 }
1817 if (namelen == brlen /* same effective size */
1818 && strncmp(name,brname,brlen) == 0) {
1819 return branch;
1820 }
1821 if (brlen == longnm.length()
1822 && strncmp(longnm.c_str(),brname,brlen) == 0) {
1823 return branch;
1824 }
1825 // This check is specific to base class
1826 if (brlen == longnm_parent.length()
1827 && strncmp(longnm_parent.c_str(),brname,brlen) == 0) {
1828 return branch;
1829 }
1830
1831 if (namelen>brlen && name[brlen]=='.' && strncmp(name,brname,brlen)==0) {
1832 // The prefix subbranch name match the branch name.
1833 return branch->FindBranch(name+brlen+1);
1834 }
1835 }
1836 }
1837 }
1838 TBranch *result = TBranch::FindBranch(name);
1839 if (!result) {
1840 // Look in base classes if any
1841 Int_t nbranches = fBranches.GetEntries();
1842 for(Int_t i = 0; i < nbranches; ++i) {
1843 TObject *obj = fBranches.UncheckedAt(i);
1844 if(obj->IsA() != TBranchElement :: Class() )
1845 continue;
1846 TBranchElement *br = (TBranchElement*)obj;
1847 TVirtualStreamerInfo* si = br->GetInfoImp();
1848 if (si && br->GetID() >= 0) {
1849 TStreamerElement* se = si->GetElement(br->GetID());
1850 if (se && se->IsBase()) {
1851 result = br->FindBranch(name);
1852 }
1853 }
1854 }
1855 }
1856 return result;
1857}
1858
1859////////////////////////////////////////////////////////////////////////////////
1860/// Find the leaf corresponding to the name 'searchname'.
1861
1863{
1864 TLeaf *leaf = TBranch::FindLeaf(name);
1865
1866 if (leaf==0 && GetListOfLeaves()->GetEntries()==1) {
1867 TBranch *br = GetMother()->GetSubBranch( this );
1868 if( br->IsA() != TBranchElement::Class() )
1869 return 0;
1870
1871 TBranchElement *parent = (TBranchElement*)br;
1872 if (parent==this || parent->GetID()<0 ) return 0;
1873
1874 TVirtualStreamerInfo* si = parent->GetInfoImp();
1875 TStreamerElement* se = si->GetElement(parent->GetID());
1876
1877 if (! se->IsBase() ) return 0;
1878
1879 br = GetMother()->GetSubBranch( parent );
1880 if( br->IsA() != TBranchElement::Class() )
1881 return 0;
1882
1883 TBranchElement *grand_parent = (TBranchElement*)br;
1884
1885 std::string longname( grand_parent->GetName() );
1886 R__CleanName(longname);
1887 longname += name;
1888
1889 std::string leafname( GetListOfLeaves()->At(0)->GetName() );
1890
1891 if ( longname == leafname ) {
1892 return (TLeaf*)GetListOfLeaves()->At(0);
1893 }
1894 }
1895 return leaf;
1896}
1897
1898////////////////////////////////////////////////////////////////////////////////
1899/// Get the branch address.
1900///
1901/// If we are *not* owned by a MakeClass() tree:
1902///
1903/// - If we are a top-level branch, return a pointer
1904/// - to the pointer to our object.
1905///
1906/// If we are *not* a top-level branch, return a pointer
1907/// to our object.
1908///
1909/// If we are owned by a MakeClass() tree:
1910///
1911/// - Return a pointer to our object.
1912
1914{
1916 return fAddress;
1917}
1918
1919
1920// For a mother branch of type 3 or 4, find the 'correct' StreamerInfo for the
1921// content of the collection by find a sub-branch corresponding to a direct data member
1922// of the containee class (valueClass)
1923// Default to the current StreamerInfo if none are found.
1925{
1926 TStreamerInfo *localInfo = nullptr;
1927
1928 // Search for the correct version.
1929 for(auto subbe : TRangeDynCast<TBranchElement>( branches )) {
1930 if (!subbe->fInfo)
1931 subbe->SetupInfo();
1932 if (valueClass == subbe->fInfo->GetClass()) { // Use GetInfo to provoke its creation.
1933 localInfo = subbe->fInfo;
1934 break;
1935 }
1936 }
1937 if (!localInfo) {
1938 // This is likely sub-optimal as we really should call GetFile but it is non-const.
1939 auto file = fDirectory ? fDirectory->GetFile() : nullptr;
1940 if (file && file->GetSeekInfo()) {
1941 localInfo = (TStreamerInfo*)file->GetStreamerInfoCache()->FindObject(valueClass->GetName());
1942 if (localInfo) {
1943 if (valueClass->IsVersioned()) {
1944 localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1945 } else {
1946 localInfo = (TStreamerInfo*)valueClass->FindStreamerInfo(localInfo->GetCheckSum());
1947 if (localInfo) {
1948 // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
1949 localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1950 }
1951 }
1952 }
1953 }
1954 }
1955 if (!localInfo)
1956 localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo();
1957
1958 if (localInfo) {
1959 // See if we need any conversion.
1960 TClass *targetValueClass = fInfo->GetClass()->GetCollectionProxy()
1962 : nullptr;
1963 // For TClonesArray, the rest of the code probably does not support change in
1964 // value class, but if it does, we would have to look up the target value class
1965 // in the TClonesArray instance.
1966 // if (type == 3 && instance) targetValueClass = ((TClonesArray*)instance)->GetClass();
1967
1968 if (targetValueClass && localInfo->GetClass() != targetValueClass) {
1969 localInfo = (TStreamerInfo*)targetValueClass->GetConversionStreamerInfo(localInfo->GetClass(),
1970 localInfo->GetClassVersion());
1971 }
1972 }
1973 return localInfo;
1974}
1975
1976namespace {
1977static void GatherArtificialElements(const TObjArray &branches, TStreamerInfoActions::TIDs &ids, TString prefix, TStreamerInfo *info, Int_t offset) {
1978 size_t ndata = info->GetNelement();
1979 for (size_t i =0; i < ndata; ++i) {
1980 TStreamerElement *nextel = info->GetElement(i);
1981
1982 if (nextel->GetType() == TStreamerInfo::kCacheDelete
1983 || nextel->GetType() == TStreamerInfo::kCacheNew) {
1984 continue;
1985 }
1986
1987 TString ename = prefix + nextel->GetName();
1988
1989 if (ename[0]=='*')
1990 ename.Remove(0,1);
1991
1992 Ssiz_t pos;
1993 while ((pos = ename.Last('[')) != TString::kNPOS) {
1994 ename = ename.Remove(pos);
1995 }
1996
1997 TBranchElement *be = (TBranchElement*)branches.FindObject(ename);
1998 if (nextel->IsA() == TStreamerArtificial::Class()
1999 && be == nullptr) {
2000
2001 ids.push_back(i);
2002 ids.back().fElement = nextel;
2003 ids.back().fInfo = info;
2004 }
2005
2006 if (nextel->CannotSplit() || nextel->IsTransient() || nextel->GetOffset() == TStreamerInfo::kMissing)
2007 continue;
2008
2009 if (!be && nextel->IsBase()) {
2010 // We could be in the case of a branch created from a Folder or
2011 // a top level branch with a non-trailing dot in its name (case inadvertently confused with the folder case).
2012 // In those case, the name of the base class is *not* used to create the corresponding branch.
2013 TString subprefix(prefix);
2014 if (subprefix.Length() && subprefix[subprefix.Length()-1] == '.')
2015 subprefix.Remove(subprefix.Length()-1);
2016
2017 be = (TBranchElement*)branches.FindObject(subprefix);
2018 if (be) {
2019 // There is at least 'one' base class branch all with the same name, so let's find the
2020 // right one.
2021 TClass *expectedClass = nullptr;
2022 EDataType expectedType;
2023 if (0 != be->GetExpectedType(expectedClass,expectedType)
2024 || expectedClass != nextel->GetClassPointer())
2025 {
2026 be = nullptr;
2027 Int_t nbranches = branches.GetEntriesFast();
2028 for (Int_t bi = 0; bi < nbranches; ++bi) {
2029 TBranchElement* branch = (TBranchElement*) branches[bi];
2030 if (subprefix != branch->GetName())
2031 continue;
2032 if (0 == branch->GetExpectedType(expectedClass,expectedType)
2033 && expectedClass == nextel->GetClassPointer())
2034 {
2035 be = branch;
2036 break;
2037 }
2038 }
2039 } // else we have already found the right branch.
2040 }
2041 }
2042
2043 TClass *elementClass = nextel->GetClassPointer();
2044 if (elementClass && (!be || be->GetType() == -2)) {
2045 // Recurse on sub-objects.
2046 TStreamerInfo *nextinfo = nullptr;
2047
2048 // nextinfo_version = ....
2049 auto search = be ? be->GetListOfBranches() : &branches;
2050 TVirtualArray *onfileObject = nullptr;
2051
2052 TString subprefix;
2053 if (prefix.Length() && nextel->IsA() == TStreamerBase::Class()) {
2054 // We skip the name of the base class if there is already a prefix.
2055 // See TBranchElement::Unroll
2056 subprefix = prefix;
2057 } else {
2058 subprefix = ename + ".";
2059 }
2060 auto nbranches = search->GetEntriesFast();
2061 bool foundRelatedSplit = false;
2062 for (Int_t bi = 0; bi < nbranches; ++bi) {
2063 TBranchElement* subbe = (TBranchElement*)search->At(bi);
2064 bool matchSubPrefix = strncmp(subbe->GetFullName(), subprefix.Data(), subprefix.Length()) == 0;
2065 if (!foundRelatedSplit)
2066 foundRelatedSplit = matchSubPrefix;
2067 if (elementClass == subbe->GetInfo()->GetClass() // Use GetInfo to provoke its creation.
2068 && subbe->GetOnfileObject()
2069 && matchSubPrefix)
2070 {
2071 nextinfo = subbe->GetInfo();
2072 onfileObject = subbe->GetOnfileObject();
2073 break;
2074 }
2075 }
2076
2077 if (!foundRelatedSplit) {
2078 continue;
2079 }
2080
2081 if (!nextinfo) {
2082 nextinfo = (TStreamerInfo *)elementClass->GetStreamerInfo();
2083 if (elementClass->GetCollectionProxy() && elementClass->GetCollectionProxy()->GetValueClass()) {
2084 nextinfo = (TStreamerInfo *)elementClass->GetCollectionProxy()->GetValueClass()->GetStreamerInfo(); // NOTE: need to find the right version
2085 }
2086 }
2087 ids.emplace_back(nextinfo, offset + nextel->GetOffset());
2088 if (!onfileObject && nextinfo && nextinfo->GetNelement() && nextinfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew) {
2089 onfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), 1 /* is that always right? */ );
2090 ids.back().fNestedIDs->fOwnOnfileObject = kTRUE;
2091 }
2092 ids.back().fNestedIDs->fOnfileObject = onfileObject;
2093 GatherArtificialElements(branches, ids.back().fNestedIDs->fIDs, subprefix, nextinfo, offset + nextel->GetOffset());
2094 if (ids.back().fNestedIDs->fIDs.empty())
2095 ids.pop_back();
2096 }
2097 }
2098};
2099} // Anonymous namespace.
2100
2101
2102////////////////////////////////////////////////////////////////////////////////
2103/// Set the value of fInfo. This is part one of InitInfo.
2104/// To be used as:
2105/// if (!fInfo)
2106/// SetupInfo();
2107/// It would only be used within InitInfo (and its callees)
2108
2110{
2111 // We did not already have streamer info, so now we must find it.
2113
2114 //------------------------------------------------------------------------
2115 // Check if we're dealing with the name change
2116 //////////////////////////////////////////////////////////////////////////
2117
2118 TClass* targetClass = 0;
2119 if( fTargetClass.GetClassName()[0] ) {
2120 targetClass = fTargetClass;
2121 if (!targetClass && GetCollectionProxy()) {
2122 // We are in the case where the branch holds a custom collection
2123 // proxy but the dictionary is not loaded, calling
2124 // GetCollectionProxy had the side effect of creating the TClass
2125 // corresponding to this emulated collection.
2126 targetClass = fTargetClass;
2127 }
2128 if ( !targetClass ) {
2129 Error( "InitInfo", "The target class dictionary is not present!" );
2130 return;
2131 }
2132 } else {
2133 targetClass = cl;
2134 }
2135 if (cl) {
2136 //---------------------------------------------------------------------
2137 // Get the streamer info for given version
2138 ///////////////////////////////////////////////////////////////////////
2139
2140 {
2141 if ( (cl->Property() & kIsAbstract) && cl == targetClass) {
2143 if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
2144 // Our parent's class is emulated and we represent an abstract class.
2145 // and the target class has not been set explicilty.
2146 TString target = cl->GetName();
2147 target += "@@emulated";
2148 fTargetClass.SetName(target);
2149
2150 if (!fTargetClass) {
2152 }
2153 targetClass = fTargetClass;
2154 }
2155 }
2156 if( targetClass != cl ) {
2158 } else {
2160 }
2161 }
2162
2163 // FIXME: Check that the found streamer info checksum matches our branch class checksum here.
2164 // Check to see if the class code was unloaded/reloaded
2165 // since we were created.
2167 if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) {
2168 // Try to compensate for a class that got unloaded on us.
2169 // Search through the streamer infos by checksum
2170 // and take the first match.
2171
2172 TStreamerInfo* info;
2173 if( targetClass != cl )
2174 info = (TStreamerInfo*)targetClass->FindConversionStreamerInfo( cl, fCheckSum );
2175 else {
2177 if (info) {
2178 // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
2179 info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion());
2180 }
2181 }
2182 if( info ) {
2183 fInfo = info;
2184 // We no longer reset the class version so that in case the user is passing us later
2185 // the address of a class that require (another) Conversion we can find the proper
2186 // StreamerInfo.
2187 // fClassVersion = fInfo->GetClassVersion();
2188 }
2189 }
2190 }
2191}
2192
2193
2194////////////////////////////////////////////////////////////////////////////////
2195/// Init the streamer info for the branch class, try to compensate for class
2196/// code unload/reload and schema evolution.
2197
2199{
2200 if (!fInfo)
2201 SetupInfo();
2202
2203 //
2204 // Fixup cached streamer info if necessary.
2205 //
2206 // FIXME: What if the class code was unloaded/reloaded since we were cached?
2207
2208 if (fInfo) {
2209
2210 if (!fInfo->IsCompiled()) {
2211 // Streamer info has not yet been compiled.
2212
2213 Error("InitInfo","StreamerInfo is not compiled.");
2214 }
2215 // return immediately if we are called recursively.
2216 if (fInInitInfo)
2217 return;
2219 if (!fInit) {
2220 // We were read in from a file, figure out what our fID should be,
2221 // schema evolution must be considered.
2222 //
2223 // Force our fID to be the id of the first streamer element that matches our name.
2224 //
2225 auto SetOnfileObject = [this](TStreamerInfo *info) {
2226 Int_t arrlen = 1;
2227 if (fType==31 || fType==41) {
2228 TLeaf *leaf = (TLeaf*)fLeaves.At(0);
2229 if (leaf) {
2230 arrlen = leaf->GetMaximum();
2231 }
2232 }
2233 Bool_t toplevel = (fType == 3 || fType == 4 || (fType == 0 && fID == -2));
2234 Bool_t seenExisting = kFALSE;
2235
2236 fOnfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), arrlen );
2237 // Propagate this to all the other branches belonging to the same object.
2238 TObjArray *branches = toplevel ? GetListOfBranches() : GetMother()->GetSubBranch(this)->GetListOfBranches();
2239 Int_t nbranches = branches->GetEntriesFast();
2240 TBranchElement *lastbranch = this;
2241
2242 TClass *currentClass = fBranchClass;
2243 auto currentVersion = fClassVersion;
2244 if (toplevel) {
2245 // Note: Fragile/wrong when using conversion StreamerInfo?
2246 currentClass = info->GetClass();
2247 currentVersion = info->GetClassVersion();
2248 }
2249
2250 // First find the first branch corresponding to the same class as 'this'
2251 // branch
2252 Int_t index = branches->IndexOf(this);
2253 Int_t firstindex = 0;
2254 Int_t lastindex = nbranches - 1;
2255 if (index >= 0) {
2256 TString fullname( GetFullName() );
2257 Ssiz_t lastdot = fullname.Last('.');
2258 if (lastdot == TString::kNPOS) {
2259 // No prefix or index, thus this is a first level branch
2260 TBranchElement* subbranch = (TBranchElement*)branches->At(0);
2261 if (!subbranch->fInfo)
2262 subbranch->SetupInfo();
2263 } else {
2264 TString &thisprefix = fullname.Remove(lastdot + 1); // Mod fullname and 'rename' the variable.
2265 for(Int_t i = index - 1; i >= 0; --i) {
2266 TBranchElement* subbranch = (TBranchElement*)branches->At(i);
2267 TString subbranch_name(subbranch->GetFullName());
2268 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2269 // We moved to another data member (of the enclosing class)
2270 firstindex = i + 1;
2271 break;
2272 }
2273 if (!subbranch->fInfo)
2274 subbranch->SetupInfo();
2275 }
2276 for(Int_t i = index; i < nbranches; ++i) {
2277 TBranchElement* subbranch = (TBranchElement*)branches->At(i);
2278 TString subbranch_name(subbranch->GetFullName());
2279 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2280 lastindex = i - 1;
2281 break;
2282 }
2283 }
2284 }
2285 } else {
2286 // Case of a top level branch or 'empty node' (object marker for split sub-object)
2287 TString fullname( GetFullName() );
2288 Ssiz_t lastdot = fullname.Last('.');
2289 if (lastdot != TString::kNPOS) {
2290 TString &thisprefix = fullname.Remove(lastdot + 1); // Mod fullname and 'rename' the variable.
2291 for(Int_t i = 0; i < nbranches; ++i) {
2292 TBranchElement* subbranch = (TBranchElement*)branches->At(i);
2293 TString subbranch_name(subbranch->GetFullName());
2294 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2295 lastindex = i - 1;
2296 break;
2297 }
2298 }
2299 }
2300 }
2301 for (Int_t i = firstindex; i <= lastindex; ++i) {
2302 TBranchElement* subbranch = (TBranchElement*)branches->At(i);
2303 Bool_t match = kFALSE;
2304 if (this != subbranch) {
2305
2306 if (!subbranch->fInfo)
2307 subbranch->SetupInfo();
2308
2309 if (subbranch->fInfo == info)
2310 match = kTRUE;
2311 else if (subbranch->fInfo == nullptr && subbranch->fBranchClass == currentClass) {
2312 if (!toplevel) {
2313 if (subbranch->fCheckSum == fCheckSum)
2314 match = kTRUE;
2315 } else {
2316 if (!subbranch->fBranchClass->IsForeign() && subbranch->fClassVersion == currentVersion)
2317 match = kTRUE;
2318 else if (subbranch->fCheckSum == info->GetCheckSum()) {
2319 match = kTRUE;
2320 }
2321 }
2322 }
2323 }
2324 if (match) {
2325 if (subbranch->fOnfileObject && subbranch->fOnfileObject != fOnfileObject) {
2326 if (seenExisting) {
2327 Error("SetOnfileObject (lambda)", "2 distincts fOnfileObject are in the hierarchy of %s for type %s",
2328 toplevel ? GetName() : GetMother()->GetSubBranch(this)->GetName(), info->GetName());
2329 } else {
2330 delete fOnfileObject;
2331 fOnfileObject = subbranch->fOnfileObject;
2332 seenExisting = kTRUE;
2333 }
2334 }
2335 subbranch->fOnfileObject = fOnfileObject;
2336 lastbranch = subbranch;
2337 }
2338 }
2339 if (toplevel) {
2341 if (lastbranch != this)
2342 lastbranch->ResetBit(kOwnOnfileObj);
2343 } else {
2344 lastbranch->SetBit(kOwnOnfileObj);
2345 }
2346 };
2347 if (GetID() > -1) {
2348 // We are *not* a top-level branch.
2349 std::string s(GetName());
2350 size_t pos = s.rfind('.');
2351 if (pos != std::string::npos) {
2352 s = s.substr(pos+1);
2353 }
2354 while ((pos = s.rfind('[')) != std::string::npos) {
2355 s = s.substr(0, pos);
2356 }
2357 int offset = 0;
2358 TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset);
2359 if (elt && offset!=TStreamerInfo::kMissing) {
2360 size_t ndata = fInfo->GetNelement();
2361 fNewIDs.clear();
2362 for (size_t i = 0; i < ndata; ++i) {
2363 if (fInfo->GetElement(i) == elt) {
2365 && (i+1) < ndata
2366 && s == fInfo->GetElement(i)->GetName())
2367 {
2368 // If the TStreamerElement we found is storing the information in the
2369 // cache and is a repeater, we need to use the real one (the next one).
2370 // (At least until the cache/repeat mechanism is properly handle by
2371 // ReadLeaves).
2372 // fID = i+1;
2373 fID = i;
2374 if (fType != 2) {
2376 fNewIDs.push_back(fID+1);
2377 fNewIDs.back().fElement = fInfo->GetElement(i+1);
2378 fNewIDs.back().fInfo = fInfo;
2379 } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) {
2380 fNewIDs.push_back(fID+1);
2381 fNewIDs.back().fElement = fInfo->GetElement(i+1);
2382 fNewIDs.back().fInfo = fInfo;
2383 }
2384 }
2385 } else {
2386 fID = i;
2387 }
2388 if (elt->TestBit (TStreamerElement::kCache)) {
2390 }
2391 break;
2392 }
2393 }
2394 for (size_t i = fID+1+(fNewIDs.size()); i < ndata; ++i) {
2395 TStreamerElement *nextel = fInfo->GetElement(i);
2396
2397 std::string ename = nextel->GetName();
2398 if (ename[0] == '*')
2399 ename = ename.substr(1);
2400
2401 while ((pos = ename.rfind('[')) != std::string::npos) {
2402 ename = ename.substr(0, pos);
2403 }
2404
2405 if (s != ename) {
2406 // We moved on to the next set
2407 break;
2408 }
2409 // Add all (and only) the Artificial Elements that follows this StreamerInfo.
2410 // fprintf(stderr,"%s/%d[%zu] passing trhough %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2411 if (fType==31||fType==41) {
2412 // The nested objects are unfolded and their branch can not be used to
2413 // execute StreamerElements of this StreamerInfo.
2414 if ((nextel->GetType() == TStreamerInfo::kObject
2415 || nextel->GetType() == TStreamerInfo::kAny)
2416 && nextel->GetClassPointer()->CanSplit())
2417 {
2418 continue;
2419 }
2420 }
2421 if (nextel->GetOffset() == TStreamerInfo::kMissing) {
2422 // This element will be 'skipped', it's TBranchElement's fObject will null
2423 // and thus can not be used to execute the artifical StreamerElements
2424 continue;
2425 }
2426 if (nextel->IsA() != TStreamerArtificial::Class()
2427 || nextel->GetType() == TStreamerInfo::kCacheDelete ) {
2428 continue;
2429 }
2430 // NOTE: We should verify that the rule's source are 'before'
2431 // or 'at' this branch.
2432 // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2433 fNewIDs.push_back(i);
2434 fNewIDs.back().fElement = nextel;
2435 fNewIDs.back().fInfo = fInfo;
2436 }
2437 } else if (elt && offset==TStreamerInfo::kMissing) {
2438 // Still re-assign fID properly.
2439 fNewIDs.clear();
2440 size_t ndata = fInfo->GetNelement();
2441 for (size_t i = 0; i < ndata; ++i) {
2442 if (fInfo->GetElement(i) == elt) {
2443 fID = i;
2444 break;
2445 }
2446 }
2447 } else {
2448 // We have not even found the element .. this is strange :(
2449 // fNewIDs.clear();
2450 // fID = -3;
2451 // SetBit(kDoNotProcess);
2452 }
2453 if (fOnfileObject==0 && (fType==31 || fType==41 || (0 <= fType && fType <=2) ) && fInfo->GetNelement()
2455 {
2456 SetOnfileObject(fInfo);
2457 }
2458 }
2459 if (fType == 3 || fType == 4 || (fType == 0 && fID == -2) || fType == 2) {
2460 // Need to add the rule targeting transient members.
2461 TStreamerInfo *localInfo = fInfo;
2462 if (fType == 3 || fType == 4) {
2463 // Don't we have real version information?
2464 // Not unless there is a subbranch with a non-split element of the class.
2465 // Search for the correct version.
2467 }
2468
2469 TString prefix(GetFullName());
2470 if (fType == 2 && fID >= 0) {
2471 auto start = prefix.Length();
2472 if (prefix[start - 1] == '.')
2473 --start;
2474 std::string_view view(prefix.Data(), start);
2475 auto cutoff = view.find_last_of('.');
2476 if (cutoff != std::string::npos) {
2477 prefix.Remove(cutoff + 1);
2478 }
2479 }
2480 if (prefix[prefix.Length()-1] != '.') {
2481 if (fType == 3 || fType == 4 || prefix.Index('.') != TString::kNPOS) {
2482 prefix += ".";
2483 } else {
2484 prefix = "";
2485 }
2486 }
2487 fNewIDs.clear();
2488
2489 GatherArtificialElements(fBranches, fNewIDs, prefix, localInfo, 0);
2490
2491 if (!fNewIDs.empty() && fOnfileObject == nullptr && localInfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew)
2492 {
2493 SetOnfileObject(localInfo);
2494 }
2495
2496 }
2497 fInit = kTRUE;
2498
2499 // Get the action sequence we need to copy for reading.
2502 } else if (!fReadActionSequence) {
2503 // Get the action sequence we need to copy for reading.
2506 }
2510 }
2511}
2512
2513////////////////////////////////////////////////////////////////////////////////
2514/// Return the collection proxy describing the branch content, if any.
2515
2517{
2518 if (fCollProxy) {
2519 return fCollProxy;
2520 }
2521 TBranchElement* thiscast = const_cast<TBranchElement*>(this);
2522 if (fType == 4) {
2523 // STL container top-level branch.
2524 const char* className = 0;
2525 TClass* cl = nullptr;
2526 if (fID < 0) {
2527 // We are a top-level branch.
2528 if (fBranchClass.GetClass()) {
2529 cl = fBranchClass.GetClass();
2530 }
2531 } else {
2532 // We are not a top-level branch.
2533 TVirtualStreamerInfo* si = thiscast->GetInfoImp();
2534 if (fCollProxy) {
2535 // The GetInfo set fProxy for us, let's not
2536 // redo it; the value of fCollProxy is possibly
2537 // used/recorded is the actions sequences, so
2538 // if we change it here, we would need to propagate
2539 // the change.
2540 return fCollProxy;
2541 }
2542 TStreamerElement* se = si->GetElement(fID);
2543 cl = se->GetClassPointer();
2544 }
2545 if (!cl) {
2546 // The TClass was not created but we do know (since it
2547 // is used as a collection) that it 'className' was a
2548 // class, so let's create it by hand!.
2549
2550 if (fID < 0) {
2553 className = cl->GetName();
2554 } else {
2555 cl = new TClass(className, fClassVersion);
2557 className = cl->GetName();
2558 }
2559 }
2561 if (!proxy) {
2562 // humm, we must have an older file with a custom collection
2563 // let's try to work-around it.
2564 TString equiv;
2565 equiv.Form("vector<%s>",fClonesName.Data());
2566 TClass *clequiv = TClass::GetClass(equiv);
2567 proxy = clequiv->GetCollectionProxy();
2568 if (!proxy) {
2569 Fatal("GetCollectionProxy",
2570 "Can not create a Collection Proxy of any kind for the class \"%s\" needed by the branch \"%s\" of the TTree \"%s\"!",
2571 className, GetName(), GetTree()->GetName());
2572 }
2573 if (gDebug > 0) Info("GetCollectionProxy",
2574 "Fixing the collection proxy of the class \"%s\" \n"
2575 "\tneeded by the branch \"%s\" of the TTree \"%s\" to be similar to \"%s\".",
2576 className, GetName(), GetTree()->GetName(),equiv.Data());
2577 cl->CopyCollectionProxy( *proxy );
2578 }
2579 fCollProxy = proxy->Generate();
2580 fSTLtype = proxy->GetCollectionType();
2581 } else if (fType == 41) {
2582 // STL container sub-branch.
2584 }
2585 return fCollProxy;
2586}
2587
2588////////////////////////////////////////////////////////////////////////////////
2589/// Return a pointer to the current type of the data member corresponding to branch element.
2590
2592{
2593 TClass* cl = fCurrentClass;
2594 if (cl) {
2595 return cl;
2596 }
2597
2599 if (!brInfo) {
2601 R__ASSERT(cl && cl->GetCollectionProxy());
2602 fCurrentClass = cl;
2603 return cl;
2604 }
2605 TClass* motherCl = brInfo->GetClass();
2606 if (motherCl->GetCollectionProxy()) {
2607 cl = motherCl->GetCollectionProxy()->GetCollectionClass();
2608 if (cl) {
2609 fCurrentClass = cl;
2610 }
2611 return cl;
2612 }
2613 if (GetID() < 0 || GetID()>=brInfo->GetNelement()) {
2614 return 0;
2615 }
2616 TStreamerElement* currentStreamerElement = brInfo->GetElement(GetID());
2617 TDataMember* dm = (TDataMember*) motherCl->GetListOfDataMembers()->FindObject(currentStreamerElement->GetName());
2618
2619 TString newType;
2620 if (!dm) {
2621 // Either the class is not loaded or the data member is gone
2622 if (!motherCl->IsLoaded()) {
2623 TVirtualStreamerInfo* newInfo = motherCl->GetStreamerInfo();
2624 if (newInfo != brInfo) {
2625 TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(currentStreamerElement->GetName());
2626 if (newElems) {
2627 if (newElems->GetClassPointer())
2628 newType = newElems->GetClassPointer()->GetName();
2629 else
2630 newType = newElems->GetTypeName();
2631 }
2632 }
2633 if (newType.Length()==0) {
2634 if (currentStreamerElement->GetClassPointer())
2635 newType = currentStreamerElement->GetClassPointer()->GetName();
2636 else
2637 newType = currentStreamerElement->GetTypeName();
2638 }
2639 }
2640 } else {
2641 newType = dm->GetTypeName();
2642 }
2643 cl = TClass::GetClass(newType);
2644 if (cl) {
2645 fCurrentClass = cl;
2646 }
2647 return cl;
2648}
2649
2650////////////////////////////////////////////////////////////////////////////////
2651/// Read all branches of a BranchElement and return total number of bytes.
2652///
2653/// - If entry = 0, then use current entry number + 1.
2654/// - If entry < 0, then reset entry number to 0.
2655///
2656/// Returns the number of bytes read from the input buffer.
2657/// - If entry does not exist, then returns 0.
2658/// - If an I/O error occurs, then returns -1.
2659///
2660/// See IMPORTANT REMARKS in TTree::GetEntry.
2661
2663{
2664 // Remember which entry we are reading.
2665 fReadEntry = entry;
2666
2667 // If our tree has a branch ref, make it remember the entry and
2668 // this branch. This allows a TRef::GetObject() call done during
2669 // the following I/O operation, for example in a custom streamer,
2670 // to search for the referenced object in the proper element of the
2671 // proper branch.
2672 TBranchRef* bref = fTree->GetBranchRef();
2673 if (R__unlikely(bref)) {
2674 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2675 fBranchID = bref->SetParent(this, fBranchID);
2676 bref->SetRequestedEntry(entry);
2677 }
2678
2679 Int_t nbytes = 0;
2680
2681 if (R__unlikely(IsAutoDelete())) {
2684 } else {
2686 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2688 }
2689 }
2690
2691 Int_t nbranches = fBranches.GetEntriesFast();
2692 if (nbranches) {
2693 // -- Branch has daughters.
2694 // One must always read the branch counter.
2695 // In the case when one reads consecutively twice the same entry,
2696 // the user may have cleared the TClonesArray between the GetEntry calls.
2697 if ((fType == 3) || (fType == 4)) {
2698 Int_t nb = TBranch::GetEntry(entry, getall);
2699 if (nb < 0) {
2700 return nb;
2701 }
2702 nbytes += nb;
2703 }
2704 switch(fSTLtype) {
2705 case ROOT::kSTLset:
2706 case ROOT::kSTLmultiset:
2709 case ROOT::kSTLmap:
2710 case ROOT::kSTLmultimap:
2713 break;
2714 default:
2715 ValidateAddress(); // There is no ReadLeave for this node, so we need to do the validation here.
2716 for (Int_t i = 0; i < nbranches; ++i) {
2717 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2718 Int_t nb = branch->GetEntry(entry, getall);
2719 if (nb < 0) {
2720 return nb;
2721 }
2722 nbytes += nb;
2723 }
2724 break;
2725 }
2727 if (fType == 3) {
2728 // Apply the unattached rules; by definition they do not need any
2729 // input from a buffer.
2731
2732 auto ndata = GetNdata();
2733
2734 TClonesArray* clones = (TClonesArray*) fObject;
2735 if (clones->IsZombie()) {
2736 return -1;
2737 }
2738 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2739
2740 char **arr = (char **)clones->GetObjectRef();
2741 char **end = arr + fNdata;
2742
2743 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
2744 } else if (fType == 4) {
2745 // Apply the unattached rules; by definition they do not need any
2746 // input from a buffer.
2748
2749 auto ndata = GetNdata();
2750
2751 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2754
2756 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
2757 } else {
2758 // Apply the unattached rules; by definition they do not need any
2759 // input from a buffer.
2761 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
2762 b.ApplySequence(*fReadActionSequence, fObject);
2763 }
2764 }
2765 } else {
2766 // -- Terminal branch.
2767 if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
2768 Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
2769 if (nb < 0) {
2770 return nb;
2771 }
2772 nbytes += nb;
2773 }
2774 Int_t nb = TBranch::GetEntry(entry, getall);
2775 if (nb < 0) {
2776 return nb;
2777 }
2778 nbytes += nb;
2779 }
2780
2781 if (R__unlikely(fTree->Debug() > 0)) {
2782 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
2783 Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
2784 }
2785 }
2786 return nbytes;
2787}
2788
2789////////////////////////////////////////////////////////////////////////////////
2790/// Fill expectedClass and expectedType with information on the data type of the
2791/// object/values contained in this branch (and thus the type of pointers
2792/// expected to be passed to Set[Branch]Address
2793/// return 0 in case of success and > 0 in case of failure.
2794
2796{
2797 expectedClass = 0;
2798 expectedType = kOther_t;
2799
2801 if ((type == -1) || (fID == -1)) {
2802 expectedClass = fBranchClass;
2803 } else {
2804 // Case of an object data member. Here we allow for the
2805 // variable name to be ommitted. Eg, for Event.root with split
2806 // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
2808 if (element) {
2809 expectedClass = element->GetClassPointer();
2810 if (!expectedClass) {
2811 TDataType* data = gROOT->GetType(element->GetTypeNameBasic());
2812 if (!data) {
2813 Error("GetExpectedType", "Did not find the type number for %s", element->GetTypeNameBasic());
2814 return 1;
2815 } else {
2816 expectedType = (EDataType) data->GetType();
2817 }
2818 }
2819 } else {
2820 Error("GetExpectedType", "Did not find the type for %s",GetName());
2821 return 2;
2822 }
2823 }
2824 return 0;
2825}
2826
2827////////////////////////////////////////////////////////////////////////////////
2828/// Return the 'full' name of the branch. In particular prefix the mother's name
2829/// when it does not end in a trailing dot and thus is not part of the branch name
2831{
2832 TBranchElement* mother = static_cast<TBranchElement*>(GetMother());
2833 if (!mother || mother==this || mother->GetType() == 3 || mother->GetType() == 4) {
2834 // The parent's name is already included in the name for split TClonesArray and STL collections
2835 return fName;
2836 }
2837 TString motherName(mother->GetName());
2838 if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
2839 return fName;
2840 }
2841 return motherName + "." + fName;
2842}
2843
2844////////////////////////////////////////////////////////////////////////////////
2845/// Return icon name depending on type of branch element.
2846
2848{
2849 if (IsFolder()) {
2850 return "TBranchElement-folder";
2851 } else {
2852 return "TBranchElement-leaf";
2853 }
2854}
2855
2856////////////////////////////////////////////////////////////////////////////////
2857/// Return whether this branch is in a mode where the object are decomposed
2858/// or not (Also known as MakeClass mode).
2859
2861{
2862 return TestBit(kDecomposedObj); // Same as TestBit(kMakeClass)
2863}
2864
2865////////////////////////////////////////////////////////////////////////////////
2866/// Return maximum count value of the branchcount if any.
2867
2869{
2870 if (fBranchCount) {
2871 return fBranchCount->GetMaximum();
2872 }
2873 return fMaximum;
2874}
2875
2876////////////////////////////////////////////////////////////////////////////////
2877/// Return a pointer to our object.
2878
2880{
2882 return fObject;
2883}
2884
2885////////////////////////////////////////////////////////////////////////////////
2886/// Return a pointer to the parent class of the branch element.
2887
2889{
2890 return fParentClass.GetClass();
2891}
2892
2893////////////////////////////////////////////////////////////////////////////////
2894/// Return type name of element in the branch.
2895
2897{
2898 if (fType == 3 || fType == 4) {
2899 return "Int_t";
2900 }
2901 // FIXME: Use symbolic constants here.
2902 if ((fStreamerType < 1) || (fStreamerType > 59)) {
2903 if (fBranchClass.GetClass()) {
2904 if (fID>=0) {
2905 return GetInfoImp()->GetElement(fID)->GetTypeName();
2906 } else {
2907 return fBranchClass.GetClass()->GetName();
2908 }
2909 } else {
2910 return 0;
2911 }
2912 }
2913 const char *types[20] = {
2914 "",
2915 "Char_t",
2916 "Short_t",
2917 "Int_t",
2918 "Long_t",
2919 "Float_t",
2920 "Int_t",
2921 "char*",
2922 "Double_t",
2923 "Double32_t",
2924 "",
2925 "UChar_t",
2926 "UShort_t",
2927 "UInt_t",
2928 "ULong_t",
2929 "UInt_t",
2930 "Long64_t",
2931 "ULong64_t",
2932 "Bool_t",
2933 "Float16_t"
2934 };
2935 Int_t itype = fStreamerType % 20;
2936 return types[itype];
2937}
2938
2939////////////////////////////////////////////////////////////////////////////////
2940
2941template Double_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2942template Long64_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2943template LongDouble_t TBranchElement::GetTypedValue(Int_t j, Int_t len, Bool_t subarr) const;
2944
2945template <typename T>
2947{
2948 // -- Returns the branch value.
2949 //
2950 // If the leaf is an array, j is the index in the array.
2951 //
2952 // If leaf is an array inside a TClonesArray, len should be the length
2953 // of the array.
2954 //
2955 // If subarr is true, then len is actually the index within the sub-array.
2956 //
2957
2959
2960 Int_t prID = fID;
2961 char *object = fObject;
2962 if (TestBit(kCache)) {
2963 if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2964 prID = fID+1;
2965 } else if (fOnfileObject) {
2966 object = fOnfileObject->GetObjectAt(0);
2967 }
2968 }
2969
2970 if (!j && fBranchCount) {
2971 Long64_t entry = fTree->GetReadEntry();
2972 // Since reloading the index, will reset the ClonesArray, let's
2973 // skip the load if we already read this entry.
2974 if (entry != fBranchCount->GetReadEntry()) {
2975 fBranchCount->TBranch::GetEntry(entry);
2976 }
2977 if (fBranchCount2 && entry != fBranchCount2->GetReadEntry()) {
2978 fBranchCount2->TBranch::GetEntry(entry);
2979 }
2980 }
2981
2982 if (TestBit(kDecomposedObj)) {
2983 if (!fAddress) {
2984 return 0;
2985 }
2986 if ((fType == 3) || (fType == 4)) {
2987 // Top-level branch of a TClonesArray.
2988 return fNdata;
2989 } else if ((fType == 31) || (fType == 41)) {
2990 // sub branch of a TClonesArray
2991 Int_t atype = fStreamerType;
2992 if (atype < 20) {
2993 atype += 20;
2994 }
2995 return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
2996 } else if (fType <= 2) {
2997 // branch in split mode
2998 // FIXME: This should probably be < 60 instead!
2999 if ((fStreamerType > 40) && (fStreamerType < 55)) {
3000 Int_t atype = fStreamerType - 20;
3001 return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
3002 } else {
3003 return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
3004 }
3005 }
3006 }
3007
3008 if (object == 0)
3009 {
3010 // We have nowhere to read the data from (probably because the data member was
3011 // 'dropped' from the current schema).
3012 return 0;
3013 }
3014
3015 if (fType == 31) {
3016 TClonesArray* clones = (TClonesArray*) object;
3017 if (subarr) {
3018 return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j, len, fOffset);
3019 }
3020 return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j/len, j%len, fOffset);
3021 } else if (fType == 41) {
3024 {
3025 if (subarr)
3026 return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
3027
3028 return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
3029 }
3030 else
3031 {
3032 if (subarr)
3033 return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
3034 return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
3035 }
3036 } else {
3037 if (GetInfoImp()) {
3038 return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
3039 }
3040 return 0;
3041 }
3042}
3043
3044////////////////////////////////////////////////////////////////////////////////
3045/// Returns pointer to first data element of this branch.
3046/// Currently used only for members of type character.
3047
3049{
3051
3052 Int_t prID = fID;
3053 char *object = fObject;
3054 if (TestBit(kCache)) {
3055 if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
3056 prID = fID+1;
3057 } else if (fOnfileObject) {
3058 object = fOnfileObject->GetObjectAt(0);
3059 }
3060 }
3061
3062 if (fBranchCount) {
3063 Long64_t entry = fTree->GetReadEntry();
3064 fBranchCount->TBranch::GetEntry(entry);
3065 if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
3066 }
3067 if (TestBit(kDecomposedObj)) {
3068 if (!fAddress) {
3069 return 0;
3070 }
3071 if (fType == 3) { //top level branch of a TClonesArray
3072 //return &fNdata;
3073 return 0;
3074 } else if (fType == 4) { //top level branch of a TClonesArray
3075 //return &fNdata;
3076 return 0;
3077 } else if (fType == 31) { // sub branch of a TClonesArray
3078 //Int_t atype = fStreamerType;
3079 //if (atype < 20) atype += 20;
3080 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3081 return 0;
3082 } else if (fType == 41) { // sub branch of a TClonesArray
3083 //Int_t atype = fStreamerType;
3084 //if (atype < 20) atype += 20;
3085 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3086 return 0;
3087 } else if (fType <= 2) { // branch in split mode
3088 // FIXME: This should probably be < 60 instead!
3089 if (fStreamerType > 40 && fStreamerType < 55) {
3090 //Int_t atype = fStreamerType - 20;
3091 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3092 return 0;
3093 } else {
3094 //return GetInfoImp()->GetValue(object, fID, j, -1);
3095 return 0;
3096 }
3097 }
3098 }
3099
3100 if (fType == 31) {
3101 return 0;
3102 } else if (fType == 41) {
3103 return 0;
3104 } else if (prID < 0) {
3105 return object;
3106 } else {
3107 //return GetInfoImp()->GetValue(object,fID,j,-1);
3108 if (!GetInfoImp() || !object) return 0;
3109 char **val = (char**)(object+GetInfoImp()->TStreamerInfo::GetElementOffset(prID));
3110 return *val;
3111 }
3112}
3113
3114////////////////////////////////////////////////////////////////////////////////
3115/// Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a container sub-branch.
3116///
3117/// Note: The offsets are zero for data members so that when
3118/// SetAddress recursively sets their address, they will get the
3119/// same address as their containing class because i/o is based
3120/// on streamer info offsets from the addresss of the containing
3121/// class.
3122///
3123/// Offsets are non-zero for base-class sub-branches that are
3124/// not the leftmost direct base class. They are laid out in
3125/// memory sequentially and only the leftmost direct base class
3126/// has the same address as the derived class. The streamer
3127/// offsets need to be added to the address of the base class
3128/// subobject which is not the same as the address of the
3129/// derived class for the non-leftmost direct base classes.
3130
3132{
3133 Int_t nbranches = fBranches.GetEntriesFast();
3134
3135 // See https://sft.its.cern.ch/jira/browse/ROOT-8742
3136 // and https://sft.its.cern.ch/jira/browse/ROOT-9253
3137 // As of commit e21b4f1a3b, removing this lock lead to a failure
3138 // in the test testSetAddress[Loop].
3139 // As of commit 4f8b237849, removing this lock does not lead to
3140 // a visible failure in test. This might be due to the underlying
3141 // problem (missing lock or ?) being solved somewhere else or some
3142 // other pertubation reducing the failure rate.
3143 // Having the lock here is not too costly as InitializeOffsets is
3144 // one called once in the lifetime of the TBranch.
3146
3147 if (fID < 0) {
3148 // -- We are a top-level branch. Let's mark whether we need to use MapObject.
3149 if (CanSelfReference(fBranchClass)) {
3150 if (fBranchClass.GetClass()->IsTObject()) {
3152 } else {
3154 }
3155 }
3156 }
3157 if (nbranches) {
3158 // Allocate space for the new sub-branch offsets.
3159 delete[] fBranchOffset;
3160 fBranchOffset = 0;
3161 fBranchOffset = new Int_t[nbranches];
3162 // Make sure we can instantiate our class meta info.
3163 if (!fBranchClass.GetClass()) {
3164 Warning("InitializeOffsets", "No branch class set for branch: %s", GetName());
3166 return;
3167 }
3168 // Make sure we can instantiate our class streamer info.
3169 if (!GetInfoImp()) {
3170 Warning("InitializeOffsets", "No streamer info available for branch: %s of class: %s", GetName(), fBranchClass.GetClass()->GetName());
3172 return;
3173 }
3174
3175 // Get the class we are a member of now (which is the
3176 // type of our containing subobject) and get our offset
3177 // inside of our containing subobject (our local offset).
3178 // Note: branchElem stays zero if we are a top-level branch,
3179 // we have to be careful about this later.
3180 TStreamerElement* branchElem = 0;
3181 Int_t localOffset = 0;
3182 TClass* branchClass = fBranchClass.GetClass();
3183 Bool_t renamed = kFALSE;
3184 if (fID > -1) {
3185 // -- Branch is *not* a top-level branch.
3186 // Instead of the streamer info class, we want the class of our
3187 // specific element in the streamer info. We could be a data
3188 // member of a base class or a split class, in which case our
3189 // streamer info will be for our containing sub-object, while
3190 // we are actually a different type.
3192 // Note: We tested to make sure the streamer info was available previously.
3193 if (!si->IsCompiled()) {
3194 Warning("InitializeOffsets", "Streamer info for branch: %s has no elements array!", GetName());
3196 return;
3197 }
3198 // FIXME: Check that fID is in range.
3199 branchElem = si->GetElement(fID);
3200 if (!branchElem) {
3201 Warning("InitializeOffsets", "Cannot get streamer element for branch: %s!", GetName());
3203 return;
3204 } else if (branchElem->TestBit(TStreamerElement::kRepeat)) {
3205 // If we have a repeating streamerElement, use the next
3206 // one as it actually hold the 'real' data member('s offset)
3207 if (si->GetElement(fID+1)) {
3208 branchElem = si->GetElement(fID+1);
3209 }
3210 }
3211 localOffset = branchElem->GetOffset();
3212 branchClass = branchElem->GetClassPointer();
3213 if (localOffset == TStreamerInfo::kMissing) {
3214 fObject = 0;
3215 } else {
3216 renamed = branchClass && branchElem->GetNewClass() && (branchClass != branchElem->GetNewClass());
3217 }
3218 } else {
3219 renamed = fTargetClass != fBranchClass;
3220 }
3221 if (!branchClass) {
3222 Error("InitializeOffsets", "Could not find class for branch: %s", GetName());
3224 return;
3225 }
3226
3227 //------------------------------------------------------------------------
3228 // Extract the name of the STL branch in case it has been split.
3229 //////////////////////////////////////////////////////////////////////////
3230
3231 TString stlParentName;
3232 Bool_t stlParentNameUpdated = kFALSE;
3233 if( fType == 4 )
3234 {
3235 TBranch *br = GetMother()->GetSubBranch( this );
3236 stlParentName = br->GetName();
3237 stlParentName = stlParentName.Strip( TString::kTrailing, '.' );
3238
3239 // We may ourself contain the 'Mother' branch name.
3240 // To avoid code duplication, we delegate the removal
3241 // of the mother's name to the first sub-branch loop.
3242 }
3243
3244 // Loop over our sub-branches and compute their offsets.
3245 for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
3246 bool alternateElement = false;
3247
3248 fBranchOffset[subBranchIdx] = 0;
3249 TBranchElement* subBranch = dynamic_cast<TBranchElement*> (fBranches[subBranchIdx]);
3250 if (subBranch == 0) {
3251 // -- Skip sub-branches that are not TBranchElements.
3252 continue;
3253 }
3254
3255 if (renamed) {
3256 if (subBranch->fBranchClass == branchClass) {
3257 if (branchElem) subBranch->SetTargetClass(branchElem->GetNewClass()->GetName());
3258 else subBranch->SetTargetClass(fTargetClass->GetName());
3259 }
3260 }
3261
3262 TVirtualStreamerInfo* sinfo = subBranch->GetInfoImp();
3263 if (!sinfo) {
3264 Warning("InitializeOffsets", "No streamer info for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3265 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3266 continue;
3267 }
3268 if (!sinfo->IsCompiled()) {
3269 Warning("InitializeOffsets", "No elements array for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3270 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3271 continue;
3272 }
3273 // FIXME: Make sure subBranch->fID is in range.
3274 TStreamerElement* subBranchElement = sinfo->GetElement(subBranch->fID);
3275 if (!subBranchElement) {
3276 Warning("InitializeOffsets", "No streamer element for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3277 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3278 continue;
3279 } else if (subBranchElement->TestBit(TStreamerElement::kRepeat)) {
3280 // If we have a repeating streamerElement, use the next
3281 // one as it actually hold the 'real' data member('s offset)
3282 if (sinfo->GetElement(subBranch->fID+1)) {
3283 subBranchElement = sinfo->GetElement(subBranch->fID+1);
3284 }
3285 } else if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3286 // We have a cached item which is not a repeated but we might still
3287 // have some Actions triggered by a rule that affect real
3288 // data member(s).
3289 if (subBranch->fReadActionSequence && subBranch->fReadActionSequence->fActions.size() > 1) {
3290 typedef TStreamerInfoActions::ActionContainer_t::iterator iterator;
3291 iterator end = subBranch->fReadActionSequence->fActions.end();
3292 for(iterator iter = subBranch->fReadActionSequence->fActions.begin();
3293 iter != end; ++iter) {
3294 TStreamerInfoActions::TConfiguration *config = iter->fConfiguration;
3295 UInt_t id = config->fElemId;
3297 if (e && !e->TestBit(TStreamerElement::kCache)) {
3298 subBranchElement = e;
3299 alternateElement = true;
3300 break;
3301 }
3302 }
3303 }
3304 }
3305
3306 localOffset = subBranchElement->GetOffset();
3307 if (localOffset == TStreamerInfo::kMissing) {
3308 subBranch->fObject = 0;
3309 }
3310 {
3311 Int_t streamerType = subBranchElement->GetType();
3312 if (streamerType > TStreamerInfo::kObject
3313 && subBranch->GetListOfBranches()->GetEntriesFast()==0
3314 && CanSelfReference(subBranchElement->GetClass()))
3315 {
3316 subBranch->SetBit(kBranchAny);
3317 } else {
3318 subBranch->ResetBit(kBranchAny);
3319 }
3320 }
3321
3322 if (subBranchElement->GetNewType()<0) {
3323 subBranch->ResetBit(kBranchAny);
3324 subBranch->ResetBit(kBranchObject);
3325 }
3326
3327 // Note: This call is expensive, do it only once.
3328 TBranch* mother = GetMother();
3329 if (!mother) {
3330 Warning("InitializeOffsets", "Branch '%s' has no mother!", GetName());
3331 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3332 continue;
3333 }
3334 TString motherName(mother->GetName());
3335 Bool_t motherDot = kFALSE;
3336 if (motherName.Length() && strchr(motherName.Data(), '.')) {
3337 motherDot = kTRUE;
3338 }
3339 Bool_t motherDotAtEnd = kFALSE;
3340 if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
3341 motherDotAtEnd = kTRUE;
3342 }
3343
3344 Bool_t isBaseSubBranch = kFALSE;
3345 if ((subBranch->fType == 1) || (subBranchElement && subBranchElement->IsBase())) {
3346 // -- Base class sub-branch (1).
3347 //
3348 // Note: Our type will not be 1, even though we are
3349 // a base class branch, if we are not split (see the
3350 // constructor), or if we are an STL container master
3351 // branch and a base class branch at the same time
3352 // or an std::string.
3353 isBaseSubBranch = kTRUE;
3354 }
3355
3356 Bool_t isContDataMember = kFALSE;
3357 if ((subBranch->fType == 31) || (subBranch->fType == 41)) {
3358 // -- Container data member sub-branch (31 or 41).
3359 isContDataMember = kTRUE;
3360 }
3361
3362 // I am either a data member sub-branch (0), or a base class
3363 // sub-branch (1), or TClonesArray master sub-branch (3),
3364 // or an STL container master sub-branch (4), or TClonesArray
3365 // data member sub-branch (31), or an STL container data member
3366 // sub-branch (41).
3367 //
3368 // My parent branch is either a top-level branch ((0), fID==(-2,-1)),
3369 // or a base class sub-branch (1), or a split-class branch (2),
3370 // or a TClonesArray master branch (3), or an STL container
3371 // master branch (4).
3372 //
3373
3374 //
3375 // We need to extract from our name the name
3376 // of the data member which contains us, so
3377 // that we may then do a by-name lookup in the
3378 // dictionary meta info of our parent class to
3379 // get our offset in our parent class.
3380 //
3381
3382 // Get our name.
3383 TString dataName(subBranch->GetName());
3384 if (motherDotAtEnd) {
3385 // -- Remove the top-level branch name from our name.
3386 dataName.Remove(0, motherName.Length());
3387 // stlParentNameUpdated is false the first time in this loop.
3388 if (!stlParentNameUpdated && stlParentName.Length()) {
3389 stlParentName.Remove(0, motherName.Length());
3390 stlParentNameUpdated = kTRUE;
3391 }
3392 } else if (motherDot) {
3393 // -- Remove the top-level branch name from our name, folder case.
3394 //
3395 // Note: We are in the case where our mother was created
3396 // by the branch constructor which takes a folder
3397 // as an argument. The mother branch has internal
3398 // dots in its name to represent the folder heirarchy.
3399 // The TTree::Bronch() routine has handled us as a
3400 // special case, we must compensate.
3401 if ((fID < 0) && (subBranchElement->IsA() == TStreamerBase::Class())) {
3402 // -- Our name is the mother name, remove it.
3403 // Note: The test is our parent is a top-level branch
3404 // and our streamer is the base class streamer,
3405 // this matches the exact test in TTree::Bronch().
3406 if (dataName.Length() == motherName.Length()) {
3407 dataName.Remove(0, motherName.Length());
3408 // stlParentNameUpdated is false the first time in this loop.
3409 if (!stlParentNameUpdated && stlParentName.Length()) {
3410 stlParentName.Remove(0, motherName.Length());
3411 }
3412 }
3413 } else {
3414 // -- Remove the mother name and the dot.
3415 if (dataName.Length() > motherName.Length()) {
3416 dataName.Remove(0, motherName.Length() + 1);
3417 if (!stlParentNameUpdated && stlParentName.Length()) {
3418 stlParentName.Remove(0, motherName.Length());
3419 }
3420 }
3421 }
3422 }
3423 stlParentNameUpdated = kTRUE;
3424 if (isBaseSubBranch) {
3425 // -- Remove the base class name suffix from our name.
3426 // Note: The pattern is the name of the base class.
3427 TString pattern(subBranchElement->GetName());
3428 if (pattern.Length() <= dataName.Length()) {
3429 if (!strcmp(dataName.Data() + (dataName.Length() - pattern.Length()), pattern.Data())) {
3430 // The branch name contains the name of the base class in it.
3431 // This name is not reproduced in the sub-branches, so we need to
3432 // remove it.
3433 dataName.Remove(dataName.Length() - pattern.Length());
3434 }
3435 }
3436 // Remove any leading dot.
3437 if (dataName.Length()) {
3438 if (dataName[0] == '.') {
3439 dataName.Remove(0, 1);
3440 }
3441 }
3442 // Note: We intentionally leave any trailing dot
3443 // in our modified name here.
3444 }
3445
3446 // Get our parent branch's name.
3447 TString parentName(GetName());
3448 if (motherDotAtEnd) {
3449 // -- Remove the top-level branch name from our parent's name.
3450 parentName.Remove(0, motherName.Length());
3451 } else if (motherDot) {
3452 // -- Remove the top-level branch name from our parent's name, folder case.
3453 //
3454 // Note: We are in the case where our mother was created
3455 // by the branch constructor which takes a folder
3456 // as an argument. The mother branch has internal
3457 // dots in its name to represent the folder heirarchy.
3458 // The TTree::Bronch() routine has handled us as a
3459 // special case, we must compensate.
3460 if ((fID > -1) && (mother == mother->GetSubBranch(this)) && (branchElem->IsA() == TStreamerBase::Class())) {
3461 // -- Our parent's name is the mother name, remove it.
3462 // Note: The test is our parent's parent is a top-level branch
3463 // and our parent's streamer is the base class streamer,
3464 // this matches the exact test in TTree::Bronch().
3465 if (parentName.Length() == motherName.Length()) {
3466 parentName.Remove(0, motherName.Length());
3467 }
3468 } else {
3469 // -- Remove the mother name and the dot.
3470 if (parentName.Length() > motherName.Length()) {
3471 parentName.Remove(0, motherName.Length() + 1);
3472 }
3473 }
3474 }
3475 // FIXME: Do we need to use the other tests for a base class here?
3476 if (fType == 1) {
3477 // -- Our parent is a base class sub-branch, remove the base class name suffix from its name.
3478 if (mother != mother->GetSubBranch(this)) {
3479 // -- My parent's parent is not a top-level branch.
3480 // Remove the base class name suffix from the parent name.
3481 // Note: The pattern is the name of the base class.
3482 // coverity[var_deref_model] branchElem is non zero here since fType==1 and thus fID > -1
3483 TString pattern(branchElem->GetName());
3484 if (pattern.Length() <= parentName.Length()) {
3485 if (!strcmp(parentName.Data() + (parentName.Length() - pattern.Length()), pattern.Data())) {
3486 // The branch name contains the name of the base class in it.
3487 // This name is not reproduced in the sub-branches, so we need to
3488 // remove it.
3489 parentName.Remove(parentName.Length() - pattern.Length());
3490 }
3491 }
3492 }
3493 // Note: We intentionally leave any trailing dots
3494 // in the modified parent name here.
3495 }
3496
3497 // Remove the parent branch name part from our name,
3498 // but only if the parent branch is not a top-level branch.
3499 // FIXME: We should not assume parent name does not have length 0.
3500 if (fID > -1) {
3501 RemovePrefix(dataName, parentName);
3502 }
3503
3504 // Remove any leading dot.
3505 if (dataName.Length()) {
3506 if (dataName[0] == '.') {
3507 dataName.Remove(0, 1);
3508 }
3509 }
3510
3511 // Remove any trailing dot.
3512 if (dataName.Length()) {
3513 if (dataName[dataName.Length()-1] == '.') {
3514 dataName.Remove(dataName.Length() - 1, 1);
3515 }
3516 }
3517
3518 //
3519 // Now that we have our data member name, find our offset
3520 // in our parent class.
3521 //
3522 // Note: Our data member name can have many dots in it
3523 // if branches were elided between our parent branch
3524 // and us by Unroll().
3525 //
3526 // FIXME: This may not work if our member name is ambiguous.
3527 //
3528
3529 Int_t offset = 0;
3530 if (dataName.Length()) {
3531 // -- We have our data member name, do a lookup in the dictionary meta info of our parent class.
3532 // Get our parent class.
3533 TClass* pClass = 0;
3534 // First check whether this sub-branch is part of the 'cache' (because the data member it
3535 // represents is no longer in the current class layout.
3536 TStreamerInfo *subInfo = subBranch->GetInfoImp();
3537 //if (subInfo && subBranch->TestBit(kCache)) { // subInfo->GetElements()->At(subBranch->GetID())->TestBit(TStreamerElement::kCache)) {
3538 if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3539 pClass = ((TStreamerElement*)subInfo->GetElements()->At(0))->GetClassPointer();
3540 }
3541 // FIXME: Do we need the other base class tests here?
3542 if (!pClass) {
3543 if (fType == 1) {
3544 // -- Parent branch is a base class branch.
3545 // FIXME: Is using branchElem here the right thing?
3546 pClass = branchElem->GetClassPointer();
3547 if (pClass->Property() & kIsAbstract) {
3548 // the class is abstract, let see if the
3549
3551 if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
3552 // Our parent's class is emulated and we represent an abstract class.
3553 // and the target class has not been set explicilty.
3554 TString target = pClass->GetName();
3555 target += "@@emulated";
3556
3557 pClass = TClass::GetClass(target);
3558 }
3559 }
3560 } else {
3561 // -- Parent branch is *not* a base class branch.
3562 // FIXME: This sometimes returns a null pointer.
3563 pClass = subBranch->GetParentClass();
3564 }
3565 }
3566 if (!pClass) {
3567 // -- No parent class, fix it.
3568 // FIXME: This is probably wrong!
3569 // Assume parent class is our parent branch's clones class or value class.
3570 if (GetClonesName() && strlen(GetClonesName())) {
3571 pClass = fClonesClass;
3572 if (!pClass) {
3573 Warning("InitializeOffsets", "subBranch: '%s' has no parent class, and cannot get class for clones class: '%s'!", subBranch->GetName(), GetClonesName());
3574 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3575 continue;
3576 }
3577 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3578 }
3581 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass ? pClass->GetName() : "unknowned class");
3582 }
3583 if (!pClass) {
3584 // -- Still no parent class, assume our parent class is our parent branch's class.
3585 // FIXME: This is probably wrong!
3586 pClass = branchClass;
3587 // FIXME: Enable this warning!
3588 //Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3589 }
3590 }
3591 if (renamed && pClass) {
3592 if (pClass == branchClass) {
3593 pClass = branchElem->GetNewClass();
3594 } else if (fCollProxy && pClass == branchClass->GetCollectionProxy()->GetValueClass()) {
3595 pClass = fCollProxy->GetValueClass();
3596 }
3597 }
3598
3599 //------------------------------------------------------------------
3600 // If we have the are the sub-branch of the TBranchSTL, we need
3601 // to remove it's name to get the correct real data offsets
3602 ////////////////////////////////////////////////////////////////////
3603
3604 const bool isToplevelCollection = (this == GetMother() && (fType == 3 || fType == 4));
3605 if( stlParentName.Length() && (dynamic_cast<TBranchSTL*>(fParent) || isToplevelCollection))
3606 {
3607 if( !strncmp( stlParentName.Data(), dataName.Data(), stlParentName.Length()-1 )
3608 && dataName[ stlParentName.Length() ] == '.' )
3609 dataName.Remove( 0, stlParentName.Length()+1 );
3610 }
3611
3612 // Find our offset in our parent class using
3613 // a lookup by name in the dictionary meta info
3614 // for our parent class.
3615
3616 if (alternateElement) {
3617 Ssiz_t dotpos = dataName.Last('.');
3618 Ssiz_t endpos = dataName.Length();
3619 if (dotpos != kNPOS) ++dotpos; else dotpos = 0;
3620 dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
3621 }
3622 TRealData* rd = pClass->GetRealData(dataName);
3623 if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
3624 // -- Data member exists in the dictionary meta info, get the offset.
3625 // If we are using an alternateElement, it is the target of a rule
3626 // and might be indeed transient.
3627 offset = rd->GetThisOffset();
3628 } else if (subBranchElement->TestBit(TStreamerElement::kWholeObject)) {
3629 // We are a rule with no specific target, it applies to the whole
3630 // object, let's set the offset to zero
3631 offset = 0;
3632 } else {
3633 // -- No dictionary meta info for this data member, it must no
3634 // longer exist
3635 if (fEntries == 0) {
3636 // ... unless we creating the branch in which case
3637 // we have an internal error.
3638 if (pClass->GetListOfRealData()->GetEntries() == 0) {
3639 // We are probably missing the ShowMember, let's
3640 // just issue an error.
3641 Error("InitializeOffsets",
3642 "Could not find the real data member '%s' when constructing the branch '%s' [Likely missing ShowMember].",
3643 dataName.Data(),GetName());
3644 } else if (subInfo && subInfo->GetClassVersion()!=subInfo->GetClass()->GetClassVersion()) {
3645 // In the case where we are cloning a TTree that was created with an older version of the layout, we may not
3646 // able to find all the members
3647 Info("InitializeOffsets",
3648 "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'. ",
3649 dataName.Data(),GetName());
3650 } else {
3651 // Something really bad happen.
3652 Fatal("InitializeOffsets",
3653 "Could not find the real data member '%s' when constructing the branch '%s' [Likely an internal error, please report to the developers].",
3654 dataName.Data(),GetName());
3655 }
3656 }
3657 localOffset = TStreamerInfo::kMissing;
3658 }
3659 } else {
3660 // -- We have no data member name, ok for a base class, not good otherwise.
3661 if (isBaseSubBranch) {
3662 // I am a direct base class of my parent class, my local offset is enough.
3663 } else {
3664 Warning("InitializeOffsets", "Could not find the data member name for branch '%s' with parent branch '%s', assuming offset is zero!", subBranch->GetName(), GetName());
3665 }
3666 }
3667
3668 //
3669 // Ok, do final calculations for fOffset and fBranchOffset.
3670 //
3671
3672 if (isContDataMember) {
3673 // -- Container data members set fOffset instead of fBranchOffset.
3674 // The fOffset is what should be added to the start of the entry
3675 // in the collection (i.e., its current absolute address) to find
3676 // the beginning of the data member described by the current branch.
3677 //
3678 // Compensate for the i/o routines adding our local offset later.
3679 if (subBranch->fObject == 0 && localOffset == TStreamerInfo::kMissing) {
3680 subBranch->SetMissing();
3681 // We stil need to set fBranchOffset in the case of a missing
3682 // element so that SetAddress is (as expected) not called
3683 // recursively in this case.
3684 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3685 } else {
3686 if (isBaseSubBranch) {
3687 // The value of 'offset' for a base class does not include its
3688 // 'localOffset'.
3689 subBranch->SetOffset(offset);
3690 } else {
3691 // The value of 'offset' for a regular data member does include its
3692 // 'localOffset', we need to remove it explicitly.
3693 subBranch->SetOffset(offset - localOffset);
3694 }
3695 }
3696 } else {
3697 // -- Set fBranchOffset for sub-branch.
3698 Int_t isSplit = 0 != subBranch->GetListOfBranches()->GetEntriesFast();
3699 if (subBranch->fObject == 0 && localOffset == TStreamerInfo::kMissing) {
3700 // The branch is missing
3701 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3702
3703 } else if (isSplit) {
3704 if (isBaseSubBranch) {
3705 // We are split, so we need to add in our local offset
3706 // to get our absolute address for our children.
3707 fBranchOffset[subBranchIdx] = offset + localOffset;
3708 } else {
3709 // We are split so our offset will never be
3710 // used in an i/o, so we do not have to subtract
3711 // off our local offset like below.
3712 fBranchOffset[subBranchIdx] = offset;
3713 }
3714 } else {
3715 if (isBaseSubBranch) {
3716 // We are not split, so our local offset will be
3717 // added later by the i/o routines.
3718 fBranchOffset[subBranchIdx] = offset;
3719 } else {
3720 // Compensate for the fact that the i/o routines
3721 // are going to add my local offset later.
3722 fBranchOffset[subBranchIdx] = offset - localOffset;
3723 }
3724 }
3725 }
3726 }
3727 }
3728 else {
3729 if (fID > -1) {
3730 // Branch is *not* a top-level branch.
3731 // Let's check if the target member is still present in memory
3733 fObject = 0;
3734 }
3735 }
3736 }
3737 const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
3738 if (fReadActionSequence && isSplitNode) {
3739 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3740 auto index = parent->fBranches.IndexOf(this);
3741 if (index >= 0) {
3742 fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
3743 }
3744 }
3745
3747}
3748
3749////////////////////////////////////////////////////////////////////////////////
3750/// Return kTRUE if more than one leaf, kFALSE otherwise.
3751
3753{
3754 Int_t nbranches = fBranches.GetEntriesFast();
3755 if (nbranches >= 1) {
3756 return kTRUE;
3757 }
3758 TList* browsables = const_cast<TBranchElement*>(this)->GetBrowsables();
3759 return browsables && browsables->GetSize();
3760}
3761
3762////////////////////////////////////////////////////////////////////////////////
3763/// Detect a collection written using a zero pointer in old versions of root.
3764/// In versions of ROOT older than 4.00/03, if a collection (TClonesArray
3765/// or STL container) was split but the pointer to the collection was zeroed
3766/// out, nothing was saved. Hence there is no __easy__ way to detect the
3767/// case. In newer versions, a zero is written so that a 'missing' collection
3768/// appears to be an empty collection.
3769
3771{
3772 Bool_t ismissing = kFALSE;
3774 if (basket && fTree) {
3775 Long64_t entry = fTree->GetReadEntry();
3777 Long64_t last;
3778 if (fReadBasket == fWriteBasket) {
3779 last = fEntryNumber - 1;
3780 } else {
3781 last = fBasketEntry[fReadBasket+1] - 1;
3782 }
3783 Int_t* entryOffset = basket->GetEntryOffset();
3784 Int_t bufbegin;
3785 Int_t bufnext;
3786 if (entryOffset) {
3787 bufbegin = entryOffset[entry-first];
3788
3789 if (entry < last) {
3790 bufnext = entryOffset[entry+1-first];
3791 } else {
3792 bufnext = basket->GetLast();
3793 }
3794 if (bufnext == bufbegin) {
3795 ismissing = kTRUE;
3796 } else {
3797 // fixed length buffer so this is not the case here.
3798 if (basket->GetNevBufSize() == 0) {
3799 ismissing = kTRUE;
3800 }
3801 }
3802 }
3803 }
3804 return ismissing;
3805}
3806
3807////////////////////////////////////////////////////////////////////////////////
3808/// Print branch parameters.
3809
3810static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids)
3811{
3812 for(auto &cursor : ids) {
3813 auto id = cursor.fElemID;
3814 if (id >= 0) {
3815 auto el = info->GetElement(id);
3816 if (el)
3817 el->ls();
3818 else {
3819 Error("TBranchElement::Print", "Element for id #%d not found in StreamerInfo for %s",
3820 id, info->GetName());
3821 info->ls();
3822 }
3823 } else if (cursor.fNestedIDs) {
3824 Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
3825 PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
3826 }
3827 }
3828}
3829
3831{
3832 Int_t nbranches = fBranches.GetEntriesFast();
3833 if (strncmp(option,"debugAddress",strlen("debugAddress"))==0) {
3834 if (strlen(option)==strlen("debugAddress")) {
3835 Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s %s\n",
3836 "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject", "fOnfileObject");
3837 }
3838 if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3839 else Printf("%-24s ", GetName());
3840
3841 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3842 Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3843 TVirtualStreamerInfo *info = ((TBranchElement*)this)->GetInfoImp();
3844
3845 Printf("%-16s %2d %4d %-16s %-16s %8x %8x %p %p%s\n",
3846 info ? info->GetName() : "StreamerInfo unavailable", GetID(), GetType(),
3848 (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3849 GetOffset(), GetObject(), fOnfileObject, TestBit(kOwnOnfileObj) ? " (owned)" : "");
3850 for (Int_t i = 0; i < nbranches; ++i) {
3851 TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3852 subbranch->Print("debugAddressSub");
3853 }
3854 return;
3855 }
3856 if (strncmp(option,"debugInfo",strlen("debugInfo"))==0) {
3857 Printf("Branch %s uses:",GetName());
3858 if (fID>=0) {
3859 // GetInfoImp()->GetElement(fID)->ls();
3860 // for(UInt_t i=0; i< fIDs.size(); ++i) {
3861 // GetInfoImp()->GetElement(fIDs[i])->ls();
3862 // }
3863 TStreamerInfo *localInfo = GetInfoImp();
3864 if (fType == 3 || fType == 4) {
3865 // Search for the correct version.
3867 }
3868 Printf(" With elements:");
3869 if (fType != 3 && fType != 4)
3870 localInfo->GetElement(fID)->ls();
3871 PrintElements(localInfo, fNewIDs);
3872 Printf(" with read actions:");
3874 Printf(" with write actions:");
3876 } else if (!fNewIDs.empty() && GetInfoImp()) {
3877 TStreamerInfo *localInfo = GetInfoImp();
3878 if (fType == 3 || fType == 4) {
3879 // Search for the correct version.
3881 }
3882 PrintElements(localInfo, fNewIDs);
3883 Printf(" with read actions:");
3885 Printf(" with write actions:");
3887 }
3888 TString suboption = "debugInfoSub";
3889 suboption += (option+strlen("debugInfo"));
3890 for (Int_t i = 0; i < nbranches; ++i) {
3891 TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3892 subbranch->Print(suboption);
3893 }
3894 Printf(" ");
3895 return;
3896 }
3897 if (nbranches) {
3898 if (fID == -2) {
3899 if (strcmp(GetName(),GetTitle()) == 0) {
3900 Printf("*Branch :%-66s *",GetName());
3901 } else {
3902 Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3903 }
3904 Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3905 Printf("*............................................................................*");
3906 }
3907 if (fType >= 2) {
3908 TBranch::Print(option);
3909 }
3910 for (Int_t i=0;i<nbranches;i++) {
3911 TBranch *branch = (TBranch*)fBranches.At(i);
3912 branch->Print(option);
3913 }
3914 } else {
3915 TBranch::Print(option);
3916 }
3917}
3918
3919////////////////////////////////////////////////////////////////////////////////
3920/// Prints values of leaves.
3921
3923{
3925
3926 TStreamerInfo *info = GetInfoImp();
3927 Int_t prID = fID;
3928 char *object = fObject;
3929 if (TestBit(kCache)) {
3931 prID = fID+1;
3932 } else if (fOnfileObject) {
3933 object = fOnfileObject->GetObjectAt(0);
3934 }
3935 }
3936
3937 if (TestBit(kDecomposedObj)) {
3938 if (!fAddress) {
3939 return;
3940 }
3941 if (fType == 3 || fType == 4) {
3942 // TClonesArray or STL container top-level branch.
3943 printf(" %-15s = %d\n", GetName(), fNdata);
3944 return;
3945 } else if (fType == 31 || fType == 41) {
3946 // TClonesArray or STL container sub-branch.
3947 Int_t n = TMath::Min(10, fNdata);
3950 // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
3951 // printed as a string and could print weird characters.
3952 // So we print an unsigned char instead (not perfect, but better).
3954 }
3955 if (atype > 54) {
3956 // FIXME: More logic required here (like in ReadLeaves)
3957 printf(" %-15s = %d\n", GetName(), fNdata);
3958 return;
3959 }
3960 if (fStreamerType > 20) {
3961 atype -= 20;
3963 n = n * leaf->GetLenStatic();
3964 }
3965 if (GetInfoImp()) {
3966 GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3967 }
3968 return;
3969 } else if (fType <= 2) {
3970 // Branch in split mode.
3971 // FIXME: This should probably be < 60 instead.
3972 if ((fStreamerType > 40) && (fStreamerType < 55)) {
3973 Int_t atype = fStreamerType - 20;
3974 TBranchElement* counterElement = (TBranchElement*) fBranchCount;
3975 Int_t n = (Int_t) counterElement->GetValue(0, 0);
3976 if (GetInfoImp()) {
3977 GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3978 }
3979 } else {
3980 if (GetInfoImp()) {
3981 GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3982 }
3983 }
3984 return;
3985 }
3986 } else if (fType == 3) {
3987 printf(" %-15s = %d\n", GetName(), fNdata);
3988 } else if (fType == 31) {
3989 TClonesArray* clones = (TClonesArray*) object;
3990 if (GetInfoImp()) {
3991 GetInfoImp()->PrintValueClones(GetName(), clones, prID, fOffset, lenmax);
3992 }
3993 } else if (fType == 41) {
3995 if (GetInfoImp()) {
3996 GetInfoImp()->PrintValueSTL(GetName(), ((TBranchElement*) this)->GetCollectionProxy(), prID, fOffset, lenmax);
3997 }
3998 } else {
3999 if (GetInfoImp()) {
4000 GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
4001 }
4002 }
4003}
4004
4005////////////////////////////////////////////////////////////////////////////////
4006/// Unconfiguration Read Leave function.
4007
4009{
4010 Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
4011}
4012
4013////////////////////////////////////////////////////////////////////////////////
4014/// Read leaves into i/o buffers for this branch.
4015/// For the case where the branch is set in MakeClass mode (decomposed object).
4016
4018{
4020
4021 if (fType == 3 || fType == 4) {
4022 // Top level branch of a TClonesArray.
4023 Int_t *n = (Int_t*) fAddress;
4024 b >> n[0];
4025 if ((n[0] < 0) || (n[0] > fMaximum)) {
4026 if (IsMissingCollection()) {
4027 n[0] = 0;
4028 b.SetBufferOffset(b.Length() - sizeof(n));
4029 } else {
4030 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());
4031 n[0] = 0;
4032 }
4033 }
4034 fNdata = n[0];
4035 if (fType == 4) {
4036 Int_t nbranches = fBranches.GetEntriesFast();
4037 switch(fSTLtype) {
4038 case ROOT::kSTLset:
4039 case ROOT::kSTLmultiset:
4040 case ROOT::kSTLmap:
4041 case ROOT::kSTLmultimap:
4042 for (Int_t i=0; i<nbranches; i++) {
4043 TBranch *branch = (TBranch*)fBranches[i];
4044 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4045 if (nb < 0) {
4046 break;
4047 }
4048 }
4049 break;
4050 default:
4051 break;
4052 }
4053 }
4054 return;
4055 } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
4057 Int_t atype = fStreamerType;
4058 // FIXME: This should probably be > 59 instead.
4059 if (atype > 54) return;
4060 if (!fAddress) {
4061 return;
4062 }
4063 Int_t n = fNdata;
4064 if (atype>40) {
4065 atype -= 40;
4066 if (!fBranchCount2) return;
4067 const char *len_where = (char*)fBranchCount2->fAddress;
4068 if (!len_where) return;
4069 Int_t len_atype = fBranchCount2->fStreamerType;
4070 Int_t length;
4071 Int_t k;
4072 Char_t isArray;
4073 for( k=0; k<n; k++) {
4074 char **where = &(((char**)fAddress)[k]);
4075 delete [] *where;
4076 *where = 0;
4077 switch(len_atype) {
4078 case 1: {length = ((Char_t*) len_where)[k]; break;}
4079 case 2: {length = ((Short_t*) len_where)[k]; break;}
4080 case 3: {length = ((Int_t*) len_where)[k]; break;}
4081 case 4: {length = ((Long_t*) len_where)[k]; break;}
4082 //case 5: {length = ((Float_t*) len_where)[k]; break;}
4083 case 6: {length = ((Int_t*) len_where)[k]; break;}
4084 //case 8: {length = ((Double_t*)len_where)[k]; break;}
4085 case 11: {length = ((UChar_t*) len_where)[k]; break;}
4086 case 12: {length = ((UShort_t*) len_where)[k]; break;}
4087 case 13: {length = ((UInt_t*) len_where)[k]; break;}
4088 case 14: {length = ((ULong_t*) len_where)[k]; break;}
4089 case 15: {length = ((UInt_t*) len_where)[k]; break;}
4090 case 16: {length = ((Long64_t*) len_where)[k]; break;}
4091 case 17: {length = ((ULong64_t*)len_where)[k]; break;}
4092 case 18: {length = ((Bool_t*) len_where)[k]; break;}
4093 default: continue;
4094 }
4095 b >> isArray;
4096 if (length <= 0) continue;
4097 if (isArray == 0) continue;
4098 switch (atype) {
4099 case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
4100 case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
4101 case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4102 case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
4103 case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
4104 case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4105 case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
4106 case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
4107 case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
4108 case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4109 case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
4110 case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4111 case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
4112 case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
4113 case 18: {*where=new char[sizeof(Bool_t)*length]; b.ReadFastArray((Bool_t*) *where, length); break;}
4114 }
4115 }
4116 return;
4117 }
4118 if (atype > 20) {
4119 atype -= 20;
4121 n *= leaf->GetLenStatic();
4122 }
4123 switch (atype) {
4124 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4125 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4126 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4127 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4128 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4129 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4130 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4131 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4132 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4133 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4134 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4135 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4136 case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
4137 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4138 case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
4139 case 9: {
4142 Double_t *xx = (Double_t*) fAddress;
4143 for (Int_t ii=0;ii<n;ii++) {
4144 b.ReadDouble32(&(xx[ii]),se);
4145 }
4146 break;
4147 }
4148 case 19: {
4151 Float_t *xx = (Float_t*) fAddress;
4152 for (Int_t ii=0;ii<n;ii++) {
4153 b.ReadFloat16(&(xx[ii]),se);
4154 }
4155 break;
4156 }
4157 }
4158 return;
4159 } else if (fType <= 2) { // branch in split mode
4160 // FIXME: This should probably be < 60 instead.
4161 if (fStreamerType > 40 && fStreamerType < 55) {
4162 Int_t atype = fStreamerType - 40;
4163 Int_t n;
4164 if (fBranchCount==0) {
4165 // Missing fBranchCount. let's attempts to recover.
4166
4167 TString countname( GetName() );
4168 Ssiz_t dot = countname.Last('.');
4169 if (dot>=0) {
4170 countname.Remove(dot+1);
4171 } else {
4172 countname = "";
4173 }
4174 TString counter( GetTitle() );
4175 Ssiz_t loc = counter.Last('[');
4176 if (loc>=0) {
4177 counter.Remove(0,loc+1);
4178 }
4179 loc = counter.Last(']');
4180 if (loc>=0) {
4181 counter.Remove(loc);
4182 }
4183 countname += counter;
4185 }
4186 if (fBranchCount) {
4187 n = (Int_t)fBranchCount->GetValue(0,0);
4188 } else {
4189 Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4190 n = 0;
4191 }
4192 fNdata = n;
4193 Char_t isArray;
4194 b >> isArray;
4195 switch (atype) {
4196 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4197 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4198 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4199 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4200 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4201 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4202 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4203 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4204 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4205 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4206 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4207 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4208 case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
4209 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4210 case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
4211 case 9: {
4214 Double_t *xx = (Double_t*) fAddress;
4215 for (Int_t ii=0;ii<n;ii++) {
4216 b.ReadDouble32(&(xx[ii]),se);
4217 }
4218 break;
4219 }
4220 case 19: {
4223 Float_t *xx = (Float_t*) fAddress;
4224 for (Int_t ii=0;ii<n;ii++) {
4225 b.ReadFloat16(&(xx[ii]),se);
4226 }
4227 break;
4228 }
4229 }
4230 } else {
4231 fNdata = 1;
4232 if (fAddress) {
4233 if (fType<0) {
4234 // Non TObject, Non collection classes with a custom streamer.
4235
4236 // if (fObject)
4238 } else {
4239 TStreamerInfo *info = GetInfoImp();
4240 if (!info) {
4241 return;
4242 }
4243 // Since info is not null, fReadActionSequence is not null either.
4244 b.ApplySequence(*fReadActionSequence, fObject);
4245 }
4247 fNdata = (Int_t) GetValue(0, 0);
4248 }
4249 } else {
4250 fNdata = 0;
4251 }
4252 }
4253 return;
4254 }
4255}
4256
4257////////////////////////////////////////////////////////////////////////////////
4258/// Read leaves into i/o buffers for this branch.
4259/// Case of a collection (fType == 4).
4260
4262{
4264 if (fObject == 0)
4265 {
4266 // We have nowhere to copy the data (probably because the data member was
4267 // 'dropped' from the current schema) so let's no copy it in a random place.
4268 return;
4269 }
4270
4271 // STL container master branch (has only the number of elements).
4272 Int_t n;
4273 b >> n;
4274 if ((n < 0) || (n > fMaximum)) {
4275 if (IsMissingCollection()) {
4276 n = 0;
4277 b.SetBufferOffset(b.Length()-sizeof(n));
4278 } else {
4279 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());
4280 n = 0;
4281 }
4282 }
4283 fNdata = n;
4284
4285 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4286
4287 // Note: Proxy-helper needs to "embrace" the entire
4288 // streaming of this STL container if the container
4289 // is a set/multiset/map/multimap (what we do not
4290 // know here).
4291 // For vector/list/deque Allocate == Resize
4292 // and Commit == noop.
4293 // TODO: Exception safety a la TPushPop
4296 void* alternate = proxy->Allocate(fNdata, true);
4298 fPtrIterators->CreateIterators(alternate, proxy);
4299 } else {
4300 fIterators->CreateIterators(alternate, proxy);
4301 }
4302
4303 Int_t nbranches = fBranches.GetEntriesFast();
4304 switch (fSTLtype) {
4305 case ROOT::kSTLset:
4308 case ROOT::kSTLmultiset:
4309 case ROOT::kSTLmap:
4310 case ROOT::kSTLmultimap:
4313 for (Int_t i = 0; i < nbranches; ++i) {
4314 TBranch *branch = (TBranch*) fBranches[i];
4315 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4316 if (nb < 0) {
4317 // Give up on i/o failure.
4318 // FIXME: We need an error message here.
4319 break;
4320 }
4321 }
4322 break;
4323 default:
4324 break;
4325 }
4326 //------------------------------------------------------------------------
4327 // We have split this stuff, so we need to create the the pointers
4328 /////////////////////////////////////////////////////////////////////////////
4329
4331 {
4332 TClass *elClass = proxy->GetValueClass();
4333
4334 //--------------------------------------------------------------------
4335 // The allocation is done in this strange way because ReadLeaves
4336 // is being called many times by TTreeFormula!!!
4337 //////////////////////////////////////////////////////////////////////////
4338
4339 Int_t i = 0;
4340 // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4341 if( !fNdata || *(void**)proxy->At( 0 ) != 0 )
4342 i = fNdata;
4343
4344 for( ; i < fNdata; ++i )
4345 {
4346 void **el = (void**)proxy->At( i );
4347 // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4348 *el = elClass->New();
4349 }
4350 }
4351
4352 proxy->Commit(alternate);
4353}
4354
4355////////////////////////////////////////////////////////////////////////////////
4356/// Read leaves into i/o buffers for this branch.
4357/// Case of a data member within a collection (fType == 41).
4358
4360{
4362 if (fObject == 0)
4363 {
4364 // We have nowhere to copy the data (probably because the data member was
4365 // 'dropped' from the current schema) so let's no copy it in a random place.
4366 return;
4367 }
4368
4369 // STL container sub-branch (contains the elements).
4371 if (!fNdata) {
4372 return;
4373 }
4374
4375 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4376
4377 TStreamerInfo *info = GetInfoImp();
4378 if (info == 0) return;
4379
4382
4383 // R__ASSERT(0);
4385 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4386}
4387
4388////////////////////////////////////////////////////////////////////////////////
4389/// Read leaves into i/o buffers for this branch.
4390/// Case of a data member within a collection (fType == 41).
4391
4393{
4395 if (fObject == 0)
4396 {
4397 // We have nowhere to copy the data (probably because the data member was
4398 // 'dropped' from the current schema) so let's no copy it in a random place.
4399 return;
4400 }
4401
4402 // STL container sub-branch (contains the elements).
4404 if (!fNdata) {
4405 return;
4406 }
4407 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4408
4409 TStreamerInfo *info = GetInfoImp();
4410 if (info == 0) return;
4411
4414
4416 b.ApplySequenceVecPtr(*fReadActionSequence,iter->fBegin,iter->fEnd);
4417}
4418
4419////////////////////////////////////////////////////////////////////////////////
4420/// Read leaves into i/o buffers for this branch.
4421/// Case of a data member within a collection (fType == 41).
4422
4424{
4426 if (fObject == 0)
4427 {
4428 // We have nowhere to copy the data (probably because the data member was
4429 // 'dropped' from the current schema) so let's no copy it in a random place.
4430 return;
4431 }
4432
4433 // STL container sub-branch (contains the elements).
4435 if (!fNdata) {
4436 return;
4437 }
4438 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4439
4440 TStreamerInfo *info = GetInfoImp();
4441 if (info == 0) return;
4442 // Since info is not null, fReadActionSequence is not null either.
4443
4444 // Still calling PushPop for the legacy entries.
4447
4449 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4450}
4451
4452////////////////////////////////////////////////////////////////////////////////
4453/// Read leaves into i/o buffers for this branch.
4454/// Case of a TClonesArray (fType == 3).
4455
4457{
4459 if (fObject == 0)
4460 {
4461 // We have nowhere to copy the data (probably because the data member was
4462 // 'dropped' from the current schema) so let's no copy it in a random place.
4463 return;
4464 }
4465
4466 // TClonesArray master branch (has only the number of elements).
4467 Int_t n;
4468 b >> n;
4469 if ((n < 0) || (n > fMaximum)) {
4470 if (IsMissingCollection()) {
4471 n = 0;
4472 b.SetBufferOffset(b.Length()-sizeof(n));
4473 } else {
4474 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());
4475 n = 0;
4476 }
4477 }
4478 fNdata = n;
4479 TClonesArray* clones = (TClonesArray*) fObject;
4480 if (clones->IsZombie()) {
4481 return;
4482 }
4483 // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4484 // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4485 // clones->Clear();
4486 clones->ExpandCreateFast(fNdata);
4487}
4488
4489////////////////////////////////////////////////////////////////////////////////
4490/// Read leaves into i/o buffers for this branch.
4491/// Case of a data member within a TClonesArray (fType == 31).
4492
4494{
4495 // No need to validate the address here, if we are a member of a split ClonesArray,
4496 // fID is positive
4497 // ValidateAddress();
4498
4499 if (fObject == 0)
4500 {
4501 // We have nowhere to copy the data (probably because the data member was
4502 // 'dropped' from the current schema) so let's no copy it in a random place.
4503 return;
4504 }
4505
4506 // TClonesArray sub-branch (contains the elements).
4508 TClonesArray* clones = (TClonesArray*) fObject;
4509 if (clones->IsZombie()) {
4510 return;
4511 }
4512 TStreamerInfo *info = GetInfoImp();
4513 if (info==0) return;
4514 // Since info is not null, fReadActionSequence is not null either.
4515
4516 // Note, we could (possibly) save some more, by configuring the action
4517 // based on the value of fOnfileObject rather than pushing in on a stack.
4518 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4519
4520 char **arr = (char **)clones->GetObjectRef();
4521 char **end = arr + fNdata;
4522 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
4523}
4524
4525////////////////////////////////////////////////////////////////////////////////
4526/// Read leaves into i/o buffers for this branch.
4527/// For split-class branch, base class branch, data member branch, or top-level branch.
4528/// which do not have a branch count and are not a counter.
4529
4531{
4534
4536 if (fObject == 0)
4537 {
4538 // We have nowhere to copy the data (probably because the data member was
4539 // 'dropped' from the current schema) so let's no copy it in a random place.
4540 return;
4541 }
4542
4543 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4544 // If not a TClonesArray or STL container master branch
4545 // or sub-branch and branch inherits from tobject,
4546 // then register with the buffer so that pointers are
4547 // handled properly.
4548 if (TestBit(kBranchObject)) {
4549 b.MapObject((TObject*) fObject);
4550 } else if (TestBit(kBranchAny)) {
4551 b.MapObject(fObject, fBranchClass);
4552 }
4553
4554 fNdata = 1;
4555 TStreamerInfo *info = GetInfoImp();
4556 if (!info) {
4557 return;
4558 }
4559 // Since info is not null, fReadActionSequence is not null either.
4560 b.ApplySequence(*fReadActionSequence, fObject);
4561}
4562
4563////////////////////////////////////////////////////////////////////////////////
4564/// Read leaves into i/o buffers for this branch.
4565/// For split-class branch, base class branch, data member branch, or top-level branch.
4566/// which do have a branch count and are not a counter.
4567
4569{
4571
4573 if (fObject == 0)
4574 {
4575 // We have nowhere to copy the data (probably because the data member was
4576 // 'dropped' from the current schema) so let's no copy it in a random place.
4577 return;
4578 }
4579
4580 // If not a TClonesArray or STL container master branch
4581 // or sub-branch and branch inherits from tobject,
4582 // then register with the buffer so that pointers are
4583 // handled properly.
4584 if (TestBit(kBranchObject)) {
4585 b.MapObject((TObject*) fObject);
4586 } else if (TestBit(kBranchAny)) {
4587 b.MapObject(fObject, fBranchClass);
4588 }
4589
4590 fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4591 TStreamerInfo *info = GetInfoImp();
4592 if (!info) {
4593 return;
4594 }
4595 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1); // Here we have a single object that contains a variable size C-style array.
4596 // Since info is not null, fReadActionSequence is not null either.
4597 b.ApplySequence(*fReadActionSequence, fObject);
4598}
4599
4600////////////////////////////////////////////////////////////////////////////////
4601/// Read leaves into i/o buffers for this branch.
4602/// For split-class branch, base class branch, data member branch, or top-level branch.
4603/// which do not have a branch count and are a counter.
4604
4606{
4608 if (fObject == 0)
4609 {
4610 // We have nowhere to copy the data (probably because the data member was
4611 // 'dropped' from the current schema) so let's no copy it in a random place.
4612 return;
4613 }
4614
4615 // If not a TClonesArray or STL container master branch
4616 // or sub-branch and branch inherits from tobject,
4617 // then register with the buffer so that pointers are
4618 // handled properly.
4619 if (TestBit(kBranchObject)) {
4620 b.MapObject((TObject*) fObject);
4621 } else if (TestBit(kBranchAny)) {
4622 b.MapObject(fObject, fBranchClass);
4623 }
4624
4625 TStreamerInfo *info = GetInfoImp();
4626 if (!info) {
4627 return;
4628 }
4629
4630 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4631
4632 // Since info is not null, fReadActionSequence is not null either.
4633 b.ApplySequence(*fReadActionSequence, fObject);
4634 fNdata = (Int_t) GetValue(0, 0);
4635}
4636
4637////////////////////////////////////////////////////////////////////////////////
4638/// Read leaves into i/o buffers for this branch.
4639/// Non TObject, Non collection classes with a custom streamer.
4640
4642{
4644 if (fObject == 0)
4645 {
4646 // We have nowhere to copy the data (probably because the data member was
4647 // 'dropped' from the current schema) so let's no copy it in a random place.
4648 return;
4649 }
4650
4651 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4653}
4654
4655////////////////////////////////////////////////////////////////////////////////
4656/// Unconfiguration Fill Leave function.
4657
4659{
4660 Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4661}
4662
4663////////////////////////////////////////////////////////////////////////////////
4664/// Delete any object we may have allocated on a previous call to SetAddress.
4665
4667{
4668 if (fObject && TestBit(kDeleteObject)) {
4669 if (IsAutoDelete() && fAddress != (char*)&fObject) {
4670 *((char**) fAddress) = 0;
4671 }
4673 if (fType == 3) {
4674 // -- We are a TClonesArray master branch.
4675 TClonesArray::Class()->Destructor(fObject);
4676 fObject = 0;
4679 // -- We are a pointer to a TClonesArray.
4680 // We must zero the pointer in the object.
4681 *((char**) fAddress) = 0;
4682 }
4683 } else if (fType == 4) {
4684 // -- We are an STL container master branch.
4686
4687 if (!proxy) {
4688 Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4689 fObject = 0;
4690 } else {
4692 if (needDelete && fID >= 0) {
4695 needDelete = !se->TestBit(TStreamerElement::kDoNotDelete);
4696 }
4697 if (needDelete) {
4699 proxy->Clear("force");
4700 }
4701 proxy->Destructor(fObject);
4702 fObject = 0;
4703 }
4705 // -- We are a pointer to an STL container.
4706 // We must zero the pointer in the object.
4707 *((char**) fAddress) = 0;
4708 }
4709 } else {
4710 // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4712 if (!cl) {
4713 Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4714 fObject = 0;
4715 } else {
4717
4718 if (proxy) {
4719 if (fID >= 0) {
4721 TStreamerElement* se = si->GetElement(fID);
4724 proxy->Clear("force");
4725 }
4728 proxy->Clear("force");
4729 }
4730
4731 }
4732 cl->Destructor(fObject);
4733 fObject = 0;
4734 }
4735 }
4736 }
4737}
4738
4739////////////////////////////////////////////////////////////////////////////////
4740/// Reset a Branch.
4741///
4742/// Existing i/o buffers are deleted.
4743/// Entries, max and min are reset.
4744///
4745
4747{
4748 Int_t nbranches = fBranches.GetEntriesFast();
4749 for (Int_t i = 0; i < nbranches; ++i) {
4750 TBranch* branch = (TBranch*) fBranches[i];
4751 branch->Reset(option);
4752 }
4753 fBranchID = -1;
4754 TBranch::Reset(option);
4755}
4756
4757////////////////////////////////////////////////////////////////////////////////
4758/// Reset a Branch after a Merge operation (drop data but keep customizations)
4759///
4760
4762{
4763 Int_t nbranches = fBranches.GetEntriesFast();
4764 for (Int_t i = 0; i < nbranches; ++i) {
4765 TBranch* branch = (TBranch*) fBranches[i];
4766 branch->ResetAfterMerge(info);
4767 }
4769}
4770
4771////////////////////////////////////////////////////////////////////////////////
4772/// Set branch address to zero and free all allocated memory.
4773
4775{
4776 for (Int_t i = 0; i < fNleaves; ++i) {
4777 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
4778 //if (leaf) leaf->SetAddress(0);
4779 leaf->SetAddress(0);
4780 }
4781
4782 // Note: We *must* do the sub-branches first, otherwise
4783 // we may delete the object containing the sub-branches
4784 // before giving them a chance to cleanup.
4785 Int_t nbranches = fBranches.GetEntriesFast();
4786 for (Int_t i = 0; i < nbranches; ++i) {
4787 TBranch* br = (TBranch*) fBranches[i];
4788 if (br) br->ResetAddress();
4789 }
4790
4791 //
4792 // SetAddress may have allocated an object.
4793 //
4794
4795 ReleaseObject();
4796
4798 fAddress = 0;
4799 fObject = 0;
4800}
4801
4802////////////////////////////////////////////////////////////////////////////////
4803/// Release ownership of any allocated objects.
4804///
4805/// Note: This interface was added so that clone trees could
4806/// be told they do not own the allocated objects.
4807
4809{
4812 for (Int_t i = 0; i < nb; ++i) {
4813 TBranch* br = (TBranch*) fBranches[i];
4815 ((TBranchElement*) br)->ResetDeleteObject();
4816 }
4817 }
4818}
4819
4820////////////////////////////////////////////////////////////////////////////////
4821/// \brief Reset offset and StremerInfo information from this branch.
4822/// \param[in] recurse When true call ResetInitInfo on all subbranches.
4823///
4824
4826{
4827 fInfo = nullptr;
4828 fInit = kFALSE;
4830 fCurrentClass = nullptr;
4831 delete fReadActionSequence;
4832 fReadActionSequence = nullptr;
4833 delete fFillActionSequence;
4834 fFillActionSequence = nullptr;
4835
4836 if (recurse) {
4837 Int_t nbranches = fBranches.GetEntriesFast();
4838 for (Int_t i = 0; i < nbranches; ++i) {
4840 sub->ResetInitInfo(kTRUE);
4841 }
4842 }
4843}
4844
4845////////////////////////////////////////////////////////////////////////////////
4846/// Point this branch at an object.
4847///
4848/// For a sub-branch, addr is a pointer to the branch object.
4849///
4850/// For a top-level branch the meaning of addr is as follows:
4851///
4852/// If addr is zero, then we allocate a branch object
4853/// internally and the branch is the owner of the allocated
4854/// object, not the caller. However the caller may obtain
4855/// a pointer to the branch object with GetObject().
4856/// The pointer is reset to zero (nullptr) when the relevant
4857/// branch object is destroyed.
4858///
4859/// Example:
4860/// ~~~ {.cpp}
4861/// branch->SetAddress(0);
4862/// Event* event = branch->GetObject();
4863/// ... Do some work.
4864/// ~~~
4865/// If addr is not zero, but the pointer addr points at is
4866/// zero, then we allocate a branch object and set the passed
4867/// pointer to point at the allocated object. The caller
4868/// owns the allocated object and is responsible for deleting
4869/// it when it is no longer needed.
4870///
4871/// Example:
4872/// ~~~ {.cpp}
4873/// Event* event = 0;
4874/// branch->SetAddress(&event);
4875/// ... Do some work.
4876/// delete event;
4877/// event = 0;
4878/// ~~~
4879/// If addr is not zero and the pointer addr points at is
4880/// also not zero, then the caller has allocated a branch
4881/// object and is asking us to use it. The caller owns it
4882/// and must delete it when it is no longer needed.
4883///
4884/// Example:
4885/// ~~~ {.cpp}
4886/// Event* event = new Event();
4887/// branch->SetAddress(&event);
4888/// ... Do some work.
4889/// delete event;
4890/// event = 0;
4891/// ~~~
4892/// These rules affect users of TTree::Branch(),
4893/// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4894/// as well because those routines call this one.
4895///
4896/// An example of a tree with branches with objects allocated
4897/// and owned by us:
4898/// ~~~ {.cpp}
4899/// TFile* f1 = new TFile("myfile_original.root");
4900/// TTree* t1 = (TTree*) f->Get("MyTree");
4901/// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4902/// TTree* t2 = t1->Clone(0);
4903/// for (Int_t i = 0; i < 10; ++i) {
4904/// t1->GetEntry(i);
4905/// t2->Fill();
4906/// }
4907/// t2->Write()
4908/// delete f2;
4909/// f2 = 0;
4910/// delete f1;
4911/// f1 = 0;
4912/// ~~~
4913/// An example of a branch with an object allocated by us,
4914/// but owned by the caller:
4915/// ~~~ {.cpp}
4916/// TFile* f = new TFile("myfile.root", "recreate");
4917/// TTree* t = new TTree("t", "A test tree.")
4918/// Event* event = 0;
4919/// TBranchElement* br = t->Branch("event.", &event);
4920/// for (Int_t i = 0; i < 10; ++i) {
4921/// ... Fill event with meaningful data in some way.
4922/// t->Fill();
4923/// }
4924/// t->Write();
4925/// delete event;
4926/// event = 0;
4927/// delete f;
4928/// f = 0;
4929/// ~~~
4930/// Notice that the only difference between this example
4931/// and the following example is that the event pointer
4932/// is zero when the branch is created.
4933///
4934/// An example of a branch with an object allocated and
4935/// owned by the caller:
4936/// ~~~ {.cpp}
4937/// TFile* f = new TFile("myfile.root", "recreate");
4938/// TTree* t = new TTree("t", "A test tree.")
4939/// Event* event = new Event();
4940/// TBranchElement* br = t->Branch("event.", &event);
4941/// for (Int_t i = 0; i < 10; ++i) {
4942/// ... Fill event with meaningful data in some way.
4943/// t->Fill();
4944/// }
4945/// t->Write();
4946/// delete event;
4947/// event = 0;
4948/// delete f;
4949/// f = 0;
4950/// ~~~
4951/// If AutoDelete is on (see TBranch::SetAutoDelete),
4952/// the top level objet will be deleted and recreate
4953/// each time an entry is read, whether or not the
4954/// TTree owns the object.
4955
4957{
4958 SetAddressImpl(addr, (addr == nullptr));
4959}
4960
4961/// See TBranchElement::SetAddress.
4962/// If implied is true, we do not over-ride existing address for
4963/// sub-branches.
4964void TBranchElement::SetAddressImpl(void* addr, bool implied)
4965{
4966 //
4967 // Don't bother if we are disabled.
4968 //
4969
4970 if (TestBit(kDoNotProcess)) {
4971 return;
4972 }
4973
4974 //
4975 // FIXME: When would this happen?
4976 //
4977
4978 if (fType < -1) {
4979 return;
4980 }
4981
4982 //
4983 // Special case when called from code generated by TTree::MakeClass.
4984 //
4985
4986 if (Long_t(addr) == -1) {
4987 // FIXME: Do we have to release an object here?
4988 // ReleaseObject();
4989 fAddress = (char*) -1;
4990 fObject = (char*) -1;
4993 return;
4994 }
4995
4996 //
4997 // Reset last read entry number, we have a new user object now.
4998 //
4999
5000 fReadEntry = -1;
5001
5002 //
5003 // Make sure our branch class is instantiated.
5004 //
5005 TClass* clOfBranch = fBranchClass.GetClass();
5006 if( fTargetClass.GetClassName()[0] ) {
5007 clOfBranch = fTargetClass;
5008 }
5009
5010 //
5011 // Try to build the streamer info.
5012 //
5013
5014 TStreamerInfo *info = GetInfoImp();
5015
5016 // FIXME: Warn about failure to get the streamer info here?
5017
5018 //
5019 // We may have allocated an object last time we were called.
5020 //
5021
5022 if (fObject && TestBit(kDeleteObject)){
5023 ReleaseObject();
5024 }
5025
5026 //
5027 // Remember the pointer to the pointer to our object.
5028 //
5029
5030 fAddress = (char*) addr;
5031 if (fAddress != (char*)(&fObject)) {
5032 fObject = 0;
5033 }
5036
5037 //
5038 // Do special stuff if we got called from a MakeClass class.
5039 // Allow sub-branches to have independently set addresses.
5040 //
5041
5042 if (TestBit(kDecomposedObj)) {
5043 if (fID > -1) {
5044 // We are *not* a top-level branch.
5045 if (!info) {
5046 // No streamer info, give up.
5047 // FIXME: We should have an error message here.
5048 fObject = fAddress;
5049 } else {
5050 // Compensate for the fact that the i/o routines
5051 // will add the streamer offset to the address.
5052 fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
5053 }
5054 return;
5055 }
5056 }
5057
5058 //
5059 // Check whether the container type is still the same
5060 // to support schema evolution; what is written on the file
5061 // may no longer match the class code which is loaded.
5062 //
5063
5064 if (fType == 3) {
5065 // split TClonesArray, counter/master branch.
5066 TClass* clm = fClonesClass;
5067 if (clm) {
5068 // In case clm derives from an abstract class.
5069 clm->BuildRealData();
5070 clm->GetStreamerInfo();
5071 }
5072 TClass* newType = GetCurrentClass();
5073 if (newType && (newType != TClonesArray::Class())) {
5074 // The data type of the container has changed.
5075 //
5076 // Let's check if it is a compatible type:
5077 Bool_t matched = kFALSE;
5078 if (newType->GetCollectionProxy()) {
5079 TClass *content = newType->GetCollectionProxy()->GetValueClass();
5080 if (clm == content) {
5081 matched = kTRUE;
5082 } else {
5083 Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
5084 }
5085 } else {
5086 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());
5087 }
5088 if (matched) {
5089 // Change from 3/31 to 4/41
5090 SetType(4);
5091 // Set the proxy.
5092 fSTLtype = newType->GetCollectionType();
5093 fCollProxy = newType->GetCollectionProxy()->Generate();
5094
5098
5104 } else {
5106 }
5107 } else {
5108 // FIXME: Must maintain fObject here as well.
5109 fAddress = 0;
5111 }
5112 }
5113 } else if (fType == 4) {
5114 // split STL container, counter/master branch.
5115 TClass* newType = GetCurrentClass();
5116 if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
5117 // Let's check if it is a compatible type:
5118 TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
5120 if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
5121 delete fCollProxy;
5122 Int_t nbranches = GetListOfBranches()->GetEntries();
5123 fCollProxy = newType->GetCollectionProxy()->Generate();
5125 for (Int_t i = 0; i < nbranches; ++i) {
5127 br->fCollProxy = 0;
5128 if (br->fReadActionSequence) {
5130 }
5131 if (br->fFillActionSequence) {
5133 }
5134 }
5139 delete fIterators;
5140 delete fPtrIterators;
5146 } else {
5148 }
5149 }
5150 else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=0) && (newProxy->GetValueClass()!=0)) {
5151 // Let see if there is a rule to convert the content of the collection into each other.
5152 if (newType->GetSchemaRules()->HasRuleWithSourceClass( oldProxy->GetCollectionClass()->GetName())) {
5153 TClass *oldValueClass = oldProxy->GetValueClass();
5154 delete fCollProxy;
5155 Int_t nbranches = GetListOfBranches()->GetEntries();
5156 fCollProxy = newType->GetCollectionProxy()->Generate();
5158 for (Int_t i = 0; i < nbranches; ++i) {
5160 br->fCollProxy = 0;
5161 if (br->fBranchClass == oldValueClass) {
5163 }
5164 if (br->fReadActionSequence) {
5166 }
5167 if (br->fFillActionSequence) {
5169 }
5170 }
5175 delete fIterators;
5176 delete fPtrIterators;
5182 } else {
5184 }
5185 } else {
5186 Error("SetAddress","For %s, we can not convert %s into %s\n",
5187 GetName(),oldProxy->GetCollectionClass()->GetName(),newType->GetName());
5188 fAddress = 0;
5189 fObject = 0;
5191 return;
5192 }
5193 }
5194 else if ((newType == TClonesArray::Class()) && (oldProxy->GetValueClass() && !oldProxy->HasPointers() && oldProxy->GetValueClass()->IsTObject()))
5195 {
5196 // The new collection and the old collection are not compatible,
5197 // we cannot use the new collection to read the data.
5198 // Actually we could check if the new collection is a
5199 // compatible ROOT collection.
5200
5201 // We cannot insure that the TClonesArray is set for the
5202 // proper class (oldProxy->GetValueClass()), so we assume that
5203 // the transformation was done properly by the class designer.
5204
5205 // Change from 4/41 to 3/31
5206 SetType(3);
5207 // Reset the proxy.
5208 fSTLtype = kNone;
5209 switch(fStreamerType) {
5213 break;
5217 break;
5220 break;
5221 }
5222 fClonesClass = oldProxy->GetValueClass();
5224 delete fCollProxy;
5225 fCollProxy = 0;
5226 TClass* clm = fClonesClass;
5227 if (clm) {
5228 clm->BuildRealData(); //just in case clm derives from an abstract class
5229 clm->GetStreamerInfo();
5230 }
5234 delete fIterators;
5235 fIterators = 0;
5236 delete fPtrIterators;
5237 fPtrIterators =0;
5238 } else {
5239 // FIXME: We must maintain fObject here as well.
5240 Error("SetAddress","For %s can not convert %s into %s\n",GetName(),GetCurrentClass()->GetName(),newType->GetName());
5241 fAddress = 0;
5243 return;
5244 }
5245 } else {
5246 if (!fIterators && !fPtrIterators) {
5252 } else {
5254 }
5255 }
5256 }
5257 }
5258
5259 //
5260 // Establish the semantics of fObject and fAddress.
5261 //
5262 // Top-level branch:
5263 // fObject is a ptr to the object,
5264 // fAddress is a ptr to a pointer to the object.
5265 //
5266 // Sub-branch:
5267 // fObject is a ptr to the object,
5268 // fAddress is the same as fObject.
5269 //
5270 //
5271 // There are special cases for TClonesArray and STL containers.
5272 // If there is no user-provided object, we allocate one. We must
5273 // also initialize any STL container proxy.
5274 //
5275
5276 if (fType == 3) {
5277 // -- We are a TClonesArray master branch.
5278 if (fAddress) {
5279 // -- We have been given a non-zero address, allocate if necessary.
5281 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5282 // Case of an embedded TClonesArray.
5283 fObject = fAddress;
5284 // Check if it has already been properly built.
5285 TClonesArray* clones = (TClonesArray*) fObject;
5286 if (!clones->GetClass()) {
5288 }
5289 } else {
5290 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5291 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5292 if ((fStreamerType != -1) &&
5295 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5296 } else if (fStreamerType == -1) {
5297 // -- We are a top-level branch.
5299 if (!*pp) {
5300 // -- Caller wants us to allocate the clones array, but they will own it.
5301 *pp = new TClonesArray(fClonesClass);
5302 }
5303 fObject = (char*) *pp;
5304 } else {
5305 // -- We are a pointer to a TClonesArray.
5306 // Note: We do this so that the default constructor,
5307 // or the i/o constructor can be lazy.
5309 if (!*pp) {
5310 // -- Caller wants us to allocate the clones array, but they will own it.
5311 *pp = new TClonesArray(fClonesClass);
5312 }
5313 fObject = (char*) *pp;
5314 }
5315 }
5316 } else {
5317 // -- We have been given a zero address, allocate for top-level only.
5319 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5320 // Case of an embedded TClonesArray.
5321 Error("SetAddress", "Embedded TClonesArray given a zero address for branch '%s'", GetName());
5322 } else {
5323 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5324 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5325 if ((fStreamerType != -1) &&
5328 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5329 } else if (fStreamerType == -1) {
5330 // -- We are a top-level branch.
5331 // Idea: Consider making a zero address not allocate.
5333 fObject = (char*) new TClonesArray(fClonesClass);
5334 fAddress = (char*) &fObject;
5335 } else {
5336 // -- We are a sub-branch which is a pointer to a TClonesArray.
5337 Error("SetAddress", "Embedded pointer to a TClonesArray given a zero address for branch '%s'", GetName());
5338 }
5339 }
5340 }
5341 } else if (fType == 4) {
5342 // -- We are an STL container master branch.
5343 //
5344 // Initialize fCollProxy.
5346 if (fAddress) {
5347 // -- We have been given a non-zero address, allocate if necessary.
5351 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5352 // Case of an embedded STL container.
5353 // Note: We test for the kObject and kAny types to support
5354 // the (unwise) choice of inheriting from an STL container.
5355 fObject = fAddress;
5356 } else {
5357 // We are either a top-level branch or subbranch which is a pointer to an STL container.
5358 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5360 Error("SetAddress",
5361 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5363 } else if (fStreamerType == -1) {
5364 // -- We are a top-level branch.
5365 void** pp = (void**) fAddress;
5366 if (!*pp) {
5367 // -- Caller wants us to allocate the STL container, but they will own it.
5368 *pp = proxy->New();
5369 if (!(*pp)) {
5370 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5371 // FIXME: Should we do this? Lots of other code wants
5372 // fAddress to be zero if no fObject, but is
5373 // that a good thing?
5374 fAddress = 0;
5376 }
5377 }
5378 fObject = (char*) *pp;
5379 } else {
5380 // -- We are a pointer to an STL container.
5381 // Note: We do this so that the default constructor,
5382 // or the i/o constructor can be lazy.
5383 void** pp = (void**) fAddress;
5384 if (!*pp) {
5385 // -- Caller wants us to allocate the STL container, but they will own it.
5386 *pp = proxy->New();
5387 if (!(*pp)) {
5388 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5389 // FIXME: Should we do this? Lots of other code wants
5390 // fAddress to be zero if no fObject, but is
5391 // that a good thing?
5392 fAddress = 0;
5394 }
5395 }
5396 fObject = (char*) *pp;
5397 }
5398 }
5399 } else {
5400 // -- We have been given a zero address, allocate for top-level only.
5404 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5405 // Case of an embedded STL container.
5406 // Note: We test for the kObject and kAny types to support
5407 // the (unwise) choice of inheriting from an STL container.
5408 Error("SetAddress", "Embedded STL container given a zero address for branch '%s'", GetName());
5409 } else {
5410 // We are either a top-level branch or sub-branch which is a pointer to an STL container.
5411 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5413 Error("SetAddress",
5414 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5416 } else if (fStreamerType == -1) {
5417 // -- We are a top-level branch, allocate.
5419 fObject = (char*) proxy->New();
5420 if (fObject) {
5421 fAddress = (char*) &fObject;
5422 } else {
5423 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5424 // FIXME: Should we do this? Lots of other code wants
5425 // fAddress to be zero if no fObject, but is
5426 // that a good thing?
5427 fAddress = 0;
5429 }
5430 } else {
5431 // -- We are a sub-branch which is a pointer to an STL container.
5432 Error("SetAddress", "Embedded pointer to an STL container given a zero address for branch '%s'", GetName());
5433 }
5434 }
5435 }
5436 } else if (fType == 41) {
5437 // -- We are an STL container sub-branch.
5438 // Initialize fCollProxy.
5440 // We are not at top-level branch.
5441 fObject = fAddress;
5442 } else if (fID < 0) {
5443 // -- We are a top-level branch.
5444 char** pp = (char**) fAddress;
5445 if (pp && *pp) {
5446 // -- Caller provided an i/o buffer for us to use.
5447 fObject = *pp;
5448 } else {
5449 // -- Caller did not provide an i/o buffer for us to use, we must make one for ourselves.
5450 if (clOfBranch) {
5451 if (!pp) {
5452 // -- Caller wants us to own the object.
5454 }
5455 fObject = (char*) clOfBranch->New();
5456 if (pp) {
5457 *pp = fObject;
5458 } else {
5459 fAddress = (char*) &fObject;
5460 }
5461 } else {
5462 Error("SetAddress", "I have no TClass for branch %s, so I cannot allocate an I/O buffer!", GetName());
5463 if (pp) {
5464 fObject = 0;
5465 *pp = 0;
5466 }
5467 }
5468 }
5469 } else {
5470 // -- We are *not* a top-level branch.
5471 fObject = fAddress;
5472 }
5473
5474 if (!info) {
5475 // FIXME: We need and error message here, no streamer info, so cannot set offsets.
5476 return;
5477 }
5478
5479 // We do this only once because it depends only on
5480 // the type of our object, not on its address.
5481 if (!fInitOffsets) {
5483 }
5484
5485 // We are split, recurse down to our sub-branches.
5486 //
5487 // FIXME: This is a tail recursion, we burn stack.
5488 Int_t nbranches = fBranches.GetEntriesFast();
5489 for (Int_t i = 0; i < nbranches; ++i) {
5490 TBranch *abranch = (TBranch*) fBranches.UncheckedAt(i);
5491 // FIXME: This is a tail recursion!
5492 if (fBranchOffset[i] != TStreamerInfo::kMissing && !(implied && abranch->TestBit(kAddressSet))) {
5493 abranch->SetAddressImpl(fObject + fBranchOffset[i], implied);
5494 abranch->SetBit(kAddressSet);
5495 if (TestBit(kDecomposedObj) != abranch->TestBit(kDecomposedObj))
5497 } else {
5498 // When the member is missing, just leave the address alone
5499 // (since setting explicitly to 0 would trigger error/warning
5500 // messages).
5501 // abranch->SetAddress(0);
5502 abranch->SetBit(kAddressSet);
5503 }
5504 }
5505}
5506
5507////////////////////////////////////////////////////////////////////////////////
5508/// Reset the basket size for all sub-branches of this branch element.
5509
5511{
5512 TBranch::SetBasketSize(buffsize);
5513 Int_t nbranches = fBranches.GetEntriesFast();
5514 for (Int_t i = 0; i < nbranches; ++i) {
5515 TBranch* branch = (TBranch*) fBranches[i];
5516 branch->SetBasketSize(fBasketSize);
5517 }
5518}
5519
5520////////////////////////////////////////////////////////////////////////////////
5521/// Set the branch counter for this branch.
5522
5524{
5525 fBranchCount = brOfCounter;
5526 if (fBranchCount==0) return;
5527
5528 TLeafElement* leafOfCounter = (TLeafElement*) brOfCounter->GetListOfLeaves()->At(0);
5530 if (leafOfCounter && leaf) {
5531 leaf->SetLeafCount(leafOfCounter);
5532 } else {
5533 if (!leafOfCounter) {
5534 Warning("SetBranchCount", "Counter branch %s for branch %s has no leaves!", brOfCounter->GetName(), GetName());
5535 }
5536 if (!leaf) {
5537 Warning("SetBranchCount", "Branch %s has no leaves!", GetName());
5538 }
5539 }
5540}
5541
5542////////////////////////////////////////////////////////////////////////////////
5543/// Set the branch in a mode where the object are decomposed
5544/// (Also known as MakeClass mode).
5545/// Return whether the setting was possible (it is not possible for
5546/// TBranch and TBranchObject).
5547
5549{
5550 if (decomposeObj)
5551 SetBit(kDecomposedObj); // Same as SetBit(kMakeClass)
5552 else
5554
5555 Int_t nbranches = fBranches.GetEntriesFast();
5556 for (Int_t i = 0; i < nbranches; ++i) {
5557 TBranchElement* branch = (TBranchElement*) fBranches[i];
5558 branch->SetMakeClass(decomposeObj);
5559 }
5562
5563 return kTRUE;
5564}
5565
5566////////////////////////////////////////////////////////////////////////////////
5567/// Set object this branch is pointing to.
5568
5570{
5571 if (TestBit(kDoNotProcess)) {
5572 return;
5573 }
5574 fObject = (char*)obj;
5575 SetAddress( &fObject );
5576}
5577
5578////////////////////////////////////////////////////////////////////////////////
5579/// Set offset of the object (to which the data member represented by this
5580/// branch belongs) inside its containing object (if any).
5581
5583{
5584 // We need to make sure that the Read and Write action's configuration
5585 // properly reflect this value.
5586
5587 if (offset == TVirtualStreamerInfo::kMissing) {
5588 SetMissing();
5589 return;
5590 }
5591
5592 if (fReadActionSequence) {
5594 }
5595 if (fFillActionSequence) {
5597 }
5598 fOffset = offset;
5599}
5600
5601////////////////////////////////////////////////////////////////////////////////
5602/// Set offset of the object (to which the data member represented by this
5603/// branch belongs) inside its containing object (if any) to mark it as missing.
5604
5606{
5607 // We need to make sure that the Read and Write action's configuration
5608 // properly reflect this value.
5609
5610 if (fReadActionSequence) {
5612 }
5613 if (fFillActionSequence) {
5615 }
5617}
5618
5619
5620////////////////////////////////////////////////////////////////////////////////
5621/// Set the sequence of actions needed to read the data out of the buffer.
5623{
5624 // A 'split' node does not store data itself (it has not associated baskets)
5625 const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
5626
5627 if (!isSplitNode) {
5628 fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
5629 }
5630
5631 if (actionSequence) delete actionSequence;
5632 auto original = create(localInfo, GetCollectionProxy(), originalClass);
5633
5634 actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
5635
5636 if (!isSplitNode)
5637 fNewIDs.erase(fNewIDs.begin());
5638
5639 else if (fInitOffsets && fType != 3 && fType != 4) {
5640 // fObject has the address of the sub-object but the streamer action have
5641 // offset relative to the parent.
5642
5643 // Note: We skipped this for the top node of split collection because the
5644 // sequence is about the content, we need to review what happens where an
5645 // action related to the collection itself will land.
5646 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
5647
5648 auto index = parent->fBranches.IndexOf(this);
5649 if (index >= 0) {
5650 actionSequence->AddToOffset( - parent->fBranchOffset[index] );
5651 }
5652 } // else it will be done by InitOffsets
5653}
5654
5655////////////////////////////////////////////////////////////////////////////////
5656/// Set the sequence of actions needed to read the data out of the buffer.
5658{
5659 if (fInfo == 0) {
5660 // We are called too soon. We will be called again by InitInfo
5661 return;
5662 }
5663
5665 TClass *originalClass = nullptr;
5666 TStreamerInfo *localInfo = fInfo;
5667 if (fType == 41) {
5670 } else {
5672 if (GetParentClass() == info->GetClass()) {
5674 originalClass = fBranchClass;
5676 } else {
5678 }
5679 } else if (GetCollectionProxy()) {
5680 // Base class and embedded objects.
5682 }
5683 }
5684 } else if (fType == 31) {
5686 } else if (0<=fType && fType<=2) {
5687 // Note: this still requires the ObjectWise sequence to not be optimized!
5689 } else if ( fType == 4 && !fNewIDs.empty()) {
5692 } else if ( fType == 3 && !fNewIDs.empty()) {
5695 }
5696
5697 if (create) {
5698 SetActionSequence(originalClass, localInfo, create, fReadActionSequence);
5699 }
5700}
5701
5702////////////////////////////////////////////////////////////////////////////////
5703/// Set the ReadLeaves pointer to execute the expected operations.
5704
5706{
5707 if (TestBit(kDecomposedObj)) {
5709 } else if (fType == 4) {
5711 } else if (fType == 41) {
5715 } else {
5717 }
5718 } else {
5720 }
5721 } else if (fType == 3) {
5723 } else if (fType == 31) {
5725 } else if (fType < 0) {
5727 } else if (fType == 0 && fID == -1) {
5728 // top-level branch.
5730 if (hasCustomStreamer) {
5731 // We are in the case where the object did *not* have a custom
5732 // Streamer when the TTree was written but now *does* have a custom
5733 // Streamer thus we must use it.
5735 } else {
5737 }
5738 } else if (fType <= 2) {
5739 // split-class branch, base class branch or data member branch.
5740 if (fBranchCount) {
5744 } else {
5746 }
5747 } else {
5748 Fatal("SetReadLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5749 }
5750
5752}
5753
5754////////////////////////////////////////////////////////////////////////////////
5755/// Set the sequence of actions needed to write the data out from the buffer.
5756
5758{
5759 if (fInfo == 0) {
5760 // We are called too soon. We will be called again by InitInfo
5761 return;
5762 }
5763
5765 TClass *originalClass = nullptr;
5766 TStreamerInfo *localInfo = fInfo;
5767 if (fType == 41) {
5770 } else {
5772 if (GetParentClass() == info->GetClass()) {
5773 // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
5774 // originalClass = fBranchClass;
5775 // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter;
5776 // } else {
5778 // }
5779 } else if (GetCollectionProxy()) {
5780 // Base class and embedded objects.
5782 }
5783 }
5784 } else if (fType == 31) {
5786 } else if (0<=fType && fType<=2) {
5787 // Note: this still requires the ObjectWise sequence to not be optimized!
5789 } else if ( fType == 4 && !fNewIDs.empty()) {
5792 } else if ( fType == 3 && !fNewIDs.empty()) {
5795 }
5796
5797 if (create) {
5798 SetActionSequence(originalClass, localInfo, create, fFillActionSequence);
5799 }
5800}
5801
5802////////////////////////////////////////////////////////////////////////////////
5803/// Set the FillLeaves pointer to execute the expected operations.
5804
5806{
5807 if (TestBit(kDecomposedObj) && ((fType==3)||(fType==31))) {
5809 } else if (fType == 4) {
5811 } else if (fType == 41) {
5815 } else {
5817 }
5820 } else {
5822 }
5823 } else if (fType == 3) {
5825 } else if (fType == 31) {
5827 } else if (fType < 0) {
5829 } else if (fType <=2) {
5830 //split-class branch, base class branch, data member branch, or top-level branch.
5831 if (fBranchCount) {
5835 } else {
5837 }
5838 } else {
5839 Fatal("SetFillLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5840 }
5841
5843}
5844
5845////////////////////////////////////////////////////////////////////////////////
5846/// Set the name of the class of the in-memory object into which the data will
5847/// loaded.
5848
5850{
5851 if (name == 0) return;
5852
5853 if (strcmp(fTargetClass.GetClassName(),name) != 0 )
5854 {
5855 // We are changing target class, let's reset the meta information and
5856 // the sub-branches.
5857
5858 ResetInitInfo(/*recurse=*/ kFALSE);
5859
5860 Int_t nbranches = fBranches.GetEntriesFast();
5861 for (Int_t i = 0; i < nbranches; ++i) {
5863
5864 if (sub->fTargetClass == fTargetClass ) {
5865 sub->SetTargetClass(name);
5866 } else {
5867 // Since the top level changes, the StreamerInfo (in particular for split collection)
5868 // may still need to change (and the info might be updated else (see for example SetAddress for the
5869 // the case fType 4/41)
5870 sub->ResetInitInfo(kTRUE);
5871 }
5872 if (sub->fParentClass == fTargetClass ) {
5874 }
5875 }
5877 }
5878
5879}
5880
5881////////////////////////////////////////////////////////////////////////////////
5882/// If the branch address is not set, we set all addresses starting with
5883/// the top level parent branch. This is required to be done in order for
5884/// GetOffset to be correct and for GetEntry to run.
5885
5887{
5888 // Check to see if the user changed the branch address on us.
5890
5892 // -- Do nothing if already setup or if we are a MakeClass branch.
5893 return;
5894 }
5896}
5897
5898////////////////////////////////////////////////////////////////////////////////
5899/// If the branch address is not set, we set all addresses starting with
5900/// the top level parent branch. This is required to be done in order for
5901/// GetOffset to be correct and for GetEntry to run.
5902
5904{
5906 // -- Do nothing if we have been told not to.
5907 // Or the data member in this branch is not longer part of the
5908 // parent's layout.
5909 return;
5910 }
5911
5912 //--------------------------------------------------------------------------
5913 // Check if we are splited STL collection of pointers
5914 /////////////////////////////////////////////////////////////////////////////
5915
5917 {
5918 TBranchElement *parent = (TBranchElement *)GetMother()->GetSubBranch( this );
5919
5920 // Make sure the StreamerInfo is loaded and initialized.
5921 GetInfoImp();
5922
5923 if( !parent->GetAddress() )
5924 parent->SetAddress( 0 );
5925 return;
5926 }
5927
5928 //--------------------------------------------------------------------------
5929 // Any other case
5930 /////////////////////////////////////////////////////////////////////////////
5931
5933 if (!mother) {
5934 return;
5935 }
5936 TClass* cl = TClass::GetClass(mother->GetClassName());
5937
5938 // Make sure the StreamerInfo is loaded and initialized.
5939 GetInfoImp();
5940
5941 if (!cl) {
5942 return;
5943 }
5944
5945 if (!mother->GetAddress()) {
5946 // -- Our top-level branch has no address.
5947 Bool_t motherStatus = mother->TestBit(kDoNotProcess);
5948 mother->ResetBit(kDoNotProcess);
5949 // Note: This will allocate an object.
5950 mother->SetAddress(0);
5951 mother->SetBit(kDoNotProcess, motherStatus);
5952 }
5953}
5954
5955////////////////////////////////////////////////////////////////////////////////
5956/// Stream an object of class TBranchElement.
5957
5958void TBranchElement::Streamer(TBuffer& R__b)
5959{
5960 if (R__b.IsReading()) {
5966 // The fAddress and fObject data members are not persistent,
5967 // therefore we do not own anything.
5968 // Also clear the bit possibly set by the schema evolution.
5970 // Fixup a case where the TLeafElement was missing
5971 if ((fType == 0) && (fLeaves.GetEntriesFast() == 0)) {
5972 TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
5973 leaf->SetTitle(GetTitle());
5974 fNleaves = 1;
5975 fLeaves.Add(leaf);
5976 fTree->GetListOfLeaves()->Add(leaf);
5977 }
5978
5979 // SetReadLeavesPtr();
5980 }
5981 else {
5982 TDirectory* dirsav = fDirectory;
5983 fDirectory = 0; // to avoid recursive calls
5984 {
5985 // Save class version.
5986 Int_t classVersion = fClassVersion;
5987 // Record only positive 'version number'
5988 if (fClassVersion < 0) {
5990 }
5991 // TODO: Should we clear the kDeleteObject bit before writing?
5992 // If we did we would have to remember the old value and
5993 // put it back, we wouldn't want to forget that we owned
5994 // something just because we got written to disk.
5996 // Restore class version.
5997 fClassVersion = classVersion;
5998 }
5999 //
6000 // Mark all streamer infos used by this branch element
6001 // to be written to our output file.
6002 //
6003 {
6005 }
6006 //
6007 // If we are a clones array master branch, or an
6008 // STL container master branch, we must also mark
6009 // the streamer infos used by the value class to
6010 // be written to our output file.
6011 //
6012 if (fType == 3) {
6013 // -- TClonesArray, counter/master branch
6014 //
6015 // We must mark the streamer info for the
6016 // value class to be written to the file.
6017 //
6018 TClass* cl = fClonesClass;
6019 if (cl) {
6021 }
6022 }
6023 else if (fType == 4) {
6024 // -- STL container, counter/master branch
6025 //
6026 // We must mark the streamer info for the
6027 // value class to be written to the file.
6028 //
6030 if (cp) {
6031 TClass* cl = cp->GetValueClass();
6032 if (cl) {
6034 }
6035 }
6036 }
6037 // If we are in a separate file, then save
6038 // ourselves as an independent key.
6039 if (!dirsav) {
6040 // Note: No need to restore fDirectory, it was already zero.
6041 return;
6042 }
6043 if (!dirsav->IsWritable()) {
6044 fDirectory = dirsav;
6045 return;
6046 }
6047 TDirectory* pdirectory = fTree->GetDirectory();
6048 if (!pdirectory) {
6049 fDirectory = dirsav;
6050 return;
6051 }
6052 const char* treeFileName = pdirectory->GetFile()->GetName();
6053 TBranch* mother = GetMother();
6054 const char* motherFileName = treeFileName;
6055 if (mother && (mother != this)) {
6056 motherFileName = mother->GetFileName();
6057 }
6058 if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
6059 dirsav->WriteTObject(this);
6060 }
6061 fDirectory = dirsav;
6062 }
6063}
6064
6065
6066////////////////////////////////////////////////////////////////////////////////
6067/// Split class cl into sub-branches of this branch.
6068///
6069/// This version of Unroll was formerly embedded in TTree::BronchExec
6070/// It is moved here so we can make sure to call SetReadActionSequence.
6071
6072void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Int_t bufsize, Int_t splitlevel)
6073{
6074 //
6075 // Do we have a final dot in our name?
6076 //
6077
6078 // Note: The branch constructor which takes a folder as input
6079 // creates top-level branch names with dots in them to
6080 // indicate the folder hierarchy.
6081 char* dot = (char*) strchr(name, '.');
6082 Int_t nch = strlen(name);
6083 Bool_t dotlast = kFALSE;
6084 if (nch && (name[nch-1] == '.')) {
6085 dotlast = kTRUE;
6086 }
6087
6088 // Loop on all public data members of the class and its base classes and create branches for each one.
6089 TObjArray* blist = this->GetListOfBranches();
6090 TIter next(sinfo->GetElements());
6091 TStreamerElement* element = 0;
6092 TString bname;
6093 for (Int_t id = 0; (element = (TStreamerElement*) next()); ++id) {
6094 if (element->IsA() == TStreamerArtificial::Class()) {
6095 continue;
6096 }
6097 if (element->TestBit(TStreamerElement::kRepeat)) {
6098 continue;
6099 }
6101 continue;
6102 }
6103 char* pointer = (char*) (objptr + element->GetOffset());
6104 // FIXME: This is not good enough, an STL container can be
6105 // a base, and the test will fail.
6106 // See TBranchElement::InitializeOffsets() for the
6107 // correct test.
6108 Bool_t isBase = (element->IsA() == TStreamerBase::Class());
6109 if (isBase) {
6110 TClass* clbase = element->GetClassPointer();
6111 if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) {
6112 // Note: TStreamerInfo::Compile() leaves this element
6113 // out of the optimized info, although it does
6114 // exists in the non-compiled and non-optimized info.
6115 // FIXME: The test that TStreamerInfo::Compile() uses
6116 // is element->GetType() < 0, so that is what
6117 // we should do as well.
6118 continue;
6119 }
6120 if (clbase->GetListOfRealData()->GetSize() == 0) {
6121 // Do not create a branch for empty bases.
6122 continue;
6123 }
6124 }
6125 if (dot) {
6126 if (dotlast) {
6127 bname.Form("%s%s", name, element->GetFullName());
6128 } else {
6129 // FIXME: We are in the case where we have a top-level
6130 // branch name that was created by the branch
6131 // constructor which takes a folder as input.
6132 // The internal dots in the name are in place of
6133 // of the original slashes and represent the
6134 // folder hierarchy.
6135 if (isBase) {
6136 // FIXME: This is very strange, this is the only case where
6137 // we create a branch for a base class that does
6138 // not have the base class name in the branch name.
6139 // FIXME: This is also quite bad since classes with two
6140 // or more base classes end up with sub-branches
6141 // that have the same name.
6142 bname = name;
6143 } else {
6144 bname.Form("%s.%s", name, element->GetFullName());
6145 }
6146 }
6147 } else {
6148 // Note: For a base class element, this results in the branchname
6149 // being the name of the base class.
6150 bname.Form("%s", element->GetFullName());
6151 }
6152
6153 if( splitlevel > TTree::kSplitCollectionOfPointers && element->GetClass() &&
6154 element->GetClass()->GetCollectionProxy() &&
6155 element->GetClass()->GetCollectionProxy()->HasPointers() )
6156 {
6157 TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id );
6158 blist->Add(brSTL);
6159 }
6160 else
6161 {
6162 TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1);
6163 bre->SetParentClass(cl);
6164 blist->Add(bre);
6165 }
6166 }
6167 // Now that we know that this branch is split, let's redo the actions.
6170}
6171
6172////////////////////////////////////////////////////////////////////////////////
6173/// Split class cl into sub-branches of this branch.
6174///
6175/// Create a sub-branch of this branch for each non-empty,
6176/// non-abstract base class of cl (unless we are a sub-branch
6177/// of a TClonesArray or an STL container, in which case we
6178/// do *not* create a sub-branch), and for each non-split data
6179/// member of cl.
6180///
6181/// Note: We do *not* create sub-branches for base classes of cl
6182/// if we are a sub-branch of a TClonesArray or an STL container.
6183///
6184/// Note: We do *not* create sub-branches for data members which
6185/// have a class type and which we are splitting.
6186///
6187/// Note: The above rules imply that the branch heirarchy increases
6188/// in depth only for base classes of cl (unless we are inside
6189/// of a TClonesArray or STL container, in which case the depth
6190/// does *not* increase, the base class is elided) and for
6191/// TClonesArray or STL container data members (which have one
6192/// additional level of sub-branches). The only other way the
6193/// depth increases is when the top-level branch has a split
6194/// class data member, in that case the constructor will create
6195/// a sub-branch for it. In other words, the interior nodes of
6196/// the branch tree are all either: base class nodes; split
6197/// class nodes which are direct sub-branches of top-level nodes
6198/// (created by TClass::Bronch usually); or TClonesArray or STL
6199/// container master nodes.
6200///
6201/// Note: The exception to the above is for the top-level branches,
6202/// Tree::Bronch creates nodes for everything in that case,
6203/// except for a TObject base class of a class which has the
6204/// can ignore tobject streamer flag set.
6205
6206Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype)
6207{
6208 //----------------------------------------------------------------------------
6209 // Handling the case of STL collections of pointers
6210 /////////////////////////////////////////////////////////////////////////////
6211
6212 Int_t splitSTLP = splitlevel - (splitlevel%TTree::kSplitCollectionOfPointers);
6214
6215 TString branchname;
6216
6217 if ((cl == TObject::Class()) && clParent->CanIgnoreTObjectStreamer()) {
6218 return 0;
6219 }
6220
6222
6223 //
6224 // Do nothing if we couldn't build the streamer info for cl.
6225 //
6226
6227 if (!sinfo) {
6228 return 0;
6229 }
6230
6231 Int_t ndata = sinfo->GetNelement();
6232
6233 if ((ndata == 1) && cl->GetCollectionProxy() && !strcmp(sinfo->GetElement(0)->GetName(), "This")) {
6234 // -- Class cl is an STL collection, refuse to split it.
6235 // Question: Why? We certainly could by switching to the value class.
6236 // Partial Answer: Only the branch element constructor can split STL containers.
6237 return 1;
6238 }
6239
6240 for (Int_t elemID = 0; elemID < ndata; ++elemID) {
6241 // -- Loop over all the streamer elements and create sub-branches as needed.
6242 TStreamerElement* elem = sinfo->GetElement(elemID);
6243 if (elem->IsA() == TStreamerArtificial::Class()) {
6244 continue;
6245 }
6247 continue;
6248 }
6250 continue;
6251 }
6252 Int_t offset = elem->GetOffset();
6253 // FIXME: An STL container as a base class gets TStreamerSTL as its class, so this test is not enough.
6254 // See InitializeOffsets() for the proper test.
6255 if (elem->IsA() == TStreamerBase::Class()) {
6256 // -- This is a base class of cl.
6257 TClass* clOfBase = elem->GetClassPointer();
6258 if (!clOfBase || ((clOfBase->Property() & kIsAbstract) && cl->InheritsFrom(TCollection::Class()))) {
6259 // -- Do nothing if we are one of the abstract collection (we know they have no data).
6260 return -1;
6261 }
6262 if ((btype == 31) || (btype == 41)) {
6263 // -- Elide the base-class sub-branches of a split TClonesArray or STL container.
6264 //
6265 // Note: We are eliding the base class here, that is, we never
6266 // create a branch for it, so the branch heirarchy is not
6267 // complete.
6268 // Note: The clParent parameter is the value class of the
6269 // container which we are splitting. It does not
6270 // appear in the branch heirarchy either.
6271 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6272 Int_t unroll = -1;
6273 if (!elem->CannotSplit() || clOfBase == TObject::Class()) {
6274 unroll = Unroll(name, clParent, clOfBase, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6275 }
6276 if (unroll < 0) {
6277 // FIXME: We could not split because we are abstract, should we be doing this?
6278 if (strlen(name)) {
6279 branchname.Form("%s.%s", name, elem->GetFullName());
6280 } else {
6281 branchname.Form("%s", elem->GetFullName());
6282 }
6283 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, 0, basketsize, 0, btype);
6284 branch->SetParentClass(clParent);
6285 fBranches.Add(branch);
6286 }
6287 } else if (clOfBase->GetListOfRealData()->GetSize()) {
6288 // -- Create a branch for a non-empty base class.
6289 if (strlen(name)) {
6290 branchname.Form("%s.%s", name, elem->GetFullName());
6291 // Elide the base class name when creating the sub-branches.
6292 // Note: The branch names for sub-branches of a base class branch
6293 // do not represent the full class heirarchy because we do
6294 // this, however it does keep the branch names for the
6295 // inherited data members simple.
6296 TBranchElement* branch = new TBranchElement(this, name, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6297 // Then reset it to the proper name.
6298 branch->SetName(branchname);
6299 branch->SetTitle(branchname);
6300 branch->SetParentClass(clParent);
6301 fBranches.Add(branch);
6302 } else {
6303 branchname.Form("%s", elem->GetFullName());
6304 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6305 branch->SetParentClass(clParent);
6306 fBranches.Add(branch);
6307 }
6308 }
6309 } else {
6310 // -- This is a data member of cl.
6311 if (strlen(name)) {
6312 branchname.Form("%s.%s", name, elem->GetFullName());
6313 } else {
6314 branchname.Form("%s", elem->GetFullName());
6315 }
6316 if ((splitlevel > 1) && ((elem->IsA() == TStreamerObject::Class()) || (elem->IsA() == TStreamerObjectAny::Class()))) {
6317 // -- We are splitting a non-TClonesArray (may inherit from TClonesArray though), non-STL container object.
6318 //
6319 // Ignore an abstract class.
6320 // FIXME: How could an abstract class get here?
6321 // Partial answer: It is a base class. But this is a data member!
6322 TClass* elemClass = elem->GetClassPointer();
6323 if (!elemClass || elemClass->Property() & kIsAbstract) {
6324 return -1;
6325 }
6326 if (elem->CannotSplit()) {
6327 // We are not splitting.
6328 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6329 branch->SetParentClass(clParent);
6330 fBranches.Add(branch);
6331 } else if (elemClass->InheritsFrom(TClonesArray::Class())) {
6332 // Splitting something derived from TClonesArray.
6333 Int_t subSplitlevel = splitlevel-1;
6334 if (btype == 31 || btype == 41 || elem->CannotSplit()) {
6335 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6336 subSplitlevel = 0;
6337 }
6338 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel, btype);
6339 branch->SetParentClass(clParent);
6340 fBranches.Add(branch);
6341 } else {
6342 // Splitting a normal class.
6343 // FIXME: We are eliding the class we are splitting here,
6344 // i.e., we do not create a branch for it, so the
6345 // branch heirarchy does not match the class heirarchy.
6346 // Note: clParent is the class which contains a data member of
6347 // the class type which we are splitting.
6348 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6349 Int_t unroll = Unroll(branchname, clParent, elemClass, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6350 if (unroll < 0) {
6351 // FIXME: We could not split because we are abstract, should we be doing this?
6352 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6353 branch->SetParentClass(clParent);
6354 fBranches.Add(branch);
6355 }
6356 }
6357 }
6358 else if( elem->GetClassPointer() &&
6361 splitSTLP && fType != 4 )
6362 {
6363
6364 TBranchSTL* branch = new TBranchSTL( this, branchname,
6366 basketsize, splitlevel - 1+splitSTLP, sinfo, elemID );
6367 branch->SetAddress( ptr+offset );
6368 fBranches.Add( branch );
6369 }
6370 else if ((elem->IsA() == TStreamerSTL::Class()) && !elem->IsaPointer()) {
6371 // -- We have an STL container.
6372 // Question: What if splitlevel == 0 here?
6373 // Answer: then we should not be here.
6374 Int_t subSplitlevel = splitlevel - 1;
6375 if ((btype == 31) || (btype == 41) || elem->CannotSplit()) {
6376 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6377 subSplitlevel = 0;
6378 }
6379 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel+splitSTLP, btype);
6380 branch->SetParentClass(clParent);
6381 fBranches.Add(branch);
6382 } else if (((btype != 31) && (btype != 41)) && ptr && ((elem->GetClassPointer() == TClonesArray::Class()) || ((elem->IsA() == TStreamerSTL::Class()) && !elem->CannotSplit()))) {
6383 // -- We have a TClonesArray.
6384 // FIXME: We could get a ptr to a TClonesArray here by mistake.
6385 // Question: What if splitlevel == 0 here?
6386 // Answer: then we should not be here.
6387 // Note: ptr may be null in case of a TClonesArray inside another
6388 // TClonesArray or STL container, see the else clause.
6389 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6390 branch->SetParentClass(clParent);
6391 fBranches.Add(branch);
6392 } else {
6393 // -- We are not going to split this element any farther.
6394 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, 0, basketsize, splitSTLP, btype);
6395 branch->SetType(btype);
6396 branch->SetParentClass(clParent);
6397 fBranches.Add(branch);
6398 }
6399 }
6400 }
6401
6402 if (!fBranches.IsEmpty()) {
6403 // Refresh this branch's action now that we know whether it is split or not.
6406 }
6407 return 1;
6408}
6409
6410////////////////////////////////////////////////////////////////////////////////
6411/// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
6412/// with the current value of fTree->GetCurrentFile unless this branch has been
6413/// redirected to a different file. Also update the sub-branches.
6414
6416{
6417 // The BranchCount and BranchCount2 are part of higher level branches' list of
6418 // branches.
6419 // if (fBranchCount) fBranchCount->UpdateFile();
6420 // if (fBranchCount2) fBranchCount2->UpdateFile();
6422}
void Class()
Definition: Class.C:29
std::string fBuffer
const Handle_t kNone
Definition: GuiTypes.h:87
#define R__unlikely(expr)
Definition: RConfig.hxx:604
#define b(i)
Definition: RSha256.hxx:100
#define e(i)
Definition: RSha256.hxx:103
unsigned short UShort_t
Definition: RtypesCore.h:38
const Ssiz_t kNPOS
Definition: RtypesCore.h:113
int Int_t
Definition: RtypesCore.h:43
float Size_t
Definition: RtypesCore.h:85
unsigned char UChar_t
Definition: RtypesCore.h:36
int Ssiz_t
Definition: RtypesCore.h:65
char Char_t
Definition: RtypesCore.h:31
unsigned int UInt_t
Definition: RtypesCore.h:44
const Bool_t kFALSE
Definition: RtypesCore.h:90
unsigned long ULong_t
Definition: RtypesCore.h:53
long Long_t
Definition: RtypesCore.h:52
bool Bool_t
Definition: RtypesCore.h:61
short Short_t
Definition: RtypesCore.h:37
double Double_t
Definition: RtypesCore.h:57
long double LongDouble_t
Definition: RtypesCore.h:59
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
long long Long64_t
Definition: RtypesCore.h:71
unsigned long long ULong64_t
Definition: RtypesCore.h:72
float Float_t
Definition: RtypesCore.h:55
const Bool_t kTRUE
Definition: RtypesCore.h:89
const char Option_t
Definition: RtypesCore.h:64
#define ClassImp(name)
Definition: Rtypes.h:361
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:41
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:59
#define gROOT
Definition: TROOT.h:406
void Printf(const char *fmt,...)
#define R__LOCKGUARD_IMT(mutex)
#define R__LOCKGUARD(mutex)
#define gPad
Definition: TVirtualPad.h:287
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:69
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:23
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:2515
virtual void SetAutoDelete(Bool_t autodel=kTRUE)
Set the automatic delete bit.
Definition: TBranch.cxx:2580
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:1300
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:1591
const char * GetFileName() const
Definition: TBranch.h:232
TIOFeatures GetIOFeatures() const
Returns the IO settings currently in use for this branch.
Definition: TBranch.cxx:2119
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:2028
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:2135
Bool_t IsAutoDelete() const
Return kTRUE if an existing object in a TBranchObject must be deleted.
Definition: TBranch.cxx:2127
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:1069
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:3168
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:2205
TObjArray fBranches
-> List of Branches of this branch
Definition: TBranch.h:136
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset a Branch.
Definition: TBranch.cxx:2462
virtual TBranch * FindBranch(const char *name)
Find the immediate sub-branch with passed name.
Definition: TBranch.cxx:1023
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:2791
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:2593
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:2421
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:1991
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:844
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
@ 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:28
void SetName(const char *new_name)
Definition: TClassRef.h:65
TClass * GetClass() const
Definition: TClassRef.h:70
const char * GetClassName()
Definition: TClassRef.h:69
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
UInt_t GetCheckSum(ECheckSum code=kCurrentCheckSum) const
Call GetCheckSum with validity check.
Definition: TClass.cxx:6429
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3407
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition: TClass.cxx:2300
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition: TClass.cxx:2866
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:4672
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4941
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Copy the argument.
Definition: TClass.cxx:2450
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:2011
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5363
TClassStreamer * GetStreamer() const
Return the Streamer Class allowing streaming (if any).
Definition: TClass.cxx:2894
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3738
TList * GetListOfRealData() const
Definition: TClass.h:450
Bool_t CanIgnoreTObjectStreamer()
Definition: TClass.h:391
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition: TClass.cxx:1912
const TObjArray * GetStreamerInfos() const
Definition: TClass.h:489
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition: TClass.cxx:5875
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5901
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method).
Definition: TClass.cxx:5910
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition: TClass.cxx:4562
Long_t Property() const
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition: TClass.cxx:6010
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2877
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=0) const
Definition: TClass.h:602
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:7007
TVirtualStreamerInfo * FindConversionStreamerInfo(const char *onfile_classname, UInt_t checksum) const
Return a Conversion StreamerInfo from the class 'classname' for the layout represented by 'checksum' ...
Definition: TClass.cxx:7114
Bool_t IsVersioned() const
Definition: TClass.h:517
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition: TClass.cxx:6987
Version_t GetClassVersion() const
Definition: TClass.h:417
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4837
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3471
@ kHasCustomStreamerMember
Definition: TClass.h:105
@ kIsEmulation
Definition: TClass.h:101
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:2948
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:40
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:163
virtual Bool_t IsWritable() const
Definition: TDirectory.h:179
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:53
Int_t GetCompressionSettings() const
Definition: TFile.h:398
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:577
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:605
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:523
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:415
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:228
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:877
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition: TObject.h:149
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:891
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:919
void ResetBit(UInt_t f)
Definition: TObject.h:186
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:865
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:46
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:78
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition: TTree.cxx:5209
Int_t GetDefaultEntryOffsetLen() const
Definition: TTree.h:453
virtual TObjArray * GetListOfLeaves()
Definition: TTree.h:483
TDirectory * GetDirectory() const
Definition: TTree.h:456
Int_t Debug() const
Definition: TTree.h:424
virtual TBranchRef * GetBranchRef() const
Definition: TTree.h:444
virtual Long64_t GetReadEntry() const
Definition: TTree.h:503
@ kSplitCollectionOfPointers
Definition: TTree.h:261
Long64_t GetDebugMin() const
Definition: TTree.h:455
virtual void Draw(Option_t *opt)
Default Draw method for all objects.
Definition: TTree.h:426
TStreamerInfo * BuildStreamerInfo(TClass *cl, void *pointer=0, Bool_t canOptimize=kTRUE)
Build StreamerInfo for class cl.
Definition: TTree.cxx:2633
Wrapper around an object and giving indirect access to its content even if the object is not of a cla...
Definition: TVirtualArray.h:27
char * GetObjectAt(UInt_t ind) const
Definition: TVirtualArray.h:41
void SetSize(UInt_t size)
Definition: TVirtualArray.h:43
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
double T(double x)
Definition: ChebyshevPol.h:34
static const std::string pattern("pattern")
int GetClassVersion(const clang::RecordDecl *cl, const cling::Interpreter &interp)
Return the version number of the class or -1 if the function Class_Version does not exist.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
TClass * GetClass(T *)
Definition: TClass.h:658
@ 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