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
51
52////////////////////////////////////////////////////////////////////////////////
53
54namespace {
55 void RemovePrefix(TString& str, const TString &prefix) {
56 // -- Remove a prefix from a string.
57 // -- Require a '.' after the prefix.
58 if (prefix.Length() && prefix.Length() <= str.Length()
59 && (str.Data()[prefix.Length()] == '.' || (prefix[prefix.Length()-1]=='.')))
60 {
61 if (!str.Index(prefix))
62 str.Remove(0, prefix.Length());
63 }
64 }
65 struct R__PushCache {
67 TVirtualArray *fOnfileObject;
68
69 R__PushCache(TBuffer &b, TVirtualArray *in, UInt_t size) : fBuffer(b), fOnfileObject(in)
70 {
71 if (fOnfileObject) {
72 fOnfileObject->SetSize(size);
73 fBuffer.PushDataCache( fOnfileObject );
74 }
75 }
77 if (fOnfileObject) fBuffer.PopDataCache();
78 }
79 };
80}
81
82////////////////////////////////////////////////////////////////////////////////
83/// Modify the container type of the branches
84
86 const Int_t nbranches = branches->GetEntriesFast();
87 for (Int_t i = 0; i < nbranches; ++i) {
89 switch (br->GetType()) {
90 case 31: br->SetType(41); break;
91 case 41: {
92 br->SetType(31);
93 br->fCollProxy = nullptr;
94 break;
95 }
96 }
97 br->SetReadLeavesPtr();
98 br->SetFillLeavesPtr();
99 // Note: This is a tail recursion.
100 SwitchContainer(br->GetListOfBranches());
101 }
102}
103
104////////////////////////////////////////////////////////////////////////////////
105
106namespace {
107 bool CanSelfReference(TClass *cl) {
108 if (cl) {
109 if (cl->GetCollectionProxy()) {
110 TClass *inside = cl->GetCollectionProxy()->GetValueClass();
111 if (inside) {
112 return CanSelfReference(inside);
113 } else {
114 return false;
115 }
116 }
117 const static TClassRef stringClass("std::string");
118 if (cl == stringClass || cl == TString::Class()) {
119 return false;
120 }
121 // Here we could scan through the TStreamerInfo to see if there
122 // is any pointer anywhere and know whether this is a possibility
123 // of selfreference (but watch out for very indirect cases).
124 return true;
125 }
126 return false;
127 }
128}
129
130////////////////////////////////////////////////////////////////////////////////
131/// Default and I/O constructor.
132
134: TBranch()
135, fClassName()
136, fParentName()
137, fClonesName()
138, fCollProxy(nullptr)
139, fCheckSum(0)
140, fClassVersion(0)
141, fID(0)
142, fType(0)
143, fStreamerType(-1)
144, fMaximum(0)
145, fSTLtype(ROOT::kNotSTL)
146, fNdata(1)
147, fBranchCount(nullptr)
148, fBranchCount2(nullptr)
149, fInfo(nullptr)
150, fObject(nullptr)
151, fOnfileObject(nullptr)
152, fInit(false)
153, fInInitInfo(false)
154, fInitOffsets(false)
155, fTargetClass()
156, fCurrentClass()
157, fParentClass()
158, fBranchClass()
159, fClonesClass()
160, fBranchOffset(nullptr)
161, fBranchID(-1)
162, fReadActionSequence(nullptr)
163, fFillActionSequence(nullptr)
164, fIterators(nullptr)
165, fWriteIterators(nullptr)
166, fPtrIterators(nullptr)
167{
168 fNleaves = 0;
171}
172
173////////////////////////////////////////////////////////////////////////////////
174/// Constructor when the branch object is not a TClonesArray nor an STL container.
175///
176/// If splitlevel > 0 this branch in turn is split into sub-branches.
177
178TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
179: TBranch()
180, fClassName(sinfo->GetName())
181, fParentName()
182, fClonesName()
183, fCollProxy(nullptr)
184, fCheckSum(sinfo->GetCheckSum())
185, fClassVersion(sinfo->GetClass()->GetClassVersion())
186, fID(id)
187, fType(0)
188, fStreamerType(-1)
189, fMaximum(0)
190, fSTLtype(ROOT::kNotSTL)
191, fNdata(1)
192, fBranchCount(nullptr)
193, fBranchCount2(nullptr)
194, fInfo(sinfo)
195, fObject(nullptr)
196, fOnfileObject(nullptr)
197, fInit(true)
198, fInInitInfo(false)
199, fInitOffsets(false)
200, fTargetClass(fClassName)
201, fCurrentClass()
202, fParentClass()
203, fBranchClass(sinfo->GetClass())
204, fClonesClass()
205, fBranchOffset(nullptr)
206, fBranchID(-1)
207, fReadActionSequence(nullptr)
208, fFillActionSequence(nullptr)
209, fIterators(nullptr)
210, fWriteIterators(nullptr)
211, fPtrIterators(nullptr)
212{
213 if (tree) {
214 ROOT::TIOFeatures features = tree->GetIOFeatures();
216 }
217 Init(tree, nullptr, bname,sinfo,id,pointer,basketsize,splitlevel,btype);
218}
219
220////////////////////////////////////////////////////////////////////////////////
221/// Constructor when the branch object is not a TClonesArray nor an STL container.
222///
223/// If splitlevel > 0 this branch in turn is split into sub-branches.
224
225TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
226: TBranch()
227, fClassName(sinfo->GetName())
228, fParentName()
229, fClonesName()
230, fCollProxy(nullptr)
231, fCheckSum(sinfo->GetCheckSum())
232, fClassVersion(sinfo->GetClass()->GetClassVersion())
233, fID(id)
234, fType(0)
235, fStreamerType(-1)
236, fMaximum(0)
237, fSTLtype(ROOT::kNotSTL)
238, fNdata(1)
239, fBranchCount(nullptr)
240, fBranchCount2(nullptr)
241, fInfo(sinfo)
242, fObject(nullptr)
243, fOnfileObject(nullptr)
244, fInit(true)
245, fInInitInfo(false)
246, fInitOffsets(false)
247, fTargetClass( fClassName )
248, fCurrentClass()
249, fParentClass()
250, fBranchClass(sinfo->GetClass())
251, fClonesClass()
252, fBranchOffset(nullptr)
253, fBranchID(-1)
254, fReadActionSequence(nullptr)
255, fFillActionSequence(nullptr)
256, fIterators(nullptr)
257, fWriteIterators(nullptr)
258, fPtrIterators(nullptr)
259{
262 Init(parent ? parent->GetTree() : nullptr, parent, bname,sinfo,id,pointer,basketsize,splitlevel,btype);
263}
264
265////////////////////////////////////////////////////////////////////////////////
266/// Init when the branch object is not a TClonesArray nor an STL container.
267///
268/// If splitlevel > 0 this branch in turn is split into sub-branches.
269
270void TBranchElement::Init(TTree *tree, TBranch *parent,const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
271{
272 TString name(bname);
273
274 // Set our TNamed attributes.
275 SetName(name);
276 SetTitle(name);
277
278 // Set our TBranch attributes.
280 fTree = tree;
281 if (fTree == nullptr) return;
282 fMother = parent ? parent->GetMother() : this;
283 fParent = parent;
285 fFileName = "";
286
287 // Clear the bit kAutoDelete to specify that when reading
288 // the object should not be deleted before calling Streamer.
289
290 SetAutoDelete(false);
291
294
295 //---------------------------------------------------------------------------
296 // Handling the splitting of the STL collections of pointers
297 /////////////////////////////////////////////////////////////////////////////
298
301
302 fCompress = -1;
303 if (fTree->GetDirectory()) {
305 if (bfile) {
306 fCompress = bfile->GetCompressionSettings();
307 }
308 }
309
310 //
311 // Initialize streamer type and element.
312 //
313
314 if (id > -1) {
315 // We are *not* a top-level branch.
316 TStreamerElement* element = sinfo->GetElement(id);
317 fStreamerType = element->GetType();
318 }
319
320 //
321 // Handle varying-length datatypes by allocating an offsets array.
322 //
323 // The fBits part of a TObject is of varying length because the pidf
324 // is streamed only when the TObject is referenced by a TRef.
325 //
326
327 fEntryOffsetLen = 0;
330 }
331
332 //
333 // Make sure the basket is big enough to contain the
334 // entry offset array plus 100 bytes of data.
335 //
336
337 if (basketsize < (100 + fEntryOffsetLen)) {
339 }
341
342 //
343 // Allocate and initialize the basket control arrays.
344 //
345
349
350 for (Int_t i = 0; i < fMaxBaskets; ++i) {
351 fBasketBytes[i] = 0;
352 fBasketEntry[i] = 0;
353 fBasketSeek[i] = 0;
354 }
355
356 // We need to keep track of the counter branch if we have
357 // one, since we cannot set it until we have created our
358 // leaf, which we do last.
359 TBranchElement* brOfCounter = nullptr;
360
361 if (id < 0) {
362 // -- We are a top-level branch. Don't split a top-level branch, TTree::Bronch will do that work.
363 if (fBranchClass.GetClass()) {
364 bool hasCustomStreamer = false;
369 } else {
372 }
373 if (hasCustomStreamer) {
374 fType = -1;
375 }
376 }
377 } else {
378 // -- We are a sub-branch of a split object.
379 TStreamerElement* element = sinfo->GetElement(id);
381 // -- If we are an object data member which inherits from TObject,
382 // flag it so that later during i/o we will register the object
383 // with the buffer so that pointers are handled correctly.
387 } else {
389 }
390 }
391 }
392 if (element->IsA() == TStreamerBasicPointer::Class()) {
393 // -- Fixup title with counter if we are a varying length array data member.
396 countname = bname;
397 Ssiz_t dot = countname.Last('.');
398 if (dot>=0) {
399 countname.Remove(dot+1);
400 } else {
401 countname = "";
402 }
403 countname += bp->GetCountName();
405 countname.Form("%s[%s]",name.Data(),bp->GetCountName());
407
408 } else if (element->IsA() == TStreamerLoop::Class()) {
409 // -- Fixup title with counter if we are a varying length array data member.
412 countname = bname;
413 Ssiz_t dot = countname.Last('.');
414 if (dot>=0) {
415 countname.Remove(dot+1);
416 } else {
417 countname = "";
418 }
419 countname += bp->GetCountName();
421 countname.Form("%s[%s]",name.Data(),bp->GetCountName());
423
424 }
425
426 if (splitlevel > 0) {
427 // -- Create sub branches if requested by splitlevel.
428 const char* elemType = element->GetTypeName();
429 TClass *elementClass = element->GetClassPointer();
430 fSTLtype = elementClass ? elementClass->GetCollectionType() : ROOT::kNotSTL;
431 if (element->CannotSplit()) {
432 fSplitLevel = 0;
433 } else if (element->IsA() == TStreamerBase::Class()) {
434 // -- We are a base class element.
435 // Note: This does not include an STL container class which is
436 // being used as a base class because the streamer element
437 // in that case is not the base streamer element it is the
438 // STL streamer element.
439 fType = 1;
440 TClass* clOfElement = element->GetClassPointer();
442 // Note: The following code results in base class branches
443 // having two different cases for what their parent
444 // class will be, this is very annoying. It is also
445 // very annoying that the naming conventions for the
446 // sub-branch names are different as well.
447 if (!strcmp(name, clOfElement->GetName())) {
448 // -- If the branch's name is the same as the base class name,
449 // which happens when we are a child branch of a top-level
450 // branch whose name does not end in a dot and also has no
451 // internal dots, elide the branch name, and keep the branch
452 // hierarchy rooted at the ultimate parent, this keeps the base
453 // class part of the branch name from propagating downwards.
454 // FIXME: We are eliding the base class here, creating a break in the branch hierarchy.
455 // Note: We can use parent class (cltop) != branch class (elemClass) to detection elision.
459 return;
460 }
461 // If the branch's name is not the same as the base class name,
462 // keep the branch name as a prefix (i.e., continue the branch
463 // hierarchy), but start a new class hierarchy at the base class.
464 //
465 // Note: If the parent branch was created by the branch constructor
466 // which takes a folder as a parameter, then this case will
467 // be used, because the branch name will be the same as the
468 // parent branch name.
469 // Note: This means that the sub-branches of a base class branch
470 // created by TTree::Bronch() have the base class name as
471 // as part of the branch name, while those created by
472 // Unroll() do not, ouch!!!
473 //
475 if (strchr(bname, '.')) {
476 // Note: How can this happen?
477 // Answer: This is the case when using the new branch
478 // naming convention where the top-level branch ends in dot.
479 // Note: Well actually not entirely, we could also be a sub-branch
480 // of a split class, even when the top-level branch does not
481 // end in a dot.
482 // Note: Or the top-level branch could have been created by the
483 // branch constructor which takes a folder as input, in which
484 // case the top-level branch name will have internal dots
485 // representing the folder hierarchy.
488 return;
489 }
491 // -- We did not add any branches in the Unroll, finalize our name to be the base class name, because Unroll did not do it for us.
492 const auto bnamelen = strlen(bname);
493 if (bnamelen) {
494 name.Form("%s%s%s", bname, bname[bnamelen-1]=='.' ? "" : ".", clOfElement->GetName());
495 } else {
496 name.Form("%s", clOfElement->GetName());
497 }
498 SetName(name);
499 SetTitle(name);
500 }
503 return;
504 } else if (element->GetClassPointer() == TClonesArray::Class()) {
505 // -- We are a TClonesArray element.
506 bool ispointer = element->IsaPointer();
508 if (ispointer) {
509 char **ppointer = (char**)(pointer);
511 } else {
512 clones = (TClonesArray*)pointer;
513 }
514 // basket->DeleteEntryOffset(); //entryoffset not required for the clonesarray counter
515 fEntryOffsetLen = 0;
516 // ===> Create a leafcount
518 fNleaves = 1;
520 fTree->GetListOfLeaves()->Add(leaf);
521 if (!clones) {
523 return;
524 }
525 TClass* clOfClones = clones->GetClass();
526 if (!clOfClones) {
529 return;
530 }
531 fType = 3;
532 // ===> create sub branches for each data member of a TClonesArray
533 //check that the contained objects class name is part of the element title
534 //This name is mandatory when reading the Tree later on and
535 //the parent class with the pointer to the TClonesArray is not available.
536 fClonesName = clOfClones->GetName();
539 aname.Form(" (%s)", clOfClones->GetName());
540 TString atitle = element->GetTitle();
541 if (!atitle.Contains(aname)) {
542 atitle += aname;
543 element->SetTitle(atitle.Data());
544 }
546 if (branchname.EndsWith("."))
547 branchname.Remove(branchname.Length()-1);
548 branchname += "_";
550 leaf->SetName(branchname);
551 leaf->SetTitle(branchname);
552 leaf->SetRange(true);
557 return;
559 // -- We are an STL container element.
561 fCollProxy = contCl->GetCollectionProxy()->Generate();
563 // Check to see if we can split the container.
564 bool cansplit = true;
565 if (!valueClass) {
566 cansplit = false;
567 } else if ((valueClass == TString::Class()) || (valueClass == TClass::GetClass("string"))) {
568 cansplit = false;
569 } else if (GetCollectionProxy()->HasPointers() && !splitSTLP ) {
570 cansplit = false;
571 } else if (!valueClass->CanSplit() && !(GetCollectionProxy()->HasPointers() && splitSTLP)) {
572 cansplit = false;
573 } else if (valueClass->GetCollectionProxy()) {
574 // -- A collection was stored in a collection, we choose not to split it.
575 // Note: Splitting it would require extending TTreeFormula
576 // to understand how to access it.
577 cansplit = false;
578 }
579 if (cansplit) {
580 // -- Do the splitting work if we are allowed to.
581 fType = 4;
582 // Create a leaf for the master branch (the counter).
584 fNleaves = 1;
586 fTree->GetListOfLeaves()->Add(leaf);
587 // Check that the contained objects class name is part of the element title.
588 // This name is mandatory when reading the tree later on and
589 // the parent class with the pointer to the STL container is not available.
590 fClonesName = valueClass->GetName();
593 aname.Form(" (%s)", valueClass->GetName());
594 TString atitle = element->GetTitle();
595 if (!atitle.Contains(aname)) {
596 atitle += aname;
597 element->SetTitle(atitle.Data());
598 }
600 if (branchname.EndsWith("."))
601 branchname.Remove(branchname.Length()-1);
602 branchname += "_";
604 leaf->SetName(branchname);
605 leaf->SetTitle(branchname);
606 leaf->SetRange(true);
607 // Create sub branches for each data member of an STL container.
612 return;
613 }
615 // -- Create sub-branches for members that are classes.
616 //
617 // Note: This can only happen if we were called directly
618 // (usually by TClass::Bronch) because Unroll never
619 // calls us for an element of this type.
620 fType = 2;
622 Int_t err = Unroll(name, clm, clm, pointer, basketsize, splitlevel+splitSTLP, 0);
623 if (err >= 0) {
624 // Return on success.
625 // FIXME: Why not on error too?
628 return;
629 }
630 }
631 }
632 }
633
634 //
635 // Create a leaf to represent this branch.
636 //
637
639 leaf->SetTitle(GetTitle());
640 fNleaves = 1;
642 fTree->GetListOfLeaves()->Add(leaf);
643
644 //
645 // If we have a counter branch set it now that we have
646 // created our leaf, we cannot do it before then.
647 //
648
649 if (brOfCounter) {
651 }
652
655}
656
657////////////////////////////////////////////////////////////////////////////////
658/// Constructor when the branch object is a TClonesArray.
659///
660/// If splitlevel > 0 this branch in turn is split into sub branches.
661
663: TBranch()
664, fClassName("TClonesArray")
665, fParentName()
666, fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo())
667, fInit(true)
668, fInInitInfo(false)
669, fInitOffsets(false)
670, fTargetClass( fClassName )
671, fCurrentClass()
672, fParentClass()
673, fBranchClass(TClonesArray::Class())
674, fBranchID(-1)
675, fReadActionSequence(nullptr)
676, fFillActionSequence(nullptr)
677, fIterators(nullptr)
678, fWriteIterators(nullptr)
679, fPtrIterators(nullptr)
680{
681 Init(tree, nullptr, bname, clones, basketsize, splitlevel, compress);
682}
683
684////////////////////////////////////////////////////////////////////////////////
685/// Constructor when the branch object is a TClonesArray.
686///
687/// If splitlevel > 0 this branch in turn is split into sub branches.
688
690: TBranch()
691, fClassName("TClonesArray")
692, fParentName()
693, fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo())
694, fInit(true)
695, fInInitInfo(false)
696, fInitOffsets(false)
697, fTargetClass( fClassName )
698, fCurrentClass()
699, fParentClass()
700, fBranchClass(TClonesArray::Class())
701, fBranchID(-1)
702, fReadActionSequence(nullptr)
703, fFillActionSequence(nullptr)
704, fIterators(nullptr)
705, fWriteIterators(nullptr)
706, fPtrIterators(nullptr)
707{
708 Init(parent ? parent->GetTree() : nullptr, parent, bname, clones, basketsize, splitlevel, compress);
709}
710
711////////////////////////////////////////////////////////////////////////////////
712/// Init when the branch object is a TClonesArray.
713///
714/// If splitlevel > 0 this branch in turn is split into sub branches.
715
717{
718 fCollProxy = nullptr;
720 fID = 0;
721 fInit = true;
722 fStreamerType = -1;
723 fType = 0;
724 fClassVersion = TClonesArray::Class()->GetClassVersion();
726 fBranchCount = nullptr;
727 fBranchCount2 = nullptr;
728 fObject = nullptr;
729 fOnfileObject = nullptr;
730 fMaximum = 0;
731 fBranchOffset = nullptr;
733 fInitOffsets = false;
734
735 fTree = tree;
736 fMother = parent ? parent->GetMother() : this;
737 fParent = parent;
739 fFileName = "";
740
741 SetName(bname);
742 const char* name = GetName();
743
744 SetTitle(name);
745 //fClassName = fInfo->GetName();
747 if (compress == -1 && fTree->GetDirectory()) {
749 if (bfile) fCompress = bfile->GetCompressionSettings();
750 }
751
752 if (basketsize < 100) basketsize = 100;
757
758 for (Int_t i=0;i<fMaxBaskets;i++) {
759 fBasketBytes[i] = 0;
760 fBasketEntry[i] = 0;
761 fBasketSeek[i] = 0;
762 }
763
764 // Reset the bit kAutoDelete to specify that when reading
765 // the object should not be deleted before calling the streamer.
766 SetAutoDelete(false);
767
768 // create sub branches if requested by splitlevel
770 TClass* clonesClass = clones->GetClass();
771 if (!clonesClass) {
772 Error("Init","Missing class object of the TClonesArray %s\n",clones->GetName());
773 return;
774 }
775 fType = 3;
776 // ===> Create a leafcount
778 fNleaves = 1;
780 fTree->GetListOfLeaves()->Add(leaf);
781 // ===> create sub branches for each data member of a TClonesArray
782 fClonesName = clonesClass->GetName();
785 if (branchname[branchname.Length()-1]=='.') {
786 branchname.Remove(branchname.Length()-1);
787 }
788 branchname += "_";
790 leaf->SetName(branchname);
791 leaf->SetTitle(branchname);
796 return;
797 }
798
799 if (!clones->GetClass() || CanSelfReference(clones->GetClass())) {
801 }
803 leaf->SetTitle(GetTitle());
804 fNleaves = 1;
806 fTree->GetListOfLeaves()->Add(leaf);
807
810}
811
812////////////////////////////////////////////////////////////////////////////////
813/// Constructor when the branch object is an STL collection.
814///
815/// If splitlevel > 0 this branch in turn is split into sub branches.
816
818: TBranch()
819, fClassName(cont->GetCollectionClass()->GetName())
820, fParentName()
821, fInit(true)
822, fInInitInfo(false)
823, fInitOffsets(false)
824, fTargetClass( fClassName )
825, fCurrentClass()
826, fParentClass()
827, fBranchClass(cont->GetCollectionClass())
828, fBranchID(-1)
829, fReadActionSequence(nullptr)
830, fFillActionSequence(nullptr)
831, fIterators(nullptr)
832, fWriteIterators(nullptr)
833, fPtrIterators(nullptr)
834{
835 Init(tree, nullptr, bname, cont, basketsize, splitlevel, compress);
836}
837
838////////////////////////////////////////////////////////////////////////////////
839/// Constructor when the branch object is an STL collection.
840///
841/// If splitlevel > 0 this branch in turn is split into sub branches.
842
844: TBranch()
845, fClassName(cont->GetCollectionClass()->GetName())
846, fParentName()
847, fInit(true)
848, fInInitInfo(false)
849, fInitOffsets(false)
850, fTargetClass( fClassName )
851, fCurrentClass()
852, fParentClass()
853, fBranchClass(cont->GetCollectionClass())
854, fBranchID(-1)
855, fReadActionSequence(nullptr)
856, fFillActionSequence(nullptr)
857, fIterators(nullptr)
858, fWriteIterators(nullptr)
859, fPtrIterators(nullptr)
860{
861 Init(parent ? parent->GetTree() : nullptr, parent, bname, cont, basketsize, splitlevel, compress);
862}
863
864////////////////////////////////////////////////////////////////////////////////
865/// Init when the branch object is an STL collection.
866///
867/// If splitlevel > 0 this branch in turn is split into sub branches.
868
870{
871 fCollProxy = cont->Generate();
872 TString name( bname );
873 if (name[name.Length()-1]=='.') {
874 name.Remove(name.Length()-1);
875 }
876 fInitOffsets = false;
878 fInfo = nullptr;
879 fID = -1;
880 fInit = true;
881 fStreamerType = -1; // TVirtualStreamerInfo::kSTLp;
882 fType = 0;
883 fClassVersion = cont->GetCollectionClass()->GetClassVersion();
884 fCheckSum = cont->GetCollectionClass()->GetCheckSum();
885 fBranchCount = nullptr;
886 fBranchCount2 = nullptr;
887 fObject = nullptr;
888 fOnfileObject = nullptr;
889 fMaximum = 0;
890 fBranchOffset = nullptr;
891
892 //Must be set here so that write actions will be properly matched to the ReadLeavesPtr
893 fSTLtype = cont->GetCollectionType();
894 if (fSTLtype < 0) {
896 }
897
898 fTree = tree;
899 fMother = parent ? parent->GetMother() : this;
900 fParent = parent;
902 fFileName = "";
903
904 SetName(name);
905 SetTitle(name);
906 //fClassName = fBranchClass.GetClass()->GetName();
908 if ((compress == -1) && fTree->GetDirectory()) {
910 if (bfile) {
911 fCompress = bfile->GetCompressionSettings();
912 }
913 }
914
915 if (basketsize < 100) {
916 basketsize = 100;
917 }
919
923
924 for (Int_t i = 0; i < fMaxBaskets; ++i) {
925 fBasketBytes[i] = 0;
926 fBasketEntry[i] = 0;
927 fBasketSeek[i] = 0;
928 }
929
930 // Reset the bit kAutoDelete to specify that, when reading,
931 // the object should not be deleted before calling the streamer.
932 SetAutoDelete(false);
933
934 // create sub branches if requested by splitlevel
936 (cont->HasPointers() && splitlevel > TTree::kSplitCollectionOfPointers && cont->GetValueClass() && cont->GetValueClass()->CanSplit() ) )
937 {
938 fType = 4;
939 // ===> Create a leafcount
941 fNleaves = 1;
943 fTree->GetListOfLeaves()->Add(leaf);
944 // ===> create sub branches for each data member of an STL container value class
945 TClass* valueClass = cont->GetValueClass();
946 if (!valueClass) {
947 return;
948 }
949 fClonesName = valueClass->GetName();
952 branchname += "_";
954 leaf->SetName(branchname);
955 leaf->SetTitle(branchname);
960 return;
961 }
962
964 leaf->SetTitle(GetTitle());
965 fNleaves = 1;
967 fTree->GetListOfLeaves()->Add(leaf);
970}
971
972////////////////////////////////////////////////////////////////////////////////
973/// Destructor.
974
976{
977 // Release any allocated I/O buffers.
979 delete fOnfileObject;
980 fOnfileObject = nullptr;
981 }
982 ResetAddress();
983
984 delete[] fBranchOffset;
985 fBranchOffset = nullptr;
986
987 fInfo = nullptr;
988 fBranchCount2 = nullptr;
989 fBranchCount = nullptr;
990
991 if (fType == 4 || fType == 0) {
992 // Only the top level TBranchElement containing an STL container,
993 // owns the collectionproxy.
994 delete fCollProxy;
995 }
996 fCollProxy = nullptr;
997
998 delete fReadActionSequence;
999 delete fFillActionSequence;
1000 delete fIterators;
1001 delete fWriteIterators;
1002 delete fPtrIterators;
1003}
1004
1005//
1006// This function is located here to allow inlining by the optimizer.
1007//
1008////////////////////////////////////////////////////////////////////////////////
1009/// Get streamer info for the branch class.
1010
1012{
1013 // Note: we need to find a way to reduce the complexity of
1014 // this often executed condition.
1015 if (!fInfo || (fInfo && (!fInit || !fInfo->IsCompiled()))) {
1016 const_cast<TBranchElement*>(this)->InitInfo();
1017 }
1018 return fInfo;
1019}
1020
1021////////////////////////////////////////////////////////////////////////////////
1022/// Get streamer info for the branch class.
1023
1025{
1026 return GetInfoImp();
1027}
1028
1029////////////////////////////////////////////////////////////////////////////////
1030/// Browse the branch content.
1031
1033{
1035 if (nbranches > 0) {
1037 TBranch* branch=nullptr;
1038 TIter iB(&fBranches);
1039 while((branch=(TBranch*)iB())) {
1040 if (branch->IsFolder()) persistentBranches.Add(branch);
1041 else {
1042 // only show branches corresponding to persistent members
1043 TClass* cl=nullptr;
1044 if (strlen(GetClonesName()))
1045 // this works both for top level branches and for sub-branches,
1046 // as GetClonesName() is properly updated for sub-branches
1047 cl=fClonesClass;
1048 else {
1050
1051 // check if we're in a sub-branch of this class
1052 // we can only find out asking the streamer given our ID
1053 TStreamerElement *element=nullptr;
1054 TClass* clsub=nullptr;
1055 auto info = (fID >= 0) ? GetInfoImp() : nullptr;
1056 if (info
1057 && info->IsCompiled()
1058 && ((element=info->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 auto info = GetInfoImp();
3045 if (info) {
3046 return info->GetTypedValue<T>(object, prID, j, -1);
3047 }
3048 return 0;
3049 }
3050}
3051
3052////////////////////////////////////////////////////////////////////////////////
3053/// Returns pointer to first data element of this branch.
3054/// Currently used only for members of type character.
3055
3057{
3059
3060 TStreamerInfo *info = nullptr;
3061 Int_t prID = fID;
3062 char *object = fObject;
3063 if (TestBit(kCache)) {
3064 info = GetInfoImp();
3065 if (info->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
3066 prID = fID+1;
3067 } else if (fOnfileObject) {
3068 object = fOnfileObject->GetObjectAt(0);
3069 }
3070 }
3071
3072 if (fBranchCount) {
3074 fBranchCount->TBranch::GetEntry(entry);
3075 if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
3076 }
3077 if (TestBit(kDecomposedObj)) {
3078 if (!fAddress) {
3079 return nullptr;
3080 }
3081 if (fType == 3) { //top level branch of a TClonesArray
3082 //return &fNdata;
3083 return nullptr;
3084 } else if (fType == 4) { //top level branch of a TClonesArray
3085 //return &fNdata;
3086 return nullptr;
3087 } else if (fType == 31) { // sub branch of a TClonesArray
3088 //Int_t atype = fStreamerType;
3089 //if (atype < 20) atype += 20;
3090 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3091 return nullptr;
3092 } else if (fType == 41) { // sub branch of a TClonesArray
3093 //Int_t atype = fStreamerType;
3094 //if (atype < 20) atype += 20;
3095 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3096 return nullptr;
3097 } else if (fType <= 2) { // branch in split mode
3098 // FIXME: This should probably be < 60 instead!
3099 if (fStreamerType > 40 && fStreamerType < 55) {
3100 //Int_t atype = fStreamerType - 20;
3101 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3102 return nullptr;
3103 } else {
3104 //return GetInfoImp()->GetValue(object, fID, j, -1);
3105 return nullptr;
3106 }
3107 }
3108 }
3109
3110 if (fType == 31) {
3111 return nullptr;
3112 } else if (fType == 41) {
3113 return nullptr;
3114 } else if (prID < 0) {
3115 return object;
3116 } else {
3117 //return GetInfoImp()->GetValue(object,fID,j,-1);
3118 if (!info)
3119 info = GetInfoImp();
3120 if (!info || !object) return nullptr;
3121 char **val = (char**)(object+info->TStreamerInfo::GetElementOffset(prID));
3122 return *val;
3123 }
3124}
3125
3126////////////////////////////////////////////////////////////////////////////////
3127/// Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a container sub-branch.
3128///
3129/// Note: The offsets are zero for data members so that when
3130/// SetAddress recursively sets their address, they will get the
3131/// same address as their containing class because i/o is based
3132/// on streamer info offsets from the address of the containing
3133/// class.
3134///
3135/// Offsets are non-zero for base-class sub-branches that are
3136/// not the leftmost direct base class. They are laid out in
3137/// memory sequentially and only the leftmost direct base class
3138/// has the same address as the derived class. The streamer
3139/// offsets need to be added to the address of the base class
3140/// subobject which is not the same as the address of the
3141/// derived class for the non-leftmost direct base classes.
3142
3144{
3146
3147 // See https://sft.its.cern.ch/jira/browse/ROOT-8742
3148 // and https://sft.its.cern.ch/jira/browse/ROOT-9253
3149 // As of commit e21b4f1a3b, removing this lock lead to a failure
3150 // in the test testSetAddress[Loop].
3151 // As of commit 4f8b237849, removing this lock does not lead to
3152 // a visible failure in test. This might be due to the underlying
3153 // problem (missing lock or ?) being solved somewhere else or some
3154 // other perturbation reducing the failure rate.
3155 // Having the lock here is not too costly as InitializeOffsets is
3156 // one called once in the lifetime of the TBranch.
3158
3159 if (fID < 0) {
3160 // -- We are a top-level branch. Let's mark whether we need to use MapObject.
3162 if (fBranchClass.GetClass()->IsTObject()) {
3164 } else {
3166 }
3167 }
3168 }
3169 if (nbranches) {
3170 // Allocate space for the new sub-branch offsets.
3171 delete[] fBranchOffset;
3172 fBranchOffset = nullptr;
3174 // Make sure we can instantiate our class meta info.
3175 if (!fBranchClass.GetClass()) {
3176 Warning("InitializeOffsets", "No branch class set for branch: %s", GetName());
3177 fInitOffsets = true;
3178 return;
3179 }
3180 // Make sure we can instantiate our class streamer info.
3182 if (!info) {
3183 Warning("InitializeOffsets", "No streamer info available for branch: %s of class: %s", GetName(), fBranchClass.GetClass()->GetName());
3184 fInitOffsets = true;
3185 return;
3186 }
3187
3188 // Get the class we are a member of now (which is the
3189 // type of our containing subobject) and get our offset
3190 // inside of our containing subobject (our local offset).
3191 // Note: branchElem stays zero if we are a top-level branch,
3192 // we have to be careful about this later.
3193 TStreamerElement* branchElem = nullptr;
3194 Int_t localOffset = 0;
3196 bool renamed = false;
3197 if (fID > -1) {
3198 // -- Branch is *not* a top-level branch.
3199 // Instead of the streamer info class, we want the class of our
3200 // specific element in the streamer info. We could be a data
3201 // member of a base class or a split class, in which case our
3202 // streamer info will be for our containing sub-object, while
3203 // we are actually a different type.
3204 // Note: We tested to make sure the streamer info was available previously.
3205 if (!info->IsCompiled()) {
3206 Warning("InitializeOffsets", "Streamer info for branch: %s has no elements array!", GetName());
3207 fInitOffsets = true;
3208 return;
3209 }
3210 // FIXME: Check that fID is in range.
3211 branchElem = info->GetElement(fID);
3212 if (!branchElem) {
3213 Warning("InitializeOffsets", "Cannot get streamer element for branch: %s!", GetName());
3214 fInitOffsets = true;
3215 return;
3216 } else if (branchElem->TestBit(TStreamerElement::kRepeat)) {
3217 // If we have a repeating streamerElement, use the next
3218 // one as it actually hold the 'real' data member('s offset)
3219 if (info->GetElement(fID+1)) {
3220 branchElem = info->GetElement(fID+1);
3221 }
3222 }
3223 localOffset = branchElem->GetOffset();
3224 branchClass = branchElem->GetClassPointer();
3226 fObject = nullptr;
3227 } else {
3228 renamed = branchClass && branchElem->GetNewClass() && (branchClass != branchElem->GetNewClass());
3229 }
3230 } else {
3232 }
3233 if (!branchClass) {
3234 Error("InitializeOffsets", "Could not find class for branch: %s", GetName());
3235 fInitOffsets = true;
3236 return;
3237 }
3238
3239 //------------------------------------------------------------------------
3240 // Extract the name of the STL branch in case it has been split.
3241 //////////////////////////////////////////////////////////////////////////
3242
3244 bool stlParentNameUpdated = false;
3245 if( fType == 4 )
3246 {
3247 TBranch *br = GetMother()->GetSubBranch( this );
3248 stlParentName = br->GetName();
3250
3251 // We may ourself contain the 'Mother' branch name.
3252 // To avoid code duplication, we delegate the removal
3253 // of the mother's name to the first sub-branch loop.
3254 }
3255
3256 // Loop over our sub-branches and compute their offsets.
3258 bool alternateElement = false;
3259
3262 if (subBranch == nullptr) {
3263 // -- Skip sub-branches that are not TBranchElements.
3264 continue;
3265 }
3266
3267 if (renamed) {
3268 if (subBranch->fBranchClass == branchClass) {
3269 if (branchElem) subBranch->SetTargetClass(branchElem->GetNewClass()->GetName());
3270 else subBranch->SetTargetClass(fTargetClass->GetName());
3271 }
3272 }
3273
3274 TVirtualStreamerInfo* sinfo = subBranch->GetInfoImp();
3275 if (!sinfo) {
3276 Warning("InitializeOffsets", "No streamer info for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3278 continue;
3279 }
3280 if (!sinfo->IsCompiled()) {
3281 Warning("InitializeOffsets", "No elements array for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3283 continue;
3284 }
3285 // FIXME: Make sure subBranch->fID is in range.
3286 TStreamerElement* subBranchElement = sinfo->GetElement(subBranch->fID);
3287 if (!subBranchElement) {
3288 Warning("InitializeOffsets", "No streamer element for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3290 continue;
3291 } else if (subBranchElement->TestBit(TStreamerElement::kRepeat)) {
3292 // If we have a repeating streamerElement, use the next
3293 // one as it actually hold the 'real' data member('s offset)
3294 if (sinfo->GetElement(subBranch->fID+1)) {
3295 subBranchElement = sinfo->GetElement(subBranch->fID+1);
3296 }
3297 } else if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3298 // We have a cached item which is not a repeated but we might still
3299 // have some Actions triggered by a rule that affect real
3300 // data member(s).
3301 if (subBranch->fReadActionSequence && subBranch->fReadActionSequence->fActions.size() > 1) {
3302 typedef TStreamerInfoActions::ActionContainer_t::iterator iterator;
3303 iterator end = subBranch->fReadActionSequence->fActions.end();
3304 for(iterator iter = subBranch->fReadActionSequence->fActions.begin();
3305 iter != end; ++iter) {
3306 TStreamerInfoActions::TConfiguration *config = iter->fConfiguration;
3307 UInt_t id = config->fElemId;
3308 TStreamerElement *e = (TStreamerElement*)config->fInfo->GetElements()->At(id);
3309 if (e && !e->TestBit(TStreamerElement::kCache)) {
3311 alternateElement = true;
3312 break;
3313 }
3314 }
3315 }
3316 }
3317
3318 localOffset = subBranchElement->GetOffset();
3320 subBranch->fObject = nullptr;
3321 }
3322 {
3323 Int_t streamerType = subBranchElement->GetType();
3325 && subBranch->GetListOfBranches()->GetEntriesFast()==0
3326 && CanSelfReference(subBranchElement->GetClass()))
3327 {
3328 subBranch->SetBit(kBranchAny);
3329 } else {
3330 subBranch->ResetBit(kBranchAny);
3331 }
3332 }
3333
3334 if (subBranchElement->GetNewType()<0) {
3335 subBranch->ResetBit(kBranchAny);
3336 subBranch->ResetBit(kBranchObject);
3337 }
3338
3339 // Note: This call is expensive, do it only once.
3341 if (!mother) {
3342 Warning("InitializeOffsets", "Branch '%s' has no mother!", GetName());
3344 continue;
3345 }
3346 TString motherName(mother->GetName());
3347 bool motherDot = false;
3348 if (motherName.Length() && strchr(motherName.Data(), '.')) {
3349 motherDot = true;
3350 }
3351 bool motherDotAtEnd = false;
3352 if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
3353 motherDotAtEnd = true;
3354 }
3355
3356 bool isBaseSubBranch = false;
3357 if ((subBranch->fType == 1) || (subBranchElement && subBranchElement->IsBase())) {
3358 // -- Base class sub-branch (1).
3359 //
3360 // Note: Our type will not be 1, even though we are
3361 // a base class branch, if we are not split (see the
3362 // constructor), or if we are an STL container master
3363 // branch and a base class branch at the same time
3364 // or an std::string.
3365 isBaseSubBranch = true;
3366 }
3367
3368 bool isContDataMember = false;
3369 if ((subBranch->fType == 31) || (subBranch->fType == 41)) {
3370 // -- Container data member sub-branch (31 or 41).
3371 isContDataMember = true;
3372 }
3373
3374 // I am either a data member sub-branch (0), or a base class
3375 // sub-branch (1), or TClonesArray master sub-branch (3),
3376 // or an STL container master sub-branch (4), or TClonesArray
3377 // data member sub-branch (31), or an STL container data member
3378 // sub-branch (41).
3379 //
3380 // My parent branch is either a top-level branch ((0), fID==(-2,-1)),
3381 // or a base class sub-branch (1), or a split-class branch (2),
3382 // or a TClonesArray master branch (3), or an STL container
3383 // master branch (4).
3384 //
3385
3386 //
3387 // We need to extract from our name the name
3388 // of the data member which contains us, so
3389 // that we may then do a by-name lookup in the
3390 // dictionary meta info of our parent class to
3391 // get our offset in our parent class.
3392 //
3393
3394 // Get our name.
3395 TString dataName(subBranch->GetName());
3396 if (motherDotAtEnd) {
3397 // -- Remove the top-level branch name from our name.
3398 dataName.Remove(0, motherName.Length());
3399 // stlParentNameUpdated is false the first time in this loop.
3400 if (!stlParentNameUpdated && stlParentName.Length()) {
3401 stlParentName.Remove(0, motherName.Length());
3402 stlParentNameUpdated = true;
3403 }
3404 } else if (fType == 4) {
3405 // This is a top-level branch of type STL collection. In this current
3406 // iteration, we are trying to calculate the offset of one of the
3407 // base classes of the element type of the STL collection. The
3408 // dataName string in this case will be akin to
3409 // "nameOfBranch.BaseClassName". Later logic in this function will
3410 // try to get the TRealData relative to "BaseClassName". But if the
3411 // base class is not splittable (i.e. it has a custom streamer), that
3412 // will not work anyway. The treatment of base classes follows a
3413 // different path: we remove the leading name of the branch, so only
3414 // the name of the base class is left. This will be later detected
3415 // and dataName will be stripped from the name of the base class,
3416 // leaving the string completely empty. Since the dataName string
3417 // will be empty, the logic of this function skips the part related
3418 // to finding the TRealData and directly computes the base class
3419 // offset.
3420 // Only perform the modification of the string if it looks as we
3421 // expect
3422 if (dataName == (motherName + '.' + subBranchElement->GetName()))
3423 dataName = subBranchElement->GetName();
3424 } else if (motherDot) {
3425 // -- Remove the top-level branch name from our name, folder case.
3426 //
3427 // Note: We are in the case where our mother was created
3428 // by the branch constructor which takes a folder
3429 // as an argument. The mother branch has internal
3430 // dots in its name to represent the folder hierarchy.
3431 // The TTree::Bronch() routine has handled us as a
3432 // special case, we must compensate.
3433 if ((fID < 0) && (subBranchElement->IsA() == TStreamerBase::Class())) {
3434 // -- Our name is the mother name, remove it.
3435 // Note: The test is our parent is a top-level branch
3436 // and our streamer is the base class streamer,
3437 // this matches the exact test in TTree::Bronch().
3438 if (dataName.Length() == motherName.Length()) {
3439 dataName.Remove(0, motherName.Length());
3440 // stlParentNameUpdated is false the first time in this loop.
3441 if (!stlParentNameUpdated && stlParentName.Length()) {
3442 stlParentName.Remove(0, motherName.Length());
3443 }
3444 }
3445 } else {
3446 // -- Remove the mother name and the dot.
3447 if (dataName.Length() > motherName.Length()) {
3448 dataName.Remove(0, motherName.Length() + 1);
3449 if (!stlParentNameUpdated && stlParentName.Length()) {
3450 stlParentName.Remove(0, motherName.Length());
3451 }
3452 }
3453 }
3454 }
3455 stlParentNameUpdated = true;
3456 if (isBaseSubBranch) {
3457 // -- Remove the base class name suffix from our name.
3458 // Note: The pattern is the name of the base class.
3459 TString pattern(subBranchElement->GetName());
3460 if (pattern.Length() <= dataName.Length()) {
3461 if (!strcmp(dataName.Data() + (dataName.Length() - pattern.Length()), pattern.Data())) {
3462 // The branch name contains the name of the base class in it.
3463 // This name is not reproduced in the sub-branches, so we need to
3464 // remove it.
3465 dataName.Remove(dataName.Length() - pattern.Length());
3466 }
3467 }
3468 // Remove any leading dot.
3469 if (dataName.Length()) {
3470 if (dataName[0] == '.') {
3471 dataName.Remove(0, 1);
3472 }
3473 }
3474 // Note: We intentionally leave any trailing dot
3475 // in our modified name here.
3476 }
3477
3478 // Get our parent branch's name.
3480 if (motherDotAtEnd) {
3481 // -- Remove the top-level branch name from our parent's name.
3482 parentName.Remove(0, motherName.Length());
3483 } else if (motherDot) {
3484 // -- Remove the top-level branch name from our parent's name, folder case.
3485 //
3486 // Note: We are in the case where our mother was created
3487 // by the branch constructor which takes a folder
3488 // as an argument. The mother branch has internal
3489 // dots in its name to represent the folder hierarchy.
3490 // The TTree::Bronch() routine has handled us as a
3491 // special case, we must compensate.
3492 if ((fID > -1) && (mother == mother->GetSubBranch(this)) && (branchElem->IsA() == TStreamerBase::Class())) {
3493 // -- Our parent's name is the mother name, remove it.
3494 // Note: The test is our parent's parent is a top-level branch
3495 // and our parent's streamer is the base class streamer,
3496 // this matches the exact test in TTree::Bronch().
3497 if (parentName.Length() == motherName.Length()) {
3498 parentName.Remove(0, motherName.Length());
3499 }
3500 } else {
3501 // -- Remove the mother name and the dot.
3502 if (parentName.Length() > motherName.Length()) {
3503 parentName.Remove(0, motherName.Length() + 1);
3504 }
3505 }
3506 }
3507 // FIXME: Do we need to use the other tests for a base class here?
3508 if (fType == 1) {
3509 // -- Our parent is a base class sub-branch, remove the base class name suffix from its name.
3510 if (mother != mother->GetSubBranch(this)) {
3511 // -- My parent's parent is not a top-level branch.
3512 // Remove the base class name suffix from the parent name.
3513 // Note: The pattern is the name of the base class.
3514 // coverity[var_deref_model] branchElem is non zero here since fType==1 and thus fID > -1
3515 TString pattern(branchElem->GetName());
3516 if (pattern.Length() <= parentName.Length()) {
3517 if (!strcmp(parentName.Data() + (parentName.Length() - pattern.Length()), pattern.Data())) {
3518 // The branch name contains the name of the base class in it.
3519 // This name is not reproduced in the sub-branches, so we need to
3520 // remove it.
3521 parentName.Remove(parentName.Length() - pattern.Length());
3522 }
3523 }
3524 }
3525 // Note: We intentionally leave any trailing dots
3526 // in the modified parent name here.
3527 }
3528
3529 // Remove the parent branch name part from our name,
3530 // but only if the parent branch is not a top-level branch.
3531 // FIXME: We should not assume parent name does not have length 0.
3532 if (fID > -1) {
3534 }
3535
3536 // Remove any leading dot.
3537 if (dataName.Length()) {
3538 if (dataName[0] == '.') {
3539 dataName.Remove(0, 1);
3540 }
3541 }
3542
3543 // Remove any trailing dot.
3544 if (dataName.Length()) {
3545 if (dataName[dataName.Length()-1] == '.') {
3546 dataName.Remove(dataName.Length() - 1, 1);
3547 }
3548 }
3549
3550 //
3551 // Now that we have our data member name, find our offset
3552 // in our parent class.
3553 //
3554 // Note: Our data member name can have many dots in it
3555 // if branches were elided between our parent branch
3556 // and us by Unroll().
3557 //
3558 // FIXME: This may not work if our member name is ambiguous.
3559 //
3560
3561 Int_t offset = 0;
3562 if (dataName.Length()) {
3563 // -- We have our data member name, do a lookup in the dictionary meta info of our parent class.
3564 // Get our parent class.
3565 TClass* pClass = nullptr;
3566 // First check whether this sub-branch is part of the 'cache' (because the data member it
3567 // represents is no longer in the current class layout.
3568 TStreamerInfo *subInfo = subBranch->GetInfoImp();
3569 //if (subInfo && subBranch->TestBit(kCache)) { // subInfo->GetElements()->At(subBranch->GetID())->TestBit(TStreamerElement::kCache)) {
3571 pClass = ((TStreamerElement*)subInfo->GetElements()->At(0))->GetClassPointer();
3572 }
3573 // FIXME: Do we need the other base class tests here?
3574 if (!pClass) {
3575 if (fType == 1) {
3576 // -- Parent branch is a base class branch.
3577 // FIXME: Is using branchElem here the right thing?
3578 pClass = branchElem->GetClassPointer();
3579 if (pClass->Property() & kIsAbstract) {
3580 // the class is abstract, let see if the
3581
3583 if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
3584 // Our parent's class is emulated and we represent an abstract class.
3585 // and the target class has not been set explicitly.
3586 TString target = pClass->GetName();
3587 target += "@@emulated";
3588
3590 }
3591 }
3592 } else {
3593 // -- Parent branch is *not* a base class branch.
3594 // FIXME: This sometimes returns a null pointer.
3595 pClass = subBranch->GetParentClass();
3596 }
3597 }
3598 if (!pClass) {
3599 // -- No parent class, fix it.
3600 // FIXME: This is probably wrong!
3601 // Assume parent class is our parent branch's clones class or value class.
3602 if (GetClonesName() && strlen(GetClonesName())) {
3604 if (!pClass) {
3605 Warning("InitializeOffsets", "subBranch: '%s' has no parent class, and cannot get class for clones class: '%s'!", subBranch->GetName(), GetClonesName());
3607 continue;
3608 }
3609 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3610 }
3613 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass ? pClass->GetName() : "unknown class");
3614 }
3615 if (!pClass) {
3616 // -- Still no parent class, assume our parent class is our parent branch's class.
3617 // FIXME: This is probably wrong!
3619 // FIXME: Enable this warning!
3620 //Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3621 }
3622 }
3623 if (renamed && pClass) {
3624 if (pClass == branchClass) {
3625 pClass = branchElem->GetNewClass();
3626 } else if (fCollProxy && pClass == branchClass->GetCollectionProxy()->GetValueClass()) {
3628 }
3629 }
3630
3631 //------------------------------------------------------------------
3632 // If we have the are the sub-branch of the TBranchSTL, we need
3633 // to remove it's name to get the correct real data offsets
3634 ////////////////////////////////////////////////////////////////////
3635
3636 const bool isToplevelCollection = (this == GetMother() && (fType == 3 || fType == 4));
3637 if( stlParentName.Length() && (dynamic_cast<TBranchSTL*>(fParent) || isToplevelCollection))
3638 {
3639 if( !strncmp( stlParentName.Data(), dataName.Data(), stlParentName.Length()-1 )
3640 && dataName[ stlParentName.Length() ] == '.' )
3641 dataName.Remove( 0, stlParentName.Length()+1 );
3642 }
3643
3644 // Find our offset in our parent class using
3645 // a lookup by name in the dictionary meta info
3646 // for our parent class.
3647
3648 if (alternateElement) {
3649 Ssiz_t dotpos = dataName.Last('.');
3650 Ssiz_t endpos = dataName.Length();
3651 if (dotpos != kNPOS) ++dotpos; else dotpos = 0;
3652 dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
3653 }
3654 TRealData* rd = pClass->GetRealData(dataName);
3655 if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
3656 // -- Data member exists in the dictionary meta info, get the offset.
3657 // If we are using an alternateElement, it is the target of a rule
3658 // and might be indeed transient.
3659 offset = rd->GetThisOffset();
3660 } else if (subBranchElement->TestBit(TStreamerElement::kWholeObject)) {
3661 // We are a rule with no specific target, it applies to the whole
3662 // object, let's set the offset to zero
3663 offset = 0;
3664 } else {
3665 // -- No dictionary meta info for this data member, it must no
3666 // longer exist
3667 if (fEntries == 0) {
3668 // ... unless we creating the branch in which case
3669 // we have an internal error.
3670 if (pClass->GetListOfRealData()->GetEntries() == 0) {
3671 // We are probably missing the ShowMember, let's
3672 // just issue an error.
3673 Error("InitializeOffsets",
3674 "Could not find the real data member '%s' when constructing the branch '%s' [Likely missing ShowMember].",
3675 dataName.Data(),GetName());
3676 } else if (subInfo && subInfo->GetClassVersion()!=subInfo->GetClass()->GetClassVersion()) {
3677 // In the case where we are cloning a TTree that was created with an older version of the layout, we may not
3678 // able to find all the members
3679 Info("InitializeOffsets",
3680 "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'. ",
3681 dataName.Data(),GetName());
3682 } else {
3683 // Something really bad happen.
3684 Fatal("InitializeOffsets",
3685 "Could not find the real data member '%s' when constructing the branch '%s' [Likely an internal error, please report to the developers].",
3686 dataName.Data(),GetName());
3687 }
3688 }
3690 }
3691 } else {
3692 // -- We have no data member name, ok for a base class, not good otherwise.
3693 if (isBaseSubBranch) {
3694 // I am a direct base class of my parent class, my local offset is enough.
3695 } else {
3696 Warning("InitializeOffsets", "Could not find the data member name for branch '%s' with parent branch '%s', assuming offset is zero!", subBranch->GetName(), GetName());
3697 }
3698 }
3699
3700 //
3701 // Ok, do final calculations for fOffset and fBranchOffset.
3702 //
3703
3704 if (isContDataMember) {
3705 // -- Container data members set fOffset instead of fBranchOffset.
3706 // The fOffset is what should be added to the start of the entry
3707 // in the collection (i.e., its current absolute address) to find
3708 // the beginning of the data member described by the current branch.
3709 //
3710 // Compensate for the i/o routines adding our local offset later.
3711 if (subBranch->fObject == nullptr && localOffset == TStreamerInfo::kMissing) {
3712 subBranch->SetMissing();
3713 // We stil need to set fBranchOffset in the case of a missing
3714 // element so that SetAddress is (as expected) not called
3715 // recursively in this case.
3717 } else {
3718 if (isBaseSubBranch) {
3719 // The value of 'offset' for a base class does not include its
3720 // 'localOffset'.
3721 subBranch->SetOffset(offset);
3722 } else {
3723 // The value of 'offset' for a regular data member does include its
3724 // 'localOffset', we need to remove it explicitly.
3725 subBranch->SetOffset(offset - localOffset);
3726 }
3727 }
3728 } else {
3729 // -- Set fBranchOffset for sub-branch.
3730 Int_t isSplit = 0 != subBranch->GetListOfBranches()->GetEntriesFast();
3731 if (subBranch->fObject == nullptr && localOffset == TStreamerInfo::kMissing) {
3732 // The branch is missing
3734
3735 } else if (isSplit) {
3736 if (isBaseSubBranch) {
3737 // We are split, so we need to add in our local offset
3738 // to get our absolute address for our children.
3740 } else {
3741 // We are split so our offset will never be
3742 // used in an i/o, so we do not have to subtract
3743 // off our local offset like below.
3745 }
3746 } else {
3747 if (isBaseSubBranch) {
3748 // We are not split, so our local offset will be
3749 // added later by the i/o routines.
3751 } else {
3752 // Compensate for the fact that the i/o routines
3753 // are going to add my local offset later.
3755 }
3756 }
3757 }
3758 }
3759 }
3760 else {
3761 if (fID > -1) {
3762 // Branch is *not* a top-level branch.
3763 // Let's check if the target member is still present in memory
3765 fObject = nullptr;
3766 }
3767 }
3768 }
3769 const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
3771 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3772 auto index = parent->fBranches.IndexOf(this);
3773 if (index >= 0) {
3775 }
3776 }
3777
3778 fInitOffsets = true;
3779}
3780
3781////////////////////////////////////////////////////////////////////////////////
3782/// Return true if more than one leaf, false otherwise.
3783
3785{
3787 if (nbranches >= 1) {
3788 return true;
3789 }
3790 TList* browsables = const_cast<TBranchElement*>(this)->GetBrowsables();
3791 return browsables && browsables->GetSize();
3792}
3793
3794////////////////////////////////////////////////////////////////////////////////
3795/// Detect a collection written using a zero pointer in old versions of root.
3796/// In versions of ROOT older than 4.00/03, if a collection (TClonesArray
3797/// or STL container) was split but the pointer to the collection was zeroed
3798/// out, nothing was saved. Hence there is no __easy__ way to detect the
3799/// case. In newer versions, a zero is written so that a 'missing' collection
3800/// appears to be an empty collection.
3801
3803{
3804 bool ismissing = false;
3806 if (basket && fTree) {
3809 Long64_t last;
3810 if (fReadBasket == fWriteBasket) {
3811 last = fEntryNumber - 1;
3812 } else {
3813 last = fBasketEntry[fReadBasket+1] - 1;
3814 }
3815 Int_t* entryOffset = basket->GetEntryOffset();
3817 Int_t bufnext;
3818 if (entryOffset) {
3819 bufbegin = entryOffset[entry-first];
3820
3821 if (entry < last) {
3822 bufnext = entryOffset[entry+1-first];
3823 } else {
3824 bufnext = basket->GetLast();
3825 }
3826 if (bufnext == bufbegin) {
3827 ismissing = true;
3828 } else {
3829 // fixed length buffer so this is not the case here.
3830 if (basket->GetNevBufSize() == 0) {
3831 ismissing = true;
3832 }
3833 }
3834 }
3835 }
3836 return ismissing;
3837}
3838
3839////////////////////////////////////////////////////////////////////////////////
3840/// Print branch parameters.
3841
3843{
3844 for(auto &cursor : ids) {
3845 auto id = cursor.fElemID;
3846 if (id >= 0) {
3847 auto el = info->GetElement(id);
3848 if (el)
3849 el->ls();
3850 else {
3851 Error("TBranchElement::Print", "Element for id #%d not found in StreamerInfo for %s",
3852 id, info->GetName());
3853 info->ls();
3854 }
3855 } else if (cursor.fNestedIDs) {
3856 Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
3857 PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
3858 }
3859 }
3860}
3861
3863{
3864 constexpr auto length = std::char_traits<char>::length;
3866 if (strncmp(option,"debugAddress",length("debugAddress"))==0) {
3867 if (strlen(option)==length("debugAddress")) {
3868 Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s %s\n",
3869 "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject", "fOnfileObject");
3870 }
3871 if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3872 else Printf("%-24s ", GetName());
3873
3874 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3875 Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3876 TVirtualStreamerInfo *info = ((TBranchElement*)this)->GetInfoImp();
3877
3878 Printf("%-16s %2d %4d %-16s %-16s %8x %8x %p %p%s\n",
3879 info ? info->GetName() : "StreamerInfo unavailable", GetID(), GetType(),
3881 (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3882 GetOffset(), GetObject(), fOnfileObject, TestBit(kOwnOnfileObj) ? " (owned)" : "");
3883 for (Int_t i = 0; i < nbranches; ++i) {
3885 subbranch->Print("debugAddressSub");
3886 }
3887 return;
3888 }
3889 if (strncmp(option,"debugInfo",length("debugInfo"))==0) {
3890 Printf("Branch %s uses:",GetName());
3892 if (fID>= 0) {
3893 // GetInfoImp()->GetElement(fID)->ls();
3894 // for(UInt_t i=0; i< fIDs.size(); ++i) {
3895 // GetInfoImp()->GetElement(fIDs[i])->ls();
3896 // }
3897 if (fType == 3 || fType == 4) {
3898 // Search for the correct version.
3900 }
3901 Printf(" With elements:");
3902 if (fType != 3 && fType != 4)
3903 localInfo->GetElement(fID)->ls();
3905 Printf(" with read actions:");
3907 Printf(" with write actions:");
3909 } else if (!fNewIDs.empty() && localInfo) {
3910 if (fType == 3 || fType == 4) {
3911 // Search for the correct version.
3913 }
3915 Printf(" with read actions:");
3917 Printf(" with write actions:");
3919 }
3920 TString suboption = "debugInfoSub";
3921 suboption += (option+length("debugInfo"));
3922 for (Int_t i = 0; i < nbranches; ++i) {
3924 subbranch->Print(suboption);
3925 }
3926 Printf(" ");
3927 return;
3928 }
3929 if (nbranches) {
3930 if (fID == -2) {
3931 if (strcmp(GetName(),GetTitle()) == 0) {
3932 Printf("*Branch :%-66s *",GetName());
3933 } else {
3934 Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3935 }
3936 Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3937 Printf("*............................................................................*");
3938 }
3939 if (fType >= 2) {
3941 }
3942 for (Int_t i=0;i<nbranches;i++) {
3944 branch->Print(option);
3945 }
3946 } else {
3948 }
3949}
3950
3951////////////////////////////////////////////////////////////////////////////////
3952/// Prints values of leaves.
3953
3955{
3957
3959 Int_t prID = fID;
3960 char *object = fObject;
3961 if (TestBit(kCache)) {
3962 if (info->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
3963 prID = fID+1;
3964 } else if (fOnfileObject) {
3965 object = fOnfileObject->GetObjectAt(0);
3966 }
3967 }
3968
3969 if (TestBit(kDecomposedObj)) {
3970 if (!fAddress) {
3971 return;
3972 }
3973 if (fType == 3 || fType == 4) {
3974 // TClonesArray or STL container top-level branch.
3975 printf(" %-15s = %d\n", GetName(), fNdata);
3976 return;
3977 } else if (fType == 31 || fType == 41) {
3978 // TClonesArray or STL container sub-branch.
3979 Int_t n = TMath::Min(10, fNdata);
3982 // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
3983 // printed as a string and could print weird characters.
3984 // So we print an unsigned char instead (not perfect, but better).
3986 }
3987 if (atype > 54) {
3988 // FIXME: More logic required here (like in ReadLeaves)
3989 printf(" %-15s = %d\n", GetName(), fNdata);
3990 return;
3991 }
3992 if (fStreamerType > 20) {
3993 atype -= 20;
3995 n = n * leaf->GetLenStatic();
3996 }
3997 if (info) {
3998 info->PrintValue(GetName(), fAddress, atype, n, lenmax);
3999 }
4000 return;
4001 } else if (fType <= 2) {
4002 // Branch in split mode.
4003 // FIXME: This should probably be < 60 instead.
4004 if ((fStreamerType > 40) && (fStreamerType < 55)) {
4005 Int_t atype = fStreamerType - 20;
4007 Int_t n = (Int_t) counterElement->GetValue(0, 0);
4008 if (info) {
4009 info->PrintValue(GetName(), fAddress, atype, n, lenmax);
4010 }
4011 } else {
4012 if (info) {
4013 info->PrintValue(GetName(), object, prID, -1, lenmax);
4014 }
4015 }
4016 return;
4017 }
4018 } else if (fType == 3) {
4019 printf(" %-15s = %d\n", GetName(), fNdata);
4020 } else if (fType == 31) {
4021 TClonesArray* clones = (TClonesArray*) object;
4022 if (info) {
4023 info->PrintValueClones(GetName(), clones, prID, fOffset, lenmax);
4024 }
4025 } else if (fType == 41) {
4027 if (info) {
4028 info->PrintValueSTL(GetName(), ((TBranchElement*) this)->GetCollectionProxy(), prID, fOffset, lenmax);
4029 }
4030 } else {
4031 if (info) {
4032 info->PrintValue(GetName(), object, prID, -1, lenmax);
4033 }
4034 }
4035}
4036
4037////////////////////////////////////////////////////////////////////////////////
4038/// Unconfiguration Read Leave function.
4039
4041{
4042 Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
4043}
4044
4045////////////////////////////////////////////////////////////////////////////////
4046/// Read leaves into i/o buffers for this branch.
4047/// For the case where the branch is set in MakeClass mode (decomposed object).
4048
4050{
4052
4053 if (fType == 3 || fType == 4) {
4054 // Top level branch of a TClonesArray.
4055 Int_t *n = (Int_t*) fAddress;
4056 b >> n[0];
4057 if ((n[0] < 0) || (n[0] > fMaximum)) {
4058 if (IsMissingCollection()) {
4059 n[0] = 0;
4060 b.SetBufferOffset(b.Length() - sizeof(n));
4061 } else {
4062 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());
4063 n[0] = 0;
4064 }
4065 }
4066 fNdata = n[0];
4067 if (fType == 4) {
4069 switch(fSTLtype) {
4070 case ROOT::kSTLset:
4071 case ROOT::kSTLmultiset:
4072 case ROOT::kSTLmap:
4073 case ROOT::kSTLmultimap:
4074 for (Int_t i=0; i<nbranches; i++) {
4076 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4077 if (nb < 0) {
4078 break;
4079 }
4080 }
4081 break;
4082 default:
4083 break;
4084 }
4085 }
4086 return;
4087 } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
4090 // FIXME: This should probably be > 59 instead.
4091 if (atype > 54) return;
4092 if (!fAddress) {
4093 return;
4094 }
4095 Int_t n = fNdata;
4096 if (atype>40) {
4097 atype -= 40;
4098 if (!fBranchCount2) return;
4099 const char *len_where = (char*)fBranchCount2->fAddress;
4100 if (!len_where) return;
4102 Int_t length;
4103 Int_t k;
4105 for( k=0; k<n; k++) {
4106 char **where = &(((char**)fAddress)[k]);
4107 delete [] *where;
4108 *where = nullptr;
4109 switch(len_atype) {
4110 case 1: {length = ((Char_t*) len_where)[k]; break;}
4111 case 2: {length = ((Short_t*) len_where)[k]; break;}
4112 case 3: {length = ((Int_t*) len_where)[k]; break;}
4113 case 4: {length = ((Long_t*) len_where)[k]; break;}
4114 //case 5: {length = ((Float_t*) len_where)[k]; break;}
4115 case 6: {length = ((Int_t*) len_where)[k]; break;}
4116 //case 8: {length = ((Double_t*)len_where)[k]; break;}
4117 case 11: {length = ((UChar_t*) len_where)[k]; break;}
4118 case 12: {length = ((UShort_t*) len_where)[k]; break;}
4119 case 13: {length = ((UInt_t*) len_where)[k]; break;}
4120 case 14: {length = ((ULong_t*) len_where)[k]; break;}
4121 case 15: {length = ((UInt_t*) len_where)[k]; break;}
4122 case 16: {length = ((Long64_t*) len_where)[k]; break;}
4123 case 17: {length = ((ULong64_t*)len_where)[k]; break;}
4124 case 18: {length = ((bool*) len_where)[k]; break;}
4125 default: continue;
4126 }
4127 b >> isArray;
4128 if (length <= 0) continue;
4129 if (isArray == 0) continue;
4130 switch (atype) {
4131 case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
4132 case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
4133 case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4134 case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
4135 case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
4136 case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4137 case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
4138 case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
4139 case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
4140 case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4141 case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
4142 case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4143 case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
4144 case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
4145 case 18: {*where=new char[sizeof(bool)*length]; b.ReadFastArray((bool*) *where, length); break;}
4146 }
4147 }
4148 return;
4149 }
4150 if (atype > 20) {
4151 atype -= 20;
4153 n *= leaf->GetLenStatic();
4154 }
4155 switch (atype) {
4156 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4157 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4158 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4159 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4160 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4161 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4162 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4163 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4164 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4165 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4166 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4167 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4168 case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
4169 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4170 case 18: {b.ReadFastArray((bool*) fAddress, n); break;}
4171 case 9: {
4173 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4175 for (Int_t ii=0;ii<n;ii++) {
4176 b.ReadDouble32(&(xx[ii]),se);
4177 }
4178 break;
4179 }
4180 case 19: {
4182 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4183 Float_t *xx = (Float_t*) fAddress;
4184 for (Int_t ii=0;ii<n;ii++) {
4185 b.ReadFloat16(&(xx[ii]),se);
4186 }
4187 break;
4188 }
4189 }
4190 return;
4191 } else if (fType <= 2) { // branch in split mode
4192 // FIXME: This should probably be < 60 instead.
4193 if (fStreamerType > 40 && fStreamerType < 55) {
4194 Int_t atype = fStreamerType - 40;
4195 Int_t n;
4196 if (fBranchCount==nullptr) {
4197 // Missing fBranchCount. let's attempts to recover.
4198
4200 Ssiz_t dot = countname.Last('.');
4201 if (dot>=0) {
4202 countname.Remove(dot+1);
4203 } else {
4204 countname = "";
4205 }
4206 TString counter( GetTitle() );
4207 Ssiz_t loc = counter.Last('[');
4208 if (loc>=0) {
4209 counter.Remove(0,loc+1);
4210 }
4211 loc = counter.Last(']');
4212 if (loc>=0) {
4213 counter.Remove(loc);
4214 }
4215 countname += counter;
4217 }
4218 if (fBranchCount) {
4219 n = (Int_t)fBranchCount->GetValue(0,0);
4220 } else {
4221 Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4222 n = 0;
4223 }
4224 fNdata = n;
4226 b >> isArray;
4227 switch (atype) {
4228 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4229 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4230 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4231 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4232 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4233 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4234 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4235 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4236 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4237 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4238 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4239 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4240 case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
4241 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4242 case 18: {b.ReadFastArray((bool*) fAddress, n); break;}
4243 case 9: {
4245 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4247 for (Int_t ii=0;ii<n;ii++) {
4248 b.ReadDouble32(&(xx[ii]),se);
4249 }
4250 break;
4251 }
4252 case 19: {
4254 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4255 Float_t *xx = (Float_t*) fAddress;
4256 for (Int_t ii=0;ii<n;ii++) {
4257 b.ReadFloat16(&(xx[ii]),se);
4258 }
4259 break;
4260 }
4261 }
4262 } else {
4263 fNdata = 1;
4264 if (fAddress) {
4265 if (fType<0) {
4266 // Non TObject, Non collection classes with a custom streamer.
4267
4268 // if (fObject)
4270 } else {
4272 if (!info) {
4273 return;
4274 }
4275 // Since info is not null, fReadActionSequence is not null either.
4276 b.ApplySequence(*fReadActionSequence, fObject);
4277 }
4279 fNdata = (Int_t) GetValue(0, 0);
4280 }
4281 } else {
4282 fNdata = 0;
4283 }
4284 }
4285 return;
4286 }
4287}
4288
4289////////////////////////////////////////////////////////////////////////////////
4290/// Read leaves into i/o buffers for this branch.
4291/// Case of a collection (fType == 4).
4292
4294{
4296 if (fObject == nullptr)
4297 {
4298 // We have nowhere to copy the data (probably because the data member was
4299 // 'dropped' from the current schema) so let's no copy it in a random place.
4300 return;
4301 }
4302
4303 // STL container master branch (has only the number of elements).
4304 Int_t n;
4305 b >> n;
4306 if ((n < 0) || (n > fMaximum)) {
4307 if (IsMissingCollection()) {
4308 n = 0;
4309 b.SetBufferOffset(b.Length()-sizeof(n));
4310 } else {
4311 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());
4312 n = 0;
4313 }
4314 }
4315 fNdata = n;
4316
4317 R__PushCache onfileObject(b, fOnfileObject, 1);
4318
4319 // Note: Proxy-helper needs to "embrace" the entire
4320 // streaming of this STL container if the container
4321 // is a set/multiset/map/multimap (what we do not
4322 // know here).
4323 // For vector/list/deque Allocate == Resize
4324 // and Commit == noop.
4325 // TODO: Exception safety a la TPushPop
4328 void* alternate = proxy->Allocate(fNdata, true);
4331 } else {
4333 }
4334
4336 switch (fSTLtype) {
4337 case ROOT::kSTLset:
4340 case ROOT::kSTLmultiset:
4341 case ROOT::kSTLmap:
4342 case ROOT::kSTLmultimap:
4345 for (Int_t i = 0; i < nbranches; ++i) {
4347 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4348 if (nb < 0) {
4349 // Give up on i/o failure.
4350 // FIXME: We need an error message here.
4351 break;
4352 }
4353 }
4354 break;
4355 default:
4356 break;
4357 }
4358 //------------------------------------------------------------------------
4359 // We have split this stuff, so we need to create the pointers
4360 /////////////////////////////////////////////////////////////////////////////
4361
4362 if( proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers )
4363 {
4364 TClass *elClass = proxy->GetValueClass();
4365
4366 //--------------------------------------------------------------------
4367 // The allocation is done in this strange way because ReadLeaves
4368 // is being called many times by TTreeFormula!!!
4369 //////////////////////////////////////////////////////////////////////////
4370
4371 Int_t i = 0;
4372 // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4373 if( !fNdata || *(void**)proxy->At( 0 ) != nullptr )
4374 i = fNdata;
4375
4376 for( ; i < fNdata; ++i )
4377 {
4378 void **el = (void**)proxy->At( i );
4379 // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4380 *el = elClass->New();
4381 }
4382 }
4383
4384 proxy->Commit(alternate);
4385}
4386
4387////////////////////////////////////////////////////////////////////////////////
4388/// Read leaves into i/o buffers for this branch.
4389/// Case of a data member within a collection (fType == 41).
4390
4392{
4394 if (fObject == nullptr)
4395 {
4396 // We have nowhere to copy the data (probably because the data member was
4397 // 'dropped' from the current schema) so let's no copy it in a random place.
4398 return;
4399 }
4400
4401 // STL container sub-branch (contains the elements).
4403 if (!fNdata) {
4404 return;
4405 }
4406
4407 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4408
4410 if (info == nullptr) return;
4411
4414
4415 // R__ASSERT(0);
4417 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4418}
4419
4420////////////////////////////////////////////////////////////////////////////////
4421/// Read leaves into i/o buffers for this branch.
4422/// Case of a data member within a collection (fType == 41).
4423
4425{
4427 if (fObject == nullptr)
4428 {
4429 // We have nowhere to copy the data (probably because the data member was
4430 // 'dropped' from the current schema) so let's no copy it in a random place.
4431 return;
4432 }
4433
4434 // STL container sub-branch (contains the elements).
4436 if (!fNdata) {
4437 return;
4438 }
4439 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4440
4442 if (info == nullptr) return;
4443
4446
4448 b.ApplySequenceVecPtr(*fReadActionSequence,iter->fBegin,iter->fEnd);
4449}
4450
4451////////////////////////////////////////////////////////////////////////////////
4452/// Read leaves into i/o buffers for this branch.
4453/// Case of a data member within a collection (fType == 41).
4454
4456{
4458 if (fObject == nullptr)
4459 {
4460 // We have nowhere to copy the data (probably because the data member was
4461 // 'dropped' from the current schema) so let's no copy it in a random place.
4462 return;
4463 }
4464
4465 // STL container sub-branch (contains the elements).
4467 if (!fNdata) {
4468 return;
4469 }
4470 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4471
4473 if (info == nullptr) return;
4474 // Since info is not null, fReadActionSequence is not null either.
4475
4476 // Still calling PushPop for the legacy entries.
4479
4481 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4482}
4483
4484////////////////////////////////////////////////////////////////////////////////
4485/// Read leaves into i/o buffers for this branch.
4486/// Case of a TClonesArray (fType == 3).
4487
4489{
4491 if (fObject == nullptr)
4492 {
4493 // We have nowhere to copy the data (probably because the data member was
4494 // 'dropped' from the current schema) so let's no copy it in a random place.
4495 return;
4496 }
4497
4498 // TClonesArray master branch (has only the number of elements).
4499 Int_t n;
4500 b >> n;
4501 if ((n < 0) || (n > fMaximum)) {
4502 if (IsMissingCollection()) {
4503 n = 0;
4504 b.SetBufferOffset(b.Length()-sizeof(n));
4505 } else {
4506 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());
4507 n = 0;
4508 }
4509 }
4510 fNdata = n;
4512 if (clones->IsZombie()) {
4513 return;
4514 }
4515 // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4516 // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4517 // clones->Clear();
4518 clones->ExpandCreateFast(fNdata);
4519}
4520
4521////////////////////////////////////////////////////////////////////////////////
4522/// Read leaves into i/o buffers for this branch.
4523/// Case of a data member within a TClonesArray (fType == 31).
4524
4526{
4527 // No need to validate the address here, if we are a member of a split ClonesArray,
4528 // fID is positive
4529 // ValidateAddress();
4530
4531 if (fObject == nullptr)
4532 {
4533 // We have nowhere to copy the data (probably because the data member was
4534 // 'dropped' from the current schema) so let's no copy it in a random place.
4535 return;
4536 }
4537
4538 // TClonesArray sub-branch (contains the elements).
4541 if (clones->IsZombie()) {
4542 return;
4543 }
4545 if (info==nullptr) return;
4546 // Since info is not null, fReadActionSequence is not null either.
4547
4548 // Note, we could (possibly) save some more, by configuring the action
4549 // based on the value of fOnfileObject rather than pushing in on a stack.
4550 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4551
4552 char **arr = (char **)clones->GetObjectRef();
4553 char **end = arr + fNdata;
4554 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
4555}
4556
4557////////////////////////////////////////////////////////////////////////////////
4558/// Read leaves into i/o buffers for this branch.
4559/// For split-class branch, base class branch, data member branch, or top-level branch.
4560/// which do not have a branch count and are not a counter.
4561
4563{
4564 R__ASSERT(fBranchCount==nullptr);
4566
4568 if (fObject == nullptr)
4569 {
4570 // We have nowhere to copy the data (probably because the data member was
4571 // 'dropped' from the current schema) so let's no copy it in a random place.
4572 return;
4573 }
4574
4575 R__PushCache onfileObject(b, fOnfileObject, 1);
4576 // If not a TClonesArray or STL container master branch
4577 // or sub-branch and branch inherits from tobject,
4578 // then register with the buffer so that pointers are
4579 // handled properly.
4580 if (TestBit(kBranchObject)) {
4581 b.MapObject((TObject*) fObject);
4582 } else if (TestBit(kBranchAny)) {
4583 b.MapObject(fObject, fBranchClass);
4584 }
4585
4586 fNdata = 1;
4588 if (!info) {
4589 return;
4590 }
4591 // Since info is not null, fReadActionSequence is not null either.
4592 b.ApplySequence(*fReadActionSequence, fObject);
4593}
4594
4595////////////////////////////////////////////////////////////////////////////////
4596/// Read leaves into i/o buffers for this branch.
4597/// For split-class branch, base class branch, data member branch, or top-level branch.
4598/// which do have a branch count and are not a counter.
4599
4601{
4603
4605 if (fObject == nullptr)
4606 {
4607 // We have nowhere to copy the data (probably because the data member was
4608 // 'dropped' from the current schema) so let's no copy it in a random place.
4609 return;
4610 }
4611
4612 // If not a TClonesArray or STL container master branch
4613 // or sub-branch and branch inherits from tobject,
4614 // then register with the buffer so that pointers are
4615 // handled properly.
4616 if (TestBit(kBranchObject)) {
4617 b.MapObject((TObject*) fObject);
4618 } else if (TestBit(kBranchAny)) {
4619 b.MapObject(fObject, fBranchClass);
4620 }
4621
4622 fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4624 if (!info) {
4625 return;
4626 }
4627 R__PushCache onfileObject(b, fOnfileObject,
4628 1); // Here we have a single object that contains a variable size C-style array.
4629 // Since info is not null, fReadActionSequence is not null either.
4630 b.ApplySequence(*fReadActionSequence, fObject);
4631}
4632
4633////////////////////////////////////////////////////////////////////////////////
4634/// Read leaves into i/o buffers for this branch.
4635/// For split-class branch, base class branch, data member branch, or top-level branch.
4636/// which do not have a branch count and are a counter.
4637
4639{
4641 if (fObject == nullptr)
4642 {
4643 // We have nowhere to copy the data (probably because the data member was
4644 // 'dropped' from the current schema) so let's no copy it in a random place.
4645 return;
4646 }
4647
4648 // If not a TClonesArray or STL container master branch
4649 // or sub-branch and branch inherits from tobject,
4650 // then register with the buffer so that pointers are
4651 // handled properly.
4652 if (TestBit(kBranchObject)) {
4653 b.MapObject((TObject*) fObject);
4654 } else if (TestBit(kBranchAny)) {
4655 b.MapObject(fObject, fBranchClass);
4656 }
4657
4659 if (!info) {
4660 return;
4661 }
4662
4663 R__PushCache onfileObject(b, fOnfileObject, 1);
4664
4665 // Since info is not null, fReadActionSequence is not null either.
4666 b.ApplySequence(*fReadActionSequence, fObject);
4667 fNdata = (Int_t) GetValue(0, 0);
4668}
4669
4670////////////////////////////////////////////////////////////////////////////////
4671/// Read leaves into i/o buffers for this branch.
4672/// Non TObject, Non collection classes with a custom streamer.
4673
4675{
4677 if (fObject == nullptr)
4678 {
4679 // We have nowhere to copy the data (probably because the data member was
4680 // 'dropped' from the current schema) so let's no copy it in a random place.
4681 return;
4682 }
4683
4684 R__PushCache onfileObject(b, fOnfileObject, 1);
4686}
4687
4688////////////////////////////////////////////////////////////////////////////////
4689/// Unconfiguration Fill Leave function.
4690
4692{
4693 Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4694}
4695
4696////////////////////////////////////////////////////////////////////////////////
4697/// Delete any object we may have allocated on a previous call to SetAddress.
4698
4700{
4701 if (fObject && TestBit(kDeleteObject)) {
4702 if (IsAutoDelete() && fAddress != (char*)&fObject) {
4703 *((char**) fAddress) = nullptr;
4704 }
4706 if (fType == 3) {
4707 // -- We are a TClonesArray master branch.
4708 TClonesArray::Class()->Destructor(fObject);
4709 fObject = nullptr;
4712 // -- We are a pointer to a TClonesArray.
4713 // We must zero the pointer in the object.
4714 *((char**) fAddress) = nullptr;
4715 }
4716 } else if (fType == 4) {
4717 // -- We are an STL container master branch.
4719
4720 if (!proxy) {
4721 Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4722 fObject = nullptr;
4723 } else {
4725 if (needDelete && fID >= 0) {
4727 TStreamerElement* se = (TStreamerElement*) si->GetElement(fID);
4729 }
4730 if (needDelete) {
4732 proxy->Clear("force");
4733 }
4734 proxy->Destructor(fObject);
4735 fObject = nullptr;
4736 }
4738 // -- We are a pointer to an STL container.
4739 // We must zero the pointer in the object.
4740 *((char**) fAddress) = nullptr;
4741 }
4742 } else {
4743 // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4745 if (!cl) {
4746 Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4747 fObject = nullptr;
4748 } else {
4750
4751 if (proxy) {
4752 if (fID >= 0) {
4754 TStreamerElement* se = si->GetElement(fID);
4757 proxy->Clear("force");
4758 }
4759 } else if (proxy->GetProperties()&TVirtualCollectionProxy::kNeedDelete) {
4761 proxy->Clear("force");
4762 }
4763
4764 }
4765 cl->Destructor(fObject);
4766 fObject = nullptr;
4767 }
4768 }
4769 }
4770}
4771
4772////////////////////////////////////////////////////////////////////////////////
4773/// Reset a Branch.
4774///
4775/// Existing i/o buffers are deleted.
4776/// Entries, max and min are reset.
4777///
4778
4780{
4782 for (Int_t i = 0; i < nbranches; ++i) {
4784 branch->Reset(option);
4785 }
4786 fBranchID = -1;
4788}
4789
4790////////////////////////////////////////////////////////////////////////////////
4791/// Reset a Branch after a Merge operation (drop data but keep customizations)
4792///
4793
4795{
4797 for (Int_t i = 0; i < nbranches; ++i) {
4799 branch->ResetAfterMerge(info);
4800 }
4802}
4803
4804////////////////////////////////////////////////////////////////////////////////
4805/// Set branch address to zero and free all allocated memory.
4806
4808{
4809 for (Int_t i = 0; i < fNleaves; ++i) {
4811 //if (leaf) leaf->SetAddress(0);
4812 leaf->SetAddress(nullptr);
4813 }
4814
4815 // Note: We *must* do the sub-branches first, otherwise
4816 // we may delete the object containing the sub-branches
4817 // before giving them a chance to cleanup.
4819 for (Int_t i = 0; i < nbranches; ++i) {
4820 TBranch* br = (TBranch*) fBranches[i];
4821 if (br) br->ResetAddress();
4822 }
4823
4824 //
4825 // SetAddress may have allocated an object.
4826 //
4827
4828 ReleaseObject();
4829
4831 fAddress = nullptr;
4832 fObject = nullptr;
4833}
4834
4835////////////////////////////////////////////////////////////////////////////////
4836/// Release ownership of any allocated objects.
4837///
4838/// Note: This interface was added so that clone trees could
4839/// be told they do not own the allocated objects.
4840
4842{
4845 for (Int_t i = 0; i < nb; ++i) {
4846 TBranch* br = (TBranch*) fBranches[i];
4847 if (br->InheritsFrom(TBranchElement::Class())) {
4848 ((TBranchElement*) br)->ResetDeleteObject();
4849 }
4850 }
4851}
4852
4853////////////////////////////////////////////////////////////////////////////////
4854/// \brief Reset offset and StreamerInfo information from this branch.
4855/// \param[in] recurse When true call ResetInitInfo on all subbranches.
4856///
4857
4859{
4860 fInfo = nullptr;
4861 fInit = false;
4862 fInitOffsets = false;
4863 fCurrentClass = nullptr;
4864 delete fReadActionSequence;
4865 fReadActionSequence = nullptr;
4866 delete fFillActionSequence;
4867 fFillActionSequence = nullptr;
4868
4869 if (recurse) {
4871 for (Int_t i = 0; i < nbranches; ++i) {
4873 sub->ResetInitInfo(true);
4874 }
4875 }
4876}
4877
4878////////////////////////////////////////////////////////////////////////////////
4879/// Point this branch at an object.
4880///
4881/// For a sub-branch, addr is a pointer to the branch object.
4882///
4883/// For a top-level branch the meaning of addr is as follows:
4884///
4885/// If addr is zero, then we allocate a branch object
4886/// internally and the branch is the owner of the allocated
4887/// object, not the caller. However the caller may obtain
4888/// a pointer to the branch object with GetObject().
4889/// The pointer is reset to zero (nullptr) when the relevant
4890/// branch object is destroyed.
4891///
4892/// Example:
4893/// ~~~ {.cpp}
4894/// branch->SetAddress(0);
4895/// Event* event = branch->GetObject();
4896/// ... Do some work.
4897/// ~~~
4898/// If addr is not zero, but the pointer addr points at is
4899/// zero, then we allocate a branch object and set the passed
4900/// pointer to point at the allocated object. The caller
4901/// owns the allocated object and is responsible for deleting
4902/// it when it is no longer needed.
4903///
4904/// Example:
4905/// ~~~ {.cpp}
4906/// Event* event = 0;
4907/// branch->SetAddress(&event);
4908/// ... Do some work.
4909/// delete event;
4910/// event = 0;
4911/// ~~~
4912/// If addr is not zero and the pointer addr points at is
4913/// also not zero, then the caller has allocated a branch
4914/// object and is asking us to use it. The caller owns it
4915/// and must delete it when it is no longer needed.
4916///
4917/// Example:
4918/// ~~~ {.cpp}
4919/// Event* event = new Event();
4920/// branch->SetAddress(&event);
4921/// ... Do some work.
4922/// delete event;
4923/// event = 0;
4924/// ~~~
4925/// These rules affect users of TTree::Branch(),
4926/// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4927/// as well because those routines call this one.
4928///
4929/// An example of a tree with branches with objects allocated
4930/// and owned by us:
4931/// ~~~ {.cpp}
4932/// TFile* f1 = new TFile("myfile_original.root");
4933/// TTree* t1 = (TTree*) f->Get("MyTree");
4934/// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4935/// TTree* t2 = t1->Clone(0);
4936/// for (Int_t i = 0; i < 10; ++i) {
4937/// t1->GetEntry(i);
4938/// t2->Fill();
4939/// }
4940/// t2->Write()
4941/// delete f2;
4942/// f2 = 0;
4943/// delete f1;
4944/// f1 = 0;
4945/// ~~~
4946/// An example of a branch with an object allocated by us,
4947/// but owned by the caller:
4948/// ~~~ {.cpp}
4949/// TFile* f = new TFile("myfile.root", "recreate");
4950/// TTree* t = new TTree("t", "A test tree.")
4951/// Event* event = 0;
4952/// TBranchElement* br = t->Branch("event.", &event);
4953/// for (Int_t i = 0; i < 10; ++i) {
4954/// ... Fill event with meaningful data in some way.
4955/// t->Fill();
4956/// }
4957/// t->Write();
4958/// delete event;
4959/// event = 0;
4960/// delete f;
4961/// f = 0;
4962/// ~~~
4963/// Notice that the only difference between this example
4964/// and the following example is that the event pointer
4965/// is zero when the branch is created.
4966///
4967/// An example of a branch with an object allocated and
4968/// owned by the caller:
4969/// ~~~ {.cpp}
4970/// TFile* f = new TFile("myfile.root", "recreate");
4971/// TTree* t = new TTree("t", "A test tree.")
4972/// Event* event = new Event();
4973/// TBranchElement* br = t->Branch("event.", &event);
4974/// for (Int_t i = 0; i < 10; ++i) {
4975/// ... Fill event with meaningful data in some way.
4976/// t->Fill();
4977/// }
4978/// t->Write();
4979/// delete event;
4980/// event = 0;
4981/// delete f;
4982/// f = 0;
4983/// ~~~
4984/// If AutoDelete is on (see TBranch::SetAutoDelete),
4985/// the top level objet will be deleted and recreate
4986/// each time an entry is read, whether or not the
4987/// TTree owns the object.
4988
4990{
4991 SetAddressImpl(addr, (addr == nullptr), 0);
4992}
4993
4994/// See TBranchElement::SetAddress.
4995/// If implied is true, we do not over-ride existing address for
4996/// sub-branches.
4997/// The `offset` is the offset of the sub-object within its parent,
4998/// it is already included in the addr but is still needed to be added
4999/// the OnfileObject address when/if we need to use that address.
5001{
5002 //
5003 // Don't bother if we are disabled.
5004 //
5005
5006 if (TestBit(kDoNotProcess)) {
5007 return;
5008 }
5009
5010 //
5011 // FIXME: When would this happen?
5012 //
5013
5014 if (fType < -1) {
5015 return;
5016 }
5017
5018 //
5019 // Special case when called from code generated by TTree::MakeClass.
5020 //
5021
5022 if (Longptr_t(addr) == -1) {
5023 // FIXME: Do we have to release an object here?
5024 // ReleaseObject();
5025 fAddress = (char*) -1;
5026 fObject = (char*) -1;
5029 return;
5030 }
5031
5032 //
5033 // Reset last read entry number, we have a new user object now.
5034 //
5035
5036 fReadEntry = -1;
5037
5038 //
5039 // Make sure our branch class is instantiated.
5040 //
5042 if( fTargetClass.GetClassName()[0] ) {
5044 }
5045
5046 //
5047 // Try to build the streamer info.
5048 //
5049
5051
5052 // FIXME: Warn about failure to get the streamer info here?
5053
5054 //
5055 // We may have allocated an object last time we were called.
5056 //
5057
5058 if (fObject && TestBit(kDeleteObject)){
5059 ReleaseObject();
5060 }
5061
5062 //
5063 // Remember the pointer to the pointer to our object.
5064 //
5065
5066 fAddress = (char*) addr;
5067 if (fAddress != (char*)(&fObject)) {
5068 fObject = nullptr;
5069 }
5072
5073 //
5074 // Do special stuff if we got called from a MakeClass class.
5075 // Allow sub-branches to have independently set addresses.
5076 //
5077
5078 if (TestBit(kDecomposedObj)) {
5079 if (fID > -1) {
5080 // We are *not* a top-level branch.
5081 if (!info) {
5082 // No streamer info, give up.
5083 // FIXME: We should have an error message here.
5084 fObject = fAddress;
5085 } else {
5086 // Compensate for the fact that the i/o routines
5087 // will add the streamer offset to the address.
5088 fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
5089 }
5090 return;
5091 }
5092 }
5093
5094 //
5095 // Check whether the container type is still the same
5096 // to support schema evolution; what is written on the file
5097 // may no longer match the class code which is loaded.
5098 //
5099
5100 if (fType == 3) {
5101 // split TClonesArray, counter/master branch.
5103 if (clm) {
5104 // In case clm derives from an abstract class.
5105 clm->BuildRealData();
5106 clm->GetStreamerInfo();
5107 }
5109 if (newType && (newType != TClonesArray::Class())) {
5110 // The data type of the container has changed.
5111 //
5112 // Let's check if it is a compatible type:
5113 bool matched = false;
5114 if (newType->GetCollectionProxy()) {
5115 TClass *content = newType->GetCollectionProxy()->GetValueClass();
5116 if (clm == content) {
5117 matched = true;
5118 } else {
5119 Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
5120 }
5121 } else {
5122 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());
5123 }
5124 if (matched) {
5125 // Change from 3/31 to 4/41
5126 SetType(4);
5127 // Set the proxy.
5128 fSTLtype = newType->GetCollectionType();
5129 fCollProxy = newType->GetCollectionProxy()->Generate();
5130
5134
5140 } else {
5142 }
5143 } else {
5144 // FIXME: Must maintain fObject here as well.
5145 fAddress = nullptr;
5147 }
5148 }
5149 } else if (fType == 4) {
5150 // split STL container, counter/master branch.
5152 if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
5153 // Let's check if it is a compatible type:
5154 TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
5156 if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
5157 delete fCollProxy;
5159 fCollProxy = newType->GetCollectionProxy()->Generate();
5161 for (Int_t i = 0; i < nbranches; ++i) {
5163 br->fCollProxy = nullptr;
5164 if (br->fReadActionSequence) {
5165 br->SetReadActionSequence();
5166 }
5167 if (br->fFillActionSequence) {
5168 br->SetFillActionSequence();
5169 }
5170 }
5175 delete fIterators;
5176 delete fPtrIterators;
5182 } else {
5184 }
5185 }
5186 else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=nullptr) && (newProxy->GetValueClass()!=nullptr)) {
5187 // Let see if there is a rule to convert the content of the collection into each other.
5188 if (newType->GetSchemaRules()->HasRuleWithSourceClass( oldProxy->GetCollectionClass()->GetName())) {
5189 TClass *oldValueClass = oldProxy->GetValueClass();
5190 delete fCollProxy;
5192 fCollProxy = newType->GetCollectionProxy()->Generate();
5194 for (Int_t i = 0; i < nbranches; ++i) {
5196 br->fCollProxy = nullptr;
5197 if (br->fBranchClass == oldValueClass) {
5198 br->SetTargetClass(fCollProxy->GetValueClass()->GetName());
5199 }
5200 if (br->fReadActionSequence) {
5201 br->SetReadActionSequence();
5202 }
5203 if (br->fFillActionSequence) {
5204 br->SetFillActionSequence();
5205 }
5206 }
5211 delete fIterators;
5212 delete fPtrIterators;
5218 } else {
5220 }
5221 } else {
5222 Error("SetAddress","For %s, we can not convert %s into %s\n",
5223 GetName(),oldProxy->GetCollectionClass()->GetName(),newType->GetName());
5224 fAddress = nullptr;
5225 fObject = nullptr;
5227 return;
5228 }
5229 }
5230 else if ((newType == TClonesArray::Class()) && (oldProxy->GetValueClass() && !oldProxy->HasPointers() && oldProxy->GetValueClass()->IsTObject()))
5231 {
5232 // The new collection and the old collection are not compatible,
5233 // we cannot use the new collection to read the data.
5234 // Actually we could check if the new collection is a
5235 // compatible ROOT collection.
5236
5237 // We cannot insure that the TClonesArray is set for the
5238 // proper class (oldProxy->GetValueClass()), so we assume that
5239 // the transformation was done properly by the class designer.
5240
5241 // Change from 4/41 to 3/31
5242 SetType(3);
5243 // Reset the proxy.
5244 fSTLtype = kNone;
5245 switch(fStreamerType) {
5249 break;
5253 break;
5256 break;
5257 }
5258 fClonesClass = oldProxy->GetValueClass();
5260 delete fCollProxy;
5261 fCollProxy = nullptr;
5263 if (clm) {
5264 clm->BuildRealData(); //just in case clm derives from an abstract class
5265 clm->GetStreamerInfo();
5266 }
5270 delete fIterators;
5271 fIterators = nullptr;
5272 delete fPtrIterators;
5273 fPtrIterators =nullptr;
5274 } else {
5275 // FIXME: We must maintain fObject here as well.
5276 Error("SetAddress","For %s can not convert %s into %s\n",GetName(),GetCurrentClass()->GetName(),newType->GetName());
5277 fAddress = nullptr;
5279 return;
5280 }
5281 } else {
5282 if (!fIterators && !fPtrIterators) {
5288 } else {
5290 }
5291 }
5292 }
5293 }
5294
5295 //
5296 // Establish the semantics of fObject and fAddress.
5297 //
5298 // Top-level branch:
5299 // fObject is a ptr to the object,
5300 // fAddress is a ptr to a pointer to the object.
5301 //
5302 // Sub-branch:
5303 // fObject is a ptr to the object,
5304 // fAddress is the same as fObject.
5305 //
5306 //
5307 // There are special cases for TClonesArray and STL containers.
5308 // If there is no user-provided object, we allocate one. We must
5309 // also initialize any STL container proxy.
5310 //
5311
5312 if (fType == 3) {
5313 // -- We are a TClonesArray master branch.
5314 if (fAddress) {
5315 // -- We have been given a non-zero address, allocate if necessary.
5317 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5318 // Case of an embedded TClonesArray.
5319 fObject = fAddress;
5320 // Check if it has already been properly built.
5322 if (!clones->GetClass()) {
5324 }
5325 } else {
5326 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5327 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5328 if ((fStreamerType != -1) &&
5331 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5332 } else if (fStreamerType == -1) {
5333 // -- We are a top-level branch.
5335 if (!*pp) {
5336 // -- Caller wants us to allocate the clones array, but they will own it.
5337 *pp = new TClonesArray(fClonesClass);
5338 }
5339 fObject = (char*) *pp;
5340 } else {
5341 // -- We are a pointer to a TClonesArray.
5342 // Note: We do this so that the default constructor,
5343 // or the i/o constructor can be lazy.
5345 if (!*pp) {
5346 // -- Caller wants us to allocate the clones array, but they will own it.
5347 *pp = new TClonesArray(fClonesClass);
5348 }
5349 fObject = (char*) *pp;
5350 }
5351 }
5352 } else {
5353 // -- We have been given a zero address, allocate for top-level only.
5355 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5356 // Case of an embedded TClonesArray.
5357 Error("SetAddress", "Embedded TClonesArray given a zero address for branch '%s'", GetName());
5358 } else {
5359 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5360 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5361 if ((fStreamerType != -1) &&
5364 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5365 } else if (fStreamerType == -1) {
5366 // -- We are a top-level branch.
5367 // Idea: Consider making a zero address not allocate.
5369 fObject = (char*) new TClonesArray(fClonesClass);
5370 fAddress = (char*) &fObject;
5371 } else {
5372 // -- We are a sub-branch which is a pointer to a TClonesArray.
5373 Error("SetAddress", "Embedded pointer to a TClonesArray given a zero address for branch '%s'", GetName());
5374 }
5375 }
5376 }
5377 } else if (fType == 4) {
5378 // -- We are an STL container master branch.
5379 //
5380 // Initialize fCollProxy.
5382 if (fAddress) {
5383 // -- We have been given a non-zero address, allocate if necessary.
5387 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5388 // Case of an embedded STL container.
5389 // Note: We test for the kObject and kAny types to support
5390 // the (unwise) choice of inheriting from an STL container.
5391 fObject = fAddress;
5392 } else {
5393 // We are either a top-level branch or subbranch which is a pointer to an STL container.
5394 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5396 Error("SetAddress",
5397 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5399 } else if (fStreamerType == -1) {
5400 // -- We are a top-level branch.
5401 void** pp = (void**) fAddress;
5402 if (!*pp) {
5403 // -- Caller wants us to allocate the STL container, but they will own it.
5404 *pp = proxy->New();
5405 if (!(*pp)) {
5406 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5407 // FIXME: Should we do this? Lots of other code wants
5408 // fAddress to be zero if no fObject, but is
5409 // that a good thing?
5410 fAddress = nullptr;
5412 }
5413 }
5414 fObject = (char*) *pp;
5415 } else {
5416 // -- We are a pointer to an STL container.
5417 // Note: We do this so that the default constructor,
5418 // or the i/o constructor can be lazy.
5419 void** pp = (void**) fAddress;
5420 if (!*pp) {
5421 // -- Caller wants us to allocate the STL container, but they will own it.
5422 *pp = proxy->New();
5423 if (!(*pp)) {
5424 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5425 // FIXME: Should we do this? Lots of other code wants
5426 // fAddress to be zero if no fObject, but is
5427 // that a good thing?
5428 fAddress = nullptr;
5430 }
5431 }
5432 fObject = (char*) *pp;
5433 }
5434 }
5435 } else {
5436 // -- We have been given a zero address, allocate for top-level only.
5440 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5441 // Case of an embedded STL container.
5442 // Note: We test for the kObject and kAny types to support
5443 // the (unwise) choice of inheriting from an STL container.
5444 Error("SetAddress", "Embedded STL container given a zero address for branch '%s'", GetName());
5445 } else {
5446 // We are either a top-level branch or sub-branch which is a pointer to an STL container.
5447 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5449 Error("SetAddress",
5450 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5452 } else if (fStreamerType == -1) {
5453 // -- We are a top-level branch, allocate.
5455 fObject = (char*) proxy->New();
5456 if (fObject) {
5457 fAddress = (char*) &fObject;
5458 } else {
5459 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5460 // FIXME: Should we do this? Lots of other code wants
5461 // fAddress to be zero if no fObject, but is
5462 // that a good thing?
5463 fAddress = nullptr;
5465 }
5466 } else {
5467 // -- We are a sub-branch which is a pointer to an STL container.
5468 Error("SetAddress", "Embedded pointer to an STL container given a zero address for branch '%s'", GetName());
5469 }
5470 }
5471 }
5472 } else if (fType == 41) {
5473 // -- We are an STL container sub-branch.
5474 // Initialize fCollProxy.
5476 // We are not at top-level branch.
5477 fObject = fAddress;
5478 } else if (fID < 0) {
5479 // -- We are a top-level branch.
5480 char** pp = (char**) fAddress;
5481 if (pp && *pp) {
5482 // -- Caller provided an i/o buffer for us to use.
5483 fObject = *pp;
5484 } else {
5485 // -- Caller did not provide an i/o buffer for us to use, we must make one for ourselves.
5486 if (clOfBranch) {
5487 if (!pp) {
5488 // -- Caller wants us to own the object.
5490 }
5491 fObject = (char*) clOfBranch->New();
5492 if (pp) {
5493 *pp = fObject;
5494 } else {
5495 fAddress = (char*) &fObject;
5496 }
5497 } else {
5498 Error("SetAddress", "I have no TClass for branch %s, so I cannot allocate an I/O buffer!", GetName());
5499 if (pp) {
5500 fObject = nullptr;
5501 *pp = nullptr;
5502 }
5503 }
5504 }
5505 } else {
5506 // -- We are *not* a top-level branch.
5507 fObject = fAddress;
5508 }
5509
5510 if (!info) {
5511 // FIXME: We need and error message here, no streamer info, so cannot set offsets.
5512 return;
5513 }
5514
5515 // We do this only once because it depends only on
5516 // the type of our object, not on its address.
5517 if (!fInitOffsets) {
5519 }
5520
5521 // We are split, recurse down to our sub-branches.
5522 //
5523 // FIXME: This is a tail recursion, we burn stack.
5525 char *localObject = fObject;
5526 if (fOnfileObject && this != GetMother()) {
5528 }
5529 for (Int_t i = 0; i < nbranches; ++i) {
5531 // FIXME: This is a tail recursion!
5532 if (fBranchOffset[i] != TStreamerInfo::kMissing && !(implied && abranch->TestBit(kAddressSet))) {
5533 abranch->SetAddressImpl(localObject + fBranchOffset[i], implied, fBranchOffset[i]);
5534 abranch->SetBit(kAddressSet);
5535 if (TestBit(kDecomposedObj) != abranch->TestBit(kDecomposedObj))
5536 abranch->SetMakeClass(TestBit(kDecomposedObj));
5537 } else {
5538 // When the member is missing, just leave the address alone
5539 // (since setting explicitly to 0 would trigger error/warning
5540 // messages).
5541 // abranch->SetAddress(0);
5542 abranch->SetBit(kAddressSet);
5543 }
5544 }
5545}
5546
5547////////////////////////////////////////////////////////////////////////////////
5548/// Reset the basket size for all sub-branches of this branch element.
5549
5551{
5554 for (Int_t i = 0; i < nbranches; ++i) {
5556 branch->SetBasketSize(fBasketSize);
5557 }
5558}
5559
5560////////////////////////////////////////////////////////////////////////////////
5561/// Set the branch counter for this branch.
5562
5564{
5566 if (fBranchCount==nullptr) return;
5567
5568 TLeafElement* leafOfCounter = (TLeafElement*) brOfCounter->GetListOfLeaves()->At(0);
5570 if (leafOfCounter && leaf) {
5571 leaf->SetLeafCount(leafOfCounter);
5572 } else {
5573 if (!leafOfCounter) {
5574 Warning("SetBranchCount", "Counter branch %s for branch %s has no leaves!", brOfCounter->GetName(), GetName());
5575 }
5576 if (!leaf) {
5577 Warning("SetBranchCount", "Branch %s has no leaves!", GetName());
5578 }
5579 }
5580}
5581
5582////////////////////////////////////////////////////////////////////////////////
5583/// Set the branch in a mode where the object are decomposed
5584/// (Also known as MakeClass mode).
5585/// Return whether the setting was possible (it is not possible for
5586/// TBranch and TBranchObject).
5587
5589{
5590 if (decomposeObj)
5591 SetBit(kDecomposedObj); // Same as SetBit(kMakeClass)
5592 else
5594
5596 for (Int_t i = 0; i < nbranches; ++i) {
5598 branch->SetMakeClass(decomposeObj);
5599 }
5602
5603 return true;
5604}
5605
5606////////////////////////////////////////////////////////////////////////////////
5607/// Set object this branch is pointing to.
5608
5610{
5611 if (TestBit(kDoNotProcess)) {
5612 return;
5613 }
5614 fObject = (char*)obj;
5615 SetAddress( &fObject );
5616}
5617
5618////////////////////////////////////////////////////////////////////////////////
5619/// Set offset of the object (to which the data member represented by this
5620/// branch belongs) inside its containing object (if any).
5621
5623{
5624 // We need to make sure that the Read and Write action's configuration
5625 // properly reflect this value.
5626
5628 SetMissing();
5629 return;
5630 }
5631
5632 if (fReadActionSequence) {
5634 }
5635 if (fFillActionSequence) {
5637 }
5638 fOffset = offset;
5639}
5640
5641////////////////////////////////////////////////////////////////////////////////
5642/// Set offset of the object (to which the data member represented by this
5643/// branch belongs) inside its containing object (if any) to mark it as missing.
5644
5646{
5647 // We need to make sure that the Read and Write action's configuration
5648 // properly reflect this value.
5649
5650 if (fReadActionSequence) {
5652 }
5653 if (fFillActionSequence) {
5655 }
5657}
5658
5659
5660////////////////////////////////////////////////////////////////////////////////
5661/// Set the sequence of actions needed to read the data out of the buffer.
5663{
5664 // A 'split' node does not store data itself (it has not associated baskets)
5665 const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
5666
5667 if (!isSplitNode) {
5668 fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
5669 }
5670
5671 if (actionSequence) delete actionSequence;
5673
5674 actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
5675
5676 if (!isSplitNode)
5677 fNewIDs.erase(fNewIDs.begin());
5678
5679 else if (fInitOffsets && fType != 3 && fType != 4) {
5680 // fObject has the address of the sub-object but the streamer action have
5681 // offset relative to the parent.
5682
5683 // Note: We skipped this for the top node of split collection because the
5684 // sequence is about the content, we need to review what happens where an
5685 // action related to the collection itself will land.
5686 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
5687
5688 auto index = parent->fBranches.IndexOf(this);
5689 if (index >= 0) {
5690 actionSequence->AddToOffset( - parent->fBranchOffset[index] );
5691 }
5692 } // else it will be done by InitOffsets
5693}
5694
5695////////////////////////////////////////////////////////////////////////////////
5696/// Set the sequence of actions needed to read the data out of the buffer.
5698{
5699 if (fInfo == nullptr) {
5700 // We are called too soon. We will be called again by InitInfo
5701 return;
5702 }
5703
5705 TClass *originalClass = nullptr;
5707 if (fType == 41) {
5710 } else {
5712 if (GetParentClass() == info->GetClass()) {
5716 } else {
5718 }
5719 } else if (GetCollectionProxy()) {
5720 // Base class and embedded objects.
5722 }
5723 }
5724 } else if (fType == 31) {
5726 } else if (0<=fType && fType<=2) {
5727 // Note: this still requires the ObjectWise sequence to not be optimized!
5729 } else if ( fType == 4 && !fNewIDs.empty()) {
5732 } else if ( fType == 3 && !fNewIDs.empty()) {
5735 }
5736
5737 if (create) {
5739 }
5740}
5741
5742////////////////////////////////////////////////////////////////////////////////
5743/// Set the ReadLeaves pointer to execute the expected operations.
5744
5746{
5747 if (TestBit(kDecomposedObj)) {
5749 } else if (fType == 4) {
5751 } else if (fType == 41) {
5755 } else {
5757 }
5758 } else {
5760 }
5761 } else if (fType == 3) {
5763 } else if (fType == 31) {
5765 } else if (fType < 0) {
5767 } else if (fType == 0 && fID == -1) {
5768 // top-level branch.
5770 if (hasCustomStreamer) {
5771 // We are in the case where the object did *not* have a custom
5772 // Streamer when the TTree was written but now *does* have a custom
5773 // Streamer thus we must use it.
5775 } else {
5777 }
5778 } else if (fType <= 2) {
5779 // split-class branch, base class branch or data member branch.
5780 if (fBranchCount) {
5784 } else {
5786 }
5787 } else {
5788 Fatal("SetReadLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5789 }
5790
5792}
5793
5794////////////////////////////////////////////////////////////////////////////////
5795/// Set the sequence of actions needed to write the data out from the buffer.
5796
5798{
5799 if (fInfo == nullptr) {
5800 // We are called too soon. We will be called again by InitInfo
5801 return;
5802 }
5803
5805 TClass *originalClass = nullptr;
5807 if (fType == 41) {
5810 } else {
5812 if (GetParentClass() == info->GetClass()) {
5813 // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
5814 // originalClass = fBranchClass;
5815 // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter;
5816 // } else {
5818 // }
5819 } else if (GetCollectionProxy()) {
5820 // Base class and embedded objects.
5822 }
5823 }
5824 } else if (fType == 31) {
5826 } else if (0<=fType && fType<=2) {
5827 // Note: this still requires the ObjectWise sequence to not be optimized!
5829 } else if ( fType == 4 && !fNewIDs.empty()) {
5832 } else if ( fType == 3 && !fNewIDs.empty()) {
5835 }
5836
5837 if (create) {
5839 }
5840}
5841
5842////////////////////////////////////////////////////////////////////////////////
5843/// Set the FillLeaves pointer to execute the expected operations.
5844
5846{
5847 if (TestBit(kDecomposedObj) && ((fType==3)||(fType==31))) {
5849 } else if (fType == 4) {
5851 } else if (fType == 41) {
5855 } else {
5857 }
5860 } else {
5862 }
5863 } else if (fType == 3) {
5865 } else if (fType == 31) {
5867 } else if (fType < 0) {
5869 } else if (fType <=2) {
5870 //split-class branch, base class branch, data member branch, or top-level branch.
5871 if (fBranchCount) {
5875 } else {
5877 }
5878 } else {
5879 Fatal("SetFillLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5880 }
5881
5883}
5884
5885////////////////////////////////////////////////////////////////////////////////
5886/// Set the name of the class of the in-memory object into which the data will
5887/// loaded.
5888
5890{
5891 if (name == nullptr) return;
5892
5893 if (strcmp(fTargetClass.GetClassName(),name) != 0 )
5894 {
5895 // We are changing target class, let's reset the meta information and
5896 // the sub-branches.
5897
5898 ResetInitInfo(/*recurse=*/ false);
5899
5901 for (Int_t i = 0; i < nbranches; ++i) {
5903
5904 if (sub->fTargetClass == fTargetClass ) {
5905 sub->SetTargetClass(name);
5906 } else {
5907 // Since the top level changes, the StreamerInfo (in particular for split collection)
5908 // may still need to change (and the info might be updated else (see for example SetAddress for the
5909 // the case fType 4/41)
5910 sub->ResetInitInfo(true);
5911 }
5912 if (sub->fParentClass == fTargetClass ) {
5914 }
5915 }
5917 }
5918
5919}
5920
5921////////////////////////////////////////////////////////////////////////////////
5922/// If the branch address is not set, we set all addresses starting with
5923/// the top level parent branch. This is required to be done in order for
5924/// GetOffset to be correct and for GetEntry to run.
5925
5927{
5928 // Check to see if the user changed the branch address on us.
5930
5932 // -- Do nothing if already setup or if we are a MakeClass branch.
5933 return;
5934 }
5936}
5937
5938////////////////////////////////////////////////////////////////////////////////
5939/// If the branch address is not set, we set all addresses starting with
5940/// the top level parent branch. This is required to be done in order for
5941/// GetOffset to be correct and for GetEntry to run.
5942
5944{
5945 if (TestBit((long)kDoNotProcess|(long)kAddressSet)) {
5946 // -- Do nothing if we have been told not to.
5947 // Or the data member in this branch is not longer part of the
5948 // parent's layout.
5949 return;
5950 }
5951
5952 //--------------------------------------------------------------------------
5953 // Check if we are splited STL collection of pointers
5954 /////////////////////////////////////////////////////////////////////////////
5955
5957 {
5958 TBranchElement *parent = (TBranchElement *)GetMother()->GetSubBranch( this );
5959
5960 // Make sure the StreamerInfo is loaded and initialized.
5961 GetInfoImp();
5962
5963 if( !parent->GetAddress() )
5964 parent->SetAddress( nullptr );
5965 return;
5966 }
5967
5968 //--------------------------------------------------------------------------
5969 // Any other case
5970 /////////////////////////////////////////////////////////////////////////////
5971
5973 if (!mother) {
5974 return;
5975 }
5976 TClass* cl = TClass::GetClass(mother->GetClassName());
5977
5978 // Make sure the StreamerInfo is loaded and initialized.
5979 GetInfoImp();
5980
5981 if (!cl) {
5982 return;
5983 }
5984
5985 if (!mother->GetAddress()) {
5986 // -- Our top-level branch has no address.
5987 bool motherStatus = mother->TestBit(kDoNotProcess);
5988 mother->ResetBit(kDoNotProcess);
5989 // Note: This will allocate an object.
5990 mother->SetAddress(nullptr);
5992 }
5993}
5994
5995////////////////////////////////////////////////////////////////////////////////
5996/// Stream an object of class TBranchElement.
5997
5999{
6000 if (R__b.IsReading()) {
6001 R__b.ReadClassBuffer(TBranchElement::Class(), this);
6006 // The fAddress and fObject data members are not persistent,
6007 // therefore we do not own anything.
6008 // Also clear the bit possibly set by the schema evolution.
6010 // Fixup a case where the TLeafElement was missing
6011 if ((fType == 0) && (fLeaves.GetEntriesFast() == 0)) {
6012 TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
6013 leaf->SetTitle(GetTitle());
6014 fNleaves = 1;
6015 fLeaves.Add(leaf);
6016 fTree->GetListOfLeaves()->Add(leaf);
6017 }
6018
6019 // SetReadLeavesPtr();
6020 }
6021 else {
6023 fDirectory = nullptr; // to avoid recursive calls
6024 {
6025 // Save class version.
6027 // Record only positive 'version number'
6028 if (fClassVersion < 0) {
6030 }
6031 // TODO: Should we clear the kDeleteObject bit before writing?
6032 // If we did we would have to remember the old value and
6033 // put it back, we wouldn't want to forget that we owned
6034 // something just because we got written to disk.
6035 R__b.WriteClassBuffer(TBranchElement::Class(), this);
6036 // Restore class version.
6038 }
6039 //
6040 // Mark all streamer infos used by this branch element
6041 // to be written to our output file.
6042 //
6043 {
6044 R__b.ForceWriteInfo(GetInfoImp(), true);
6045 }
6046 //
6047 // If we are a clones array master branch, or an
6048 // STL container master branch, we must also mark
6049 // the streamer infos used by the value class to
6050 // be written to our output file.
6051 //
6052 if (fType == 3) {
6053 // -- TClonesArray, counter/master branch
6054 //
6055 // We must mark the streamer info for the
6056 // value class to be written to the file.
6057 //
6058 TClass* cl = fClonesClass;
6059 if (cl) {
6060 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6061 }
6062 }
6063 else if (fType == 4) {
6064 // -- STL container, counter/master branch
6065 //
6066 // We must mark the streamer info for the
6067 // value class to be written to the file.
6068 //
6070 if (cp) {
6071 TClass* cl = cp->GetValueClass();
6072 if (cl) {
6073 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6074 }
6075 }
6076 }
6077 // If we are in a separate file, then save
6078 // ourselves as an independent key.
6079 if (!dirsav) {
6080 // Note: No need to restore fDirectory, it was already zero.
6081 return;
6082 }
6083 if (!dirsav->IsWritable()) {
6085 return;
6086 }
6088 if (!pdirectory) {
6090 return;
6091 }
6092 const char* treeFileName = pdirectory->GetFile()->GetName();
6094 const char* motherFileName = treeFileName;
6095 if (mother && (mother != this)) {
6096 motherFileName = mother->GetFileName();
6097 }
6098 if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
6099 dirsav->WriteTObject(this);
6100 }
6102 }
6103}
6104
6105
6106////////////////////////////////////////////////////////////////////////////////
6107/// Split class cl into sub-branches of this branch.
6108///
6109/// This version of Unroll was formerly embedded in TTree::BronchExec
6110/// It is moved here so we can make sure to call SetReadActionSequence.
6111
6113{
6114 //
6115 // Do we have a final dot in our name?
6116 //
6117
6118 // Note: The branch constructor which takes a folder as input
6119 // creates top-level branch names with dots in them to
6120 // indicate the folder hierarchy.
6121 char* dot = (char*) strchr(name, '.');
6122 Int_t nch = strlen(name);
6123 bool dotlast = false;
6124 if (nch && (name[nch-1] == '.')) {
6125 dotlast = true;
6126 }
6127
6128 // Loop on all public data members of the class and its base classes and create branches for each one.
6129 TObjArray* blist = this->GetListOfBranches();
6130 TIter next(sinfo->GetElements());
6131 TStreamerElement* element = nullptr;
6132 TString bname;
6133 for (Int_t id = 0; (element = (TStreamerElement*) next()); ++id) {
6134 if (element->IsA() == TStreamerArtificial::Class()) {
6135 continue;
6136 }
6137 if (element->TestBit(TStreamerElement::kRepeat)) {
6138 continue;
6139 }
6141 continue;
6142 }
6143 char* pointer = (char*) (objptr + element->GetOffset());
6144 // FIXME: This is not good enough, an STL container can be
6145 // a base, and the test will fail.
6146 // See TBranchElement::InitializeOffsets() for the
6147 // correct test.
6148 bool isBase = (element->IsA() == TStreamerBase::Class());
6149 if (isBase) {
6150 TClass* clbase = element->GetClassPointer();
6151 if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) {
6152 // Note: TStreamerInfo::Compile() leaves this element
6153 // out of the optimized info, although it does
6154 // exists in the non-compiled and non-optimized info.
6155 // FIXME: The test that TStreamerInfo::Compile() uses
6156 // is element->GetType() < 0, so that is what
6157 // we should do as well.
6158 continue;
6159 }
6160 if (clbase->GetListOfRealData()->GetSize() == 0) {
6161 // Do not create a branch for empty bases.
6162 continue;
6163 }
6164 }
6165 if (dot) {
6166 if (dotlast) {
6167 bname.Form("%s%s", name, element->GetFullName());
6168 } else {
6169 // FIXME: We are in the case where we have a top-level
6170 // branch name that was created by the branch
6171 // constructor which takes a folder as input.
6172 // The internal dots in the name are in place of
6173 // of the original slashes and represent the
6174 // folder hierarchy.
6175 if (isBase) {
6176 // FIXME: This is very strange, this is the only case where
6177 // we create a branch for a base class that does
6178 // not have the base class name in the branch name.
6179 // FIXME: This is also quite bad since classes with two
6180 // or more base classes end up with sub-branches
6181 // that have the same name.
6182 bname = name;
6183 } else {
6184 bname.Form("%s.%s", name, element->GetFullName());
6185 }
6186 }
6187 } else {
6188 // Note: For a base class element, this results in the branchname
6189 // being the name of the base class.
6190 bname.Form("%s", element->GetFullName());
6191 }
6192
6194 element->GetClass()->GetCollectionProxy() &&
6195 element->GetClass()->GetCollectionProxy()->HasPointers() )
6196 {
6197 TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id );
6198 blist->Add(brSTL);
6199 }
6200 else
6201 {
6202 TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1);
6203 bre->SetParentClass(cl);
6204 blist->Add(bre);
6205 }
6206 }
6207 // Now that we know that this branch is split, let's redo the actions.
6210}
6211
6212////////////////////////////////////////////////////////////////////////////////
6213/// Split class cl into sub-branches of this branch.
6214///
6215/// Create a sub-branch of this branch for each non-empty,
6216/// non-abstract base class of cl (unless we are a sub-branch
6217/// of a TClonesArray or an STL container, in which case we
6218/// do *not* create a sub-branch), and for each non-split data
6219/// member of cl.
6220///
6221/// Note: We do *not* create sub-branches for base classes of cl
6222/// if we are a sub-branch of a TClonesArray or an STL container.
6223///
6224/// Note: We do *not* create sub-branches for data members which
6225/// have a class type and which we are splitting.
6226///
6227/// Note: The above rules imply that the branch hierarchy increases
6228/// in depth only for base classes of cl (unless we are inside
6229/// of a TClonesArray or STL container, in which case the depth
6230/// does *not* increase, the base class is elided) and for
6231/// TClonesArray or STL container data members (which have one
6232/// additional level of sub-branches). The only other way the
6233/// depth increases is when the top-level branch has a split
6234/// class data member, in that case the constructor will create
6235/// a sub-branch for it. In other words, the interior nodes of
6236/// the branch tree are all either: base class nodes; split
6237/// class nodes which are direct sub-branches of top-level nodes
6238/// (created by TClass::Bronch usually); or TClonesArray or STL
6239/// container master nodes.
6240///
6241/// Note: The exception to the above is for the top-level branches,
6242/// Tree::Bronch creates nodes for everything in that case,
6243/// except for a TObject base class of a class which has the
6244/// can ignore tobject streamer flag set.
6245
6247{
6248 //----------------------------------------------------------------------------
6249 // Handling the case of STL collections of pointers
6250 /////////////////////////////////////////////////////////////////////////////
6251
6254
6256
6257 if ((cl == TObject::Class()) && clParent->CanIgnoreTObjectStreamer()) {
6258 return 0;
6259 }
6260
6262
6263 //
6264 // Do nothing if we couldn't build the streamer info for cl.
6265 //
6266
6267 if (!sinfo) {
6268 return 0;
6269 }
6270
6271 const auto namelen = strlen(name);
6272 bool dotlast = (namelen && (name[namelen-1] == '.'));
6273
6274 Int_t ndata = sinfo->GetNelement();
6275
6276 if ((ndata == 1) && cl->GetCollectionProxy() && !strcmp(sinfo->GetElement(0)->GetName(), "This")) {
6277 // -- Class cl is an STL collection, refuse to split it.
6278 // Question: Why? We certainly could by switching to the value class.
6279 // Partial Answer: Only the branch element constructor can split STL containers.
6280 return 1;
6281 }
6282
6283 for (Int_t elemID = 0; elemID < ndata; ++elemID) {
6284 // -- Loop over all the streamer elements and create sub-branches as needed.
6285 TStreamerElement* elem = sinfo->GetElement(elemID);
6286 if (elem->IsA() == TStreamerArtificial::Class()) {
6287 continue;
6288 }
6289 if (elem->TestBit(TStreamerElement::kRepeat)) {
6290 continue;
6291 }
6292 if (elem->TestBit(TStreamerElement::kCache) && !elem->TestBit(TStreamerElement::kWrite)) {
6293 continue;
6294 }
6295 Int_t offset = elem->GetOffset();
6296 // FIXME: An STL container as a base class gets TStreamerSTL as its class, so this test is not enough.
6297 // See InitializeOffsets() for the proper test.
6298 if (elem->IsA() == TStreamerBase::Class()) {
6299 // -- This is a base class of cl.
6300 TClass* clOfBase = elem->GetClassPointer();
6301 if (!clOfBase || ((clOfBase->Property() & kIsAbstract) && cl->InheritsFrom(TCollection::Class()))) {
6302 // -- Do nothing if we are one of the abstract collection (we know they have no data).
6303 return -1;
6304 }
6305 if ((btype == 31) || (btype == 41)) {
6306 // -- Elide the base-class sub-branches of a split TClonesArray or STL container.
6307 //
6308 // Note: We are eliding the base class here, that is, we never
6309 // create a branch for it, so the branch hierarchy is not
6310 // complete.
6311 // Note: The clParent parameter is the value class of the
6312 // container which we are splitting. It does not
6313 // appear in the branch hierarchy either.
6314 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6315 Int_t unroll = -1;
6316 if (!elem->CannotSplit() || clOfBase == TObject::Class()) {
6318 }
6319 if (unroll < 0) {
6320 // FIXME: We could not split because we are abstract, should we be doing this?
6321 if (namelen) {
6322 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6323 } else {
6324 branchname.Form("%s", elem->GetFullName());
6325 }
6326 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, nullptr, basketsize, 0, btype);
6327 branch->SetParentClass(clParent);
6329 }
6330 } else if (clOfBase->GetListOfRealData()->GetSize()) {
6331 // -- Create a branch for a non-empty base class.
6332 if (namelen) {
6333 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6334 // Elide the base class name when creating the sub-branches.
6335 // Note: The branch names for sub-branches of a base class branch
6336 // do not represent the full class hierarchy because we do
6337 // this, however it does keep the branch names for the
6338 // inherited data members simple.
6340 // Then reset it to the proper name.
6341 branch->SetName(branchname);
6342 branch->SetTitle(branchname);
6343 branch->SetParentClass(clParent);
6345 } else {
6346 branchname.Form("%s", elem->GetFullName());
6348 branch->SetParentClass(clParent);
6350 }
6351 }
6352 } else {
6353 // -- This is a data member of cl.
6354 if (namelen) {
6355 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6356 } else {
6357 branchname.Form("%s", elem->GetFullName());
6358 }
6359 if ((splitlevel > 1) && ((elem->IsA() == TStreamerObject::Class()) || (elem->IsA() == TStreamerObjectAny::Class()))) {
6360 // -- We are splitting a non-TClonesArray (may inherit from TClonesArray though), non-STL container object.
6361 //
6362 // Ignore an abstract class.
6363 // FIXME: How could an abstract class get here?
6364 // Partial answer: It is a base class. But this is a data member!
6365 TClass* elemClass = elem->GetClassPointer();
6366 if (!elemClass || elemClass->Property() & kIsAbstract) {
6367 return -1;
6368 }
6369 if (elem->CannotSplit()) {
6370 // We are not splitting.
6371 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6372 branch->SetParentClass(clParent);
6374 } else if (elemClass->InheritsFrom(TClonesArray::Class())) {
6375 // Splitting something derived from TClonesArray.
6377 if (btype == 31 || btype == 41 || elem->CannotSplit()) {
6378 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6379 subSplitlevel = 0;
6380 }
6382 branch->SetParentClass(clParent);
6384 } else {
6385 // Splitting a normal class.
6386 // FIXME: We are eliding the class we are splitting here,
6387 // i.e., we do not create a branch for it, so the
6388 // branch hierarchy does not match the class hierarchy.
6389 // Note: clParent is the class which contains a data member of
6390 // the class type which we are splitting.
6391 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6393 if (unroll < 0) {
6394 // FIXME: We could not split because we are abstract, should we be doing this?
6395 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6396 branch->SetParentClass(clParent);
6398 }
6399 }
6400 }
6401 else if( elem->GetClassPointer() &&
6402 elem->GetClassPointer()->GetCollectionProxy() &&
6403 elem->GetClassPointer()->GetCollectionProxy()->HasPointers() &&
6404 splitSTLP && fType != 4 )
6405 {
6406
6407 TBranchSTL* branch = new TBranchSTL( this, branchname,
6408 elem->GetClassPointer()->GetCollectionProxy(),
6410 branch->SetAddress( ptr+offset );
6411 fBranches.Add( branch );
6412 }
6413 else if ((elem->IsA() == TStreamerSTL::Class()) && !elem->IsaPointer()) {
6414 // -- We have an STL container.
6415 // Question: What if splitlevel == 0 here?
6416 // Answer: then we should not be here.
6418 if ((btype == 31) || (btype == 41) || elem->CannotSplit()) {
6419 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6420 subSplitlevel = 0;
6421 }
6423 branch->SetParentClass(clParent);
6425 } else if (((btype != 31) && (btype != 41)) && ptr && ((elem->GetClassPointer() == TClonesArray::Class()) || ((elem->IsA() == TStreamerSTL::Class()) && !elem->CannotSplit()))) {
6426 // -- We have a TClonesArray.
6427 // FIXME: We could get a ptr to a TClonesArray here by mistake.
6428 // Question: What if splitlevel == 0 here?
6429 // Answer: then we should not be here.
6430 // Note: ptr may be null in case of a TClonesArray inside another
6431 // TClonesArray or STL container, see the else clause.
6433 branch->SetParentClass(clParent);
6435 } else {
6436 // -- We are not going to split this element any farther.
6438 branch->SetType(btype);
6439 branch->SetParentClass(clParent);
6441 }
6442 }
6443 }
6444
6445 if (!fBranches.IsEmpty()) {
6446 // Refresh this branch's action now that we know whether it is split or not.
6449 }
6450 return 1;
6451}
6452
6453////////////////////////////////////////////////////////////////////////////////
6454/// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
6455/// with the current value of fTree->GetCurrentFile unless this branch has been
6456/// redirected to a different file. Also update the sub-branches.
6457
6459{
6460 // The BranchCount and BranchCount2 are part of higher level branches' list of
6461 // branches.
6462 // if (fBranchCount) fBranchCount->UpdateFile();
6463 // if (fBranchCount2) fBranchCount2->UpdateFile();
6465}
static void unroll(CPyCppyy_PyArgs_t packed_args, CPyCppyy_PyArgs_t unrolled, Py_ssize_t nArgs)
fBuffer
const Handle_t kNone
Definition GuiTypes.h:88
#define R__unlikely(expr)
Definition RConfig.hxx:594
#define b(i)
Definition RSha256.hxx:100
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
unsigned short UShort_t
Unsigned Short integer 2 bytes (unsigned short)
Definition RtypesCore.h:54
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
float Size_t
Attribute size (float)
Definition RtypesCore.h:103
long Longptr_t
Integer large enough to hold a pointer (platform-dependent)
Definition RtypesCore.h:89
unsigned char UChar_t
Unsigned Character 1 byte (unsigned char)
Definition RtypesCore.h:52
int Ssiz_t
String size (currently int)
Definition RtypesCore.h:81
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:51
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:69
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:60
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:71
short Short_t
Signed Short integer 2 bytes (short)
Definition RtypesCore.h:53
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
long double LongDouble_t
Long Double (not portable)
Definition RtypesCore.h:75
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:84
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids)
Print branch parameters.
static void R__CleanName(std::string &name)
Remove trailing dimensions and make sure there is a trailing dot.
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
EDataType
Definition TDataType.h:28
@ kOther_t
Definition TDataType.h:32
@ kIsAbstract
Definition TDictionary.h:71
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t cursor
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
R__EXTERN TVirtualMutex * gInterpreterMutex
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:411
static TClass * Class()
Definition Class.C:29
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2509
#define R__LOCKGUARD_IMT(mutex)
#define R__LOCKGUARD(mutex)
#define gPad
A helper class for managing IMT work during TTree:Fill operations.
const_iterator begin() const
const_iterator end() const
TIOFeatures provides the end-user with the ability to change the IO behavior of data written via a TT...
Manages buffers for branches of a Tree.
Definition TBasket.h:34
A Branch for the case of an object.
void ReadLeavesClonesMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
void SetActionSequence(TClass *originalClass, TStreamerInfo *localInfo, TStreamerInfoActions::TActionSequence::SequenceGetter_t create, TStreamerInfoActions::TActionSequence *&actionSequence)
Set the sequence of actions needed to read the data out of the buffer.
char * fObject
! Pointer to object at *fAddress
TStreamerInfo * fInfo
! Pointer to StreamerInfo
Int_t fSTLtype
! STL container type
void ReadLeavesCustomStreamer(TBuffer &b)
Read leaves into i/o buffers for this branch.
void Reset(Option_t *option="") override
Reset a Branch.
void SetParentClass(TClass *clparent)
TBranchElement * fBranchCount2
pointer to secondary branchcount branch
static TClass * Class()
Int_t fNdata
! Number of data in this branch
~TBranchElement() override
Destructor.
void SetOffset(Int_t offset) override
Set offset of the object (to which the data member represented by this branch belongs) inside its con...
void FillLeavesCollectionMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
TString fClassName
Class name of referenced object.
TStreamerInfoActions::TActionSequence * fFillActionSequence
! Set of actions to be executed to write the data to the basket.
void Print(Option_t *option="") const override
Print TBranch parameters.
void SetAddressImpl(void *addr, bool implied, Int_t offset) override
See TBranchElement::SetAddress.
Int_t GetID() const
const char * GetClassName() const override
Return the name of the user class whose content is stored in this branch, if any.
TStreamerInfo * GetInfo() const
Get streamer info for the branch class.
void ReadLeavesCollection(TBuffer &b)
Read leaves into i/o buffers for this branch.
void SetupAddresses() override
If the branch address is not set, we set all addresses starting with the top level parent branch.
void ResetAddress() override
Set branch address to zero and free all allocated memory.
virtual void SetType(Int_t btype)
void FillLeavesMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
void SetBranchCount(TBranchElement *bre)
Set the branch counter for this branch.
static void SwitchContainer(TObjArray *)
Modify the container type of the branches.
void SetReadActionSequence()
Set the sequence of actions needed to read the data out of the buffer.
bool IsMissingCollection() const
Detect a collection written using a zero pointer in old versions of root.
Int_t FillImpl(ROOT::Internal::TBranchIMTHelper *) override
Loop on all leaves of this branch to fill the basket buffer.
TVirtualCollectionProxy * GetCollectionProxy()
Return the collection proxy describing the branch content, if any.
@ kOwnOnfileObj
We are the owner of fOnfileObject.
@ kAddressSet
The addressing set have been called for this branch.
@ kDecomposedObj
More explicit alias for kMakeClass.
@ kDeleteObject
We are the owner of fObject.
@ kCache
Need to pushd/pop fOnfileObject.
void SetupAddressesImpl()
If the branch address is not set, we set all addresses starting with the top level parent branch.
void SetBasketSize(Int_t bufsize) override
Reset the basket size for all sub-branches of this branch element.
Int_t GetEntry(Long64_t entry=0, Int_t getall=0) override
Read all branches of a BranchElement and return total number of bytes.
TClassRef fParentClass
! Reference to class definition in fParentName
Double_t GetValue(Int_t i, Int_t len, bool subarr=false) const
bool fInInitInfo
! True during the 2nd part of InitInfo (cut recursion).
void BuildTitle(const char *name)
Set branch and leaf name and title in the case of a container sub-branch.
virtual Int_t GetMaximum() const
Return maximum count value of the branchcount if any.
TString fParentName
Name of parent class.
void ReadLeavesCollectionSplitPtrMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
TClassRef fBranchClass
! Reference to class definition in fClassName
TStreamerInfoActions::TIDs fNewIDs
! Nested List of the serial number of all the StreamerInfo to be used.
Int_t GetStreamerType() const
TClass * GetCurrentClass()
Return a pointer to the current type of the data member corresponding to branch element.
UInt_t fCheckSum
CheckSum of class.
void ResetAfterMerge(TFileMergeInfo *) override
Reset a Branch after a Merge operation (drop data but keep customizations)
TStreamerInfoActions::TActionSequence * fReadActionSequence
! Set of actions to be executed to extract the data from the basket.
void FillLeavesClones(TBuffer &b)
Write leaves into i/o buffers for this branch.
void ReadLeavesMemberBranchCount(TBuffer &b)
Read leaves into i/o buffers for this branch.
void SetReadLeavesPtr()
Set the ReadLeaves pointer to execute the expected operations.
Int_t Unroll(const char *name, TClass *cltop, TClass *cl, char *ptr, Int_t basketsize, Int_t splitlevel, Int_t btype)
Split class cl into sub-branches of this branch.
void FillLeavesMakeClass(TBuffer &b)
Write leaves into i/o buffers for this branch.
void FillLeavesCollectionSplitVectorPtrMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
void FillLeavesCollection(TBuffer &b)
Write leaves into i/o buffers for this branch.
Int_t fID
element serial number in fInfo
char * GetAddress() const override
Get the branch address.
void FillLeavesMemberCounter(TBuffer &b)
Write leaves into i/o buffers for this branch.
void FillLeavesCollectionSplitPtrMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
void SetAddress(void *addobj) override
Point this branch at an object.
TStreamerInfo * GetInfoImp() const
Get streamer info for the branch class.
virtual void SetTargetClass(const char *name)
Set the name of the class of the in-memory object into which the data will loaded.
virtual void ResetDeleteObject()
Release ownership of any allocated objects.
virtual const char * GetParentName() const
void ValidateAddress() const
TVirtualCollectionIterators * fWriteIterators
! holds the read (non-staging) iterators when the branch is of fType==4 and associative containers.
void PrintValue(Int_t i) const
Prints values of leaves.
TVirtualArray * fOnfileObject
! Place holder for the onfile representation of data members.
virtual const char * GetTypeName() const
Return type name of element in the branch.
void FillLeavesAssociativeCollectionMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
void Init(TTree *tree, TBranch *parent, const char *name, TStreamerInfo *sinfo, Int_t id, char *pointer, Int_t basketsize=32000, Int_t splitlevel=0, Int_t btype=0)
Init when the branch object is not a TClonesArray nor an STL container.
T GetTypedValue(Int_t i, Int_t len, bool subarr=false) const
TClassRef fClonesClass
! Reference to class definition in fClonesName
virtual void * GetValuePointer() const
Returns pointer to first data element of this branch.
void ReadLeavesImpl(TBuffer &b)
Unconfiguration Read Leave function.
bool fInitOffsets
! Initialization flag to not endlessly recalculate offsets
void SetupInfo()
Set the value of fInfo.
void FillLeavesImpl(TBuffer &b)
Unconfiguration Fill Leave function.
void FillLeavesClonesMember(TBuffer &b)
Write leaves into i/o buffers for this branch.
TClassRef fCurrentClass
! Reference to current (transient) class definition
char * GetObject() const
Return a pointer to our object.
void UpdateFile() override
Refresh the value of fDirectory (i.e.
TStreamerInfo * FindOnfileInfo(TClass *valueClass, const TObjArray &branches) const
bool SetMakeClass(bool decomposeObj=true) override
Set the branch in a mode where the object are decomposed (Also known as MakeClass mode).
void ReadLeavesClones(TBuffer &b)
Read leaves into i/o buffers for this branch.
Int_t * fBranchOffset
! Sub-Branch offsets with respect to current transient class
Int_t fType
Branch type.
virtual void ResetInitInfo(bool recurse)
Reset offset and StreamerInfo information from this branch.
friend class TLeafElement
TString GetFullName() const override
Return the 'full' name of the branch.
void ReadLeavesMakeClass(TBuffer &b)
Read leaves into i/o buffers for this branch.
TBranchElement()
Default and I/O constructor.
void FillLeavesCustomStreamer(TBuffer &b)
Write leaves into i/o buffers for this branch.
virtual const char * GetClonesName() const
virtual TClass * GetClass() const
Int_t fMaximum
Maximum entries for a TClonesArray or variable array.
void ReadLeavesMemberCounter(TBuffer &b)
Read leaves into i/o buffers for this branch.
Int_t fBranchID
! ID number assigned by a TRefTable.
TLeaf * FindLeaf(const char *name) override
Find the leaf corresponding to the name 'searchname'.
TVirtualCollectionIterators * fIterators
! holds the iterators when the branch is of fType==4.
void ReleaseObject()
Delete any object we may have allocated on a previous call to SetAddress.
TClassRef fTargetClass
! Reference to the target in-memory class
void Browse(TBrowser *b) override
Browse the branch content.
void FillLeavesMemberBranchCount(TBuffer &b)
Write leaves into i/o buffers for this branch.
bool IsFolder() const override
Return true if more than one leaf, false otherwise.
virtual void SetMissing()
Set offset of the object (to which the data member represented by this branch belongs) inside its con...
TString fClonesName
Name of class in TClonesArray (if any)
TBranchElement * fBranchCount
pointer to primary branchcount branch
Int_t GetType() const
void ReadLeavesMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
Version_t fClassVersion
Version number of class.
TVirtualCollectionPtrIterators * fPtrIterators
! holds the iterators when the branch is of fType==4 and it is a split collection of pointers.
TBranch * FindBranch(const char *name) override
Find the immediate sub-branch with passed name.
void Streamer(TBuffer &) override
Stream an object of class TBranchElement.
virtual void InitInfo()
Init the streamer info for the branch class, try to compensate for class code unload/reload and schem...
virtual void InitializeOffsets()
Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a containe...
const char * GetIconName() const override
Return icon name depending on type of branch element.
TClass * GetParentClass()
Return a pointer to the parent class of the branch element.
Int_t GetNdata() const
Int_t GetExpectedType(TClass *&clptr, EDataType &type) override
Fill expectedClass and expectedType with information on the data type of the object/values contained ...
bool fInit
! Initialization flag for branch assignment
TVirtualCollectionProxy * fCollProxy
! collection interface (if any)
void SetFillActionSequence()
Set the sequence of actions needed to write the data out from the buffer.
void SetObject(void *objadd) override
Set object this branch is pointing to.
Int_t fStreamerType
branch streamer type
void ReadLeavesCollectionSplitVectorPtrMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
bool GetMakeClass() const override
Return whether this branch is in a mode where the object are decomposed or not (Also known as MakeCla...
void SetFillLeavesPtr()
Set the FillLeaves pointer to execute the expected operations.
void ReadLeavesCollectionMember(TBuffer &b)
Read leaves into i/o buffers for this branch.
A branch containing and managing a TRefTable for TRef autoloading.
Definition TBranchRef.h:34
A Branch handling STL collection of pointers (vectors, lists, queues, sets and multisets) while stori...
Definition TBranchSTL.h:22
A TTree is a list of TBranches.
Definition TBranch.h:93
TString fFileName
Name of file where buffers are stored ("" if in same file as Tree header)
Definition TBranch.h:149
Int_t fEntryOffsetLen
Initial Length of fEntryOffset table in the basket buffers.
Definition TBranch.h:119
Int_t fMaxBaskets
Maximum number of Baskets so far.
Definition TBranch.h:125
TTree * GetTree() const
Definition TBranch.h:252
FillLeaves_t fFillLeaves
! Pointer to the FillLeaves implementation to use.
Definition TBranch.h:163
virtual TString GetFullName() const
Return the 'full' name of the branch.
Definition TBranch.cxx:2030
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:1311
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:1705
TIOFeatures GetIOFeatures() const
Returns the IO settings currently in use for this branch.
Definition TBranch.cxx:2254
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:2340
TBranch * GetSubBranch(const TBranch *br) const
Find the parent branch of child.
Definition TBranch.cxx:2163
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:2728
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:1080
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:3316
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:2262
TObjArray fBranches
-> List of Branches of this branch
Definition TBranch.h:138
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset a Branch.
Definition TBranch.cxx:2597
virtual TBranch * FindBranch(const char *name)
Find the immediate sub-branch with passed name.
Definition TBranch.cxx:1034
TDirectory * fDirectory
! Pointer to directory where this branch buffers are stored
Definition TBranch.h:148
TObjArray fBaskets
-> List of baskets of this branch
Definition TBranch.h:140
void SetIOFeatures(TIOFeatures &features)
Definition TBranch.h:283
TBranch * fMother
! Pointer to top-level parent branch in the tree.
Definition TBranch.h:145
TBranch * fParent
! Pointer to parent branch.
Definition TBranch.h:146
Int_t fWriteBasket
Last basket number written.
Definition TBranch.h:120
Long64_t * fBasketSeek
[fMaxBaskets] Addresses of baskets on file
Definition TBranch.h:143
TObjArray * GetListOfLeaves()
Definition TBranch.h:247
Int_t fReadBasket
! Current basket number when reading
Definition TBranch.h:129
Int_t fBasketSize
Initial Size of Basket Buffer.
Definition TBranch.h:118
virtual void Reset(Option_t *option="")
Reset a Branch.
Definition TBranch.cxx:2556
virtual void SetBasketSize(Int_t bufsize)
Set the basket size The function makes sure that the basket size is greater than fEntryOffsetlen.
Definition TBranch.cxx:2741
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:2126
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:855
Long64_t fEntries
Number of entries.
Definition TBranch.h:134
TTree * fTree
! Pointer to Tree header
Definition TBranch.h:144
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
Buffer base class used for serializing objects.
Definition TBuffer.h:43
@ kRead
Definition TBuffer.h:73
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h:29
void SetName(const char *new_name)
Definition TClassRef.h:62
TClass * GetClass() const
Definition TClassRef.h:67
const char * GetClassName()
Definition TClassRef.h:66
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=nullptr) const
Definition TClass.h:623
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition TClass.cxx:3470
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2324
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:4736
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Replaces the collection proxy for this class.
Definition TClass.cxx:2475
Bool_t HasCustomStreamerMember() const
The class has a Streamer method and it is implemented by the user or an older (not StreamerInfo based...
Definition TClass.h:521
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5439
TClassStreamer * GetStreamer() const
Return the Streamer Class allowing streaming (if any).
Definition TClass.cxx:2919
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:404
const TObjArray * GetStreamerInfos() const
Definition TClass.h:505
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:5954
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:5980
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method).
Definition TClass.cxx:5989
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:4626
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4901
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2902
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6128
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition TClass.cxx:7129
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:2973
An array of clone (identical) objects.
static TClass * Class()
static TClass * Class()
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
const char * GetTypeName() const
Get the decayed type name of this data member, removing const and volatile qualifiers,...
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
Describe directory structure in memory.
Definition TDirectory.h:45
virtual TFile * GetFile() const
Definition TDirectory.h:221
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:131
A TLeaf for the general case when using the branches created via a TStreamerInfo (i....
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
A doubly linked list.
Definition TList.h:38
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
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:149
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
Int_t IndexOf(const TObject *obj) const override
Int_t GetEntries() const override
Return the number of objects in array (i.e.
TObject * At(Int_t idx) const override
Definition TObjArray.h:164
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
Bool_t IsEmpty() const override
Definition TObjArray.h:65
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
void Add(TObject *obj) override
Definition TObjArray.h:68
Mother of all ROOT objects.
Definition TObject.h:41
friend class TClonesArray
Definition TObject.h:243
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:202
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx: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:246
void ResetBit(UInt_t f)
Definition TObject.h:201
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1045
The TRealData class manages the effective list of all data members for a given class.
Definition TRealData.h:30
static TClass * Class()
static TClass * Class()
static TClass * Class()
Describe one element (data member) to be Streamed.
Int_t GetType() const
const char * GetTypeName() const
static SequencePtr WriteMemberWiseActionsViaProxyGetter(TStreamerInfo *, TVirtualCollectionProxy *collectionProxy, TClass *)
static SequencePtr WriteMemberWiseActionsGetter(TStreamerInfo *info, TVirtualCollectionProxy *, TClass *)
static SequencePtr ConversionReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass)
void Print(Option_t *="") const override
This method must be overridden when a class wants to print itself.
static SequencePtr WriteMemberWiseActionsCollectionCreator(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *)
static SequencePtr ReadMemberWiseActionsCollectionCreator(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *)
static SequencePtr ReadMemberWiseActionsGetter(TStreamerInfo *info, TVirtualCollectionProxy *, TClass *)
SequencePtr(*)(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass) SequenceGetter_t
static SequencePtr WriteMemberWiseActionsCollectionGetter(TStreamerInfo *info, TVirtualCollectionProxy *, TClass *)
static SequencePtr ReadMemberWiseActionsCollectionGetter(TStreamerInfo *info, TVirtualCollectionProxy *, TClass *)
static SequencePtr ReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *)
Base class of the Configurations.
TVirtualStreamerInfo * fInfo
TStreamerInfo form which the action is derived.
UInt_t fElemId
Identifier of the TStreamerElement.
Describes a persistent version of a class.
TStreamerElement * GetElement(Int_t id) const override
T GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
Return value of element i in object at pointer.
Int_t GetNelement() const
T GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a pointer to STL container and eventually element k i...
T GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in an STL container and eventually element k in a sub-ar...
TClass * GetClass() const override
T GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
TStreamerElement * GetStreamerElement(const char *datamember, Int_t &offset) const override
Return the StreamerElement of "datamember" inside our class or any of its base classes.
UInt_t GetCheckSum() const override
static TClass * Class()
static TClass * Class()
static TClass * Class()
static TClass * Class()
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
static constexpr Ssiz_t kNPOS
Definition TString.h:286
const char * Data() const
Definition TString.h:384
@ kTrailing
Definition TString.h:284
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition TString.cxx:938
TString & Remove(Ssiz_t pos)
Definition TString.h:693
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2384
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2362
static TClass * Class()
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:659
A TTree represents a columnar dataset.
Definition TTree.h:89
TStreamerInfo * BuildStreamerInfo(TClass *cl, void *pointer=nullptr, bool canOptimize=true)
Build StreamerInfo for class cl.
Definition TTree.cxx:2682
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5430
Int_t GetDefaultEntryOffsetLen() const
Definition TTree.h:498
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:568
void Draw(Option_t *opt) override
Default Draw method for all objects.
Definition TTree.h:470
TDirectory * GetDirectory() const
Definition TTree.h:501
@ kSplitCollectionOfPointers
Definition TTree.h:302
Int_t Debug() const
Definition TTree.h:468
virtual TBranchRef * GetBranchRef() const
Definition TTree.h:489
virtual Long64_t GetReadEntry() const
Definition TTree.h:588
Long64_t GetDebugMin() const
Definition TTree.h:500
Wrapper around an object and giving indirect access to its content even if the object is not of a cla...
char * GetObjectAt(UInt_t ind) const
void SetSize(UInt_t size)
Small helper class to generically acquire and release iterators.
void CreateIterators(void *collection, TVirtualCollectionProxy *proxy)
RAII helper class that ensures that PushProxy() / PopProxy() are called when entering / leaving a C++...
Defines a common interface to inspect/change the contents of an object that represents a collection.
virtual Int_t GetProperties() const
Return miscallenous properties of the proxy (see TVirtualCollectionProxy::EProperty)
@ kNeedDelete
The collection contains directly or indirectly (via other collection) some pointers that need explici...
virtual TClass * GetValueClass() const =0
If the value type is a user-defined class, return a pointer to the TClass representing the value type...
virtual Int_t GetCollectionType() const =0
Return the type of the proxied collection (see enumeration TClassEdit::ESTLType)
virtual Bool_t HasPointers() const =0
Return true if the content is of type 'pointer to'.
void CreateIterators(void *collection, TVirtualCollectionProxy *proxy)
Abstract Interface class describing Streamer information for one class.
@ kUChar
Equal to TDataType's kchar.
virtual TObjArray * GetElements() const =0
const Int_t n
Definition legend1.C:16
@ kSTLmap
Definition ESTLType.h:33
@ kSTLunorderedmultiset
Definition ESTLType.h:43
@ kSTLend
Definition ESTLType.h:47
@ kSTLset
Definition ESTLType.h:35
@ kSTLmultiset
Definition ESTLType.h:36
@ kSTLvector
Definition ESTLType.h:30
@ kSTLunorderedmultimap
Definition ESTLType.h:45
@ kSTLunorderedset
Definition ESTLType.h:42
@ kSTLunorderedmap
Definition ESTLType.h:44
@ kNotSTL
Definition ESTLType.h:29
@ kSTLmultimap
Definition ESTLType.h:34
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:199
std::vector< TIDNode > TIDs
TCanvas * slash()
Definition slash.C:1
TMarker m
Definition textangle.C:8