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