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