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