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