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