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