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 if (fID>=0 && GetInfoImp()
1057 && GetInfoImp()->IsCompiled()
1058 && ((element=GetInfoImp()->GetElement(fID)))
1059 && ((clsub=element->GetClassPointer())))
1060 cl=clsub;
1061 }
1062 if (cl) {
1063 TString strMember=branch->GetName();
1064 Size_t mempos=strMember.Last('.');
1065 if (mempos!=kNPOS)
1066 strMember.Remove(0, (Int_t)mempos+1);
1067 mempos=strMember.First('[');
1068 if (mempos!=kNPOS)
1069 strMember.Remove((Int_t)mempos);
1071 if (!m || m->IsPersistent()) persistentBranches.Add(branch);
1072 } else persistentBranches.Add(branch);
1073 } // branch if not a folder
1074 }
1075 persistentBranches.Browse(b);
1076 // add all public const methods without params
1077 if (GetBrowsables() && GetBrowsables()->GetSize())
1078 GetBrowsables()->Browse(b);
1079 } else {
1080 if (GetBrowsables() && GetBrowsables()->GetSize()) {
1081 GetBrowsables()->Browse(b);
1082 return;
1083 }
1084 // Get the name and strip any extra brackets
1085 // in order to get the full arrays.
1086 TString slash("/");
1087 TString escapedSlash("\\/");
1088 TString name = GetName();
1089 Int_t pos = name.First('[');
1090 if (pos != kNPOS) {
1091 name.Remove(pos);
1092 }
1094 if (GetMother()) {
1096 pos = mothername.First('[');
1097 if (pos != kNPOS) {
1098 mothername.Remove(pos);
1099 }
1100 Int_t len = mothername.Length();
1101 if (len) {
1102 if (mothername(len-1) != '.') {
1103 // We do not know for sure whether the mother's name is
1104 // already preprended. So we need to check:
1105 // a) it is prepended
1106 // b) it is NOT the name of a daughter (i.e. mothername.mothername exist)
1108 doublename.Append(".");
1109 Int_t isthere = (name.Index(doublename) == 0);
1110 if (!isthere) {
1111 name.Prepend(doublename);
1112 } else {
1114 doublename.Append(mothername);
1115 isthere = (name.Index(doublename) == 0);
1116 if (!isthere) {
1117 mothername.Append(".");
1118 name.Prepend(mothername);
1119 }
1120 } else {
1121 // Nothing to do because the mother's name is
1122 // already in the name.
1123 }
1124 }
1125 } else {
1126 // If the mother's name end with a dot then
1127 // the daughter probably already contains the mother's name
1128 if (name.Index(mothername) == kNPOS) {
1129 name.Prepend(mothername);
1130 }
1131 }
1132 }
1133 }
1134 name.ReplaceAll(slash, escapedSlash);
1135 GetTree()->Draw(name, "", b ? b->GetDrawOption() : "");
1136 if (gPad) {
1137 gPad->Update();
1138 }
1139 }
1140}
1141
1142////////////////////////////////////////////////////////////////////////////////
1143/// Set branch and leaf name and title in the case of a container sub-branch.
1144
1146{
1148
1150
1152 if (indexname[indexname.Length()-1]=='.') {
1153 indexname.Remove(indexname.Length()-1);
1154 }
1155 indexname += "_";
1156
1157 for (Int_t i = 0; i < nbranches; ++i) {
1159 if (!bre)
1160 continue;
1161 if (fType == 3) {
1162 bre->SetType(31);
1163 } else if (fType == 4) {
1164 bre->SetType(41);
1165 } else {
1166 Error("BuildTitle", "This cannot happen, fType of parent is not 3 or 4!");
1167 }
1168 bre->fCollProxy = GetCollectionProxy();
1169 bre->BuildTitle(name);
1170 const char* fin = strrchr(bre->GetTitle(), '.');
1171 if (fin == nullptr) {
1172 continue;
1173 }
1174 // The branch counter for a sub-branch of a container is the container master branch.
1175 bre->SetBranchCount(this);
1176 TLeafElement* lf = (TLeafElement*) bre->GetListOfLeaves()->At(0);
1177 // If branch name is of the form fTracks.fCovar[3][4], then
1178 // set the title to fCovar[fTracks_].
1179 branchname = fin+1;
1180 Ssiz_t dim = branchname.First('[');
1181 if (dim>=0) {
1182 branchname.Remove(dim);
1183 }
1184 branchname += TString::Format("[%s]", indexname.Data());
1185 bre->SetTitle(branchname);
1186 if (lf) {
1187 lf->SetTitle(branchname);
1188 }
1189 // Is there a secondary branchcount?
1190 //
1191 // fBranchCount2 points to the secondary branchcount
1192 // in case a TClonesArray element itself has a branchcount.
1193 //
1194 // Example: In Event class with TClonesArray fTracks of Track objects.
1195 // if the Track object has two members
1196 // Int_t fNpoint;
1197 // Float_t *fPoints; //[fNpoint]
1198 // In this case the TBranchElement fTracks.fPoints has
1199 // -its primary branchcount pointing to the branch fTracks
1200 // -its secondary branchcount pointing to fTracks.fNpoint
1201 Int_t stype = bre->GetStreamerType();
1202 // FIXME: Should 60 be included here?
1203 if ((stype > 40) && (stype < 61)) {
1204 TString name2 (bre->GetName());
1205 Ssiz_t bn = name2.Last('.');
1206 if (bn<0) {
1207 continue;
1208 }
1209 TStreamerBasicPointer *el = (TStreamerBasicPointer*)bre->GetInfoImp()->GetElements()->FindObject(name2.Data()+bn+1);
1210 name2.Remove(bn+1);
1211 if (el) name2 += el->GetCountName();
1213 bre->SetBranchCount2(bc2);
1214 }
1215 bre->SetReadLeavesPtr();
1216 bre->SetFillLeavesPtr();
1217 }
1218}
1219
1220////////////////////////////////////////////////////////////////////////////////
1221/// Loop on all leaves of this branch to fill the basket buffer.
1222///
1223/// The function returns the number of bytes committed to the
1224/// individual branches. If a write error occurs, the number of
1225/// bytes returned is -1. If no data are written, because, e.g.,
1226/// the branch is disabled, the number of bytes returned is 0.
1227///
1228/// Note: We not not use any member functions from TLeafElement!
1229
1231{
1232 Int_t nbytes = 0;
1233 Int_t nwrite = 0;
1234 Int_t nerror = 0;
1236
1238
1239 //
1240 // If we are a top-level branch, update addresses.
1241 //
1242
1243 if (fID < 0) {
1244 if (!fObject) {
1245 Error("Fill", "attempt to fill branch %s while address is not set", GetName());
1246 return 0;
1247 }
1248 }
1249
1250 //
1251 // If the tree has a TRefTable, set the current branch if
1252 // branch is not a basic type.
1253 //
1254
1255 // FIXME: This test probably needs to be extended past 10.
1256 if ((fType >= -1) && (fType < 10)) {
1258 if (bref) {
1259 fBranchID = bref->SetParent(this, fBranchID);
1260 }
1261 }
1262
1263 if (!nbranches) {
1264 // No sub-branches.
1265 if (!TestBit(kDoNotProcess)) {
1267 if (nwrite < 0) {
1268 Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1269 ++nerror;
1270 } else {
1271 nbytes += nwrite;
1272 }
1273 }
1274 } else {
1275 // We have sub-branches.
1276 if (fType == 3 || fType == 4) {
1277 // TClonesArray or STL container counter
1279 if (nwrite < 0) {
1280 Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1281 ++nerror;
1282 } else {
1283 nbytes += nwrite;
1284 }
1285 } else {
1286 ++fEntries;
1287 }
1288 for (Int_t i = 0; i < nbranches; ++i) {
1290 if (!branch->TestBit(kDoNotProcess)) {
1291 nwrite = branch->FillImpl(imtHelper);
1292 if (nwrite < 0) {
1293 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d", GetName(), branch->GetName(), nwrite);
1294 nerror++;
1295 } else {
1296 nbytes += nwrite;
1297 }
1298 }
1299 }
1300 }
1301
1302 if (fTree->Debug() > 0) {
1303 // Debugging.
1305 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
1306 printf("Fill: %lld, branch=%s, nbytes=%d\n", entry, GetName(), nbytes);
1307 }
1308 }
1309
1310 if (nerror != 0) {
1311 return -1;
1312 }
1313
1314 return nbytes;
1315}
1316
1317////////////////////////////////////////////////////////////////////////////////
1318/// Write leaves into i/o buffers for this branch.
1319/// For the case where the branch is set in MakeClass mode (decomposed object).
1320
1322{
1324
1325 //
1326 // Silently do nothing if we have no user i/o buffer.
1327 //
1328
1329 if (!fObject) {
1330 return;
1331 }
1332
1333 // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1334 if(fType == 3) {
1335 // fClonesClass can not be zero since we are of type 3, see TBranchElement::Init
1337 if (!si) {
1338 Error("FillLeaves", "Cannot get streamer info for branch '%s' class '%s'", GetName(), fClonesClass->GetName());
1339 return;
1340 }
1341 b.ForceWriteInfo(si,false);
1342 Int_t* nptr = (Int_t*) fAddress;
1343 b << *nptr;
1344 } else if (fType == 31) {
1345 // -- TClonesArray sub-branch. Write out the entries in the TClonesArray.
1346 // -- A MakeClass() tree, we must use fAddress instead of fObject.
1347 if (!fAddress) {
1348 // FIXME: Enable this message.
1349 //Error("FillLeaves", "Branch address not set for branch '%s'!", GetName());
1350 return;
1351 }
1353 if (atype > 54) {
1354 // Note: We are not supporting kObjectp, kAny, kObjectp,
1355 // kObjectP, kTString, kTObject, kTNamed, kAnyp,
1356 // kAnyP, kSTLp, kSTL, kSTLstring, kStreamer,
1357 // kStreamLoop here, nor pointers to varying length
1358 // arrays of them either.
1359 // Nor do we support pointers to varying length
1360 // arrays of kBits, kLong64, kULong64, nor kBool.
1361 return;
1362 }
1364 if (!nn) {
1365 Error("FillLeaves", "The branch counter address was zero!");
1366 return;
1367 }
1368 Int_t n = *nn;
1369 if (atype > 40) {
1370 // Note: We are not supporting pointer to varying length array.
1371 Error("FillLeaves", "Clonesa: %s, n=%d, sorry not supported yet", GetName(), n);
1372 return;
1373 }
1374 if (atype > 20) {
1375 atype -= 20;
1377 n = n * leaf->GetLenStatic();
1378 }
1379 switch (atype) {
1380 // Note: Type 0 is a base class and cannot happen here, see Unroll().
1381 case TVirtualStreamerInfo::kChar /* 1 */: { b.WriteFastArray((Char_t*) fAddress, n); break; }
1382 case TVirtualStreamerInfo::kShort /* 2 */: { b.WriteFastArray((Short_t*) fAddress, n); break; }
1383 case TVirtualStreamerInfo::kInt /* 3 */: { b.WriteFastArray((Int_t*) fAddress, n); break; }
1384 case TVirtualStreamerInfo::kLong /* 4 */: { b.WriteFastArray((Long_t*) fAddress, n); break; }
1385 case TVirtualStreamerInfo::kFloat /* 5 */: { b.WriteFastArray((Float_t*) fAddress, n); break; }
1386 case TVirtualStreamerInfo::kCounter /* 6 */: { b.WriteFastArray((Int_t*) fAddress, n); break; }
1387 // FIXME: We do nothing with type 7 (TVirtualStreamerInfo::kCharStar, char*) here!
1388 case TVirtualStreamerInfo::kDouble /* 8 */: { b.WriteFastArray((Double_t*) fAddress, n); break; }
1389 case TVirtualStreamerInfo::kDouble32 /* 9 */: {
1391 // coverity[returned_null] structurally si->fComp (used in GetElem) can not be null.
1392 TStreamerElement* se = si->GetElement(fID);
1394 for (Int_t ii = 0; ii < n; ++ii) {
1395 b.WriteDouble32(&(xx[ii]),se);
1396 }
1397 break;
1398 }
1399 case TVirtualStreamerInfo::kFloat16 /* 19 */: {
1401 // coverity[dereference] structurally si can not be null.
1402 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
1403 Float_t* xx = (Float_t*) fAddress;
1404 for (Int_t ii = 0; ii < n; ++ii) {
1405 b.WriteFloat16(&(xx[ii]),se);
1406 }
1407 break;
1408 }
1409 // Note: Type 10 is unused for now.
1410 case TVirtualStreamerInfo::kUChar /* 11 */: { b.WriteFastArray((UChar_t*) fAddress, n); break; }
1411 case TVirtualStreamerInfo::kUShort /* 12 */: { b.WriteFastArray((UShort_t*) fAddress, n); break; }
1412 case TVirtualStreamerInfo::kUInt /* 13 */: { b.WriteFastArray((UInt_t*) fAddress, n); break; }
1413 case TVirtualStreamerInfo::kULong /* 14 */: { b.WriteFastArray((ULong_t*) fAddress, n); break; }
1414 // FIXME: This is wrong!!! TVirtualStreamerInfo::kBits is a variable length type.
1415 case TVirtualStreamerInfo::kBits /* 15 */: { b.WriteFastArray((UInt_t*) fAddress, n); break; }
1416 case TVirtualStreamerInfo::kLong64 /* 16 */: { b.WriteFastArray((Long64_t*) fAddress, n); break; }
1417 case TVirtualStreamerInfo::kULong64 /* 17 */: { b.WriteFastArray((ULong64_t*) fAddress, n); break; }
1418 case TVirtualStreamerInfo::kBool /* 18 */: { b.WriteFastArray((bool*) fAddress, n); break; }
1419 }
1420 }
1421}
1422
1423////////////////////////////////////////////////////////////////////////////////
1424/// Write leaves into i/o buffers for this branch.
1425/// Case of a collection (fType == 4).
1426
1428{
1429 // -- STL container top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1431
1432 //
1433 // Silently do nothing if we have no user i/o buffer.
1434 //
1435
1436 if (!fObject) {
1437 return;
1438 }
1439
1441 Int_t n = 0;
1442 // We are in a block so the helper pops as soon as possible.
1444 n = proxy->Size();
1445
1446 if (n > fMaximum) {
1447 fMaximum = n;
1448 }
1449 b << n;
1450
1453 } else {
1454 //NOTE: this does not work for not vectors since the CreateIterators expects a TGenCollectionProxy::TStaging as its argument!
1455 //NOTE: and those not work in general yet, since the TStaging object is neither created nor passed.
1456 // We need to review how to avoid the need for a TStaging during the writing.
1457 if (proxy->GetProperties() & TVirtualCollectionProxy::kIsAssociative) {
1459 } else {
1461 }
1462 }
1463
1464}
1465
1466////////////////////////////////////////////////////////////////////////////////
1467/// Write leaves into i/o buffers for this branch.
1468/// Case of a data member within a collection (fType == 41).
1469
1471{
1473
1474 //
1475 // Silently do nothing if we have no user i/o buffer.
1476 //
1477
1478 if (!fObject) {
1479 return;
1480 }
1481
1482 // FIXME: This wont work if a pointer to vector is split!
1484 // Note: We cannot pop the proxy here because we need it for the i/o.
1486 if (!si) {
1487 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1488 return;
1489 }
1490
1492 R__ASSERT(nullptr!=iter);
1493 b.ApplySequenceVecPtr(*fFillActionSequence,iter->fBegin,iter->fEnd);
1494}
1495
1496////////////////////////////////////////////////////////////////////////////////
1497/// Write leaves into i/o buffers for this branch.
1498/// Case of a data member within a collection (fType == 41).
1499
1501{
1503
1504 //
1505 // Silently do nothing if we have no user i/o buffer.
1506 //
1507
1508 if (!fObject) {
1509 return;
1510 }
1511
1512 // FIXME: This wont work if a pointer to vector is split!
1514
1515 // Note: We cannot pop the proxy here because we need it for the i/o.
1517 if (!si) {
1518 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1519 return;
1520 }
1521
1523 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1524
1525}
1526
1527////////////////////////////////////////////////////////////////////////////////
1528/// Write leaves into i/o buffers for this branch.
1529/// Case of a data member within a collection (fType == 41).
1530
1532{
1534
1535 //
1536 // Silently do nothing if we have no user i/o buffer.
1537 //
1538
1539 if (!fObject) {
1540 return;
1541 }
1542
1543 // FIXME: This wont work if a pointer to vector is split!
1545 // Note: We cannot pop the proxy here because we need it for the i/o.
1547 if (!si) {
1548 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1549 return;
1550 }
1551
1553 R__ASSERT(nullptr!=iter);
1554 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1555
1556}
1557
1558////////////////////////////////////////////////////////////////////////////////
1559/// Write leaves into i/o buffers for this branch.
1560/// Case of a data member within a collection (fType == 41).
1561
1563{
1565
1566 //
1567 // Silently do nothing if we have no user i/o buffer.
1568 //
1569
1570 if (!fObject) {
1571 return;
1572 }
1573
1574 // FIXME: This wont work if a pointer to vector is split!
1576 // Note: We cannot pop the proxy here because we need it for the i/o.
1578 if (!si) {
1579 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1580 return;
1581 }
1582
1584 R__ASSERT(nullptr!=iter);
1585 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1586
1587}
1588
1589////////////////////////////////////////////////////////////////////////////////
1590/// Write leaves into i/o buffers for this branch.
1591/// Case of a TClonesArray (fType == 3).
1592
1594{
1595 // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1597
1598 //
1599 // Silently do nothing if we have no user i/o buffer.
1600 //
1601
1602 if (!fObject) {
1603 return;
1604 }
1605
1607 Int_t n = clones->GetEntriesFast();
1608 if (n > fMaximum) {
1609 fMaximum = n;
1610 }
1611 b << n;
1612}
1613
1614////////////////////////////////////////////////////////////////////////////////
1615/// Write leaves into i/o buffers for this branch.
1616/// Case of a data member within a TClonesArray (fType == 31).
1617
1619{
1621
1622 //
1623 // Silently do nothing if we have no user i/o buffer.
1624 //
1625
1626 if (!fObject) {
1627 return;
1628 }
1629
1631 Int_t n = clones->GetEntriesFast();
1633 if (!si) {
1634 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1635 return;
1636 }
1637
1638 char **arr = (char **)clones->GetObjectRef(nullptr);
1639 char **end = arr + n;
1640 b.ApplySequenceVecPtr(*fFillActionSequence,arr,end);
1641}
1642
1643////////////////////////////////////////////////////////////////////////////////
1644/// Write leaves into i/o buffers for this branch.
1645/// Case of a non TObject, non collection class with a custom streamer
1646
1648{
1650
1651 //
1652 // Silently do nothing if we have no user i/o buffer.
1653 //
1654
1655 if (!fObject) {
1656 return;
1657 }
1658
1659 //
1660 // Remember tobjects written to the buffer so that
1661 // pointers are handled correctly later.
1662
1663 if (TestBit(kBranchObject)) {
1664 b.MapObject((TObject*) fObject);
1665 } else if (TestBit(kBranchAny)) {
1666 b.MapObject(fObject, fBranchClass);
1667 }
1668
1670}
1671
1672////////////////////////////////////////////////////////////////////////////////
1673/// Write leaves into i/o buffers for this branch.
1674/// For split-class branch, base class branch, data member branch, or top-level branch.
1675/// which do have a branch count and are not a counter.
1676
1678{
1680 /*
1681 ValidateAddress();
1682
1683 //
1684 // Silently do nothing if we have no user i/o buffer.
1685 //
1686
1687 if (!fObject) {
1688 return;
1689 }
1690 */
1691}
1692
1693////////////////////////////////////////////////////////////////////////////////
1694/// Write leaves into i/o buffers for this branch.
1695/// For split-class branch, base class branch, data member branch, or top-level branch.
1696/// which do not have a branch count and are a counter.
1697
1699{
1701
1702 //
1703 // Silently do nothing if we have no user i/o buffer.
1704 //
1705
1706 if (!fObject) {
1707 return;
1708 }
1709 // -- Top-level, data member, base class, or split class branch.
1710 // 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.
1711 // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1712 // FIXME: What happens with a split base class branch,
1713 // or a split class branch???
1715 if (!si) {
1716 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1717 return;
1718 }
1719 // Since info is not null, fFillActionSequence is not null either.
1720 b.ApplySequence(*fFillActionSequence, fObject);
1721 // Int_t n = si->WriteBufferAux(b, &fObject, fID, 1, 0, 0);
1722
1723 Int_t n = *(Int_t*)(fObject + si->TStreamerInfo::GetElementOffset(fID)); // or GetInfoImp()->GetTypedValue<Int_t>(&fObject, fID, j, -1);
1724 if (n > fMaximum) {
1725 fMaximum = n;
1726 }
1727
1728}
1729
1730////////////////////////////////////////////////////////////////////////////////
1731/// Write leaves into i/o buffers for this branch.
1732/// For split-class branch, base class branch, data member branch, or top-level branch.
1733/// which do not have a branch count and are not a counter.
1734
1736{
1738
1739 //
1740 // Silently do nothing if we have no user i/o buffer.
1741 //
1742
1743 if (!fObject) {
1744 return;
1745 }
1746
1747 if (TestBit(kBranchObject)) {
1748 b.MapObject((TObject*) fObject);
1749 } else if (TestBit(kBranchAny)) {
1750 b.MapObject(fObject, fBranchClass);
1751 }
1752
1753 // -- Top-level, data member, base class, or split class branch.
1754 // 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.
1755 // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1756 // FIXME: What happens with a split base class branch,
1757 // or a split class branch???
1759 if (!si) {
1760 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1761 return;
1762 }
1763 // Since info is not null, fFillActionSequence is not null either.
1764 b.ApplySequence(*fFillActionSequence, fObject);
1765
1766}
1767
1768////////////////////////////////////////////////////////////////////////////////
1769/// Remove trailing dimensions and make sure
1770/// there is a trailing dot.
1771
1772static void R__CleanName(std::string &name)
1773{
1774 if (name[name.length()-1]==']') {
1775 std::size_t dim = name.find_first_of('[');
1776 if (dim != std::string::npos) {
1777 name.erase(dim);
1778 }
1779 }
1780 if (name[name.size()-1] != '.') {
1781 name += '.';
1782 }
1783}
1784
1785////////////////////////////////////////////////////////////////////////////////
1786/// Find the immediate sub-branch with passed name.
1787
1789{
1790 // The default behavior of TBranch::FindBranch is sometimes
1791 // incorrect if this branch represent a base class, since
1792 // the base class name might or might not be in the name
1793 // of the sub-branches and might or might not be in the
1794 // name being passed.
1795
1796 if (fID >= 0) {
1798 TStreamerElement* se = si->GetElement(fID);
1799 if (se && se->IsBase()) {
1800 // We allow the user to pass only the last dotted component of the name.
1801 UInt_t len = strlen(name);
1802 std::string longnm;
1803 longnm.reserve(fName.Length()+len+3); // Enough space of fName + name + dots
1804 longnm = fName.Data();
1806 longnm += name;
1807 std::string longnm_parent;
1808 longnm_parent.reserve(fName.Length()+len+3);
1811 longnm_parent += name; // Name without the base class name
1812
1813 UInt_t namelen = strlen(name);
1814
1815 TBranch* branch = nullptr;
1817 for(Int_t i = 0; i < nbranches; ++i) {
1819
1820 const char *brname = branch->GetName();
1822 if (brname[brlen-1]==']') {
1823 const char *dim = strchr(brname,'[');
1824 if (dim) {
1825 brlen = dim - brname;
1826 }
1827 }
1828 if (namelen == brlen /* same effective size */
1829 && strncmp(name,brname,brlen) == 0) {
1830 return branch;
1831 }
1832 if (brlen == longnm.length()
1833 && strncmp(longnm.c_str(),brname,brlen) == 0) {
1834 return branch;
1835 }
1836 // This check is specific to base class
1837 if (brlen == longnm_parent.length()
1838 && strncmp(longnm_parent.c_str(),brname,brlen) == 0) {
1839 return branch;
1840 }
1841
1842 if (namelen>brlen && name[brlen]=='.' && strncmp(name,brname,brlen)==0) {
1843 // The prefix subbranch name match the branch name.
1844 return branch->FindBranch(name+brlen+1);
1845 }
1846 }
1847 }
1848 }
1850 if (!result) {
1851 // Look in base classes if any
1853 for(Int_t i = 0; i < nbranches; ++i) {
1854 TObject *obj = fBranches.UncheckedAt(i);
1855 if(obj->IsA() != TBranchElement :: Class() )
1856 continue;
1858 TVirtualStreamerInfo* si = br->GetInfoImp();
1859 if (si && br->GetID() >= 0) {
1860 TStreamerElement* se = si->GetElement(br->GetID());
1861 if (se && se->IsBase()) {
1862 result = br->FindBranch(name);
1863 }
1864 }
1865 }
1866 }
1867 return result;
1868}
1869
1870////////////////////////////////////////////////////////////////////////////////
1871/// Find the leaf corresponding to the name 'searchname'.
1872
1874{
1876
1877 if (leaf==nullptr && GetListOfLeaves()->GetEntries()==1) {
1878 TBranch *br = GetMother()->GetSubBranch( this );
1879 if( br->IsA() != TBranchElement::Class() )
1880 return nullptr;
1881
1882 TBranchElement *parent = (TBranchElement*)br;
1883 if (parent==this || parent->GetID()<0 ) return nullptr;
1884
1885 TVirtualStreamerInfo* si = parent->GetInfoImp();
1886 TStreamerElement* se = si->GetElement(parent->GetID());
1887
1888 if (! se->IsBase() ) return nullptr;
1889
1890 br = GetMother()->GetSubBranch( parent );
1891 if( br->IsA() != TBranchElement::Class() )
1892 return nullptr;
1893
1895
1896 std::string longname( grand_parent->GetName() );
1898 longname += name;
1899
1900 std::string leafname( GetListOfLeaves()->At(0)->GetName() );
1901
1902 if ( longname == leafname ) {
1903 return (TLeaf*)GetListOfLeaves()->At(0);
1904 }
1905 }
1906 return leaf;
1907}
1908
1909////////////////////////////////////////////////////////////////////////////////
1910/// Get the branch address.
1911///
1912/// If we are *not* owned by a MakeClass() tree:
1913///
1914/// - If we are a top-level branch, return a pointer
1915/// - to the pointer to our object.
1916///
1917/// If we are *not* a top-level branch, return a pointer
1918/// to our object.
1919///
1920/// If we are owned by a MakeClass() tree:
1921///
1922/// - Return a pointer to our object.
1923
1925{
1927 return fAddress;
1928}
1929
1930
1931// For a mother branch of type 3 or 4, find the 'correct' StreamerInfo for the
1932// content of the collection by find a sub-branch corresponding to a direct data member
1933// of the containee class (valueClass)
1934// Default to the current StreamerInfo if none are found.
1936{
1937 TStreamerInfo *localInfo = nullptr;
1938
1939 // Search for the correct version.
1941 if (!subbe->fInfo)
1942 subbe->SetupInfo();
1943 if (valueClass == subbe->fInfo->GetClass()) { // Use GetInfo to provoke its creation.
1944 localInfo = subbe->fInfo;
1945 break;
1946 }
1947 }
1948 if (!localInfo) {
1949 // This is likely sub-optimal as we really should call GetFile but it is non-const.
1950 auto file = fDirectory ? fDirectory->GetFile() : nullptr;
1951 if (file && file->GetSeekInfo()) {
1952 localInfo = (TStreamerInfo*)file->GetStreamerInfoCache()->FindObject(valueClass->GetName());
1953 if (localInfo) {
1954 if (valueClass->IsVersioned()) {
1955 localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1956 } else {
1957 localInfo = (TStreamerInfo*)valueClass->FindStreamerInfo(localInfo->GetCheckSum());
1958 if (localInfo) {
1959 // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
1960 localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1961 }
1962 }
1963 }
1964 }
1965 }
1966 if (!localInfo)
1967 localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo();
1968
1969 if (localInfo) {
1970 // See if we need any conversion.
1973 : nullptr;
1974 // For TClonesArray, the rest of the code probably does not support change in
1975 // value class, but if it does, we would have to look up the target value class
1976 // in the TClonesArray instance.
1977 // if (type == 3 && instance) targetValueClass = ((TClonesArray*)instance)->GetClass();
1978
1979 if (targetValueClass && localInfo->GetClass() != targetValueClass) {
1980 localInfo = (TStreamerInfo*)targetValueClass->GetConversionStreamerInfo(localInfo->GetClass(),
1981 localInfo->GetClassVersion());
1982 }
1983 }
1984 return localInfo;
1985}
1986
1987namespace {
1989 size_t ndata = info->GetNelement();
1990 for (size_t i =0; i < ndata; ++i) {
1991 TStreamerElement *nextel = info->GetElement(i);
1992
1993 if (nextel->GetType() == TStreamerInfo::kCacheDelete
1994 || nextel->GetType() == TStreamerInfo::kCacheNew) {
1995 continue;
1996 }
1997
1998 TString ename = prefix + nextel->GetName();
1999
2000 if (ename[0]=='*')
2001 ename.Remove(0,1);
2002
2003 Ssiz_t pos;
2004 while ((pos = ename.Last('[')) != TString::kNPOS) {
2005 ename = ename.Remove(pos);
2006 }
2007
2009 if (nextel->IsA() == TStreamerArtificial::Class()
2010 && be == nullptr) {
2011
2012 ids.push_back(i);
2013 ids.back().fElement = nextel;
2014 ids.back().fInfo = info;
2015 }
2016
2017 if (nextel->CannotSplit() || nextel->IsTransient() || nextel->GetOffset() == TStreamerInfo::kMissing)
2018 continue;
2019
2020 if (!be && nextel->IsBase()) {
2021 // We could be in the case of a branch created from a Folder or
2022 // a top level branch with a non-trailing dot in its name (case inadvertently confused with the folder case).
2023 // In those case, the name of the base class is *not* used to create the corresponding branch.
2024 TString subprefix(prefix);
2025 if (subprefix.Length() && subprefix[subprefix.Length()-1] == '.')
2026 subprefix.Remove(subprefix.Length()-1);
2027
2028 be = (TBranchElement*)branches.FindObject(subprefix);
2029 if (be) {
2030 // There is at least 'one' base class branch all with the same name, so let's find the
2031 // right one.
2032 TClass *expectedClass = nullptr;
2034 if (0 != be->GetExpectedType(expectedClass,expectedType)
2035 || expectedClass != nextel->GetClassPointer())
2036 {
2037 be = nullptr;
2038 Int_t nbranches = branches.GetEntriesFast();
2039 for (Int_t bi = 0; bi < nbranches; ++bi) {
2041 if (subprefix != branch->GetName())
2042 continue;
2043 if (0 == branch->GetExpectedType(expectedClass,expectedType)
2044 && expectedClass == nextel->GetClassPointer())
2045 {
2046 be = branch;
2047 break;
2048 }
2049 }
2050 } // else we have already found the right branch.
2051 }
2052 }
2053
2054 TClass *elementClass = nextel->GetClassPointer();
2055 if (elementClass && (!be || be->GetType() == -2)) {
2056 // Recurse on sub-objects.
2057 TStreamerInfo *nextinfo = nullptr;
2058
2059 // nextinfo_version = ....
2060 auto search = be ? be->GetListOfBranches() : &branches;
2061 TVirtualArray *onfileObject = nullptr;
2062
2064 if (prefix.Length() && nextel->IsA() == TStreamerBase::Class()) {
2065 // We skip the name of the base class if there is already a prefix.
2066 // See TBranchElement::Unroll
2067 subprefix = prefix;
2068 } else {
2069 subprefix = ename + ".";
2070 }
2071 auto nbranches = search->GetEntriesFast();
2072 bool foundRelatedSplit = false;
2073 for (Int_t bi = 0; bi < nbranches; ++bi) {
2075 bool matchSubPrefix = strncmp(subbe->GetFullName(), subprefix.Data(), subprefix.Length()) == 0;
2076 if (!foundRelatedSplit)
2078 if (elementClass == subbe->GetInfo()->GetClass() // Use GetInfo to provoke its creation.
2079 && subbe->GetOnfileObject()
2080 && matchSubPrefix)
2081 {
2082 nextinfo = subbe->GetInfo();
2083 onfileObject = subbe->GetOnfileObject();
2084 break;
2085 }
2086 }
2087
2088 if (!foundRelatedSplit) {
2089 continue;
2090 }
2091
2092 if (!nextinfo) {
2093 nextinfo = (TStreamerInfo *)elementClass->GetStreamerInfo();
2094 if (elementClass->GetCollectionProxy() && elementClass->GetCollectionProxy()->GetValueClass()) {
2095 nextinfo = (TStreamerInfo *)elementClass->GetCollectionProxy()->GetValueClass()->GetStreamerInfo(); // NOTE: need to find the right version
2096 }
2097 }
2098 ids.emplace_back(nextinfo, offset + nextel->GetOffset());
2099 if (!onfileObject && nextinfo && nextinfo->GetNelement() && nextinfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew) {
2100 onfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), 1 /* is that always right? */ );
2101 ids.back().fNestedIDs->fOwnOnfileObject = true;
2102 }
2103 ids.back().fNestedIDs->fOnfileObject = onfileObject;
2104 GatherArtificialElements(branches, ids.back().fNestedIDs->fIDs, subprefix, nextinfo, offset + nextel->GetOffset());
2105 if (ids.back().fNestedIDs->fIDs.empty())
2106 ids.pop_back();
2107 }
2108 }
2109};
2110} // Anonymous namespace.
2111
2112
2113////////////////////////////////////////////////////////////////////////////////
2114/// Set the value of fInfo. This is part one of InitInfo.
2115/// To be used as:
2116/// if (!fInfo)
2117/// SetupInfo();
2118/// It would only be used within InitInfo (and its callees)
2119
2121{
2122 // We did not already have streamer info, so now we must find it.
2124
2125 //------------------------------------------------------------------------
2126 // Check if we're dealing with the name change
2127 //////////////////////////////////////////////////////////////////////////
2128
2129 TClass* targetClass = nullptr;
2130 if( fTargetClass.GetClassName()[0] ) {
2132 if (!targetClass && GetCollectionProxy()) {
2133 // We are in the case where the branch holds a custom collection
2134 // proxy but the dictionary is not loaded, calling
2135 // GetCollectionProxy had the side effect of creating the TClass
2136 // corresponding to this emulated collection.
2138 }
2139 if ( !targetClass ) {
2140 Error("InitInfo", "Branch '%s': missing dictionary for target class '%s'!",
2142 return;
2143 }
2144 } else {
2145 targetClass = cl;
2146 }
2147 if (cl) {
2148 //---------------------------------------------------------------------
2149 // Get the streamer info for given version
2150 ///////////////////////////////////////////////////////////////////////
2151
2152 {
2153 if ( (cl->Property() & kIsAbstract) && cl == targetClass) {
2155 if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
2156 // Our parent's class is emulated and we represent an abstract class.
2157 // and the target class has not been set explicitly.
2158 TString target = cl->GetName();
2159 target += "@@emulated";
2161
2162 if (!fTargetClass) {
2164 }
2166 }
2167 }
2168 if( targetClass != cl ) {
2169 fInfo = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fClassVersion );
2170 } else {
2172 }
2173 }
2174
2175 // FIXME: Check that the found streamer info checksum matches our branch class checksum here.
2176 // Check to see if the class code was unloaded/reloaded
2177 // since we were created.
2179 if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) {
2180 // Try to compensate for a class that got unloaded on us.
2181 // Search through the streamer infos by checksum
2182 // and take the first match.
2183
2185 if( targetClass != cl )
2186 info = (TStreamerInfo*)targetClass->FindConversionStreamerInfo( cl, fCheckSum );
2187 else {
2189 if (info) {
2190 // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
2191 info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion());
2192 }
2193 }
2194 if( info ) {
2195 fInfo = info;
2196 // We no longer reset the class version so that in case the user is passing us later
2197 // the address of a class that require (another) Conversion we can find the proper
2198 // StreamerInfo.
2199 // fClassVersion = fInfo->GetClassVersion();
2200 }
2201 }
2202 }
2203}
2204
2205
2206////////////////////////////////////////////////////////////////////////////////
2207/// Init the streamer info for the branch class, try to compensate for class
2208/// code unload/reload and schema evolution.
2209
2211{
2212 if (!fInfo)
2213 SetupInfo();
2214
2215 //
2216 // Fixup cached streamer info if necessary.
2217 //
2218 // FIXME: What if the class code was unloaded/reloaded since we were cached?
2219
2220 if (fInfo) {
2221
2222 if (!fInfo->IsCompiled()) {
2223 // Streamer info has not yet been compiled.
2224
2225 Error("InitInfo","StreamerInfo is not compiled.");
2226 }
2227 // return immediately if we are called recursively.
2228 if (fInInitInfo)
2229 return;
2230 fInInitInfo = true;
2231 if (!fInit) {
2232 // We were read in from a file, figure out what our fID should be,
2233 // schema evolution must be considered.
2234 //
2235 // Force our fID to be the id of the first streamer element that matches our name.
2236 //
2237 auto SetOnfileObject = [this](TStreamerInfo *info) {
2238 Int_t arrlen = 1;
2239 if (fType==31 || fType==41) {
2240 TLeaf *leaf = (TLeaf*)fLeaves.At(0);
2241 if (leaf) {
2242 arrlen = leaf->GetMaximum();
2243 }
2244 }
2245 bool toplevel = (fType == 3 || fType == 4 || (fType == 0 && fID == -2));
2246 bool seenExisting = false;
2247
2248 fOnfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), arrlen );
2249 // Propagate this to all the other branches belonging to the same object.
2251 Int_t nbranches = branches->GetEntriesFast();
2252 TBranchElement *lastbranch = this;
2253
2256 if (toplevel) {
2257 // Note: Fragile/wrong when using conversion StreamerInfo?
2258 currentClass = info->GetClass();
2259 currentVersion = info->GetClassVersion();
2260 }
2261
2262 // First find the first branch corresponding to the same class as 'this'
2263 // branch
2264 Int_t index = branches->IndexOf(this);
2265 Int_t firstindex = 0;
2267 if (index >= 0) {
2268 TString fullname( GetFullName() );
2269 Ssiz_t lastdot = fullname.Last('.');
2270 if (lastdot == TString::kNPOS) {
2271 // No prefix or index, thus this is a first level branch
2273 if (!subbranch->fInfo)
2274 subbranch->SetupInfo();
2275 } else {
2276 TString &thisprefix = fullname.Remove(lastdot + 1); // Mod fullname and 'rename' the variable.
2277 for(Int_t i = index - 1; i >= 0; --i) {
2279 TString subbranch_name(subbranch->GetFullName());
2280 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2281 // We moved to another data member (of the enclosing class)
2282 firstindex = i + 1;
2283 break;
2284 }
2285 if (!subbranch->fInfo)
2286 subbranch->SetupInfo();
2287 }
2288 for(Int_t i = index; i < nbranches; ++i) {
2290 TString subbranch_name(subbranch->GetFullName());
2291 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2292 lastindex = i - 1;
2293 break;
2294 }
2295 }
2296 }
2297 } else {
2298 // Case of a top level branch or 'empty node' (object marker for split sub-object)
2299 TString fullname( GetFullName() );
2300 Ssiz_t lastdot = fullname.Last('.');
2301 if (lastdot != TString::kNPOS) {
2302 TString &thisprefix = fullname.Remove(lastdot + 1); // Mod fullname and 'rename' the variable.
2303 for(Int_t i = 0; i < nbranches; ++i) {
2305 TString subbranch_name(subbranch->GetFullName());
2306 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2307 lastindex = i - 1;
2308 break;
2309 }
2310 }
2311 }
2312 }
2313 for (Int_t i = firstindex; i <= lastindex; ++i) {
2315 bool match = false;
2316 if (this != subbranch) {
2317
2318 if (!subbranch->fInfo)
2319 subbranch->SetupInfo();
2320
2321 if (subbranch->fInfo == info)
2322 match = true;
2323 else if (subbranch->fInfo == nullptr && subbranch->fBranchClass == currentClass) {
2324 if (!toplevel) {
2325 if (subbranch->fCheckSum == fCheckSum)
2326 match = true;
2327 } else {
2328 if (!subbranch->fBranchClass->IsForeign() && subbranch->fClassVersion == currentVersion)
2329 match = true;
2330 else if (subbranch->fCheckSum == info->GetCheckSum()) {
2331 match = true;
2332 }
2333 }
2334 }
2335 }
2336 if (match) {
2337 if (subbranch->fOnfileObject && subbranch->fOnfileObject != fOnfileObject) {
2338 if (seenExisting) {
2339 Error("SetOnfileObject (lambda)", "2 distincts fOnfileObject are in the hierarchy of %s for type %s",
2340 toplevel ? GetName() : GetMother()->GetSubBranch(this)->GetName(), info->GetName());
2341 } else {
2342 delete fOnfileObject;
2343 fOnfileObject = subbranch->fOnfileObject;
2344 seenExisting = true;
2345 }
2346 }
2347 subbranch->fOnfileObject = fOnfileObject;
2349 }
2350 }
2351 if (toplevel) {
2353 if (lastbranch != this)
2354 lastbranch->ResetBit(kOwnOnfileObj);
2355 } else {
2356 lastbranch->SetBit(kOwnOnfileObj);
2357 }
2358 };
2359 if (GetID() > -1) {
2360 // We are *not* a top-level branch.
2361 std::string s(GetName());
2362 size_t pos = s.rfind('.');
2363 if (pos != std::string::npos) {
2364 s = s.substr(pos+1);
2365 }
2366 while ((pos = s.rfind('[')) != std::string::npos) {
2367 s = s.substr(0, pos);
2368 }
2369 int offset = 0;
2372 size_t ndata = fInfo->GetNelement();
2373 fNewIDs.clear();
2374 for (size_t i = 0; i < ndata; ++i) {
2375 if (fInfo->GetElement(i) == elt) {
2376 if (elt->TestBit (TStreamerElement::kCache)
2377 && (i+1) < ndata
2378 && s == fInfo->GetElement(i)->GetName())
2379 {
2380 // If the TStreamerElement we found is storing the information in the
2381 // cache and is a repeater, we need to use the real one (the next one).
2382 // (At least until the cache/repeat mechanism is properly handle by
2383 // ReadLeaves).
2384 // fID = i+1;
2385 fID = i;
2386 if (fType != 2) {
2387 if (elt->TestBit(TStreamerElement::kRepeat)) {
2388 fNewIDs.push_back(fID+1);
2389 fNewIDs.back().fElement = fInfo->GetElement(i+1);
2390 fNewIDs.back().fInfo = fInfo;
2391 } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) {
2392 fNewIDs.push_back(fID+1);
2393 fNewIDs.back().fElement = fInfo->GetElement(i+1);
2394 fNewIDs.back().fInfo = fInfo;
2395 }
2396 }
2397 } else {
2398 fID = i;
2399 }
2400 if (elt->TestBit (TStreamerElement::kCache)) {
2402 }
2403 break;
2404 }
2405 }
2406 for (size_t i = fID+1+(fNewIDs.size()); i < ndata; ++i) {
2408
2409 std::string ename = nextel->GetName();
2410 if (ename[0] == '*')
2411 ename = ename.substr(1);
2412
2413 while ((pos = ename.rfind('[')) != std::string::npos) {
2414 ename = ename.substr(0, pos);
2415 }
2416
2417 if (s != ename) {
2418 // We moved on to the next set
2419 break;
2420 }
2421 // Add all (and only) the Artificial Elements that follows this StreamerInfo.
2422 // fprintf(stderr,"%s/%d[%zu] passing through %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2423 if (fType==31||fType==41) {
2424 // The nested objects are unfolded and their branch can not be used to
2425 // execute StreamerElements of this StreamerInfo.
2426 if ((nextel->GetType() == TStreamerInfo::kObject
2427 || nextel->GetType() == TStreamerInfo::kAny)
2428 && nextel->GetClassPointer()->CanSplit())
2429 {
2430 continue;
2431 }
2432 }
2433 if (nextel->GetOffset() == TStreamerInfo::kMissing) {
2434 // This element will be 'skipped', it's TBranchElement's fObject will null
2435 // and thus can not be used to execute the artificial StreamerElements
2436 continue;
2437 }
2438 if (nextel->IsA() != TStreamerArtificial::Class()
2439 || nextel->GetType() == TStreamerInfo::kCacheDelete ) {
2440 continue;
2441 }
2442 // NOTE: We should verify that the rule's source are 'before'
2443 // or 'at' this branch.
2444 // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2445 fNewIDs.push_back(i);
2446 fNewIDs.back().fElement = nextel;
2447 fNewIDs.back().fInfo = fInfo;
2448 }
2449 } else if (elt && offset==TStreamerInfo::kMissing) {
2450 // Still re-assign fID properly.
2451 fNewIDs.clear();
2452 size_t ndata = fInfo->GetNelement();
2453 for (size_t i = 0; i < ndata; ++i) {
2454 if (fInfo->GetElement(i) == elt) {
2455 fID = i;
2456 break;
2457 }
2458 }
2459 } else {
2460 // We have not even found the element .. this is strange :(
2461 // fNewIDs.clear();
2462 // fID = -3;
2463 // SetBit(kDoNotProcess);
2464 }
2465 if (fOnfileObject==nullptr && (fType==31 || fType==41 || (0 <= fType && fType <=2) ) && fInfo->GetNelement()
2467 {
2469 }
2470 }
2471 if (fType == 3 || fType == 4 || (fType == 0 && fID == -2) || fType == 2) {
2472 // Need to add the rule targeting transient members.
2474 if (fType == 3 || fType == 4) {
2475 // Don't we have real version information?
2476 // Not unless there is a subbranch with a non-split element of the class.
2477 // Search for the correct version.
2479 }
2480
2481 TString prefix(GetFullName());
2482 if (fType == 2 && fID >= 0) {
2483 auto start = prefix.Length();
2484 if (prefix[start - 1] == '.')
2485 --start;
2486 std::string_view view(prefix.Data(), start);
2487 auto cutoff = view.find_last_of('.');
2488 if (cutoff != std::string::npos) {
2489 prefix.Remove(cutoff + 1);
2490 }
2491 }
2492 if (prefix[prefix.Length()-1] != '.') {
2493 if (fType == 3 || fType == 4 || prefix.Index('.') != TString::kNPOS) {
2494 prefix += ".";
2495 } else {
2496 prefix = "";
2497 }
2498 }
2499 fNewIDs.clear();
2500
2502
2503 if (!fNewIDs.empty() && fOnfileObject == nullptr && localInfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew)
2504 {
2506 }
2507
2508 }
2509 fInit = true;
2510
2511 // Get the action sequence we need to copy for reading.
2514 } else if (!fReadActionSequence) {
2515 // Get the action sequence we need to copy for reading.
2518 }
2521 fInInitInfo = false;
2522 }
2523}
2524
2525////////////////////////////////////////////////////////////////////////////////
2526/// Return the collection proxy describing the branch content, if any.
2527
2529{
2530 if (fCollProxy) {
2531 return fCollProxy;
2532 }
2533 TBranchElement* thiscast = const_cast<TBranchElement*>(this);
2534 if (fType == 4) {
2535 // STL container top-level branch.
2536 const char* className = nullptr;
2537 TClass* cl = nullptr;
2538 if (fID < 0) {
2539 // We are a top-level branch.
2540 if (fBranchClass.GetClass()) {
2541 cl = fBranchClass.GetClass();
2542 }
2543 } else {
2544 // We are not a top-level branch.
2545 TVirtualStreamerInfo* si = thiscast->GetInfoImp();
2546 if (fCollProxy) {
2547 // The GetInfo set fProxy for us, let's not
2548 // redo it; the value of fCollProxy is possibly
2549 // used/recorded is the actions sequences, so
2550 // if we change it here, we would need to propagate
2551 // the change.
2552 return fCollProxy;
2553 }
2554 TStreamerElement* se = si->GetElement(fID);
2555 cl = se->GetClassPointer();
2556 }
2557 if (!cl) {
2558 // The TClass was not created but we do know (since it
2559 // is used as a collection) that it 'className' was a
2560 // class, so let's create it by hand!.
2561
2562 if (fID < 0) {
2564 className = cl->GetName();
2565 } else {
2566 cl = new TClass(className, fClassVersion);
2567 className = cl->GetName();
2568 }
2569 }
2571 if (!proxy) {
2572 // humm, we must have an older file with a custom collection
2573 // let's try to work-around it.
2574 TString equiv;
2575 equiv.Form("vector<%s>",fClonesName.Data());
2577 proxy = clequiv->GetCollectionProxy();
2578 if (!proxy) {
2579 Fatal("GetCollectionProxy",
2580 "Can not create a Collection Proxy of any kind for the class \"%s\" needed by the branch \"%s\" of the TTree \"%s\"!",
2581 className, GetName(), GetTree()->GetName());
2582 }
2583 if (gDebug > 0) Info("GetCollectionProxy",
2584 "Fixing the collection proxy of the class \"%s\" \n"
2585 "\tneeded by the branch \"%s\" of the TTree \"%s\" to be similar to \"%s\".",
2586 className, GetName(), GetTree()->GetName(),equiv.Data());
2587 cl->CopyCollectionProxy( *proxy );
2588 }
2589 fCollProxy = proxy->Generate();
2590 fSTLtype = proxy->GetCollectionType();
2591 } else if (fType == 41) {
2592 // STL container sub-branch.
2593 thiscast->fCollProxy = fBranchCount->GetCollectionProxy();
2594 }
2595 return fCollProxy;
2596}
2597
2598////////////////////////////////////////////////////////////////////////////////
2599/// Return a pointer to the current type of the data member corresponding to branch element.
2600
2602{
2603 TClass* cl = fCurrentClass;
2604 if (cl) {
2605 return cl;
2606 }
2607
2609 if (!brInfo) {
2611 R__ASSERT(cl && cl->GetCollectionProxy());
2612 fCurrentClass = cl;
2613 return cl;
2614 }
2615 TClass* motherCl = brInfo->GetClass();
2616 if (motherCl->GetCollectionProxy()) {
2617 cl = motherCl->GetCollectionProxy()->GetCollectionClass();
2618 if (cl) {
2619 fCurrentClass = cl;
2620 }
2621 return cl;
2622 }
2623 if (GetID() < 0 || GetID()>=brInfo->GetNelement()) {
2624 return nullptr;
2625 }
2627 TDataMember* dm = (TDataMember*) motherCl->GetListOfDataMembers()->FindObject(currentStreamerElement->GetName());
2628
2630 if (!dm) {
2631 // Either the class is not loaded or the data member is gone
2632 if (!motherCl->IsLoaded()) {
2633 TVirtualStreamerInfo* newInfo = motherCl->GetStreamerInfo();
2634 if (newInfo != brInfo) {
2635 TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(currentStreamerElement->GetName());
2636 if (newElems) {
2637 if (newElems->GetClassPointer())
2638 newType = newElems->GetClassPointer()->GetName();
2639 else
2640 newType = newElems->GetTypeName();
2641 }
2642 }
2643 if (newType.Length()==0) {
2644 if (currentStreamerElement->GetClassPointer())
2645 newType = currentStreamerElement->GetClassPointer()->GetName();
2646 else
2647 newType = currentStreamerElement->GetTypeName();
2648 }
2649 }
2650 } else {
2651 newType = dm->GetTypeName();
2652 }
2654 if (cl) {
2655 fCurrentClass = cl;
2656 }
2657 return cl;
2658}
2659
2660////////////////////////////////////////////////////////////////////////////////
2661/// Read all branches of a BranchElement and return total number of bytes.
2662///
2663/// - If entry = 0, then use current entry number + 1.
2664/// - If entry < 0, then reset entry number to 0.
2665///
2666/// Returns the number of bytes read from the input buffer.
2667/// - If entry does not exist, then returns 0.
2668/// - If an I/O error occurs, then returns -1.
2669///
2670/// See IMPORTANT REMARKS in TTree::GetEntry.
2671
2673{
2674 // Remember which entry we are reading.
2675 fReadEntry = entry;
2676
2677 // If our tree has a branch ref, make it remember the entry and
2678 // this branch. This allows a TRef::GetObject() call done during
2679 // the following I/O operation, for example in a custom streamer,
2680 // to search for the referenced object in the proper element of the
2681 // proper branch.
2683 if (R__unlikely(bref)) {
2684 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2685 fBranchID = bref->SetParent(this, fBranchID);
2686 bref->SetRequestedEntry(entry);
2687 }
2688
2689 Int_t nbytes = 0;
2690
2691 if (R__unlikely(IsAutoDelete())) {
2694 } else {
2696 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2698 }
2699 }
2700
2702 if (nbranches) {
2703 // -- Branch has daughters.
2704 // One must always read the branch counter.
2705 // In the case when one reads consecutively twice the same entry,
2706 // the user may have cleared the TClonesArray between the GetEntry calls.
2707 if ((fType == 3) || (fType == 4)) {
2709 if (nb < 0) {
2710 return nb;
2711 }
2712 nbytes += nb;
2713 }
2714 switch(fSTLtype) {
2715 case ROOT::kSTLset:
2716 case ROOT::kSTLmultiset:
2719 case ROOT::kSTLmap:
2720 case ROOT::kSTLmultimap:
2723 break;
2724 default:
2725 ValidateAddress(); // There is no ReadLeave for this node, so we need to do the validation here.
2726 for (Int_t i = 0; i < nbranches; ++i) {
2728 Int_t nb = branch->GetEntry(entry, getall);
2729 if (nb < 0) {
2730 return nb;
2731 }
2732 nbytes += nb;
2733 }
2734 break;
2735 }
2737 if (fType == 3) {
2738 // Apply the unattached rules; by definition they do not need any
2739 // input from a buffer.
2741
2742 auto ndata = GetNdata();
2743
2745 if (clones->IsZombie()) {
2746 return -1;
2747 }
2748 R__PushCache onfileObject(b, fOnfileObject, ndata);
2749
2750 char **arr = (char **)clones->GetObjectRef();
2751 char **end = arr + fNdata;
2752
2753 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
2754 } else if (fType == 4) {
2755 // Apply the unattached rules; by definition they do not need any
2756 // input from a buffer.
2758
2759 auto ndata = GetNdata();
2760
2761 R__PushCache onfileObject(b, fOnfileObject, ndata);
2764
2766 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
2767 } else {
2768 // Apply the unattached rules; by definition they do not need any
2769 // input from a buffer.
2771 R__PushCache onfileObject(b, fOnfileObject, fNdata);
2772 b.ApplySequence(*fReadActionSequence, fObject);
2773 }
2774 }
2775 } else {
2776 // -- Terminal branch.
2778 Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
2779 if (nb < 0) {
2780 return nb;
2781 }
2782 nbytes += nb;
2783 }
2785 if (nb < 0) {
2786 return nb;
2787 }
2788 nbytes += nb;
2789 }
2790
2791 if (R__unlikely(fTree->Debug() > 0)) {
2792 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
2793 Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
2794 }
2795 }
2796 return nbytes;
2797}
2798
2799////////////////////////////////////////////////////////////////////////////////
2800/// Fill expectedClass and expectedType with information on the data type of the
2801/// object/values contained in this branch (and thus the type of pointers
2802/// expected to be passed to Set[Branch]Address
2803/// return 0 in case of success and > 0 in case of failure.
2804
2806{
2807 expectedClass = nullptr;
2809
2811 if ((type == -1) || (fID == -1)) {
2813 } else {
2814 // Case of an object data member. Here we allow for the
2815 // variable name to be omitted. Eg, for Event.root with split
2816 // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
2818 if (element) {
2819 expectedClass = element->GetClassPointer();
2820 if (!expectedClass) {
2821 TDataType* data = gROOT->GetType(element->GetTypeNameBasic());
2822 if (!data) {
2823 Error("GetExpectedType", "Did not find the type number for %s", element->GetTypeNameBasic());
2824 return 1;
2825 } else {
2826 expectedType = (EDataType) data->GetType();
2827 }
2828 }
2829 } else {
2830 Error("GetExpectedType", "Did not find the type for %s",GetName());
2831 return 2;
2832 }
2833 }
2834 return 0;
2835}
2836
2837////////////////////////////////////////////////////////////////////////////////
2838/// Return the 'full' name of the branch. In particular prefix the mother's name
2839/// when it does not end in a trailing dot and thus is not part of the branch name
2841{
2842 TBranchElement* mother = static_cast<TBranchElement*>(GetMother());
2843 if (!mother || mother==this || mother->GetType() == 3 || mother->GetType() == 4) {
2844 // The parent's name is already included in the name for split TClonesArray and STL collections
2845 return fName;
2846 }
2847
2848 return TBranch::GetFullName();
2849}
2850
2851////////////////////////////////////////////////////////////////////////////////
2852/// Return icon name depending on type of branch element.
2853
2855{
2856 if (IsFolder()) {
2857 return "TBranchElement-folder";
2858 } else {
2859 return "TBranchElement-leaf";
2860 }
2861}
2862
2863////////////////////////////////////////////////////////////////////////////////
2864/// Return whether this branch is in a mode where the object are decomposed
2865/// or not (Also known as MakeClass mode).
2866
2868{
2869 return TestBit(kDecomposedObj); // Same as TestBit(kMakeClass)
2870}
2871
2872////////////////////////////////////////////////////////////////////////////////
2873/// Return maximum count value of the branchcount if any.
2874
2876{
2877 if (fBranchCount) {
2878 return fBranchCount->GetMaximum();
2879 }
2880 return fMaximum;
2881}
2882
2883////////////////////////////////////////////////////////////////////////////////
2884/// Return a pointer to our object.
2885
2887{
2889 return fObject;
2890}
2891
2892////////////////////////////////////////////////////////////////////////////////
2893/// Return a pointer to the parent class of the branch element.
2894
2899
2900////////////////////////////////////////////////////////////////////////////////
2901/// Return type name of element in the branch.
2902
2904{
2905 if (fType == 3 || fType == 4) {
2906 return "Int_t";
2907 }
2908 // FIXME: Use symbolic constants here.
2909 if ((fStreamerType < 1) || (fStreamerType > 59)) {
2910 if (fBranchClass.GetClass()) {
2911 if (fID>=0) {
2912 return GetInfoImp()->GetElement(fID)->GetTypeName();
2913 } else {
2914 return fBranchClass.GetClass()->GetName();
2915 }
2916 } else {
2917 return nullptr;
2918 }
2919 }
2920 const char *types[20] = {
2921 "",
2922 "Char_t",
2923 "Short_t",
2924 "Int_t",
2925 "Long_t",
2926 "Float_t",
2927 "Int_t",
2928 "char*",
2929 "Double_t",
2930 "Double32_t",
2931 "",
2932 "UChar_t",
2933 "UShort_t",
2934 "UInt_t",
2935 "ULong_t",
2936 "UInt_t",
2937 "Long64_t",
2938 "ULong64_t",
2939 "Bool_t",
2940 "Float16_t"
2941 };
2942 Int_t itype = fStreamerType % 20;
2943 return types[itype];
2944}
2945
2946////////////////////////////////////////////////////////////////////////////////
2947
2951
2952template <typename T>
2954{
2955 // -- Returns the branch value.
2956 //
2957 // If the leaf is an array, j is the index in the array.
2958 //
2959 // If leaf is an array inside a TClonesArray, len should be the length
2960 // of the array.
2961 //
2962 // If subarr is true, then len is actually the index within the sub-array.
2963 //
2964
2966
2967 Int_t prID = fID;
2968 char *object = fObject;
2969 if (TestBit(kCache)) {
2970 if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2971 prID = fID+1;
2972 } else if (fOnfileObject) {
2973 object = fOnfileObject->GetObjectAt(0);
2974 }
2975 }
2976
2977 if (!j && fBranchCount) {
2979 // Since reloading the index, will reset the ClonesArray, let's
2980 // skip the load if we already read this entry.
2981 if (entry != fBranchCount->GetReadEntry()) {
2982 fBranchCount->TBranch::GetEntry(entry);
2983 }
2985 fBranchCount2->TBranch::GetEntry(entry);
2986 }
2987 }
2988
2989 if (TestBit(kDecomposedObj)) {
2990 if (!fAddress) {
2991 return 0;
2992 }
2993 if ((fType == 3) || (fType == 4)) {
2994 // Top-level branch of a TClonesArray.
2995 return fNdata;
2996 } else if ((fType == 31) || (fType == 41)) {
2997 // sub branch of a TClonesArray
2999 if (atype < 20) {
3000 atype += 20;
3001 }
3002 return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
3003 } else if (fType <= 2) {
3004 // branch in split mode
3005 // FIXME: This should probably be < 60 instead!
3006 if ((fStreamerType > 40) && (fStreamerType < 55)) {
3007 Int_t atype = fStreamerType - 20;
3008 return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
3009 } else {
3010 return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
3011 }
3012 }
3013 }
3014
3015 if (object == nullptr)
3016 {
3017 // We have nowhere to read the data from (probably because the data member was
3018 // 'dropped' from the current schema).
3019 return 0;
3020 }
3021
3022 if (fType == 31) {
3023 TClonesArray* clones = (TClonesArray*) object;
3024 if (subarr) {
3026 }
3028 } else if (fType == 41) {
3031 {
3032 if (subarr)
3033 return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
3034
3035 return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
3036 }
3037 else
3038 {
3039 if (subarr)
3040 return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
3041 return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
3042 }
3043 } else {
3044 if (GetInfoImp()) {
3045 return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
3046 }
3047 return 0;
3048 }
3049}
3050
3051////////////////////////////////////////////////////////////////////////////////
3052/// Returns pointer to first data element of this branch.
3053/// Currently used only for members of type character.
3054
3056{
3058
3059 Int_t prID = fID;
3060 char *object = fObject;
3061 if (TestBit(kCache)) {
3062 if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
3063 prID = fID+1;
3064 } else if (fOnfileObject) {
3065 object = fOnfileObject->GetObjectAt(0);
3066 }
3067 }
3068
3069 if (fBranchCount) {
3071 fBranchCount->TBranch::GetEntry(entry);
3072 if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
3073 }
3074 if (TestBit(kDecomposedObj)) {
3075 if (!fAddress) {
3076 return nullptr;
3077 }
3078 if (fType == 3) { //top level branch of a TClonesArray
3079 //return &fNdata;
3080 return nullptr;
3081 } else if (fType == 4) { //top level branch of a TClonesArray
3082 //return &fNdata;
3083 return nullptr;
3084 } else if (fType == 31) { // sub branch of a TClonesArray
3085 //Int_t atype = fStreamerType;
3086 //if (atype < 20) atype += 20;
3087 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3088 return nullptr;
3089 } else if (fType == 41) { // sub branch of a TClonesArray
3090 //Int_t atype = fStreamerType;
3091 //if (atype < 20) atype += 20;
3092 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3093 return nullptr;
3094 } else if (fType <= 2) { // branch in split mode
3095 // FIXME: This should probably be < 60 instead!
3096 if (fStreamerType > 40 && fStreamerType < 55) {
3097 //Int_t atype = fStreamerType - 20;
3098 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3099 return nullptr;
3100 } else {
3101 //return GetInfoImp()->GetValue(object, fID, j, -1);
3102 return nullptr;
3103 }
3104 }
3105 }
3106
3107 if (fType == 31) {
3108 return nullptr;
3109 } else if (fType == 41) {
3110 return nullptr;
3111 } else if (prID < 0) {
3112 return object;
3113 } else {
3114 //return GetInfoImp()->GetValue(object,fID,j,-1);
3115 if (!GetInfoImp() || !object) return nullptr;
3116 char **val = (char**)(object+GetInfoImp()->TStreamerInfo::GetElementOffset(prID));
3117 return *val;
3118 }
3119}
3120
3121////////////////////////////////////////////////////////////////////////////////
3122/// Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a container sub-branch.
3123///
3124/// Note: The offsets are zero for data members so that when
3125/// SetAddress recursively sets their address, they will get the
3126/// same address as their containing class because i/o is based
3127/// on streamer info offsets from the address of the containing
3128/// class.
3129///
3130/// Offsets are non-zero for base-class sub-branches that are
3131/// not the leftmost direct base class. They are laid out in
3132/// memory sequentially and only the leftmost direct base class
3133/// has the same address as the derived class. The streamer
3134/// offsets need to be added to the address of the base class
3135/// subobject which is not the same as the address of the
3136/// derived class for the non-leftmost direct base classes.
3137
3139{
3141
3142 // See https://sft.its.cern.ch/jira/browse/ROOT-8742
3143 // and https://sft.its.cern.ch/jira/browse/ROOT-9253
3144 // As of commit e21b4f1a3b, removing this lock lead to a failure
3145 // in the test testSetAddress[Loop].
3146 // As of commit 4f8b237849, removing this lock does not lead to
3147 // a visible failure in test. This might be due to the underlying
3148 // problem (missing lock or ?) being solved somewhere else or some
3149 // other perturbation reducing the failure rate.
3150 // Having the lock here is not too costly as InitializeOffsets is
3151 // one called once in the lifetime of the TBranch.
3153
3154 if (fID < 0) {
3155 // -- We are a top-level branch. Let's mark whether we need to use MapObject.
3157 if (fBranchClass.GetClass()->IsTObject()) {
3159 } else {
3161 }
3162 }
3163 }
3164 if (nbranches) {
3165 // Allocate space for the new sub-branch offsets.
3166 delete[] fBranchOffset;
3167 fBranchOffset = nullptr;
3169 // Make sure we can instantiate our class meta info.
3170 if (!fBranchClass.GetClass()) {
3171 Warning("InitializeOffsets", "No branch class set for branch: %s", GetName());
3172 fInitOffsets = true;
3173 return;
3174 }
3175 // Make sure we can instantiate our class streamer info.
3176 if (!GetInfoImp()) {
3177 Warning("InitializeOffsets", "No streamer info available for branch: %s of class: %s", GetName(), fBranchClass.GetClass()->GetName());
3178 fInitOffsets = true;
3179 return;
3180 }
3181
3182 // Get the class we are a member of now (which is the
3183 // type of our containing subobject) and get our offset
3184 // inside of our containing subobject (our local offset).
3185 // Note: branchElem stays zero if we are a top-level branch,
3186 // we have to be careful about this later.
3187 TStreamerElement* branchElem = nullptr;
3188 Int_t localOffset = 0;
3190 bool renamed = false;
3191 if (fID > -1) {
3192 // -- Branch is *not* a top-level branch.
3193 // Instead of the streamer info class, we want the class of our
3194 // specific element in the streamer info. We could be a data
3195 // member of a base class or a split class, in which case our
3196 // streamer info will be for our containing sub-object, while
3197 // we are actually a different type.
3199 // Note: We tested to make sure the streamer info was available previously.
3200 if (!si->IsCompiled()) {
3201 Warning("InitializeOffsets", "Streamer info for branch: %s has no elements array!", GetName());
3202 fInitOffsets = true;
3203 return;
3204 }
3205 // FIXME: Check that fID is in range.
3206 branchElem = si->GetElement(fID);
3207 if (!branchElem) {
3208 Warning("InitializeOffsets", "Cannot get streamer element for branch: %s!", GetName());
3209 fInitOffsets = true;
3210 return;
3211 } else if (branchElem->TestBit(TStreamerElement::kRepeat)) {
3212 // If we have a repeating streamerElement, use the next
3213 // one as it actually hold the 'real' data member('s offset)
3214 if (si->GetElement(fID+1)) {
3215 branchElem = si->GetElement(fID+1);
3216 }
3217 }
3218 localOffset = branchElem->GetOffset();
3219 branchClass = branchElem->GetClassPointer();
3221 fObject = nullptr;
3222 } else {
3223 renamed = branchClass && branchElem->GetNewClass() && (branchClass != branchElem->GetNewClass());
3224 }
3225 } else {
3227 }
3228 if (!branchClass) {
3229 Error("InitializeOffsets", "Could not find class for branch: %s", GetName());
3230 fInitOffsets = true;
3231 return;
3232 }
3233
3234 //------------------------------------------------------------------------
3235 // Extract the name of the STL branch in case it has been split.
3236 //////////////////////////////////////////////////////////////////////////
3237
3239 bool stlParentNameUpdated = false;
3240 if( fType == 4 )
3241 {
3242 TBranch *br = GetMother()->GetSubBranch( this );
3243 stlParentName = br->GetName();
3245
3246 // We may ourself contain the 'Mother' branch name.
3247 // To avoid code duplication, we delegate the removal
3248 // of the mother's name to the first sub-branch loop.
3249 }
3250
3251 // Loop over our sub-branches and compute their offsets.
3253 bool alternateElement = false;
3254
3257 if (subBranch == nullptr) {
3258 // -- Skip sub-branches that are not TBranchElements.
3259 continue;
3260 }
3261
3262 if (renamed) {
3263 if (subBranch->fBranchClass == branchClass) {
3264 if (branchElem) subBranch->SetTargetClass(branchElem->GetNewClass()->GetName());
3265 else subBranch->SetTargetClass(fTargetClass->GetName());
3266 }
3267 }
3268
3269 TVirtualStreamerInfo* sinfo = subBranch->GetInfoImp();
3270 if (!sinfo) {
3271 Warning("InitializeOffsets", "No streamer info for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3273 continue;
3274 }
3275 if (!sinfo->IsCompiled()) {
3276 Warning("InitializeOffsets", "No elements array for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3278 continue;
3279 }
3280 // FIXME: Make sure subBranch->fID is in range.
3281 TStreamerElement* subBranchElement = sinfo->GetElement(subBranch->fID);
3282 if (!subBranchElement) {
3283 Warning("InitializeOffsets", "No streamer element for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3285 continue;
3286 } else if (subBranchElement->TestBit(TStreamerElement::kRepeat)) {
3287 // If we have a repeating streamerElement, use the next
3288 // one as it actually hold the 'real' data member('s offset)
3289 if (sinfo->GetElement(subBranch->fID+1)) {
3290 subBranchElement = sinfo->GetElement(subBranch->fID+1);
3291 }
3292 } else if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3293 // We have a cached item which is not a repeated but we might still
3294 // have some Actions triggered by a rule that affect real
3295 // data member(s).
3296 if (subBranch->fReadActionSequence && subBranch->fReadActionSequence->fActions.size() > 1) {
3297 typedef TStreamerInfoActions::ActionContainer_t::iterator iterator;
3298 iterator end = subBranch->fReadActionSequence->fActions.end();
3299 for(iterator iter = subBranch->fReadActionSequence->fActions.begin();
3300 iter != end; ++iter) {
3301 TStreamerInfoActions::TConfiguration *config = iter->fConfiguration;
3302 UInt_t id = config->fElemId;
3303 TStreamerElement *e = (TStreamerElement*)config->fInfo->GetElements()->At(id);
3304 if (e && !e->TestBit(TStreamerElement::kCache)) {
3306 alternateElement = true;
3307 break;
3308 }
3309 }
3310 }
3311 }
3312
3313 localOffset = subBranchElement->GetOffset();
3315 subBranch->fObject = nullptr;
3316 }
3317 {
3318 Int_t streamerType = subBranchElement->GetType();
3320 && subBranch->GetListOfBranches()->GetEntriesFast()==0
3321 && CanSelfReference(subBranchElement->GetClass()))
3322 {
3323 subBranch->SetBit(kBranchAny);
3324 } else {
3325 subBranch->ResetBit(kBranchAny);
3326 }
3327 }
3328
3329 if (subBranchElement->GetNewType()<0) {
3330 subBranch->ResetBit(kBranchAny);
3331 subBranch->ResetBit(kBranchObject);
3332 }
3333
3334 // Note: This call is expensive, do it only once.
3336 if (!mother) {
3337 Warning("InitializeOffsets", "Branch '%s' has no mother!", GetName());
3339 continue;
3340 }
3341 TString motherName(mother->GetName());
3342 bool motherDot = false;
3343 if (motherName.Length() && strchr(motherName.Data(), '.')) {
3344 motherDot = true;
3345 }
3346 bool motherDotAtEnd = false;
3347 if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
3348 motherDotAtEnd = true;
3349 }
3350
3351 bool isBaseSubBranch = false;
3352 if ((subBranch->fType == 1) || (subBranchElement && subBranchElement->IsBase())) {
3353 // -- Base class sub-branch (1).
3354 //
3355 // Note: Our type will not be 1, even though we are
3356 // a base class branch, if we are not split (see the
3357 // constructor), or if we are an STL container master
3358 // branch and a base class branch at the same time
3359 // or an std::string.
3360 isBaseSubBranch = true;
3361 }
3362
3363 bool isContDataMember = false;
3364 if ((subBranch->fType == 31) || (subBranch->fType == 41)) {
3365 // -- Container data member sub-branch (31 or 41).
3366 isContDataMember = true;
3367 }
3368
3369 // I am either a data member sub-branch (0), or a base class
3370 // sub-branch (1), or TClonesArray master sub-branch (3),
3371 // or an STL container master sub-branch (4), or TClonesArray
3372 // data member sub-branch (31), or an STL container data member
3373 // sub-branch (41).
3374 //
3375 // My parent branch is either a top-level branch ((0), fID==(-2,-1)),
3376 // or a base class sub-branch (1), or a split-class branch (2),
3377 // or a TClonesArray master branch (3), or an STL container
3378 // master branch (4).
3379 //
3380
3381 //
3382 // We need to extract from our name the name
3383 // of the data member which contains us, so
3384 // that we may then do a by-name lookup in the
3385 // dictionary meta info of our parent class to
3386 // get our offset in our parent class.
3387 //
3388
3389 // Get our name.
3390 TString dataName(subBranch->GetName());
3391 if (motherDotAtEnd) {
3392 // -- Remove the top-level branch name from our name.
3393 dataName.Remove(0, motherName.Length());
3394 // stlParentNameUpdated is false the first time in this loop.
3395 if (!stlParentNameUpdated && stlParentName.Length()) {
3396 stlParentName.Remove(0, motherName.Length());
3397 stlParentNameUpdated = true;
3398 }
3399 } else if (motherDot) {
3400 // -- Remove the top-level branch name from our name, folder case.
3401 //
3402 // Note: We are in the case where our mother was created
3403 // by the branch constructor which takes a folder
3404 // as an argument. The mother branch has internal
3405 // dots in its name to represent the folder hierarchy.
3406 // The TTree::Bronch() routine has handled us as a
3407 // special case, we must compensate.
3408 if ((fID < 0) && (subBranchElement->IsA() == TStreamerBase::Class())) {
3409 // -- Our name is the mother name, remove it.
3410 // Note: The test is our parent is a top-level branch
3411 // and our streamer is the base class streamer,
3412 // this matches the exact test in TTree::Bronch().
3413 if (dataName.Length() == motherName.Length()) {
3414 dataName.Remove(0, motherName.Length());
3415 // stlParentNameUpdated is false the first time in this loop.
3416 if (!stlParentNameUpdated && stlParentName.Length()) {
3417 stlParentName.Remove(0, motherName.Length());
3418 }
3419 }
3420 } else {
3421 // -- Remove the mother name and the dot.
3422 if (dataName.Length() > motherName.Length()) {
3423 dataName.Remove(0, motherName.Length() + 1);
3424 if (!stlParentNameUpdated && stlParentName.Length()) {
3425 stlParentName.Remove(0, motherName.Length());
3426 }
3427 }
3428 }
3429 }
3430 stlParentNameUpdated = true;
3431 if (isBaseSubBranch) {
3432 // -- Remove the base class name suffix from our name.
3433 // Note: The pattern is the name of the base class.
3434 TString pattern(subBranchElement->GetName());
3435 if (pattern.Length() <= dataName.Length()) {
3436 if (!strcmp(dataName.Data() + (dataName.Length() - pattern.Length()), pattern.Data())) {
3437 // The branch name contains the name of the base class in it.
3438 // This name is not reproduced in the sub-branches, so we need to
3439 // remove it.
3440 dataName.Remove(dataName.Length() - pattern.Length());
3441 }
3442 }
3443 // Remove any leading dot.
3444 if (dataName.Length()) {
3445 if (dataName[0] == '.') {
3446 dataName.Remove(0, 1);
3447 }
3448 }
3449 // Note: We intentionally leave any trailing dot
3450 // in our modified name here.
3451 }
3452
3453 // Get our parent branch's name.
3455 if (motherDotAtEnd) {
3456 // -- Remove the top-level branch name from our parent's name.
3457 parentName.Remove(0, motherName.Length());
3458 } else if (motherDot) {
3459 // -- Remove the top-level branch name from our parent's name, folder case.
3460 //
3461 // Note: We are in the case where our mother was created
3462 // by the branch constructor which takes a folder
3463 // as an argument. The mother branch has internal
3464 // dots in its name to represent the folder hierarchy.
3465 // The TTree::Bronch() routine has handled us as a
3466 // special case, we must compensate.
3467 if ((fID > -1) && (mother == mother->GetSubBranch(this)) && (branchElem->IsA() == TStreamerBase::Class())) {
3468 // -- Our parent's name is the mother name, remove it.
3469 // Note: The test is our parent's parent is a top-level branch
3470 // and our parent's streamer is the base class streamer,
3471 // this matches the exact test in TTree::Bronch().
3472 if (parentName.Length() == motherName.Length()) {
3473 parentName.Remove(0, motherName.Length());
3474 }
3475 } else {
3476 // -- Remove the mother name and the dot.
3477 if (parentName.Length() > motherName.Length()) {
3478 parentName.Remove(0, motherName.Length() + 1);
3479 }
3480 }
3481 }
3482 // FIXME: Do we need to use the other tests for a base class here?
3483 if (fType == 1) {
3484 // -- Our parent is a base class sub-branch, remove the base class name suffix from its name.
3485 if (mother != mother->GetSubBranch(this)) {
3486 // -- My parent's parent is not a top-level branch.
3487 // Remove the base class name suffix from the parent name.
3488 // Note: The pattern is the name of the base class.
3489 // coverity[var_deref_model] branchElem is non zero here since fType==1 and thus fID > -1
3490 TString pattern(branchElem->GetName());
3491 if (pattern.Length() <= parentName.Length()) {
3492 if (!strcmp(parentName.Data() + (parentName.Length() - pattern.Length()), pattern.Data())) {
3493 // The branch name contains the name of the base class in it.
3494 // This name is not reproduced in the sub-branches, so we need to
3495 // remove it.
3496 parentName.Remove(parentName.Length() - pattern.Length());
3497 }
3498 }
3499 }
3500 // Note: We intentionally leave any trailing dots
3501 // in the modified parent name here.
3502 }
3503
3504 // Remove the parent branch name part from our name,
3505 // but only if the parent branch is not a top-level branch.
3506 // FIXME: We should not assume parent name does not have length 0.
3507 if (fID > -1) {
3509 }
3510
3511 // Remove any leading dot.
3512 if (dataName.Length()) {
3513 if (dataName[0] == '.') {
3514 dataName.Remove(0, 1);
3515 }
3516 }
3517
3518 // Remove any trailing dot.
3519 if (dataName.Length()) {
3520 if (dataName[dataName.Length()-1] == '.') {
3521 dataName.Remove(dataName.Length() - 1, 1);
3522 }
3523 }
3524
3525 //
3526 // Now that we have our data member name, find our offset
3527 // in our parent class.
3528 //
3529 // Note: Our data member name can have many dots in it
3530 // if branches were elided between our parent branch
3531 // and us by Unroll().
3532 //
3533 // FIXME: This may not work if our member name is ambiguous.
3534 //
3535
3536 Int_t offset = 0;
3537 if (dataName.Length()) {
3538 // -- We have our data member name, do a lookup in the dictionary meta info of our parent class.
3539 // Get our parent class.
3540 TClass* pClass = nullptr;
3541 // First check whether this sub-branch is part of the 'cache' (because the data member it
3542 // represents is no longer in the current class layout.
3543 TStreamerInfo *subInfo = subBranch->GetInfoImp();
3544 //if (subInfo && subBranch->TestBit(kCache)) { // subInfo->GetElements()->At(subBranch->GetID())->TestBit(TStreamerElement::kCache)) {
3546 pClass = ((TStreamerElement*)subInfo->GetElements()->At(0))->GetClassPointer();
3547 }
3548 // FIXME: Do we need the other base class tests here?
3549 if (!pClass) {
3550 if (fType == 1) {
3551 // -- Parent branch is a base class branch.
3552 // FIXME: Is using branchElem here the right thing?
3553 pClass = branchElem->GetClassPointer();
3554 if (pClass->Property() & kIsAbstract) {
3555 // the class is abstract, let see if the
3556
3558 if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
3559 // Our parent's class is emulated and we represent an abstract class.
3560 // and the target class has not been set explicitly.
3561 TString target = pClass->GetName();
3562 target += "@@emulated";
3563
3565 }
3566 }
3567 } else {
3568 // -- Parent branch is *not* a base class branch.
3569 // FIXME: This sometimes returns a null pointer.
3570 pClass = subBranch->GetParentClass();
3571 }
3572 }
3573 if (!pClass) {
3574 // -- No parent class, fix it.
3575 // FIXME: This is probably wrong!
3576 // Assume parent class is our parent branch's clones class or value class.
3577 if (GetClonesName() && strlen(GetClonesName())) {
3579 if (!pClass) {
3580 Warning("InitializeOffsets", "subBranch: '%s' has no parent class, and cannot get class for clones class: '%s'!", subBranch->GetName(), GetClonesName());
3582 continue;
3583 }
3584 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3585 }
3588 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass ? pClass->GetName() : "unknown class");
3589 }
3590 if (!pClass) {
3591 // -- Still no parent class, assume our parent class is our parent branch's class.
3592 // FIXME: This is probably wrong!
3594 // FIXME: Enable this warning!
3595 //Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3596 }
3597 }
3598 if (renamed && pClass) {
3599 if (pClass == branchClass) {
3600 pClass = branchElem->GetNewClass();
3601 } else if (fCollProxy && pClass == branchClass->GetCollectionProxy()->GetValueClass()) {
3603 }
3604 }
3605
3606 //------------------------------------------------------------------
3607 // If we have the are the sub-branch of the TBranchSTL, we need
3608 // to remove it's name to get the correct real data offsets
3609 ////////////////////////////////////////////////////////////////////
3610
3611 const bool isToplevelCollection = (this == GetMother() && (fType == 3 || fType == 4));
3612 if( stlParentName.Length() && (dynamic_cast<TBranchSTL*>(fParent) || isToplevelCollection))
3613 {
3614 if( !strncmp( stlParentName.Data(), dataName.Data(), stlParentName.Length()-1 )
3615 && dataName[ stlParentName.Length() ] == '.' )
3616 dataName.Remove( 0, stlParentName.Length()+1 );
3617 }
3618
3619 // Find our offset in our parent class using
3620 // a lookup by name in the dictionary meta info
3621 // for our parent class.
3622
3623 if (alternateElement) {
3624 Ssiz_t dotpos = dataName.Last('.');
3625 Ssiz_t endpos = dataName.Length();
3626 if (dotpos != kNPOS) ++dotpos; else dotpos = 0;
3627 dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
3628 }
3629 TRealData* rd = pClass->GetRealData(dataName);
3630 if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
3631 // -- Data member exists in the dictionary meta info, get the offset.
3632 // If we are using an alternateElement, it is the target of a rule
3633 // and might be indeed transient.
3634 offset = rd->GetThisOffset();
3635 } else if (subBranchElement->TestBit(TStreamerElement::kWholeObject)) {
3636 // We are a rule with no specific target, it applies to the whole
3637 // object, let's set the offset to zero
3638 offset = 0;
3639 } else {
3640 // -- No dictionary meta info for this data member, it must no
3641 // longer exist
3642 if (fEntries == 0) {
3643 // ... unless we creating the branch in which case
3644 // we have an internal error.
3645 if (pClass->GetListOfRealData()->GetEntries() == 0) {
3646 // We are probably missing the ShowMember, let's
3647 // just issue an error.
3648 Error("InitializeOffsets",
3649 "Could not find the real data member '%s' when constructing the branch '%s' [Likely missing ShowMember].",
3650 dataName.Data(),GetName());
3651 } else if (subInfo && subInfo->GetClassVersion()!=subInfo->GetClass()->GetClassVersion()) {
3652 // In the case where we are cloning a TTree that was created with an older version of the layout, we may not
3653 // able to find all the members
3654 Info("InitializeOffsets",
3655 "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'. ",
3656 dataName.Data(),GetName());
3657 } else {
3658 // Something really bad happen.
3659 Fatal("InitializeOffsets",
3660 "Could not find the real data member '%s' when constructing the branch '%s' [Likely an internal error, please report to the developers].",
3661 dataName.Data(),GetName());
3662 }
3663 }
3665 }
3666 } else {
3667 // -- We have no data member name, ok for a base class, not good otherwise.
3668 if (isBaseSubBranch) {
3669 // I am a direct base class of my parent class, my local offset is enough.
3670 } else {
3671 Warning("InitializeOffsets", "Could not find the data member name for branch '%s' with parent branch '%s', assuming offset is zero!", subBranch->GetName(), GetName());
3672 }
3673 }
3674
3675 //
3676 // Ok, do final calculations for fOffset and fBranchOffset.
3677 //
3678
3679 if (isContDataMember) {
3680 // -- Container data members set fOffset instead of fBranchOffset.
3681 // The fOffset is what should be added to the start of the entry
3682 // in the collection (i.e., its current absolute address) to find
3683 // the beginning of the data member described by the current branch.
3684 //
3685 // Compensate for the i/o routines adding our local offset later.
3686 if (subBranch->fObject == nullptr && localOffset == TStreamerInfo::kMissing) {
3687 subBranch->SetMissing();
3688 // We stil need to set fBranchOffset in the case of a missing
3689 // element so that SetAddress is (as expected) not called
3690 // recursively in this case.
3692 } else {
3693 if (isBaseSubBranch) {
3694 // The value of 'offset' for a base class does not include its
3695 // 'localOffset'.
3696 subBranch->SetOffset(offset);
3697 } else {
3698 // The value of 'offset' for a regular data member does include its
3699 // 'localOffset', we need to remove it explicitly.
3700 subBranch->SetOffset(offset - localOffset);
3701 }
3702 }
3703 } else {
3704 // -- Set fBranchOffset for sub-branch.
3705 Int_t isSplit = 0 != subBranch->GetListOfBranches()->GetEntriesFast();
3706 if (subBranch->fObject == nullptr && localOffset == TStreamerInfo::kMissing) {
3707 // The branch is missing
3709
3710 } else if (isSplit) {
3711 if (isBaseSubBranch) {
3712 // We are split, so we need to add in our local offset
3713 // to get our absolute address for our children.
3715 } else {
3716 // We are split so our offset will never be
3717 // used in an i/o, so we do not have to subtract
3718 // off our local offset like below.
3720 }
3721 } else {
3722 if (isBaseSubBranch) {
3723 // We are not split, so our local offset will be
3724 // added later by the i/o routines.
3726 } else {
3727 // Compensate for the fact that the i/o routines
3728 // are going to add my local offset later.
3730 }
3731 }
3732 }
3733 }
3734 }
3735 else {
3736 if (fID > -1) {
3737 // Branch is *not* a top-level branch.
3738 // Let's check if the target member is still present in memory
3740 fObject = nullptr;
3741 }
3742 }
3743 }
3744 const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
3746 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3747 auto index = parent->fBranches.IndexOf(this);
3748 if (index >= 0) {
3750 }
3751 }
3752
3753 fInitOffsets = true;
3754}
3755
3756////////////////////////////////////////////////////////////////////////////////
3757/// Return true if more than one leaf, false otherwise.
3758
3760{
3762 if (nbranches >= 1) {
3763 return true;
3764 }
3765 TList* browsables = const_cast<TBranchElement*>(this)->GetBrowsables();
3766 return browsables && browsables->GetSize();
3767}
3768
3769////////////////////////////////////////////////////////////////////////////////
3770/// Detect a collection written using a zero pointer in old versions of root.
3771/// In versions of ROOT older than 4.00/03, if a collection (TClonesArray
3772/// or STL container) was split but the pointer to the collection was zeroed
3773/// out, nothing was saved. Hence there is no __easy__ way to detect the
3774/// case. In newer versions, a zero is written so that a 'missing' collection
3775/// appears to be an empty collection.
3776
3778{
3779 bool ismissing = false;
3781 if (basket && fTree) {
3784 Long64_t last;
3785 if (fReadBasket == fWriteBasket) {
3786 last = fEntryNumber - 1;
3787 } else {
3788 last = fBasketEntry[fReadBasket+1] - 1;
3789 }
3790 Int_t* entryOffset = basket->GetEntryOffset();
3792 Int_t bufnext;
3793 if (entryOffset) {
3794 bufbegin = entryOffset[entry-first];
3795
3796 if (entry < last) {
3797 bufnext = entryOffset[entry+1-first];
3798 } else {
3799 bufnext = basket->GetLast();
3800 }
3801 if (bufnext == bufbegin) {
3802 ismissing = true;
3803 } else {
3804 // fixed length buffer so this is not the case here.
3805 if (basket->GetNevBufSize() == 0) {
3806 ismissing = true;
3807 }
3808 }
3809 }
3810 }
3811 return ismissing;
3812}
3813
3814////////////////////////////////////////////////////////////////////////////////
3815/// Print branch parameters.
3816
3818{
3819 for(auto &cursor : ids) {
3820 auto id = cursor.fElemID;
3821 if (id >= 0) {
3822 auto el = info->GetElement(id);
3823 if (el)
3824 el->ls();
3825 else {
3826 Error("TBranchElement::Print", "Element for id #%d not found in StreamerInfo for %s",
3827 id, info->GetName());
3828 info->ls();
3829 }
3830 } else if (cursor.fNestedIDs) {
3831 Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
3832 PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
3833 }
3834 }
3835}
3836
3838{
3839 constexpr auto length = std::char_traits<char>::length;
3841 if (strncmp(option,"debugAddress",length("debugAddress"))==0) {
3842 if (strlen(option)==length("debugAddress")) {
3843 Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s %s\n",
3844 "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject", "fOnfileObject");
3845 }
3846 if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3847 else Printf("%-24s ", GetName());
3848
3849 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3850 Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3851 TVirtualStreamerInfo *info = ((TBranchElement*)this)->GetInfoImp();
3852
3853 Printf("%-16s %2d %4d %-16s %-16s %8x %8x %p %p%s\n",
3854 info ? info->GetName() : "StreamerInfo unavailable", GetID(), GetType(),
3856 (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3857 GetOffset(), GetObject(), fOnfileObject, TestBit(kOwnOnfileObj) ? " (owned)" : "");
3858 for (Int_t i = 0; i < nbranches; ++i) {
3860 subbranch->Print("debugAddressSub");
3861 }
3862 return;
3863 }
3864 if (strncmp(option,"debugInfo",length("debugInfo"))==0) {
3865 Printf("Branch %s uses:",GetName());
3866 if (fID>=0) {
3867 // GetInfoImp()->GetElement(fID)->ls();
3868 // for(UInt_t i=0; i< fIDs.size(); ++i) {
3869 // GetInfoImp()->GetElement(fIDs[i])->ls();
3870 // }
3872 if (fType == 3 || fType == 4) {
3873 // Search for the correct version.
3875 }
3876 Printf(" With elements:");
3877 if (fType != 3 && fType != 4)
3878 localInfo->GetElement(fID)->ls();
3880 Printf(" with read actions:");
3882 Printf(" with write actions:");
3884 } else if (!fNewIDs.empty() && GetInfoImp()) {
3886 if (fType == 3 || fType == 4) {
3887 // Search for the correct version.
3889 }
3891 Printf(" with read actions:");
3893 Printf(" with write actions:");
3895 }
3896 TString suboption = "debugInfoSub";
3897 suboption += (option+length("debugInfo"));
3898 for (Int_t i = 0; i < nbranches; ++i) {
3900 subbranch->Print(suboption);
3901 }
3902 Printf(" ");
3903 return;
3904 }
3905 if (nbranches) {
3906 if (fID == -2) {
3907 if (strcmp(GetName(),GetTitle()) == 0) {
3908 Printf("*Branch :%-66s *",GetName());
3909 } else {
3910 Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3911 }
3912 Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3913 Printf("*............................................................................*");
3914 }
3915 if (fType >= 2) {
3917 }
3918 for (Int_t i=0;i<nbranches;i++) {
3920 branch->Print(option);
3921 }
3922 } else {
3924 }
3925}
3926
3927////////////////////////////////////////////////////////////////////////////////
3928/// Prints values of leaves.
3929
3931{
3933
3935 Int_t prID = fID;
3936 char *object = fObject;
3937 if (TestBit(kCache)) {
3938 if (info->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
3939 prID = fID+1;
3940 } else if (fOnfileObject) {
3941 object = fOnfileObject->GetObjectAt(0);
3942 }
3943 }
3944
3945 if (TestBit(kDecomposedObj)) {
3946 if (!fAddress) {
3947 return;
3948 }
3949 if (fType == 3 || fType == 4) {
3950 // TClonesArray or STL container top-level branch.
3951 printf(" %-15s = %d\n", GetName(), fNdata);
3952 return;
3953 } else if (fType == 31 || fType == 41) {
3954 // TClonesArray or STL container sub-branch.
3955 Int_t n = TMath::Min(10, fNdata);
3958 // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
3959 // printed as a string and could print weird characters.
3960 // So we print an unsigned char instead (not perfect, but better).
3962 }
3963 if (atype > 54) {
3964 // FIXME: More logic required here (like in ReadLeaves)
3965 printf(" %-15s = %d\n", GetName(), fNdata);
3966 return;
3967 }
3968 if (fStreamerType > 20) {
3969 atype -= 20;
3971 n = n * leaf->GetLenStatic();
3972 }
3973 if (GetInfoImp()) {
3975 }
3976 return;
3977 } else if (fType <= 2) {
3978 // Branch in split mode.
3979 // FIXME: This should probably be < 60 instead.
3980 if ((fStreamerType > 40) && (fStreamerType < 55)) {
3981 Int_t atype = fStreamerType - 20;
3983 Int_t n = (Int_t) counterElement->GetValue(0, 0);
3984 if (GetInfoImp()) {
3986 }
3987 } else {
3988 if (GetInfoImp()) {
3989 GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3990 }
3991 }
3992 return;
3993 }
3994 } else if (fType == 3) {
3995 printf(" %-15s = %d\n", GetName(), fNdata);
3996 } else if (fType == 31) {
3997 TClonesArray* clones = (TClonesArray*) object;
3998 if (GetInfoImp()) {
4000 }
4001 } else if (fType == 41) {
4003 if (GetInfoImp()) {
4005 }
4006 } else {
4007 if (GetInfoImp()) {
4008 GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
4009 }
4010 }
4011}
4012
4013////////////////////////////////////////////////////////////////////////////////
4014/// Unconfiguration Read Leave function.
4015
4017{
4018 Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
4019}
4020
4021////////////////////////////////////////////////////////////////////////////////
4022/// Read leaves into i/o buffers for this branch.
4023/// For the case where the branch is set in MakeClass mode (decomposed object).
4024
4026{
4028
4029 if (fType == 3 || fType == 4) {
4030 // Top level branch of a TClonesArray.
4031 Int_t *n = (Int_t*) fAddress;
4032 b >> n[0];
4033 if ((n[0] < 0) || (n[0] > fMaximum)) {
4034 if (IsMissingCollection()) {
4035 n[0] = 0;
4036 b.SetBufferOffset(b.Length() - sizeof(n));
4037 } else {
4038 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());
4039 n[0] = 0;
4040 }
4041 }
4042 fNdata = n[0];
4043 if (fType == 4) {
4045 switch(fSTLtype) {
4046 case ROOT::kSTLset:
4047 case ROOT::kSTLmultiset:
4048 case ROOT::kSTLmap:
4049 case ROOT::kSTLmultimap:
4050 for (Int_t i=0; i<nbranches; i++) {
4052 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4053 if (nb < 0) {
4054 break;
4055 }
4056 }
4057 break;
4058 default:
4059 break;
4060 }
4061 }
4062 return;
4063 } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
4066 // FIXME: This should probably be > 59 instead.
4067 if (atype > 54) return;
4068 if (!fAddress) {
4069 return;
4070 }
4071 Int_t n = fNdata;
4072 if (atype>40) {
4073 atype -= 40;
4074 if (!fBranchCount2) return;
4075 const char *len_where = (char*)fBranchCount2->fAddress;
4076 if (!len_where) return;
4078 Int_t length;
4079 Int_t k;
4081 for( k=0; k<n; k++) {
4082 char **where = &(((char**)fAddress)[k]);
4083 delete [] *where;
4084 *where = nullptr;
4085 switch(len_atype) {
4086 case 1: {length = ((Char_t*) len_where)[k]; break;}
4087 case 2: {length = ((Short_t*) len_where)[k]; break;}
4088 case 3: {length = ((Int_t*) len_where)[k]; break;}
4089 case 4: {length = ((Long_t*) len_where)[k]; break;}
4090 //case 5: {length = ((Float_t*) len_where)[k]; break;}
4091 case 6: {length = ((Int_t*) len_where)[k]; break;}
4092 //case 8: {length = ((Double_t*)len_where)[k]; break;}
4093 case 11: {length = ((UChar_t*) len_where)[k]; break;}
4094 case 12: {length = ((UShort_t*) len_where)[k]; break;}
4095 case 13: {length = ((UInt_t*) len_where)[k]; break;}
4096 case 14: {length = ((ULong_t*) len_where)[k]; break;}
4097 case 15: {length = ((UInt_t*) len_where)[k]; break;}
4098 case 16: {length = ((Long64_t*) len_where)[k]; break;}
4099 case 17: {length = ((ULong64_t*)len_where)[k]; break;}
4100 case 18: {length = ((bool*) len_where)[k]; break;}
4101 default: continue;
4102 }
4103 b >> isArray;
4104 if (length <= 0) continue;
4105 if (isArray == 0) continue;
4106 switch (atype) {
4107 case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
4108 case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
4109 case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4110 case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
4111 case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
4112 case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4113 case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
4114 case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
4115 case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
4116 case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4117 case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
4118 case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4119 case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
4120 case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
4121 case 18: {*where=new char[sizeof(bool)*length]; b.ReadFastArray((bool*) *where, length); break;}
4122 }
4123 }
4124 return;
4125 }
4126 if (atype > 20) {
4127 atype -= 20;
4129 n *= leaf->GetLenStatic();
4130 }
4131 switch (atype) {
4132 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4133 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4134 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4135 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4136 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4137 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4138 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4139 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4140 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4141 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4142 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4143 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4144 case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
4145 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4146 case 18: {b.ReadFastArray((bool*) fAddress, n); break;}
4147 case 9: {
4149 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4151 for (Int_t ii=0;ii<n;ii++) {
4152 b.ReadDouble32(&(xx[ii]),se);
4153 }
4154 break;
4155 }
4156 case 19: {
4158 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4159 Float_t *xx = (Float_t*) fAddress;
4160 for (Int_t ii=0;ii<n;ii++) {
4161 b.ReadFloat16(&(xx[ii]),se);
4162 }
4163 break;
4164 }
4165 }
4166 return;
4167 } else if (fType <= 2) { // branch in split mode
4168 // FIXME: This should probably be < 60 instead.
4169 if (fStreamerType > 40 && fStreamerType < 55) {
4170 Int_t atype = fStreamerType - 40;
4171 Int_t n;
4172 if (fBranchCount==nullptr) {
4173 // Missing fBranchCount. let's attempts to recover.
4174
4176 Ssiz_t dot = countname.Last('.');
4177 if (dot>=0) {
4178 countname.Remove(dot+1);
4179 } else {
4180 countname = "";
4181 }
4182 TString counter( GetTitle() );
4183 Ssiz_t loc = counter.Last('[');
4184 if (loc>=0) {
4185 counter.Remove(0,loc+1);
4186 }
4187 loc = counter.Last(']');
4188 if (loc>=0) {
4189 counter.Remove(loc);
4190 }
4191 countname += counter;
4193 }
4194 if (fBranchCount) {
4195 n = (Int_t)fBranchCount->GetValue(0,0);
4196 } else {
4197 Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4198 n = 0;
4199 }
4200 fNdata = n;
4202 b >> isArray;
4203 switch (atype) {
4204 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4205 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4206 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4207 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4208 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4209 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4210 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4211 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4212 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4213 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4214 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4215 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4216 case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
4217 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4218 case 18: {b.ReadFastArray((bool*) fAddress, n); break;}
4219 case 9: {
4221 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4223 for (Int_t ii=0;ii<n;ii++) {
4224 b.ReadDouble32(&(xx[ii]),se);
4225 }
4226 break;
4227 }
4228 case 19: {
4230 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4231 Float_t *xx = (Float_t*) fAddress;
4232 for (Int_t ii=0;ii<n;ii++) {
4233 b.ReadFloat16(&(xx[ii]),se);
4234 }
4235 break;
4236 }
4237 }
4238 } else {
4239 fNdata = 1;
4240 if (fAddress) {
4241 if (fType<0) {
4242 // Non TObject, Non collection classes with a custom streamer.
4243
4244 // if (fObject)
4246 } else {
4248 if (!info) {
4249 return;
4250 }
4251 // Since info is not null, fReadActionSequence is not null either.
4252 b.ApplySequence(*fReadActionSequence, fObject);
4253 }
4255 fNdata = (Int_t) GetValue(0, 0);
4256 }
4257 } else {
4258 fNdata = 0;
4259 }
4260 }
4261 return;
4262 }
4263}
4264
4265////////////////////////////////////////////////////////////////////////////////
4266/// Read leaves into i/o buffers for this branch.
4267/// Case of a collection (fType == 4).
4268
4270{
4272 if (fObject == nullptr)
4273 {
4274 // We have nowhere to copy the data (probably because the data member was
4275 // 'dropped' from the current schema) so let's no copy it in a random place.
4276 return;
4277 }
4278
4279 // STL container master branch (has only the number of elements).
4280 Int_t n;
4281 b >> n;
4282 if ((n < 0) || (n > fMaximum)) {
4283 if (IsMissingCollection()) {
4284 n = 0;
4285 b.SetBufferOffset(b.Length()-sizeof(n));
4286 } else {
4287 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());
4288 n = 0;
4289 }
4290 }
4291 fNdata = n;
4292
4293 R__PushCache onfileObject(b, fOnfileObject, 1);
4294
4295 // Note: Proxy-helper needs to "embrace" the entire
4296 // streaming of this STL container if the container
4297 // is a set/multiset/map/multimap (what we do not
4298 // know here).
4299 // For vector/list/deque Allocate == Resize
4300 // and Commit == noop.
4301 // TODO: Exception safety a la TPushPop
4304 void* alternate = proxy->Allocate(fNdata, true);
4307 } else {
4309 }
4310
4312 switch (fSTLtype) {
4313 case ROOT::kSTLset:
4316 case ROOT::kSTLmultiset:
4317 case ROOT::kSTLmap:
4318 case ROOT::kSTLmultimap:
4321 for (Int_t i = 0; i < nbranches; ++i) {
4323 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4324 if (nb < 0) {
4325 // Give up on i/o failure.
4326 // FIXME: We need an error message here.
4327 break;
4328 }
4329 }
4330 break;
4331 default:
4332 break;
4333 }
4334 //------------------------------------------------------------------------
4335 // We have split this stuff, so we need to create the pointers
4336 /////////////////////////////////////////////////////////////////////////////
4337
4338 if( proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers )
4339 {
4340 TClass *elClass = proxy->GetValueClass();
4341
4342 //--------------------------------------------------------------------
4343 // The allocation is done in this strange way because ReadLeaves
4344 // is being called many times by TTreeFormula!!!
4345 //////////////////////////////////////////////////////////////////////////
4346
4347 Int_t i = 0;
4348 // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4349 if( !fNdata || *(void**)proxy->At( 0 ) != nullptr )
4350 i = fNdata;
4351
4352 for( ; i < fNdata; ++i )
4353 {
4354 void **el = (void**)proxy->At( i );
4355 // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4356 *el = elClass->New();
4357 }
4358 }
4359
4360 proxy->Commit(alternate);
4361}
4362
4363////////////////////////////////////////////////////////////////////////////////
4364/// Read leaves into i/o buffers for this branch.
4365/// Case of a data member within a collection (fType == 41).
4366
4368{
4370 if (fObject == nullptr)
4371 {
4372 // We have nowhere to copy the data (probably because the data member was
4373 // 'dropped' from the current schema) so let's no copy it in a random place.
4374 return;
4375 }
4376
4377 // STL container sub-branch (contains the elements).
4379 if (!fNdata) {
4380 return;
4381 }
4382
4383 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4384
4386 if (info == nullptr) return;
4387
4390
4391 // R__ASSERT(0);
4393 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4394}
4395
4396////////////////////////////////////////////////////////////////////////////////
4397/// Read leaves into i/o buffers for this branch.
4398/// Case of a data member within a collection (fType == 41).
4399
4401{
4403 if (fObject == nullptr)
4404 {
4405 // We have nowhere to copy the data (probably because the data member was
4406 // 'dropped' from the current schema) so let's no copy it in a random place.
4407 return;
4408 }
4409
4410 // STL container sub-branch (contains the elements).
4412 if (!fNdata) {
4413 return;
4414 }
4415 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4416
4418 if (info == nullptr) return;
4419
4422
4424 b.ApplySequenceVecPtr(*fReadActionSequence,iter->fBegin,iter->fEnd);
4425}
4426
4427////////////////////////////////////////////////////////////////////////////////
4428/// Read leaves into i/o buffers for this branch.
4429/// Case of a data member within a collection (fType == 41).
4430
4432{
4434 if (fObject == nullptr)
4435 {
4436 // We have nowhere to copy the data (probably because the data member was
4437 // 'dropped' from the current schema) so let's no copy it in a random place.
4438 return;
4439 }
4440
4441 // STL container sub-branch (contains the elements).
4443 if (!fNdata) {
4444 return;
4445 }
4446 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4447
4449 if (info == nullptr) return;
4450 // Since info is not null, fReadActionSequence is not null either.
4451
4452 // Still calling PushPop for the legacy entries.
4455
4457 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4458}
4459
4460////////////////////////////////////////////////////////////////////////////////
4461/// Read leaves into i/o buffers for this branch.
4462/// Case of a TClonesArray (fType == 3).
4463
4465{
4467 if (fObject == nullptr)
4468 {
4469 // We have nowhere to copy the data (probably because the data member was
4470 // 'dropped' from the current schema) so let's no copy it in a random place.
4471 return;
4472 }
4473
4474 // TClonesArray master branch (has only the number of elements).
4475 Int_t n;
4476 b >> n;
4477 if ((n < 0) || (n > fMaximum)) {
4478 if (IsMissingCollection()) {
4479 n = 0;
4480 b.SetBufferOffset(b.Length()-sizeof(n));
4481 } else {
4482 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());
4483 n = 0;
4484 }
4485 }
4486 fNdata = n;
4488 if (clones->IsZombie()) {
4489 return;
4490 }
4491 // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4492 // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4493 // clones->Clear();
4494 clones->ExpandCreateFast(fNdata);
4495}
4496
4497////////////////////////////////////////////////////////////////////////////////
4498/// Read leaves into i/o buffers for this branch.
4499/// Case of a data member within a TClonesArray (fType == 31).
4500
4502{
4503 // No need to validate the address here, if we are a member of a split ClonesArray,
4504 // fID is positive
4505 // ValidateAddress();
4506
4507 if (fObject == nullptr)
4508 {
4509 // We have nowhere to copy the data (probably because the data member was
4510 // 'dropped' from the current schema) so let's no copy it in a random place.
4511 return;
4512 }
4513
4514 // TClonesArray sub-branch (contains the elements).
4517 if (clones->IsZombie()) {
4518 return;
4519 }
4521 if (info==nullptr) return;
4522 // Since info is not null, fReadActionSequence is not null either.
4523
4524 // Note, we could (possibly) save some more, by configuring the action
4525 // based on the value of fOnfileObject rather than pushing in on a stack.
4526 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4527
4528 char **arr = (char **)clones->GetObjectRef();
4529 char **end = arr + fNdata;
4530 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
4531}
4532
4533////////////////////////////////////////////////////////////////////////////////
4534/// Read leaves into i/o buffers for this branch.
4535/// For split-class branch, base class branch, data member branch, or top-level branch.
4536/// which do not have a branch count and are not a counter.
4537
4539{
4540 R__ASSERT(fBranchCount==nullptr);
4542
4544 if (fObject == nullptr)
4545 {
4546 // We have nowhere to copy the data (probably because the data member was
4547 // 'dropped' from the current schema) so let's no copy it in a random place.
4548 return;
4549 }
4550
4551 R__PushCache onfileObject(b, fOnfileObject, 1);
4552 // If not a TClonesArray or STL container master branch
4553 // or sub-branch and branch inherits from tobject,
4554 // then register with the buffer so that pointers are
4555 // handled properly.
4556 if (TestBit(kBranchObject)) {
4557 b.MapObject((TObject*) fObject);
4558 } else if (TestBit(kBranchAny)) {
4559 b.MapObject(fObject, fBranchClass);
4560 }
4561
4562 fNdata = 1;
4564 if (!info) {
4565 return;
4566 }
4567 // Since info is not null, fReadActionSequence is not null either.
4568 b.ApplySequence(*fReadActionSequence, fObject);
4569}
4570
4571////////////////////////////////////////////////////////////////////////////////
4572/// Read leaves into i/o buffers for this branch.
4573/// For split-class branch, base class branch, data member branch, or top-level branch.
4574/// which do have a branch count and are not a counter.
4575
4577{
4579
4581 if (fObject == nullptr)
4582 {
4583 // We have nowhere to copy the data (probably because the data member was
4584 // 'dropped' from the current schema) so let's no copy it in a random place.
4585 return;
4586 }
4587
4588 // If not a TClonesArray or STL container master branch
4589 // or sub-branch and branch inherits from tobject,
4590 // then register with the buffer so that pointers are
4591 // handled properly.
4592 if (TestBit(kBranchObject)) {
4593 b.MapObject((TObject*) fObject);
4594 } else if (TestBit(kBranchAny)) {
4595 b.MapObject(fObject, fBranchClass);
4596 }
4597
4598 fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4600 if (!info) {
4601 return;
4602 }
4603 R__PushCache onfileObject(b, fOnfileObject,
4604 1); // Here we have a single object that contains a variable size C-style array.
4605 // Since info is not null, fReadActionSequence is not null either.
4606 b.ApplySequence(*fReadActionSequence, fObject);
4607}
4608
4609////////////////////////////////////////////////////////////////////////////////
4610/// Read leaves into i/o buffers for this branch.
4611/// For split-class branch, base class branch, data member branch, or top-level branch.
4612/// which do not have a branch count and are a counter.
4613
4615{
4617 if (fObject == nullptr)
4618 {
4619 // We have nowhere to copy the data (probably because the data member was
4620 // 'dropped' from the current schema) so let's no copy it in a random place.
4621 return;
4622 }
4623
4624 // If not a TClonesArray or STL container master branch
4625 // or sub-branch and branch inherits from tobject,
4626 // then register with the buffer so that pointers are
4627 // handled properly.
4628 if (TestBit(kBranchObject)) {
4629 b.MapObject((TObject*) fObject);
4630 } else if (TestBit(kBranchAny)) {
4631 b.MapObject(fObject, fBranchClass);
4632 }
4633
4635 if (!info) {
4636 return;
4637 }
4638
4639 R__PushCache onfileObject(b, fOnfileObject, 1);
4640
4641 // Since info is not null, fReadActionSequence is not null either.
4642 b.ApplySequence(*fReadActionSequence, fObject);
4643 fNdata = (Int_t) GetValue(0, 0);
4644}
4645
4646////////////////////////////////////////////////////////////////////////////////
4647/// Read leaves into i/o buffers for this branch.
4648/// Non TObject, Non collection classes with a custom streamer.
4649
4651{
4653 if (fObject == nullptr)
4654 {
4655 // We have nowhere to copy the data (probably because the data member was
4656 // 'dropped' from the current schema) so let's no copy it in a random place.
4657 return;
4658 }
4659
4660 R__PushCache onfileObject(b, fOnfileObject, 1);
4662}
4663
4664////////////////////////////////////////////////////////////////////////////////
4665/// Unconfiguration Fill Leave function.
4666
4668{
4669 Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4670}
4671
4672////////////////////////////////////////////////////////////////////////////////
4673/// Delete any object we may have allocated on a previous call to SetAddress.
4674
4676{
4677 if (fObject && TestBit(kDeleteObject)) {
4678 if (IsAutoDelete() && fAddress != (char*)&fObject) {
4679 *((char**) fAddress) = nullptr;
4680 }
4682 if (fType == 3) {
4683 // -- We are a TClonesArray master branch.
4684 TClonesArray::Class()->Destructor(fObject);
4685 fObject = nullptr;
4688 // -- We are a pointer to a TClonesArray.
4689 // We must zero the pointer in the object.
4690 *((char**) fAddress) = nullptr;
4691 }
4692 } else if (fType == 4) {
4693 // -- We are an STL container master branch.
4695
4696 if (!proxy) {
4697 Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4698 fObject = nullptr;
4699 } else {
4701 if (needDelete && fID >= 0) {
4703 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4705 }
4706 if (needDelete) {
4708 proxy->Clear("force");
4709 }
4710 proxy->Destructor(fObject);
4711 fObject = nullptr;
4712 }
4714 // -- We are a pointer to an STL container.
4715 // We must zero the pointer in the object.
4716 *((char**) fAddress) = nullptr;
4717 }
4718 } else {
4719 // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4721 if (!cl) {
4722 Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4723 fObject = nullptr;
4724 } else {
4726
4727 if (proxy) {
4728 if (fID >= 0) {
4730 TStreamerElement* se = si->GetElement(fID);
4733 proxy->Clear("force");
4734 }
4735 } else if (proxy->GetProperties()&TVirtualCollectionProxy::kNeedDelete) {
4737 proxy->Clear("force");
4738 }
4739
4740 }
4741 cl->Destructor(fObject);
4742 fObject = nullptr;
4743 }
4744 }
4745 }
4746}
4747
4748////////////////////////////////////////////////////////////////////////////////
4749/// Reset a Branch.
4750///
4751/// Existing i/o buffers are deleted.
4752/// Entries, max and min are reset.
4753///
4754
4756{
4758 for (Int_t i = 0; i < nbranches; ++i) {
4760 branch->Reset(option);
4761 }
4762 fBranchID = -1;
4764}
4765
4766////////////////////////////////////////////////////////////////////////////////
4767/// Reset a Branch after a Merge operation (drop data but keep customizations)
4768///
4769
4771{
4773 for (Int_t i = 0; i < nbranches; ++i) {
4775 branch->ResetAfterMerge(info);
4776 }
4778}
4779
4780////////////////////////////////////////////////////////////////////////////////
4781/// Set branch address to zero and free all allocated memory.
4782
4784{
4785 for (Int_t i = 0; i < fNleaves; ++i) {
4787 //if (leaf) leaf->SetAddress(0);
4788 leaf->SetAddress(nullptr);
4789 }
4790
4791 // Note: We *must* do the sub-branches first, otherwise
4792 // we may delete the object containing the sub-branches
4793 // before giving them a chance to cleanup.
4795 for (Int_t i = 0; i < nbranches; ++i) {
4796 TBranch* br = (TBranch*) fBranches[i];
4797 if (br) br->ResetAddress();
4798 }
4799
4800 //
4801 // SetAddress may have allocated an object.
4802 //
4803
4804 ReleaseObject();
4805
4807 fAddress = nullptr;
4808 fObject = nullptr;
4809}
4810
4811////////////////////////////////////////////////////////////////////////////////
4812/// Release ownership of any allocated objects.
4813///
4814/// Note: This interface was added so that clone trees could
4815/// be told they do not own the allocated objects.
4816
4818{
4821 for (Int_t i = 0; i < nb; ++i) {
4822 TBranch* br = (TBranch*) fBranches[i];
4823 if (br->InheritsFrom(TBranchElement::Class())) {
4824 ((TBranchElement*) br)->ResetDeleteObject();
4825 }
4826 }
4827}
4828
4829////////////////////////////////////////////////////////////////////////////////
4830/// \brief Reset offset and StreamerInfo information from this branch.
4831/// \param[in] recurse When true call ResetInitInfo on all subbranches.
4832///
4833
4835{
4836 fInfo = nullptr;
4837 fInit = false;
4838 fInitOffsets = false;
4839 fCurrentClass = nullptr;
4840 delete fReadActionSequence;
4841 fReadActionSequence = nullptr;
4842 delete fFillActionSequence;
4843 fFillActionSequence = nullptr;
4844
4845 if (recurse) {
4847 for (Int_t i = 0; i < nbranches; ++i) {
4849 sub->ResetInitInfo(true);
4850 }
4851 }
4852}
4853
4854////////////////////////////////////////////////////////////////////////////////
4855/// Point this branch at an object.
4856///
4857/// For a sub-branch, addr is a pointer to the branch object.
4858///
4859/// For a top-level branch the meaning of addr is as follows:
4860///
4861/// If addr is zero, then we allocate a branch object
4862/// internally and the branch is the owner of the allocated
4863/// object, not the caller. However the caller may obtain
4864/// a pointer to the branch object with GetObject().
4865/// The pointer is reset to zero (nullptr) when the relevant
4866/// branch object is destroyed.
4867///
4868/// Example:
4869/// ~~~ {.cpp}
4870/// branch->SetAddress(0);
4871/// Event* event = branch->GetObject();
4872/// ... Do some work.
4873/// ~~~
4874/// If addr is not zero, but the pointer addr points at is
4875/// zero, then we allocate a branch object and set the passed
4876/// pointer to point at the allocated object. The caller
4877/// owns the allocated object and is responsible for deleting
4878/// it when it is no longer needed.
4879///
4880/// Example:
4881/// ~~~ {.cpp}
4882/// Event* event = 0;
4883/// branch->SetAddress(&event);
4884/// ... Do some work.
4885/// delete event;
4886/// event = 0;
4887/// ~~~
4888/// If addr is not zero and the pointer addr points at is
4889/// also not zero, then the caller has allocated a branch
4890/// object and is asking us to use it. The caller owns it
4891/// and must delete it when it is no longer needed.
4892///
4893/// Example:
4894/// ~~~ {.cpp}
4895/// Event* event = new Event();
4896/// branch->SetAddress(&event);
4897/// ... Do some work.
4898/// delete event;
4899/// event = 0;
4900/// ~~~
4901/// These rules affect users of TTree::Branch(),
4902/// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4903/// as well because those routines call this one.
4904///
4905/// An example of a tree with branches with objects allocated
4906/// and owned by us:
4907/// ~~~ {.cpp}
4908/// TFile* f1 = new TFile("myfile_original.root");
4909/// TTree* t1 = (TTree*) f->Get("MyTree");
4910/// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4911/// TTree* t2 = t1->Clone(0);
4912/// for (Int_t i = 0; i < 10; ++i) {
4913/// t1->GetEntry(i);
4914/// t2->Fill();
4915/// }
4916/// t2->Write()
4917/// delete f2;
4918/// f2 = 0;
4919/// delete f1;
4920/// f1 = 0;
4921/// ~~~
4922/// An example of a branch with an object allocated by us,
4923/// but owned by the caller:
4924/// ~~~ {.cpp}
4925/// TFile* f = new TFile("myfile.root", "recreate");
4926/// TTree* t = new TTree("t", "A test tree.")
4927/// Event* event = 0;
4928/// TBranchElement* br = t->Branch("event.", &event);
4929/// for (Int_t i = 0; i < 10; ++i) {
4930/// ... Fill event with meaningful data in some way.
4931/// t->Fill();
4932/// }
4933/// t->Write();
4934/// delete event;
4935/// event = 0;
4936/// delete f;
4937/// f = 0;
4938/// ~~~
4939/// Notice that the only difference between this example
4940/// and the following example is that the event pointer
4941/// is zero when the branch is created.
4942///
4943/// An example of a branch with an object allocated and
4944/// owned by the caller:
4945/// ~~~ {.cpp}
4946/// TFile* f = new TFile("myfile.root", "recreate");
4947/// TTree* t = new TTree("t", "A test tree.")
4948/// Event* event = new Event();
4949/// TBranchElement* br = t->Branch("event.", &event);
4950/// for (Int_t i = 0; i < 10; ++i) {
4951/// ... Fill event with meaningful data in some way.
4952/// t->Fill();
4953/// }
4954/// t->Write();
4955/// delete event;
4956/// event = 0;
4957/// delete f;
4958/// f = 0;
4959/// ~~~
4960/// If AutoDelete is on (see TBranch::SetAutoDelete),
4961/// the top level objet will be deleted and recreate
4962/// each time an entry is read, whether or not the
4963/// TTree owns the object.
4964
4966{
4967 SetAddressImpl(addr, (addr == nullptr), 0);
4968}
4969
4970/// See TBranchElement::SetAddress.
4971/// If implied is true, we do not over-ride existing address for
4972/// sub-branches.
4973/// The `offset` is the offset of the sub-object within its parent,
4974/// it is already included in the addr but is still needed to be added
4975/// the OnfileObject address when/if we need to use that address.
4977{
4978 //
4979 // Don't bother if we are disabled.
4980 //
4981
4982 if (TestBit(kDoNotProcess)) {
4983 return;
4984 }
4985
4986 //
4987 // FIXME: When would this happen?
4988 //
4989
4990 if (fType < -1) {
4991 return;
4992 }
4993
4994 //
4995 // Special case when called from code generated by TTree::MakeClass.
4996 //
4997
4998 if (Longptr_t(addr) == -1) {
4999 // FIXME: Do we have to release an object here?
5000 // ReleaseObject();
5001 fAddress = (char*) -1;
5002 fObject = (char*) -1;
5005 return;
5006 }
5007
5008 //
5009 // Reset last read entry number, we have a new user object now.
5010 //
5011
5012 fReadEntry = -1;
5013
5014 //
5015 // Make sure our branch class is instantiated.
5016 //
5018 if( fTargetClass.GetClassName()[0] ) {
5020 }
5021
5022 //
5023 // Try to build the streamer info.
5024 //
5025
5027
5028 // FIXME: Warn about failure to get the streamer info here?
5029
5030 //
5031 // We may have allocated an object last time we were called.
5032 //
5033
5034 if (fObject && TestBit(kDeleteObject)){
5035 ReleaseObject();
5036 }
5037
5038 //
5039 // Remember the pointer to the pointer to our object.
5040 //
5041
5042 fAddress = (char*) addr;
5043 if (fAddress != (char*)(&fObject)) {
5044 fObject = nullptr;
5045 }
5048
5049 //
5050 // Do special stuff if we got called from a MakeClass class.
5051 // Allow sub-branches to have independently set addresses.
5052 //
5053
5054 if (TestBit(kDecomposedObj)) {
5055 if (fID > -1) {
5056 // We are *not* a top-level branch.
5057 if (!info) {
5058 // No streamer info, give up.
5059 // FIXME: We should have an error message here.
5060 fObject = fAddress;
5061 } else {
5062 // Compensate for the fact that the i/o routines
5063 // will add the streamer offset to the address.
5064 fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
5065 }
5066 return;
5067 }
5068 }
5069
5070 //
5071 // Check whether the container type is still the same
5072 // to support schema evolution; what is written on the file
5073 // may no longer match the class code which is loaded.
5074 //
5075
5076 if (fType == 3) {
5077 // split TClonesArray, counter/master branch.
5079 if (clm) {
5080 // In case clm derives from an abstract class.
5081 clm->BuildRealData();
5082 clm->GetStreamerInfo();
5083 }
5085 if (newType && (newType != TClonesArray::Class())) {
5086 // The data type of the container has changed.
5087 //
5088 // Let's check if it is a compatible type:
5089 bool matched = false;
5090 if (newType->GetCollectionProxy()) {
5091 TClass *content = newType->GetCollectionProxy()->GetValueClass();
5092 if (clm == content) {
5093 matched = true;
5094 } else {
5095 Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
5096 }
5097 } else {
5098 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());
5099 }
5100 if (matched) {
5101 // Change from 3/31 to 4/41
5102 SetType(4);
5103 // Set the proxy.
5104 fSTLtype = newType->GetCollectionType();
5105 fCollProxy = newType->GetCollectionProxy()->Generate();
5106
5110
5116 } else {
5118 }
5119 } else {
5120 // FIXME: Must maintain fObject here as well.
5121 fAddress = nullptr;
5123 }
5124 }
5125 } else if (fType == 4) {
5126 // split STL container, counter/master branch.
5128 if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
5129 // Let's check if it is a compatible type:
5130 TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
5132 if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
5133 delete fCollProxy;
5135 fCollProxy = newType->GetCollectionProxy()->Generate();
5137 for (Int_t i = 0; i < nbranches; ++i) {
5139 br->fCollProxy = nullptr;
5140 if (br->fReadActionSequence) {
5141 br->SetReadActionSequence();
5142 }
5143 if (br->fFillActionSequence) {
5144 br->SetFillActionSequence();
5145 }
5146 }
5151 delete fIterators;
5152 delete fPtrIterators;
5158 } else {
5160 }
5161 }
5162 else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=nullptr) && (newProxy->GetValueClass()!=nullptr)) {
5163 // Let see if there is a rule to convert the content of the collection into each other.
5164 if (newType->GetSchemaRules()->HasRuleWithSourceClass( oldProxy->GetCollectionClass()->GetName())) {
5165 TClass *oldValueClass = oldProxy->GetValueClass();
5166 delete fCollProxy;
5168 fCollProxy = newType->GetCollectionProxy()->Generate();
5170 for (Int_t i = 0; i < nbranches; ++i) {
5172 br->fCollProxy = nullptr;
5173 if (br->fBranchClass == oldValueClass) {
5174 br->SetTargetClass(fCollProxy->GetValueClass()->GetName());
5175 }
5176 if (br->fReadActionSequence) {
5177 br->SetReadActionSequence();
5178 }
5179 if (br->fFillActionSequence) {
5180 br->SetFillActionSequence();
5181 }
5182 }
5187 delete fIterators;
5188 delete fPtrIterators;
5194 } else {
5196 }
5197 } else {
5198 Error("SetAddress","For %s, we can not convert %s into %s\n",
5199 GetName(),oldProxy->GetCollectionClass()->GetName(),newType->GetName());
5200 fAddress = nullptr;
5201 fObject = nullptr;
5203 return;
5204 }
5205 }
5206 else if ((newType == TClonesArray::Class()) && (oldProxy->GetValueClass() && !oldProxy->HasPointers() && oldProxy->GetValueClass()->IsTObject()))
5207 {
5208 // The new collection and the old collection are not compatible,
5209 // we cannot use the new collection to read the data.
5210 // Actually we could check if the new collection is a
5211 // compatible ROOT collection.
5212
5213 // We cannot insure that the TClonesArray is set for the
5214 // proper class (oldProxy->GetValueClass()), so we assume that
5215 // the transformation was done properly by the class designer.
5216
5217 // Change from 4/41 to 3/31
5218 SetType(3);
5219 // Reset the proxy.
5220 fSTLtype = kNone;
5221 switch(fStreamerType) {
5225 break;
5229 break;
5232 break;
5233 }
5234 fClonesClass = oldProxy->GetValueClass();
5236 delete fCollProxy;
5237 fCollProxy = nullptr;
5239 if (clm) {
5240 clm->BuildRealData(); //just in case clm derives from an abstract class
5241 clm->GetStreamerInfo();
5242 }
5246 delete fIterators;
5247 fIterators = nullptr;
5248 delete fPtrIterators;
5249 fPtrIterators =nullptr;
5250 } else {
5251 // FIXME: We must maintain fObject here as well.
5252 Error("SetAddress","For %s can not convert %s into %s\n",GetName(),GetCurrentClass()->GetName(),newType->GetName());
5253 fAddress = nullptr;
5255 return;
5256 }
5257 } else {
5258 if (!fIterators && !fPtrIterators) {
5264 } else {
5266 }
5267 }
5268 }
5269 }
5270
5271 //
5272 // Establish the semantics of fObject and fAddress.
5273 //
5274 // Top-level branch:
5275 // fObject is a ptr to the object,
5276 // fAddress is a ptr to a pointer to the object.
5277 //
5278 // Sub-branch:
5279 // fObject is a ptr to the object,
5280 // fAddress is the same as fObject.
5281 //
5282 //
5283 // There are special cases for TClonesArray and STL containers.
5284 // If there is no user-provided object, we allocate one. We must
5285 // also initialize any STL container proxy.
5286 //
5287
5288 if (fType == 3) {
5289 // -- We are a TClonesArray master branch.
5290 if (fAddress) {
5291 // -- We have been given a non-zero address, allocate if necessary.
5293 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5294 // Case of an embedded TClonesArray.
5295 fObject = fAddress;
5296 // Check if it has already been properly built.
5298 if (!clones->GetClass()) {
5300 }
5301 } else {
5302 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5303 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5304 if ((fStreamerType != -1) &&
5307 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5308 } else if (fStreamerType == -1) {
5309 // -- We are a top-level branch.
5311 if (!*pp) {
5312 // -- Caller wants us to allocate the clones array, but they will own it.
5313 *pp = new TClonesArray(fClonesClass);
5314 }
5315 fObject = (char*) *pp;
5316 } else {
5317 // -- We are a pointer to a TClonesArray.
5318 // Note: We do this so that the default constructor,
5319 // or the i/o constructor can be lazy.
5321 if (!*pp) {
5322 // -- Caller wants us to allocate the clones array, but they will own it.
5323 *pp = new TClonesArray(fClonesClass);
5324 }
5325 fObject = (char*) *pp;
5326 }
5327 }
5328 } else {
5329 // -- We have been given a zero address, allocate for top-level only.
5331 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5332 // Case of an embedded TClonesArray.
5333 Error("SetAddress", "Embedded TClonesArray given a zero address for branch '%s'", GetName());
5334 } else {
5335 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5336 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5337 if ((fStreamerType != -1) &&
5340 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5341 } else if (fStreamerType == -1) {
5342 // -- We are a top-level branch.
5343 // Idea: Consider making a zero address not allocate.
5345 fObject = (char*) new TClonesArray(fClonesClass);
5346 fAddress = (char*) &fObject;
5347 } else {
5348 // -- We are a sub-branch which is a pointer to a TClonesArray.
5349 Error("SetAddress", "Embedded pointer to a TClonesArray given a zero address for branch '%s'", GetName());
5350 }
5351 }
5352 }
5353 } else if (fType == 4) {
5354 // -- We are an STL container master branch.
5355 //
5356 // Initialize fCollProxy.
5358 if (fAddress) {
5359 // -- We have been given a non-zero address, allocate if necessary.
5363 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5364 // Case of an embedded STL container.
5365 // Note: We test for the kObject and kAny types to support
5366 // the (unwise) choice of inheriting from an STL container.
5367 fObject = fAddress;
5368 } else {
5369 // We are either a top-level branch or subbranch which is a pointer to an STL container.
5370 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5372 Error("SetAddress",
5373 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5375 } else if (fStreamerType == -1) {
5376 // -- We are a top-level branch.
5377 void** pp = (void**) fAddress;
5378 if (!*pp) {
5379 // -- Caller wants us to allocate the STL container, but they will own it.
5380 *pp = proxy->New();
5381 if (!(*pp)) {
5382 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5383 // FIXME: Should we do this? Lots of other code wants
5384 // fAddress to be zero if no fObject, but is
5385 // that a good thing?
5386 fAddress = nullptr;
5388 }
5389 }
5390 fObject = (char*) *pp;
5391 } else {
5392 // -- We are a pointer to an STL container.
5393 // Note: We do this so that the default constructor,
5394 // or the i/o constructor can be lazy.
5395 void** pp = (void**) fAddress;
5396 if (!*pp) {
5397 // -- Caller wants us to allocate the STL container, but they will own it.
5398 *pp = proxy->New();
5399 if (!(*pp)) {
5400 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5401 // FIXME: Should we do this? Lots of other code wants
5402 // fAddress to be zero if no fObject, but is
5403 // that a good thing?
5404 fAddress = nullptr;
5406 }
5407 }
5408 fObject = (char*) *pp;
5409 }
5410 }
5411 } else {
5412 // -- We have been given a zero address, allocate for top-level only.
5416 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5417 // Case of an embedded STL container.
5418 // Note: We test for the kObject and kAny types to support
5419 // the (unwise) choice of inheriting from an STL container.
5420 Error("SetAddress", "Embedded STL container given a zero address for branch '%s'", GetName());
5421 } else {
5422 // We are either a top-level branch or sub-branch which is a pointer to an STL container.
5423 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5425 Error("SetAddress",
5426 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5428 } else if (fStreamerType == -1) {
5429 // -- We are a top-level branch, allocate.
5431 fObject = (char*) proxy->New();
5432 if (fObject) {
5433 fAddress = (char*) &fObject;
5434 } else {
5435 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5436 // FIXME: Should we do this? Lots of other code wants
5437 // fAddress to be zero if no fObject, but is
5438 // that a good thing?
5439 fAddress = nullptr;
5441 }
5442 } else {
5443 // -- We are a sub-branch which is a pointer to an STL container.
5444 Error("SetAddress", "Embedded pointer to an STL container given a zero address for branch '%s'", GetName());
5445 }
5446 }
5447 }
5448 } else if (fType == 41) {
5449 // -- We are an STL container sub-branch.
5450 // Initialize fCollProxy.
5452 // We are not at top-level branch.
5453 fObject = fAddress;
5454 } else if (fID < 0) {
5455 // -- We are a top-level branch.
5456 char** pp = (char**) fAddress;
5457 if (pp && *pp) {
5458 // -- Caller provided an i/o buffer for us to use.
5459 fObject = *pp;
5460 } else {
5461 // -- Caller did not provide an i/o buffer for us to use, we must make one for ourselves.
5462 if (clOfBranch) {
5463 if (!pp) {
5464 // -- Caller wants us to own the object.
5466 }
5467 fObject = (char*) clOfBranch->New();
5468 if (pp) {
5469 *pp = fObject;
5470 } else {
5471 fAddress = (char*) &fObject;
5472 }
5473 } else {
5474 Error("SetAddress", "I have no TClass for branch %s, so I cannot allocate an I/O buffer!", GetName());
5475 if (pp) {
5476 fObject = nullptr;
5477 *pp = nullptr;
5478 }
5479 }
5480 }
5481 } else {
5482 // -- We are *not* a top-level branch.
5483 fObject = fAddress;
5484 }
5485
5486 if (!info) {
5487 // FIXME: We need and error message here, no streamer info, so cannot set offsets.
5488 return;
5489 }
5490
5491 // We do this only once because it depends only on
5492 // the type of our object, not on its address.
5493 if (!fInitOffsets) {
5495 }
5496
5497 // We are split, recurse down to our sub-branches.
5498 //
5499 // FIXME: This is a tail recursion, we burn stack.
5501 char *localObject = fObject;
5502 if (fOnfileObject && this != GetMother()) {
5504 }
5505 for (Int_t i = 0; i < nbranches; ++i) {
5507 // FIXME: This is a tail recursion!
5508 if (fBranchOffset[i] != TStreamerInfo::kMissing && !(implied && abranch->TestBit(kAddressSet))) {
5509 abranch->SetAddressImpl(localObject + fBranchOffset[i], implied, fBranchOffset[i]);
5510 abranch->SetBit(kAddressSet);
5511 if (TestBit(kDecomposedObj) != abranch->TestBit(kDecomposedObj))
5512 abranch->SetMakeClass(TestBit(kDecomposedObj));
5513 } else {
5514 // When the member is missing, just leave the address alone
5515 // (since setting explicitly to 0 would trigger error/warning
5516 // messages).
5517 // abranch->SetAddress(0);
5518 abranch->SetBit(kAddressSet);
5519 }
5520 }
5521}
5522
5523////////////////////////////////////////////////////////////////////////////////
5524/// Reset the basket size for all sub-branches of this branch element.
5525
5527{
5530 for (Int_t i = 0; i < nbranches; ++i) {
5532 branch->SetBasketSize(fBasketSize);
5533 }
5534}
5535
5536////////////////////////////////////////////////////////////////////////////////
5537/// Set the branch counter for this branch.
5538
5540{
5542 if (fBranchCount==nullptr) return;
5543
5544 TLeafElement* leafOfCounter = (TLeafElement*) brOfCounter->GetListOfLeaves()->At(0);
5546 if (leafOfCounter && leaf) {
5547 leaf->SetLeafCount(leafOfCounter);
5548 } else {
5549 if (!leafOfCounter) {
5550 Warning("SetBranchCount", "Counter branch %s for branch %s has no leaves!", brOfCounter->GetName(), GetName());
5551 }
5552 if (!leaf) {
5553 Warning("SetBranchCount", "Branch %s has no leaves!", GetName());
5554 }
5555 }
5556}
5557
5558////////////////////////////////////////////////////////////////////////////////
5559/// Set the branch in a mode where the object are decomposed
5560/// (Also known as MakeClass mode).
5561/// Return whether the setting was possible (it is not possible for
5562/// TBranch and TBranchObject).
5563
5565{
5566 if (decomposeObj)
5567 SetBit(kDecomposedObj); // Same as SetBit(kMakeClass)
5568 else
5570
5572 for (Int_t i = 0; i < nbranches; ++i) {
5574 branch->SetMakeClass(decomposeObj);
5575 }
5578
5579 return true;
5580}
5581
5582////////////////////////////////////////////////////////////////////////////////
5583/// Set object this branch is pointing to.
5584
5586{
5587 if (TestBit(kDoNotProcess)) {
5588 return;
5589 }
5590 fObject = (char*)obj;
5591 SetAddress( &fObject );
5592}
5593
5594////////////////////////////////////////////////////////////////////////////////
5595/// Set offset of the object (to which the data member represented by this
5596/// branch belongs) inside its containing object (if any).
5597
5599{
5600 // We need to make sure that the Read and Write action's configuration
5601 // properly reflect this value.
5602
5604 SetMissing();
5605 return;
5606 }
5607
5608 if (fReadActionSequence) {
5610 }
5611 if (fFillActionSequence) {
5613 }
5614 fOffset = offset;
5615}
5616
5617////////////////////////////////////////////////////////////////////////////////
5618/// Set offset of the object (to which the data member represented by this
5619/// branch belongs) inside its containing object (if any) to mark it as missing.
5620
5622{
5623 // We need to make sure that the Read and Write action's configuration
5624 // properly reflect this value.
5625
5626 if (fReadActionSequence) {
5628 }
5629 if (fFillActionSequence) {
5631 }
5633}
5634
5635
5636////////////////////////////////////////////////////////////////////////////////
5637/// Set the sequence of actions needed to read the data out of the buffer.
5639{
5640 // A 'split' node does not store data itself (it has not associated baskets)
5641 const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
5642
5643 if (!isSplitNode) {
5644 fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
5645 }
5646
5647 if (actionSequence) delete actionSequence;
5649
5650 actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
5651
5652 if (!isSplitNode)
5653 fNewIDs.erase(fNewIDs.begin());
5654
5655 else if (fInitOffsets && fType != 3 && fType != 4) {
5656 // fObject has the address of the sub-object but the streamer action have
5657 // offset relative to the parent.
5658
5659 // Note: We skipped this for the top node of split collection because the
5660 // sequence is about the content, we need to review what happens where an
5661 // action related to the collection itself will land.
5662 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
5663
5664 auto index = parent->fBranches.IndexOf(this);
5665 if (index >= 0) {
5666 actionSequence->AddToOffset( - parent->fBranchOffset[index] );
5667 }
5668 } // else it will be done by InitOffsets
5669}
5670
5671////////////////////////////////////////////////////////////////////////////////
5672/// Set the sequence of actions needed to read the data out of the buffer.
5674{
5675 if (fInfo == nullptr) {
5676 // We are called too soon. We will be called again by InitInfo
5677 return;
5678 }
5679
5681 TClass *originalClass = nullptr;
5683 if (fType == 41) {
5686 } else {
5688 if (GetParentClass() == info->GetClass()) {
5692 } else {
5694 }
5695 } else if (GetCollectionProxy()) {
5696 // Base class and embedded objects.
5698 }
5699 }
5700 } else if (fType == 31) {
5702 } else if (0<=fType && fType<=2) {
5703 // Note: this still requires the ObjectWise sequence to not be optimized!
5705 } else if ( fType == 4 && !fNewIDs.empty()) {
5708 } else if ( fType == 3 && !fNewIDs.empty()) {
5711 }
5712
5713 if (create) {
5715 }
5716}
5717
5718////////////////////////////////////////////////////////////////////////////////
5719/// Set the ReadLeaves pointer to execute the expected operations.
5720
5722{
5723 if (TestBit(kDecomposedObj)) {
5725 } else if (fType == 4) {
5727 } else if (fType == 41) {
5731 } else {
5733 }
5734 } else {
5736 }
5737 } else if (fType == 3) {
5739 } else if (fType == 31) {
5741 } else if (fType < 0) {
5743 } else if (fType == 0 && fID == -1) {
5744 // top-level branch.
5746 if (hasCustomStreamer) {
5747 // We are in the case where the object did *not* have a custom
5748 // Streamer when the TTree was written but now *does* have a custom
5749 // Streamer thus we must use it.
5751 } else {
5753 }
5754 } else if (fType <= 2) {
5755 // split-class branch, base class branch or data member branch.
5756 if (fBranchCount) {
5760 } else {
5762 }
5763 } else {
5764 Fatal("SetReadLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5765 }
5766
5768}
5769
5770////////////////////////////////////////////////////////////////////////////////
5771/// Set the sequence of actions needed to write the data out from the buffer.
5772
5774{
5775 if (fInfo == nullptr) {
5776 // We are called too soon. We will be called again by InitInfo
5777 return;
5778 }
5779
5781 TClass *originalClass = nullptr;
5783 if (fType == 41) {
5786 } else {
5788 if (GetParentClass() == info->GetClass()) {
5789 // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
5790 // originalClass = fBranchClass;
5791 // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter;
5792 // } else {
5794 // }
5795 } else if (GetCollectionProxy()) {
5796 // Base class and embedded objects.
5798 }
5799 }
5800 } else if (fType == 31) {
5802 } else if (0<=fType && fType<=2) {
5803 // Note: this still requires the ObjectWise sequence to not be optimized!
5805 } else if ( fType == 4 && !fNewIDs.empty()) {
5808 } else if ( fType == 3 && !fNewIDs.empty()) {
5811 }
5812
5813 if (create) {
5815 }
5816}
5817
5818////////////////////////////////////////////////////////////////////////////////
5819/// Set the FillLeaves pointer to execute the expected operations.
5820
5822{
5823 if (TestBit(kDecomposedObj) && ((fType==3)||(fType==31))) {
5825 } else if (fType == 4) {
5827 } else if (fType == 41) {
5831 } else {
5833 }
5836 } else {
5838 }
5839 } else if (fType == 3) {
5841 } else if (fType == 31) {
5843 } else if (fType < 0) {
5845 } else if (fType <=2) {
5846 //split-class branch, base class branch, data member branch, or top-level branch.
5847 if (fBranchCount) {
5851 } else {
5853 }
5854 } else {
5855 Fatal("SetFillLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5856 }
5857
5859}
5860
5861////////////////////////////////////////////////////////////////////////////////
5862/// Set the name of the class of the in-memory object into which the data will
5863/// loaded.
5864
5866{
5867 if (name == nullptr) return;
5868
5869 if (strcmp(fTargetClass.GetClassName(),name) != 0 )
5870 {
5871 // We are changing target class, let's reset the meta information and
5872 // the sub-branches.
5873
5874 ResetInitInfo(/*recurse=*/ false);
5875
5877 for (Int_t i = 0; i < nbranches; ++i) {
5879
5880 if (sub->fTargetClass == fTargetClass ) {
5881 sub->SetTargetClass(name);
5882 } else {
5883 // Since the top level changes, the StreamerInfo (in particular for split collection)
5884 // may still need to change (and the info might be updated else (see for example SetAddress for the
5885 // the case fType 4/41)
5886 sub->ResetInitInfo(true);
5887 }
5888 if (sub->fParentClass == fTargetClass ) {
5890 }
5891 }
5893 }
5894
5895}
5896
5897////////////////////////////////////////////////////////////////////////////////
5898/// If the branch address is not set, we set all addresses starting with
5899/// the top level parent branch. This is required to be done in order for
5900/// GetOffset to be correct and for GetEntry to run.
5901
5903{
5904 // Check to see if the user changed the branch address on us.
5906
5908 // -- Do nothing if already setup or if we are a MakeClass branch.
5909 return;
5910 }
5912}
5913
5914////////////////////////////////////////////////////////////////////////////////
5915/// If the branch address is not set, we set all addresses starting with
5916/// the top level parent branch. This is required to be done in order for
5917/// GetOffset to be correct and for GetEntry to run.
5918
5920{
5921 if (TestBit((long)kDoNotProcess|(long)kAddressSet)) {
5922 // -- Do nothing if we have been told not to.
5923 // Or the data member in this branch is not longer part of the
5924 // parent's layout.
5925 return;
5926 }
5927
5928 //--------------------------------------------------------------------------
5929 // Check if we are splited STL collection of pointers
5930 /////////////////////////////////////////////////////////////////////////////
5931
5933 {
5934 TBranchElement *parent = (TBranchElement *)GetMother()->GetSubBranch( this );
5935
5936 // Make sure the StreamerInfo is loaded and initialized.
5937 GetInfoImp();
5938
5939 if( !parent->GetAddress() )
5940 parent->SetAddress( nullptr );
5941 return;
5942 }
5943
5944 //--------------------------------------------------------------------------
5945 // Any other case
5946 /////////////////////////////////////////////////////////////////////////////
5947
5949 if (!mother) {
5950 return;
5951 }
5952 TClass* cl = TClass::GetClass(mother->GetClassName());
5953
5954 // Make sure the StreamerInfo is loaded and initialized.
5955 GetInfoImp();
5956
5957 if (!cl) {
5958 return;
5959 }
5960
5961 if (!mother->GetAddress()) {
5962 // -- Our top-level branch has no address.
5963 bool motherStatus = mother->TestBit(kDoNotProcess);
5964 mother->ResetBit(kDoNotProcess);
5965 // Note: This will allocate an object.
5966 mother->SetAddress(nullptr);
5968 }
5969}
5970
5971////////////////////////////////////////////////////////////////////////////////
5972/// Stream an object of class TBranchElement.
5973
5975{
5976 if (R__b.IsReading()) {
5977 R__b.ReadClassBuffer(TBranchElement::Class(), this);
5982 // The fAddress and fObject data members are not persistent,
5983 // therefore we do not own anything.
5984 // Also clear the bit possibly set by the schema evolution.
5986 // Fixup a case where the TLeafElement was missing
5987 if ((fType == 0) && (fLeaves.GetEntriesFast() == 0)) {
5988 TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
5989 leaf->SetTitle(GetTitle());
5990 fNleaves = 1;
5991 fLeaves.Add(leaf);
5992 fTree->GetListOfLeaves()->Add(leaf);
5993 }
5994
5995 // SetReadLeavesPtr();
5996 }
5997 else {
5999 fDirectory = nullptr; // to avoid recursive calls
6000 {
6001 // Save class version.
6003 // Record only positive 'version number'
6004 if (fClassVersion < 0) {
6006 }
6007 // TODO: Should we clear the kDeleteObject bit before writing?
6008 // If we did we would have to remember the old value and
6009 // put it back, we wouldn't want to forget that we owned
6010 // something just because we got written to disk.
6011 R__b.WriteClassBuffer(TBranchElement::Class(), this);
6012 // Restore class version.
6014 }
6015 //
6016 // Mark all streamer infos used by this branch element
6017 // to be written to our output file.
6018 //
6019 {
6020 R__b.ForceWriteInfo(GetInfoImp(), true);
6021 }
6022 //
6023 // If we are a clones array master branch, or an
6024 // STL container master branch, we must also mark
6025 // the streamer infos used by the value class to
6026 // be written to our output file.
6027 //
6028 if (fType == 3) {
6029 // -- TClonesArray, counter/master branch
6030 //
6031 // We must mark the streamer info for the
6032 // value class to be written to the file.
6033 //
6034 TClass* cl = fClonesClass;
6035 if (cl) {
6036 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6037 }
6038 }
6039 else if (fType == 4) {
6040 // -- STL container, counter/master branch
6041 //
6042 // We must mark the streamer info for the
6043 // value class to be written to the file.
6044 //
6046 if (cp) {
6047 TClass* cl = cp->GetValueClass();
6048 if (cl) {
6049 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6050 }
6051 }
6052 }
6053 // If we are in a separate file, then save
6054 // ourselves as an independent key.
6055 if (!dirsav) {
6056 // Note: No need to restore fDirectory, it was already zero.
6057 return;
6058 }
6059 if (!dirsav->IsWritable()) {
6061 return;
6062 }
6064 if (!pdirectory) {
6066 return;
6067 }
6068 const char* treeFileName = pdirectory->GetFile()->GetName();
6070 const char* motherFileName = treeFileName;
6071 if (mother && (mother != this)) {
6072 motherFileName = mother->GetFileName();
6073 }
6074 if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
6075 dirsav->WriteTObject(this);
6076 }
6078 }
6079}
6080
6081
6082////////////////////////////////////////////////////////////////////////////////
6083/// Split class cl into sub-branches of this branch.
6084///
6085/// This version of Unroll was formerly embedded in TTree::BronchExec
6086/// It is moved here so we can make sure to call SetReadActionSequence.
6087
6089{
6090 //
6091 // Do we have a final dot in our name?
6092 //
6093
6094 // Note: The branch constructor which takes a folder as input
6095 // creates top-level branch names with dots in them to
6096 // indicate the folder hierarchy.
6097 char* dot = (char*) strchr(name, '.');
6098 Int_t nch = strlen(name);
6099 bool dotlast = false;
6100 if (nch && (name[nch-1] == '.')) {
6101 dotlast = true;
6102 }
6103
6104 // Loop on all public data members of the class and its base classes and create branches for each one.
6105 TObjArray* blist = this->GetListOfBranches();
6106 TIter next(sinfo->GetElements());
6107 TStreamerElement* element = nullptr;
6108 TString bname;
6109 for (Int_t id = 0; (element = (TStreamerElement*) next()); ++id) {
6110 if (element->IsA() == TStreamerArtificial::Class()) {
6111 continue;
6112 }
6113 if (element->TestBit(TStreamerElement::kRepeat)) {
6114 continue;
6115 }
6117 continue;
6118 }
6119 char* pointer = (char*) (objptr + element->GetOffset());
6120 // FIXME: This is not good enough, an STL container can be
6121 // a base, and the test will fail.
6122 // See TBranchElement::InitializeOffsets() for the
6123 // correct test.
6124 bool isBase = (element->IsA() == TStreamerBase::Class());
6125 if (isBase) {
6126 TClass* clbase = element->GetClassPointer();
6127 if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) {
6128 // Note: TStreamerInfo::Compile() leaves this element
6129 // out of the optimized info, although it does
6130 // exists in the non-compiled and non-optimized info.
6131 // FIXME: The test that TStreamerInfo::Compile() uses
6132 // is element->GetType() < 0, so that is what
6133 // we should do as well.
6134 continue;
6135 }
6136 if (clbase->GetListOfRealData()->GetSize() == 0) {
6137 // Do not create a branch for empty bases.
6138 continue;
6139 }
6140 }
6141 if (dot) {
6142 if (dotlast) {
6143 bname.Form("%s%s", name, element->GetFullName());
6144 } else {
6145 // FIXME: We are in the case where we have a top-level
6146 // branch name that was created by the branch
6147 // constructor which takes a folder as input.
6148 // The internal dots in the name are in place of
6149 // of the original slashes and represent the
6150 // folder hierarchy.
6151 if (isBase) {
6152 // FIXME: This is very strange, this is the only case where
6153 // we create a branch for a base class that does
6154 // not have the base class name in the branch name.
6155 // FIXME: This is also quite bad since classes with two
6156 // or more base classes end up with sub-branches
6157 // that have the same name.
6158 bname = name;
6159 } else {
6160 bname.Form("%s.%s", name, element->GetFullName());
6161 }
6162 }
6163 } else {
6164 // Note: For a base class element, this results in the branchname
6165 // being the name of the base class.
6166 bname.Form("%s", element->GetFullName());
6167 }
6168
6170 element->GetClass()->GetCollectionProxy() &&
6171 element->GetClass()->GetCollectionProxy()->HasPointers() )
6172 {
6173 TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id );
6174 blist->Add(brSTL);
6175 }
6176 else
6177 {
6178 TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1);
6179 bre->SetParentClass(cl);
6180 blist->Add(bre);
6181 }
6182 }
6183 // Now that we know that this branch is split, let's redo the actions.
6186}
6187
6188////////////////////////////////////////////////////////////////////////////////
6189/// Split class cl into sub-branches of this branch.
6190///
6191/// Create a sub-branch of this branch for each non-empty,
6192/// non-abstract base class of cl (unless we are a sub-branch
6193/// of a TClonesArray or an STL container, in which case we
6194/// do *not* create a sub-branch), and for each non-split data
6195/// member of cl.
6196///
6197/// Note: We do *not* create sub-branches for base classes of cl
6198/// if we are a sub-branch of a TClonesArray or an STL container.
6199///
6200/// Note: We do *not* create sub-branches for data members which
6201/// have a class type and which we are splitting.
6202///
6203/// Note: The above rules imply that the branch hierarchy increases
6204/// in depth only for base classes of cl (unless we are inside
6205/// of a TClonesArray or STL container, in which case the depth
6206/// does *not* increase, the base class is elided) and for
6207/// TClonesArray or STL container data members (which have one
6208/// additional level of sub-branches). The only other way the
6209/// depth increases is when the top-level branch has a split
6210/// class data member, in that case the constructor will create
6211/// a sub-branch for it. In other words, the interior nodes of
6212/// the branch tree are all either: base class nodes; split
6213/// class nodes which are direct sub-branches of top-level nodes
6214/// (created by TClass::Bronch usually); or TClonesArray or STL
6215/// container master nodes.
6216///
6217/// Note: The exception to the above is for the top-level branches,
6218/// Tree::Bronch creates nodes for everything in that case,
6219/// except for a TObject base class of a class which has the
6220/// can ignore tobject streamer flag set.
6221
6223{
6224 //----------------------------------------------------------------------------
6225 // Handling the case of STL collections of pointers
6226 /////////////////////////////////////////////////////////////////////////////
6227
6230
6232
6233 if ((cl == TObject::Class()) && clParent->CanIgnoreTObjectStreamer()) {
6234 return 0;
6235 }
6236
6238
6239 //
6240 // Do nothing if we couldn't build the streamer info for cl.
6241 //
6242
6243 if (!sinfo) {
6244 return 0;
6245 }
6246
6247 const auto namelen = strlen(name);
6248 bool dotlast = (namelen && (name[namelen-1] == '.'));
6249
6250 Int_t ndata = sinfo->GetNelement();
6251
6252 if ((ndata == 1) && cl->GetCollectionProxy() && !strcmp(sinfo->GetElement(0)->GetName(), "This")) {
6253 // -- Class cl is an STL collection, refuse to split it.
6254 // Question: Why? We certainly could by switching to the value class.
6255 // Partial Answer: Only the branch element constructor can split STL containers.
6256 return 1;
6257 }
6258
6259 for (Int_t elemID = 0; elemID < ndata; ++elemID) {
6260 // -- Loop over all the streamer elements and create sub-branches as needed.
6261 TStreamerElement* elem = sinfo->GetElement(elemID);
6262 if (elem->IsA() == TStreamerArtificial::Class()) {
6263 continue;
6264 }
6265 if (elem->TestBit(TStreamerElement::kRepeat)) {
6266 continue;
6267 }
6268 if (elem->TestBit(TStreamerElement::kCache) && !elem->TestBit(TStreamerElement::kWrite)) {
6269 continue;
6270 }
6271 Int_t offset = elem->GetOffset();
6272 // FIXME: An STL container as a base class gets TStreamerSTL as its class, so this test is not enough.
6273 // See InitializeOffsets() for the proper test.
6274 if (elem->IsA() == TStreamerBase::Class()) {
6275 // -- This is a base class of cl.
6276 TClass* clOfBase = elem->GetClassPointer();
6277 if (!clOfBase || ((clOfBase->Property() & kIsAbstract) && cl->InheritsFrom(TCollection::Class()))) {
6278 // -- Do nothing if we are one of the abstract collection (we know they have no data).
6279 return -1;
6280 }
6281 if ((btype == 31) || (btype == 41)) {
6282 // -- Elide the base-class sub-branches of a split TClonesArray or STL container.
6283 //
6284 // Note: We are eliding the base class here, that is, we never
6285 // create a branch for it, so the branch hierarchy is not
6286 // complete.
6287 // Note: The clParent parameter is the value class of the
6288 // container which we are splitting. It does not
6289 // appear in the branch hierarchy either.
6290 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6291 Int_t unroll = -1;
6292 if (!elem->CannotSplit() || clOfBase == TObject::Class()) {
6294 }
6295 if (unroll < 0) {
6296 // FIXME: We could not split because we are abstract, should we be doing this?
6297 if (namelen) {
6298 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6299 } else {
6300 branchname.Form("%s", elem->GetFullName());
6301 }
6302 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, nullptr, basketsize, 0, btype);
6303 branch->SetParentClass(clParent);
6305 }
6306 } else if (clOfBase->GetListOfRealData()->GetSize()) {
6307 // -- Create a branch for a non-empty base class.
6308 if (namelen) {
6309 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6310 // Elide the base class name when creating the sub-branches.
6311 // Note: The branch names for sub-branches of a base class branch
6312 // do not represent the full class hierarchy because we do
6313 // this, however it does keep the branch names for the
6314 // inherited data members simple.
6316 // Then reset it to the proper name.
6317 branch->SetName(branchname);
6318 branch->SetTitle(branchname);
6319 branch->SetParentClass(clParent);
6321 } else {
6322 branchname.Form("%s", elem->GetFullName());
6324 branch->SetParentClass(clParent);
6326 }
6327 }
6328 } else {
6329 // -- This is a data member of cl.
6330 if (namelen) {
6331 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6332 } else {
6333 branchname.Form("%s", elem->GetFullName());
6334 }
6335 if ((splitlevel > 1) && ((elem->IsA() == TStreamerObject::Class()) || (elem->IsA() == TStreamerObjectAny::Class()))) {
6336 // -- We are splitting a non-TClonesArray (may inherit from TClonesArray though), non-STL container object.
6337 //
6338 // Ignore an abstract class.
6339 // FIXME: How could an abstract class get here?
6340 // Partial answer: It is a base class. But this is a data member!
6341 TClass* elemClass = elem->GetClassPointer();
6342 if (!elemClass || elemClass->Property() & kIsAbstract) {
6343 return -1;
6344 }
6345 if (elem->CannotSplit()) {
6346 // We are not splitting.
6347 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6348 branch->SetParentClass(clParent);
6350 } else if (elemClass->InheritsFrom(TClonesArray::Class())) {
6351 // Splitting something derived from TClonesArray.
6353 if (btype == 31 || btype == 41 || elem->CannotSplit()) {
6354 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6355 subSplitlevel = 0;
6356 }
6358 branch->SetParentClass(clParent);
6360 } else {
6361 // Splitting a normal class.
6362 // FIXME: We are eliding the class we are splitting here,
6363 // i.e., we do not create a branch for it, so the
6364 // branch hierarchy does not match the class hierarchy.
6365 // Note: clParent is the class which contains a data member of
6366 // the class type which we are splitting.
6367 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6369 if (unroll < 0) {
6370 // FIXME: We could not split because we are abstract, should we be doing this?
6371 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6372 branch->SetParentClass(clParent);
6374 }
6375 }
6376 }
6377 else if( elem->GetClassPointer() &&
6378 elem->GetClassPointer()->GetCollectionProxy() &&
6379 elem->GetClassPointer()->GetCollectionProxy()->HasPointers() &&
6380 splitSTLP && fType != 4 )
6381 {
6382
6383 TBranchSTL* branch = new TBranchSTL( this, branchname,
6384 elem->GetClassPointer()->GetCollectionProxy(),
6386 branch->SetAddress( ptr+offset );
6387 fBranches.Add( branch );
6388 }
6389 else if ((elem->IsA() == TStreamerSTL::Class()) && !elem->IsaPointer()) {
6390 // -- We have an STL container.
6391 // Question: What if splitlevel == 0 here?
6392 // Answer: then we should not be here.
6394 if ((btype == 31) || (btype == 41) || elem->CannotSplit()) {
6395 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6396 subSplitlevel = 0;
6397 }
6399 branch->SetParentClass(clParent);
6401 } else if (((btype != 31) && (btype != 41)) && ptr && ((elem->GetClassPointer() == TClonesArray::Class()) || ((elem->IsA() == TStreamerSTL::Class()) && !elem->CannotSplit()))) {
6402 // -- We have a TClonesArray.
6403 // FIXME: We could get a ptr to a TClonesArray here by mistake.
6404 // Question: What if splitlevel == 0 here?
6405 // Answer: then we should not be here.
6406 // Note: ptr may be null in case of a TClonesArray inside another
6407 // TClonesArray or STL container, see the else clause.
6409 branch->SetParentClass(clParent);
6411 } else {
6412 // -- We are not going to split this element any farther.
6414 branch->SetType(btype);
6415 branch->SetParentClass(clParent);
6417 }
6418 }
6419 }
6420
6421 if (!fBranches.IsEmpty()) {
6422 // Refresh this branch's action now that we know whether it is split or not.
6425 }
6426 return 1;
6427}
6428
6429////////////////////////////////////////////////////////////////////////////////
6430/// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
6431/// with the current value of fTree->GetCurrentFile unless this branch has been
6432/// redirected to a different file. Also update the sub-branches.
6433
6435{
6436 // The BranchCount and BranchCount2 are part of higher level branches' list of
6437 // branches.
6438 // if (fBranchCount) fBranchCount->UpdateFile();
6439 // if (fBranchCount2) fBranchCount2->UpdateFile();
6441}
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
Definition RtypesCore.h:40
int Int_t
Definition RtypesCore.h:45
float Size_t
Definition RtypesCore.h:89
long Longptr_t
Definition RtypesCore.h:75
unsigned char UChar_t
Definition RtypesCore.h:38
int Ssiz_t
Definition RtypesCore.h:67
char Char_t
Definition RtypesCore.h:37
unsigned long ULong_t
Definition RtypesCore.h:55
long Long_t
Definition RtypesCore.h:54
unsigned int UInt_t
Definition RtypesCore.h:46
float Float_t
Definition RtypesCore.h:57
short Short_t
Definition RtypesCore.h:39
double Double_t
Definition RtypesCore.h:59
long double LongDouble_t
Definition RtypesCore.h:61
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:117
long long Long64_t
Definition RtypesCore.h:69
unsigned long long ULong64_t
Definition RtypesCore.h:70
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:374
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:185
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
Definition TROOT.cxx:622
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:414
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:2503
#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.
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.
void SetBasketSize(Int_t buffsize) override
Reset the basket size for all sub-branches of this branch element.
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
virtual void SetBasketSize(Int_t buffsize)
Set the basket size The function makes sure that the basket size is greater than fEntryOffsetlen.
Definition TBranch.cxx:2742
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
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:616
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition TClass.cxx:3571
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2425
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:4837
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Replaces the collection proxy for this class.
Definition TClass.cxx:2576
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:515
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5540
TClassStreamer * GetStreamer() const
Return the Streamer Class allowing streaming (if any).
Definition TClass.cxx:3020
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:399
const TObjArray * GetStreamerInfos() const
Definition TClass.h:499
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:6055
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6081
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method).
Definition TClass.cxx:6090
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:4727
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:5002
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:3003
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6229
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition TClass.cxx:7222
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:3074
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:220
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:246
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:205
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
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:864
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1099
virtual TClass * IsA() const
Definition TObject.h:249
void ResetBit(UInt_t f)
Definition TObject.h:204
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
void PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax=1000) const
print value of element i in object at pointer The function may be called in two ways: -method1 len < ...
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 TClonesArray and eventually element k in a sub-arra...
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 a TClonesArray and eventually element k in a sub-arra...
TClass * GetClass() const override
T GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
void PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
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
void PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
static TClass * Class()
static TClass * Class()
static TClass * Class()
static TClass * Class()
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
static constexpr Ssiz_t kNPOS
Definition TString.h:278
const char * Data() const
Definition TString.h:376
@ kTrailing
Definition TString.h:276
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition TString.cxx:931
TString & Remove(Ssiz_t pos)
Definition TString.h:685
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:2378
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2356
static TClass * Class()
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
A TTree represents a columnar dataset.
Definition TTree.h:84
TStreamerInfo * BuildStreamerInfo(TClass *cl, void *pointer=nullptr, bool canOptimize=true)
Build StreamerInfo for class cl.
Definition TTree.cxx:2649
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5309
Int_t GetDefaultEntryOffsetLen() const
Definition TTree.h:471
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:541
void Draw(Option_t *opt) override
Default Draw method for all objects.
Definition TTree.h:443
TDirectory * GetDirectory() const
Definition TTree.h:474
@ kSplitCollectionOfPointers
Definition TTree.h:278
Int_t Debug() const
Definition TTree.h:441
virtual TBranchRef * GetBranchRef() const
Definition TTree.h:462
virtual Long64_t GetReadEntry() const
Definition TTree.h:561
Long64_t GetDebugMin() const
Definition TTree.h:473
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
std::ostream & Info()
Definition hadd.cxx:177
const Int_t n
Definition legend1.C:16
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
@ 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:198
std::vector< TIDNode > TIDs
TCanvas * slash()
Definition slash.C:1
TMarker m
Definition textangle.C:8