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 /// Check if a collection proxy represents an associative collection (e.g., std::map, std::set)
82 /// rather than a sequential collection (e.g., std::vector, std::list).
83 /// Both the version based on the fSTLtype integer and the one based on the TVirtualCollectionProxy
84 /// will return the same result about the 'currently' in memory collection attached to the branch.
85 /// The main difference is that the fSTLtype can be used without checking whether
86 /// fCollProxy is set or not but might (or might not) be a tad bit slower.
88 {
89 switch (stltype) {
90 case ROOT::kSTLset:
94 case ROOT::kSTLmap:
98 return true;
99 default:
100 return false;
101 }
102 }
104 {
105 return proxy.GetProperties() & TVirtualCollectionProxy::kIsAssociative;
106 }
107
109 {
110 br->ResetReadEntry();
111 for (auto sub : *br->GetListOfBranches())
113 }
114}
115
116////////////////////////////////////////////////////////////////////////////////
117/// Modify the container type of the branches
118
120 const Int_t nbranches = branches->GetEntriesFast();
121 for (Int_t i = 0; i < nbranches; ++i) {
122 TBranchElement* br = static_cast<TBranchElement*>(branches->At(i));
123 switch (br->GetType()) {
124 case 31: br->SetType(41); break;
125 case 41: {
126 br->SetType(31);
127 br->fCollProxy = nullptr;
128 break;
129 }
130 }
131 br->SetReadLeavesPtr();
132 br->SetFillLeavesPtr();
133 // Note: This is a tail recursion.
134 SwitchContainer(br->GetListOfBranches());
135 }
136}
137
138////////////////////////////////////////////////////////////////////////////////
139
140namespace {
141 bool CanSelfReference(TClass *cl) {
142 if (cl) {
143 if (cl->GetCollectionProxy()) {
144 TClass *inside = cl->GetCollectionProxy()->GetValueClass();
145 if (inside) {
146 return CanSelfReference(inside);
147 } else {
148 return false;
149 }
150 }
151 const static TClassRef stringClass("std::string");
152 if (cl == stringClass || cl == TString::Class()) {
153 return false;
154 }
155 // Here we could scan through the TStreamerInfo to see if there
156 // is any pointer anywhere and know whether this is a possibility
157 // of selfreference (but watch out for very indirect cases).
158 return true;
159 }
160 return false;
161 }
162}
163
164////////////////////////////////////////////////////////////////////////////////
165/// Default and I/O constructor.
166
168: TBranch()
169, fClassName()
170, fParentName()
171, fClonesName()
172, fCollProxy(nullptr)
173, fCheckSum(0)
174, fClassVersion(0)
175, fID(0)
176, fType(0)
177, fStreamerType(-1)
178, fMaximum(0)
179, fSTLtype(ROOT::kNotSTL)
180, fNdata(1)
181, fBranchCount(nullptr)
182, fBranchCount2(nullptr)
183, fInfo(nullptr)
184, fObject(nullptr)
185, fOnfileObject(nullptr)
186, fInit(false)
187, fInInitInfo(false)
188, fInitOffsets(false)
189, fTargetClass()
190, fCurrentClass()
191, fParentClass()
192, fBranchClass()
193, fClonesClass()
194, fBranchOffset(nullptr)
195, fBranchID(-1)
196, fReadActionSequence(nullptr)
197, fFillActionSequence(nullptr)
198, fIterators(nullptr)
199, fWriteIterators(nullptr)
200, fPtrIterators(nullptr)
201{
202 fNleaves = 0;
205}
206
207////////////////////////////////////////////////////////////////////////////////
208/// Constructor when the branch object is not a TClonesArray nor an STL container.
209///
210/// If splitlevel > 0 this branch in turn is split into sub-branches.
211
212TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
213: TBranch()
214, fClassName(sinfo->GetName())
215, fParentName()
216, fClonesName()
217, fCollProxy(nullptr)
218, fCheckSum(sinfo->GetCheckSum())
219, fClassVersion(sinfo->GetClass()->GetClassVersion())
220, fID(id)
221, fType(0)
222, fStreamerType(-1)
223, fMaximum(0)
224, fSTLtype(ROOT::kNotSTL)
225, fNdata(1)
226, fBranchCount(nullptr)
227, fBranchCount2(nullptr)
228, fInfo(sinfo)
229, fObject(nullptr)
230, fOnfileObject(nullptr)
231, fInit(true)
232, fInInitInfo(false)
233, fInitOffsets(false)
234, fTargetClass(fClassName)
235, fCurrentClass()
236, fParentClass()
237, fBranchClass(sinfo->GetClass())
238, fClonesClass()
239, fBranchOffset(nullptr)
240, fBranchID(-1)
241, fReadActionSequence(nullptr)
242, fFillActionSequence(nullptr)
243, fIterators(nullptr)
244, fWriteIterators(nullptr)
245, fPtrIterators(nullptr)
246{
247 if (tree) {
248 ROOT::TIOFeatures features = tree->GetIOFeatures();
250 }
251 Init(tree, nullptr, bname,sinfo,id,pointer,basketsize,splitlevel,btype);
252}
253
254////////////////////////////////////////////////////////////////////////////////
255/// Constructor when the branch object is not a TClonesArray nor an STL container.
256///
257/// If splitlevel > 0 this branch in turn is split into sub-branches.
258
259TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
260: TBranch()
261, fClassName(sinfo->GetName())
262, fParentName()
263, fClonesName()
264, fCollProxy(nullptr)
265, fCheckSum(sinfo->GetCheckSum())
266, fClassVersion(sinfo->GetClass()->GetClassVersion())
267, fID(id)
268, fType(0)
269, fStreamerType(-1)
270, fMaximum(0)
271, fSTLtype(ROOT::kNotSTL)
272, fNdata(1)
273, fBranchCount(nullptr)
274, fBranchCount2(nullptr)
275, fInfo(sinfo)
276, fObject(nullptr)
277, fOnfileObject(nullptr)
278, fInit(true)
279, fInInitInfo(false)
280, fInitOffsets(false)
281, fTargetClass( fClassName )
282, fCurrentClass()
283, fParentClass()
284, fBranchClass(sinfo->GetClass())
285, fClonesClass()
286, fBranchOffset(nullptr)
287, fBranchID(-1)
288, fReadActionSequence(nullptr)
289, fFillActionSequence(nullptr)
290, fIterators(nullptr)
291, fWriteIterators(nullptr)
292, fPtrIterators(nullptr)
293{
296 Init(parent ? parent->GetTree() : nullptr, parent, bname,sinfo,id,pointer,basketsize,splitlevel,btype);
297}
298
299////////////////////////////////////////////////////////////////////////////////
300/// Init when the branch object is not a TClonesArray nor an STL container.
301///
302/// If splitlevel > 0 this branch in turn is split into sub-branches.
303
304void 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)
305{
306 TString name(bname);
307
308 // Set our TNamed attributes.
309 SetName(name);
310 SetTitle(name);
311
312 // Set our TBranch attributes.
314 fTree = tree;
315 if (fTree == nullptr) return;
316 fMother = parent ? parent->GetMother() : this;
317 fParent = parent;
319 fFileName = "";
320
321 // Clear the bit kAutoDelete to specify that when reading
322 // the object should not be deleted before calling Streamer.
323
324 SetAutoDelete(false);
325
328
329 //---------------------------------------------------------------------------
330 // Handling the splitting of the STL collections of pointers
331 /////////////////////////////////////////////////////////////////////////////
332
335
336 fCompress = -1;
337 if (fTree->GetDirectory()) {
339 if (bfile) {
340 fCompress = bfile->GetCompressionSettings();
341 }
342 }
343
344 //
345 // Initialize streamer type and element.
346 //
347
348 if (id > -1) {
349 // We are *not* a top-level branch.
350 TStreamerElement* element = sinfo->GetElement(id);
351 fStreamerType = element->GetType();
352 }
353
354 //
355 // Handle varying-length datatypes by allocating an offsets array.
356 //
357 // The fBits part of a TObject is of varying length because the pidf
358 // is streamed only when the TObject is referenced by a TRef.
359 //
360
361 fEntryOffsetLen = 0;
364 }
365
366 //
367 // Make sure the basket is big enough to contain the
368 // entry offset array plus 100 bytes of data.
369 //
370
371 if (basketsize < (100 + fEntryOffsetLen)) {
373 }
375
376 //
377 // Allocate and initialize the basket control arrays.
378 //
379
383
384 for (Int_t i = 0; i < fMaxBaskets; ++i) {
385 fBasketBytes[i] = 0;
386 fBasketEntry[i] = 0;
387 fBasketSeek[i] = 0;
388 }
389
390 // We need to keep track of the counter branch if we have
391 // one, since we cannot set it until we have created our
392 // leaf, which we do last.
393 TBranchElement* brOfCounter = nullptr;
394
395 if (id < 0) {
396 // -- We are a top-level branch. Don't split a top-level branch, TTree::Bronch will do that work.
397 if (fBranchClass.GetClass()) {
398 bool hasCustomStreamer = false;
403 } else {
406 }
407 if (hasCustomStreamer) {
408 fType = -1;
409 }
410 }
411 } else {
412 // -- We are a sub-branch of a split object.
413 TStreamerElement* element = sinfo->GetElement(id);
415 // -- If we are an object data member which inherits from TObject,
416 // flag it so that later during i/o we will register the object
417 // with the buffer so that pointers are handled correctly.
421 } else {
423 }
424 }
425 }
426 if (element->IsA() == TStreamerBasicPointer::Class()) {
427 // -- Fixup title with counter if we are a varying length array data member.
430 countname = bname;
431 Ssiz_t dot = countname.Last('.');
432 if (dot>=0) {
433 countname.Remove(dot+1);
434 } else {
435 countname = "";
436 }
437 countname += bp->GetCountName();
439 countname.Form("%s[%s]",name.Data(),bp->GetCountName());
441
442 } else if (element->IsA() == TStreamerLoop::Class()) {
443 // -- Fixup title with counter if we are a varying length array data member.
444 TStreamerLoop *bp = static_cast<TStreamerLoop *>(element);
446 countname = bname;
447 Ssiz_t dot = countname.Last('.');
448 if (dot>=0) {
449 countname.Remove(dot+1);
450 } else {
451 countname = "";
452 }
453 countname += bp->GetCountName();
455 countname.Form("%s[%s]",name.Data(),bp->GetCountName());
457
458 }
459
460 if (splitlevel > 0) {
461 // -- Create sub branches if requested by splitlevel.
462 const char* elemType = element->GetTypeName();
463 TClass *elementClass = element->GetClassPointer();
464 fSTLtype = elementClass ? elementClass->GetCollectionType() : ROOT::kNotSTL;
465 if (element->CannotSplit()) {
466 fSplitLevel = 0;
467 } else if (element->IsA() == TStreamerBase::Class()) {
468 // -- We are a base class element.
469 // Note: This does not include an STL container class which is
470 // being used as a base class because the streamer element
471 // in that case is not the base streamer element it is the
472 // STL streamer element.
473 fType = 1;
474 TClass* clOfElement = element->GetClassPointer();
476 // Note: The following code results in base class branches
477 // having two different cases for what their parent
478 // class will be, this is very annoying. It is also
479 // very annoying that the naming conventions for the
480 // sub-branch names are different as well.
481 if (!strcmp(name, clOfElement->GetName())) {
482 // -- If the branch's name is the same as the base class name,
483 // which happens when we are a child branch of a top-level
484 // branch whose name does not end in a dot and also has no
485 // internal dots, elide the branch name, and keep the branch
486 // hierarchy rooted at the ultimate parent, this keeps the base
487 // class part of the branch name from propagating downwards.
488 // FIXME: We are eliding the base class here, creating a break in the branch hierarchy.
489 // Note: We can use parent class (cltop) != branch class (elemClass) to detection elision.
493 return;
494 }
495 // If the branch's name is not the same as the base class name,
496 // keep the branch name as a prefix (i.e., continue the branch
497 // hierarchy), but start a new class hierarchy at the base class.
498 //
499 // Note: If the parent branch was created by the branch constructor
500 // which takes a folder as a parameter, then this case will
501 // be used, because the branch name will be the same as the
502 // parent branch name.
503 // Note: This means that the sub-branches of a base class branch
504 // created by TTree::Bronch() have the base class name as
505 // as part of the branch name, while those created by
506 // Unroll() do not, ouch!!!
507 //
509 if (strchr(bname, '.')) {
510 // Note: How can this happen?
511 // Answer: This is the case when using the new branch
512 // naming convention where the top-level branch ends in dot.
513 // Note: Well actually not entirely, we could also be a sub-branch
514 // of a split class, even when the top-level branch does not
515 // end in a dot.
516 // Note: Or the top-level branch could have been created by the
517 // branch constructor which takes a folder as input, in which
518 // case the top-level branch name will have internal dots
519 // representing the folder hierarchy.
522 return;
523 }
525 // -- 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.
526 const auto bnamelen = strlen(bname);
527 if (bnamelen) {
528 name.Form("%s%s%s", bname, bname[bnamelen-1]=='.' ? "" : ".", clOfElement->GetName());
529 } else {
530 name.Form("%s", clOfElement->GetName());
531 }
532 SetName(name);
533 SetTitle(name);
534 }
537 return;
538 } else if (element->GetClassPointer() == TClonesArray::Class()) {
539 // -- We are a TClonesArray element.
540 bool ispointer = element->IsaPointer();
542 if (ispointer) {
543 char **ppointer = reinterpret_cast<char**>(pointer);
544 clones = reinterpret_cast<TClonesArray*>(*ppointer);
545 } else {
546 clones = reinterpret_cast<TClonesArray*>(pointer);
547 }
548 // basket->DeleteEntryOffset(); //entryoffset not required for the clonesarray counter
549 fEntryOffsetLen = 0;
550 // ===> Create a leafcount
552 fNleaves = 1;
554 fTree->GetListOfLeaves()->Add(leaf);
555 if (!clones) {
557 return;
558 }
559 TClass* clOfClones = clones->GetClass();
560 if (!clOfClones) {
563 return;
564 }
565 fType = 3;
566 // ===> create sub branches for each data member of a TClonesArray
567 //check that the contained objects class name is part of the element title
568 //This name is mandatory when reading the Tree later on and
569 //the parent class with the pointer to the TClonesArray is not available.
570 fClonesName = clOfClones->GetName();
573 aname.Form(" (%s)", clOfClones->GetName());
574 TString atitle = element->GetTitle();
575 if (!atitle.Contains(aname)) {
576 atitle += aname;
577 element->SetTitle(atitle.Data());
578 }
580 if (branchname.EndsWith("."))
581 branchname.Remove(branchname.Length()-1);
582 branchname += "_";
584 leaf->SetName(branchname);
585 leaf->SetTitle(branchname);
586 leaf->SetRange(true);
591 return;
593 // -- We are an STL container element.
595 fCollProxy = contCl->GetCollectionProxy()->Generate();
597 // Check to see if we can split the container.
598 bool cansplit = true;
599 if (!valueClass) {
600 cansplit = false;
601 } else if ((valueClass == TString::Class()) || (valueClass == TClass::GetClass("string"))) {
602 cansplit = false;
603 } else if (GetCollectionProxy()->HasPointers() && !splitSTLP ) {
604 cansplit = false;
605 } else if (!valueClass->CanSplit() && !(GetCollectionProxy()->HasPointers() && splitSTLP)) {
606 cansplit = false;
607 } else if (valueClass->GetCollectionProxy()) {
608 // -- A collection was stored in a collection, we choose not to split it.
609 // Note: Splitting it would require extending TTreeFormula
610 // to understand how to access it.
611 cansplit = false;
612 }
613 if (cansplit) {
614 // -- Do the splitting work if we are allowed to.
615 fType = 4;
616 // Create a leaf for the master branch (the counter).
618 fNleaves = 1;
620 fTree->GetListOfLeaves()->Add(leaf);
621 // Check that the contained objects class name is part of the element title.
622 // This name is mandatory when reading the tree later on and
623 // the parent class with the pointer to the STL container is not available.
624 fClonesName = valueClass->GetName();
627 aname.Form(" (%s)", valueClass->GetName());
628 TString atitle = element->GetTitle();
629 if (!atitle.Contains(aname)) {
630 atitle += aname;
631 element->SetTitle(atitle.Data());
632 }
634 if (branchname.EndsWith("."))
635 branchname.Remove(branchname.Length()-1);
636 branchname += "_";
638 leaf->SetName(branchname);
639 leaf->SetTitle(branchname);
640 leaf->SetRange(true);
641 // Create sub branches for each data member of an STL container.
646 return;
647 }
649 // -- Create sub-branches for members that are classes.
650 //
651 // Note: This can only happen if we were called directly
652 // (usually by TClass::Bronch) because Unroll never
653 // calls us for an element of this type.
654 fType = 2;
656 Int_t err = Unroll(name, clm, clm, pointer, basketsize, splitlevel+splitSTLP, 0);
657 if (err >= 0) {
658 // Return on success.
659 // FIXME: Why not on error too?
662 return;
663 }
664 }
665 }
666 }
667
668 //
669 // Create a leaf to represent this branch.
670 //
671
673 leaf->SetTitle(GetTitle());
674 fNleaves = 1;
676 fTree->GetListOfLeaves()->Add(leaf);
677
678 //
679 // If we have a counter branch set it now that we have
680 // created our leaf, we cannot do it before then.
681 //
682
683 if (brOfCounter) {
685 }
686
689}
690
691////////////////////////////////////////////////////////////////////////////////
692/// Constructor when the branch object is a TClonesArray.
693///
694/// If splitlevel > 0 this branch in turn is split into sub branches.
695
697: TBranch()
698, fClassName("TClonesArray")
699, fParentName()
700, fInfo(static_cast<TStreamerInfo*>(TClonesArray::Class()->GetStreamerInfo()))
701, fInit(true)
702, fInInitInfo(false)
703, fInitOffsets(false)
704, fTargetClass( fClassName )
705, fCurrentClass()
706, fParentClass()
707, fBranchClass(TClonesArray::Class())
708, fBranchID(-1)
709, fReadActionSequence(nullptr)
710, fFillActionSequence(nullptr)
711, fIterators(nullptr)
712, fWriteIterators(nullptr)
713, fPtrIterators(nullptr)
714{
715 Init(tree, nullptr, bname, clones, basketsize, splitlevel, compress);
716}
717
718////////////////////////////////////////////////////////////////////////////////
719/// Constructor when the branch object is a TClonesArray.
720///
721/// If splitlevel > 0 this branch in turn is split into sub branches.
722
724: TBranch()
725, fClassName("TClonesArray")
726, fParentName()
727, fInfo(static_cast<TStreamerInfo*>(TClonesArray::Class()->GetStreamerInfo()))
728, fInit(true)
729, fInInitInfo(false)
730, fInitOffsets(false)
731, fTargetClass( fClassName )
732, fCurrentClass()
733, fParentClass()
734, fBranchClass(TClonesArray::Class())
735, fBranchID(-1)
736, fReadActionSequence(nullptr)
737, fFillActionSequence(nullptr)
738, fIterators(nullptr)
739, fWriteIterators(nullptr)
740, fPtrIterators(nullptr)
741{
742 Init(parent ? parent->GetTree() : nullptr, parent, bname, clones, basketsize, splitlevel, compress);
743}
744
745////////////////////////////////////////////////////////////////////////////////
746/// Init when the branch object is a TClonesArray.
747///
748/// If splitlevel > 0 this branch in turn is split into sub branches.
749
751{
752 fCollProxy = nullptr;
754 fID = 0;
755 fInit = true;
756 fStreamerType = -1;
757 fType = 0;
758 fClassVersion = TClonesArray::Class()->GetClassVersion();
760 fBranchCount = nullptr;
761 fBranchCount2 = nullptr;
762 fObject = nullptr;
763 fOnfileObject = nullptr;
764 fMaximum = 0;
765 fBranchOffset = nullptr;
767 fInitOffsets = false;
768
769 fTree = tree;
770 fMother = parent ? parent->GetMother() : this;
771 fParent = parent;
773 fFileName = "";
774
775 SetName(bname);
776 const char* name = GetName();
777
778 SetTitle(name);
779 //fClassName = fInfo->GetName();
781 if (compress == -1 && fTree->GetDirectory()) {
783 if (bfile) fCompress = bfile->GetCompressionSettings();
784 }
785
786 if (basketsize < 100) basketsize = 100;
791
792 for (Int_t i=0;i<fMaxBaskets;i++) {
793 fBasketBytes[i] = 0;
794 fBasketEntry[i] = 0;
795 fBasketSeek[i] = 0;
796 }
797
798 // Reset the bit kAutoDelete to specify that when reading
799 // the object should not be deleted before calling the streamer.
800 SetAutoDelete(false);
801
802 // create sub branches if requested by splitlevel
804 TClass* clonesClass = clones->GetClass();
805 if (!clonesClass) {
806 Error("Init","Missing class object of the TClonesArray %s\n",clones->GetName());
807 return;
808 }
809 fType = 3;
810 // ===> Create a leafcount
812 fNleaves = 1;
814 fTree->GetListOfLeaves()->Add(leaf);
815 // ===> create sub branches for each data member of a TClonesArray
816 fClonesName = clonesClass->GetName();
819 if (branchname[branchname.Length()-1]=='.') {
820 branchname.Remove(branchname.Length()-1);
821 }
822 branchname += "_";
824 leaf->SetName(branchname);
825 leaf->SetTitle(branchname);
830 return;
831 }
832
833 if (!clones->GetClass() || CanSelfReference(clones->GetClass())) {
835 }
837 leaf->SetTitle(GetTitle());
838 fNleaves = 1;
840 fTree->GetListOfLeaves()->Add(leaf);
841
844}
845
846////////////////////////////////////////////////////////////////////////////////
847/// Constructor when the branch object is an STL collection.
848///
849/// If splitlevel > 0 this branch in turn is split into sub branches.
850
852: TBranch()
853, fClassName(cont->GetCollectionClass()->GetName())
854, fParentName()
855, fInit(true)
856, fInInitInfo(false)
857, fInitOffsets(false)
858, fTargetClass( fClassName )
859, fCurrentClass()
860, fParentClass()
861, fBranchClass(cont->GetCollectionClass())
862, fBranchID(-1)
863, fReadActionSequence(nullptr)
864, fFillActionSequence(nullptr)
865, fIterators(nullptr)
866, fWriteIterators(nullptr)
867, fPtrIterators(nullptr)
868{
869 Init(tree, nullptr, bname, cont, basketsize, splitlevel, compress);
870}
871
872////////////////////////////////////////////////////////////////////////////////
873/// Constructor when the branch object is an STL collection.
874///
875/// If splitlevel > 0 this branch in turn is split into sub branches.
876
878: TBranch()
879, fClassName(cont->GetCollectionClass()->GetName())
880, fParentName()
881, fInit(true)
882, fInInitInfo(false)
883, fInitOffsets(false)
884, fTargetClass( fClassName )
885, fCurrentClass()
886, fParentClass()
887, fBranchClass(cont->GetCollectionClass())
888, fBranchID(-1)
889, fReadActionSequence(nullptr)
890, fFillActionSequence(nullptr)
891, fIterators(nullptr)
892, fWriteIterators(nullptr)
893, fPtrIterators(nullptr)
894{
895 Init(parent ? parent->GetTree() : nullptr, parent, bname, cont, basketsize, splitlevel, compress);
896}
897
898////////////////////////////////////////////////////////////////////////////////
899/// Init when the branch object is an STL collection.
900///
901/// If splitlevel > 0 this branch in turn is split into sub branches.
902
904{
905 fCollProxy = cont->Generate();
906 TString name( bname );
907 if (name[name.Length()-1]=='.') {
908 name.Remove(name.Length()-1);
909 }
910 fInitOffsets = false;
912 fInfo = nullptr;
913 fID = -1;
914 fInit = true;
915 fStreamerType = -1; // TVirtualStreamerInfo::kSTLp;
916 fType = 0;
917 fClassVersion = cont->GetCollectionClass()->GetClassVersion();
918 fCheckSum = cont->GetCollectionClass()->GetCheckSum();
919 fBranchCount = nullptr;
920 fBranchCount2 = nullptr;
921 fObject = nullptr;
922 fOnfileObject = nullptr;
923 fMaximum = 0;
924 fBranchOffset = nullptr;
925
926 //Must be set here so that write actions will be properly matched to the ReadLeavesPtr
927 fSTLtype = cont->GetCollectionType();
928 if (fSTLtype < 0) {
930 }
931
932 fTree = tree;
933 fMother = parent ? parent->GetMother() : this;
934 fParent = parent;
936 fFileName = "";
937
938 SetName(name);
939 SetTitle(name);
940 //fClassName = fBranchClass.GetClass()->GetName();
942 if ((compress == -1) && fTree->GetDirectory()) {
944 if (bfile) {
945 fCompress = bfile->GetCompressionSettings();
946 }
947 }
948
949 if (basketsize < 100) {
950 basketsize = 100;
951 }
953
957
958 for (Int_t i = 0; i < fMaxBaskets; ++i) {
959 fBasketBytes[i] = 0;
960 fBasketEntry[i] = 0;
961 fBasketSeek[i] = 0;
962 }
963
964 // Reset the bit kAutoDelete to specify that, when reading,
965 // the object should not be deleted before calling the streamer.
966 SetAutoDelete(false);
967
968 // create sub branches if requested by splitlevel
970 (cont->HasPointers() && splitlevel > TTree::kSplitCollectionOfPointers && cont->GetValueClass() && cont->GetValueClass()->CanSplit() ) )
971 {
972 fType = 4;
973 // ===> Create a leafcount
975 fNleaves = 1;
977 fTree->GetListOfLeaves()->Add(leaf);
978 // ===> create sub branches for each data member of an STL container value class
979 TClass* valueClass = cont->GetValueClass();
980 if (!valueClass) {
981 return;
982 }
983 fClonesName = valueClass->GetName();
986 branchname += "_";
988 leaf->SetName(branchname);
989 leaf->SetTitle(branchname);
994 return;
995 }
996
998 leaf->SetTitle(GetTitle());
999 fNleaves = 1;
1000 fLeaves.Add(leaf);
1001 fTree->GetListOfLeaves()->Add(leaf);
1004}
1005
1006////////////////////////////////////////////////////////////////////////////////
1007/// Destructor.
1008
1010{
1011 // Release any allocated I/O buffers.
1013 delete fOnfileObject;
1014 fOnfileObject = nullptr;
1015 }
1016 ResetAddress();
1017
1018 delete[] fBranchOffset;
1019 fBranchOffset = nullptr;
1020
1021 fInfo = nullptr;
1022 fBranchCount2 = nullptr;
1023 fBranchCount = nullptr;
1024
1025 if (fType == 4 || fType == 0) {
1026 // Only the top level TBranchElement containing an STL container,
1027 // owns the collectionproxy.
1028 delete fCollProxy;
1029 }
1030 fCollProxy = nullptr;
1031
1032 delete fReadActionSequence;
1033 delete fFillActionSequence;
1034 delete fIterators;
1035 delete fWriteIterators;
1036 delete fPtrIterators;
1037}
1038
1039//
1040// This function is located here to allow inlining by the optimizer.
1041//
1042////////////////////////////////////////////////////////////////////////////////
1043/// Get streamer info for the branch class.
1044
1046{
1047 // Note: we need to find a way to reduce the complexity of
1048 // this often executed condition.
1049 if (!fInfo || (fInfo && (!fInit || !fInfo->IsCompiled()))) {
1050 const_cast<TBranchElement*>(this)->InitInfo();
1051 }
1052 return fInfo;
1053}
1054
1055////////////////////////////////////////////////////////////////////////////////
1056/// Get streamer info for the branch class.
1057
1059{
1060 return GetInfoImp();
1061}
1062
1063////////////////////////////////////////////////////////////////////////////////
1064/// Browse the branch content.
1065
1067{
1069 if (nbranches > 0) {
1071 TBranch* branch=nullptr;
1072 TIter iB(&fBranches);
1073 while((branch=static_cast<TBranch*>(iB()))) {
1074 if (branch->IsFolder()) persistentBranches.Add(branch);
1075 else {
1076 // only show branches corresponding to persistent members
1077 TClass* cl=nullptr;
1078 if (strlen(GetClonesName()))
1079 // this works both for top level branches and for sub-branches,
1080 // as GetClonesName() is properly updated for sub-branches
1081 cl=fClonesClass;
1082 else {
1084
1085 // check if we're in a sub-branch of this class
1086 // we can only find out asking the streamer given our ID
1087 TStreamerElement *element=nullptr;
1088 TClass* clsub=nullptr;
1089 auto info = (fID >= 0) ? GetInfoImp() : nullptr;
1090 if (info
1091 && info->IsCompiled()
1092 && ((element=info->GetElement(fID)))
1093 && ((clsub=element->GetClassPointer())))
1094 cl=clsub;
1095 }
1096 if (cl) {
1097 TString strMember=branch->GetName();
1098 Size_t mempos=strMember.Last('.');
1099 if (mempos!=kNPOS)
1100 strMember.Remove(0, (Int_t)mempos+1);
1101 mempos=strMember.First('[');
1102 if (mempos!=kNPOS)
1103 strMember.Remove((Int_t)mempos);
1105 if (!m || m->IsPersistent()) persistentBranches.Add(branch);
1106 } else persistentBranches.Add(branch);
1107 } // branch if not a folder
1108 }
1109 persistentBranches.Browse(b);
1110 // add all public const methods without params
1111 if (GetBrowsables() && GetBrowsables()->GetSize())
1112 GetBrowsables()->Browse(b);
1113 } else {
1114 if (GetBrowsables() && GetBrowsables()->GetSize()) {
1115 GetBrowsables()->Browse(b);
1116 return;
1117 }
1118 // Get the name and strip any extra brackets
1119 // in order to get the full arrays.
1120 TString slash("/");
1121 TString escapedSlash("\\/");
1122 TString name = GetName();
1123 Int_t pos = name.First('[');
1124 if (pos != kNPOS) {
1125 name.Remove(pos);
1126 }
1128 if (GetMother()) {
1130 pos = mothername.First('[');
1131 if (pos != kNPOS) {
1132 mothername.Remove(pos);
1133 }
1134 Int_t len = mothername.Length();
1135 if (len) {
1136 if (mothername(len-1) != '.') {
1137 // We do not know for sure whether the mother's name is
1138 // already preprended. So we need to check:
1139 // a) it is prepended
1140 // b) it is NOT the name of a daughter (i.e. mothername.mothername exist)
1142 doublename.Append(".");
1143 Int_t isthere = (name.Index(doublename) == 0);
1144 if (!isthere) {
1145 name.Prepend(doublename);
1146 } else {
1148 doublename.Append(mothername);
1149 isthere = (name.Index(doublename) == 0);
1150 if (!isthere) {
1151 mothername.Append(".");
1152 name.Prepend(mothername);
1153 }
1154 } else {
1155 // Nothing to do because the mother's name is
1156 // already in the name.
1157 }
1158 }
1159 } else {
1160 // If the mother's name end with a dot then
1161 // the daughter probably already contains the mother's name
1162 if (name.Index(mothername) == kNPOS) {
1163 name.Prepend(mothername);
1164 }
1165 }
1166 }
1167 }
1168 name.ReplaceAll(slash, escapedSlash);
1169 GetTree()->Draw(name, "", b ? b->GetDrawOption() : "");
1170 if (gPad) {
1171 gPad->Update();
1172 }
1173 }
1174}
1175
1176////////////////////////////////////////////////////////////////////////////////
1177/// Set branch and leaf name and title in the case of a container sub-branch.
1178
1180{
1182
1184
1186 if (indexname[indexname.Length()-1]=='.') {
1187 indexname.Remove(indexname.Length()-1);
1188 }
1189 indexname += "_";
1190
1191 for (Int_t i = 0; i < nbranches; ++i) {
1192 TBranchElement* bre = static_cast<TBranchElement*>(fBranches.At(i));
1193 if (!bre)
1194 continue;
1195 if (fType == 3) {
1196 bre->SetType(31);
1197 } else if (fType == 4) {
1198 bre->SetType(41);
1199 } else {
1200 Error("BuildTitle", "This cannot happen, fType of parent is not 3 or 4!");
1201 }
1202 bre->fCollProxy = GetCollectionProxy();
1203 bre->BuildTitle(name);
1204 const char* fin = strrchr(bre->GetTitle(), '.');
1205 if (fin == nullptr) {
1206 continue;
1207 }
1208 // The branch counter for a sub-branch of a container is the container master branch.
1209 bre->SetBranchCount(this);
1210 TLeafElement* lf = static_cast<TLeafElement*>(bre->GetListOfLeaves()->At(0));
1211 // If branch name is of the form fTracks.fCovar[3][4], then
1212 // set the title to fCovar[fTracks_].
1213 branchname = fin+1;
1214 Ssiz_t dim = branchname.First('[');
1215 if (dim>=0) {
1216 branchname.Remove(dim);
1217 }
1218 branchname += TString::Format("[%s]", indexname.Data());
1219 bre->SetTitle(branchname);
1220 if (lf) {
1221 lf->SetTitle(branchname);
1222 }
1223 // Is there a secondary branchcount?
1224 //
1225 // fBranchCount2 points to the secondary branchcount
1226 // in case a TClonesArray element itself has a branchcount.
1227 //
1228 // Example: In Event class with TClonesArray fTracks of Track objects.
1229 // if the Track object has two members
1230 // Int_t fNpoint;
1231 // Float_t *fPoints; //[fNpoint]
1232 // In this case the TBranchElement fTracks.fPoints has
1233 // -its primary branchcount pointing to the branch fTracks
1234 // -its secondary branchcount pointing to fTracks.fNpoint
1235 Int_t stype = bre->GetStreamerType();
1236 // FIXME: Should 60 be included here?
1237 if ((stype > 40) && (stype < 61)) {
1238 TString name2 (bre->GetName());
1239 Ssiz_t bn = name2.Last('.');
1240 if (bn<0) {
1241 continue;
1242 }
1243 TStreamerBasicPointer *el = dynamic_cast<TStreamerBasicPointer*>(bre->GetInfoImp()->GetElements()->FindObject(name2.Data()+bn+1));
1244 name2.Remove(bn+1);
1245 if (el) name2 += el->GetCountName();
1247 bre->SetBranchCount2(bc2);
1248 }
1249 bre->SetReadLeavesPtr();
1250 bre->SetFillLeavesPtr();
1251 }
1252}
1253
1254////////////////////////////////////////////////////////////////////////////////
1255/// Loop on all leaves of this branch to fill the basket buffer.
1256///
1257/// The function returns the number of bytes committed to the
1258/// individual branches. If a write error occurs, the number of
1259/// bytes returned is -1. If no data are written, because, e.g.,
1260/// the branch is disabled, the number of bytes returned is 0.
1261///
1262/// Note: We not not use any member functions from TLeafElement!
1263
1265{
1266 Int_t nbytes = 0;
1267 Int_t nwrite = 0;
1268 Int_t nerror = 0;
1270
1272
1273 //
1274 // If we are a top-level branch, update addresses.
1275 //
1276
1277 if (fID < 0) {
1278 if (!fObject) {
1279 Error("Fill", "attempt to fill branch %s while address is not set", GetName());
1280 return 0;
1281 }
1282 }
1283
1284 //
1285 // If the tree has a TRefTable, set the current branch if
1286 // branch is not a basic type.
1287 //
1288
1289 // FIXME: This test probably needs to be extended past 10.
1290 if ((fType >= -1) && (fType < 10)) {
1292 if (bref) {
1293 fBranchID = bref->SetParent(this, fBranchID);
1294 }
1295 }
1296
1297 if (!nbranches) {
1298 // No sub-branches.
1299 if (!TestBit(kDoNotProcess)) {
1301 if (nwrite < 0) {
1302 Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1303 ++nerror;
1304 } else {
1305 nbytes += nwrite;
1306 }
1307 }
1308 } else {
1309 // We have sub-branches.
1310 if (fType == 3 || fType == 4) {
1311 // TClonesArray or STL container counter
1313 if (nwrite < 0) {
1314 Error("Fill", "Failed filling branch:%s, nbytes=%d", GetName(), nwrite);
1315 ++nerror;
1316 } else {
1317 nbytes += nwrite;
1318 }
1319 } else {
1320 ++fEntries;
1321 }
1322 for (Int_t i = 0; i < nbranches; ++i) {
1323 TBranchElement* branch = static_cast<TBranchElement*>(fBranches[i]);
1324 if (!branch->TestBit(kDoNotProcess)) {
1325 nwrite = branch->FillImpl(imtHelper);
1326 if (nwrite < 0) {
1327 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d", GetName(), branch->GetName(), nwrite);
1328 nerror++;
1329 } else {
1330 nbytes += nwrite;
1331 }
1332 }
1333 }
1334 }
1335
1336 if (fTree->Debug() > 0) {
1337 // Debugging.
1339 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
1340 printf("Fill: %lld, branch=%s, nbytes=%d\n", entry, GetName(), nbytes);
1341 }
1342 }
1343
1344 if (nerror != 0) {
1345 return -1;
1346 }
1347
1348 return nbytes;
1349}
1350
1351////////////////////////////////////////////////////////////////////////////////
1352/// Write leaves into i/o buffers for this branch.
1353/// For the case where the branch is set in MakeClass mode (decomposed object).
1354
1356{
1358
1359 //
1360 // Silently do nothing if we have no user i/o buffer.
1361 //
1362
1363 if (!fObject) {
1364 return;
1365 }
1366
1367 // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1368 if(fType == 3) {
1369 // fClonesClass can not be zero since we are of type 3, see TBranchElement::Init
1371 if (!si) {
1372 Error("FillLeaves", "Cannot get streamer info for branch '%s' class '%s'", GetName(), fClonesClass->GetName());
1373 return;
1374 }
1375 b.ForceWriteInfo(si,false);
1376 Int_t* nptr = reinterpret_cast<Int_t*>(fAddress);
1377 b << *nptr;
1378 } else if (fType == 31) {
1379 // -- TClonesArray sub-branch. Write out the entries in the TClonesArray.
1380 // -- A MakeClass() tree, we must use fAddress instead of fObject.
1381 if (!fAddress) {
1382 // FIXME: Enable this message.
1383 //Error("FillLeaves", "Branch address not set for branch '%s'!", GetName());
1384 return;
1385 }
1387 if (atype > 54) {
1388 // Note: We are not supporting kObjectp, kAny, kObjectp,
1389 // kObjectP, kTString, kTObject, kTNamed, kAnyp,
1390 // kAnyP, kSTLp, kSTL, kSTLstring, kStreamer,
1391 // kStreamLoop here, nor pointers to varying length
1392 // arrays of them either.
1393 // Nor do we support pointers to varying length
1394 // arrays of kBits, kLong64, kULong64, nor kBool.
1395 return;
1396 }
1397 Int_t* nn = reinterpret_cast<Int_t*>(fBranchCount->GetAddress());
1398 if (!nn) {
1399 Error("FillLeaves", "The branch counter address was zero!");
1400 return;
1401 }
1402 Int_t n = *nn;
1403 if (atype > 40) {
1404 // Note: We are not supporting pointer to varying length array.
1405 Error("FillLeaves", "Clonesa: %s, n=%d, sorry not supported yet", GetName(), n);
1406 return;
1407 }
1408 if (atype > 20) {
1409 atype -= 20;
1410 TLeafElement* leaf = static_cast<TLeafElement*>(fLeaves.UncheckedAt(0));
1411 n = n * leaf->GetLenStatic();
1412 }
1413 switch (atype) {
1414 // Note: Type 0 is a base class and cannot happen here, see Unroll().
1415 case TVirtualStreamerInfo::kChar /* 1 */: { b.WriteFastArray(reinterpret_cast<Char_t*>(fAddress), n); break; }
1416 case TVirtualStreamerInfo::kShort /* 2 */: { b.WriteFastArray(reinterpret_cast<Short_t*>(fAddress), n); break; }
1417 case TVirtualStreamerInfo::kInt /* 3 */: { b.WriteFastArray(reinterpret_cast<Int_t*>(fAddress), n); break; }
1418 case TVirtualStreamerInfo::kLong /* 4 */: { b.WriteFastArray(reinterpret_cast<Long_t*>(fAddress), n); break; }
1419 case TVirtualStreamerInfo::kFloat /* 5 */: { b.WriteFastArray(reinterpret_cast<Float_t*>(fAddress), n); break; }
1420 case TVirtualStreamerInfo::kCounter /* 6 */: { b.WriteFastArray(reinterpret_cast<Int_t*>(fAddress), n); break; }
1421 // FIXME: We do nothing with type 7 (TVirtualStreamerInfo::kCharStar, char*) here!
1422 case TVirtualStreamerInfo::kDouble /* 8 */: { b.WriteFastArray(reinterpret_cast<Double_t*>(fAddress), n); break; }
1423 case TVirtualStreamerInfo::kDouble32 /* 9 */: {
1425 // coverity[returned_null] structurally si->fComp (used in GetElem) can not be null.
1426 TStreamerElement* se = si->GetElement(fID);
1427 Double_t* xx = reinterpret_cast<Double_t*>(fAddress);
1428 for (Int_t ii = 0; ii < n; ++ii) {
1429 b.WriteDouble32(&(xx[ii]),se);
1430 }
1431 break;
1432 }
1433 case TVirtualStreamerInfo::kFloat16 /* 19 */: {
1435 // coverity[dereference] structurally si can not be null.
1436 TStreamerElement* se = static_cast<TStreamerElement*>(si->GetElement(fID));
1437 Float_t* xx = reinterpret_cast<Float_t*>(fAddress);
1438 for (Int_t ii = 0; ii < n; ++ii) {
1439 b.WriteFloat16(&(xx[ii]),se);
1440 }
1441 break;
1442 }
1443 // Note: Type 10 is unused for now.
1444 case TVirtualStreamerInfo::kUChar /* 11 */: { b.WriteFastArray(reinterpret_cast<UChar_t*>(fAddress), n); break; }
1445 case TVirtualStreamerInfo::kUShort /* 12 */: { b.WriteFastArray(reinterpret_cast<UShort_t*>(fAddress), n); break; }
1446 case TVirtualStreamerInfo::kUInt /* 13 */: { b.WriteFastArray(reinterpret_cast<UInt_t*>(fAddress), n); break; }
1447 case TVirtualStreamerInfo::kULong /* 14 */: { b.WriteFastArray(reinterpret_cast<ULong_t*>(fAddress), n); break; }
1448 // FIXME: This is wrong!!! TVirtualStreamerInfo::kBits is a variable length type.
1449 case TVirtualStreamerInfo::kBits /* 15 */: { b.WriteFastArray(reinterpret_cast<UInt_t*>(fAddress), n); break; }
1450 case TVirtualStreamerInfo::kLong64 /* 16 */: { b.WriteFastArray(reinterpret_cast<Long64_t*>(fAddress), n); break; }
1451 case TVirtualStreamerInfo::kULong64 /* 17 */: { b.WriteFastArray(reinterpret_cast<ULong64_t*>(fAddress), n); break; }
1452 case TVirtualStreamerInfo::kBool /* 18 */: { b.WriteFastArray(reinterpret_cast<bool*>(fAddress), n); break; }
1453 }
1454 }
1455}
1456
1457////////////////////////////////////////////////////////////////////////////////
1458/// Write leaves into i/o buffers for this branch.
1459/// Case of a collection (fType == 4).
1460
1462{
1463 // -- STL container top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1465
1466 //
1467 // Silently do nothing if we have no user i/o buffer.
1468 //
1469
1470 if (!fObject) {
1471 return;
1472 }
1473
1475 Int_t n = 0;
1476 // We are in a block so the helper pops as soon as possible.
1478 n = proxy->Size();
1479
1480 if (n > fMaximum) {
1481 fMaximum = n;
1482 }
1483 b << n;
1484
1487 } else {
1488 //NOTE: this does not work for not vectors since the CreateIterators expects a TGenCollectionProxy::TStaging as its argument!
1489 //NOTE: and those not work in general yet, since the TStaging object is neither created nor passed.
1490 // We need to review how to avoid the need for a TStaging during the writing.
1493 } else {
1495 }
1496 }
1497
1498}
1499
1500////////////////////////////////////////////////////////////////////////////////
1501/// Write leaves into i/o buffers for this branch.
1502/// Case of a data member within a collection (fType == 41).
1503
1505{
1507
1508 //
1509 // Silently do nothing if we have no user i/o buffer.
1510 //
1511
1512 if (!fObject) {
1513 return;
1514 }
1515
1516 // FIXME: This wont work if a pointer to vector is split!
1518 // Note: We cannot pop the proxy here because we need it for the i/o.
1519 TStreamerInfo* si = static_cast<TStreamerInfo*>(GetInfoImp());
1520 if (!si) {
1521 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1522 return;
1523 }
1524
1526 R__ASSERT(nullptr!=iter);
1527 b.ApplySequenceVecPtr(*fFillActionSequence,iter->fBegin,iter->fEnd);
1528}
1529
1530////////////////////////////////////////////////////////////////////////////////
1531/// Write leaves into i/o buffers for this branch.
1532/// Case of a data member within a collection (fType == 41).
1533
1535{
1537
1538 //
1539 // Silently do nothing if we have no user i/o buffer.
1540 //
1541
1542 if (!fObject) {
1543 return;
1544 }
1545
1546 // FIXME: This wont work if a pointer to vector is split!
1548
1549 // Note: We cannot pop the proxy here because we need it for the i/o.
1550 TStreamerInfo* si = static_cast<TStreamerInfo*>(GetInfoImp());
1551 if (!si) {
1552 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1553 return;
1554 }
1555
1557 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1558
1559}
1560
1561////////////////////////////////////////////////////////////////////////////////
1562/// Write leaves into i/o buffers for this branch.
1563/// Case of a data member within a collection (fType == 41).
1564
1566{
1568
1569 //
1570 // Silently do nothing if we have no user i/o buffer.
1571 //
1572
1573 if (!fObject) {
1574 return;
1575 }
1576
1577 // FIXME: This wont work if a pointer to vector is split!
1579 // Note: We cannot pop the proxy here because we need it for the i/o.
1580 TStreamerInfo* si = static_cast<TStreamerInfo*>(GetInfoImp());
1581 if (!si) {
1582 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1583 return;
1584 }
1585
1587 R__ASSERT(nullptr!=iter);
1588 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1589
1590}
1591
1592////////////////////////////////////////////////////////////////////////////////
1593/// Write leaves into i/o buffers for this branch.
1594/// Case of a data member within a collection (fType == 41).
1595
1597{
1599
1600 //
1601 // Silently do nothing if we have no user i/o buffer.
1602 //
1603
1604 if (!fObject) {
1605 return;
1606 }
1607
1608 // FIXME: This wont work if a pointer to vector is split!
1610 // Note: We cannot pop the proxy here because we need it for the i/o.
1611 TStreamerInfo* si = static_cast<TStreamerInfo*>(GetInfoImp());
1612 if (!si) {
1613 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1614 return;
1615 }
1616
1618 R__ASSERT(nullptr!=iter);
1619 b.ApplySequence(*fFillActionSequence,iter->fBegin,iter->fEnd);
1620
1621}
1622
1623////////////////////////////////////////////////////////////////////////////////
1624/// Write leaves into i/o buffers for this branch.
1625/// Case of a TClonesArray (fType == 3).
1626
1628{
1629 // -- TClonesArray top-level branch. Write out number of entries, sub-branch writes the entries themselves.
1631
1632 //
1633 // Silently do nothing if we have no user i/o buffer.
1634 //
1635
1636 if (!fObject) {
1637 return;
1638 }
1639
1640 TClonesArray* clones = reinterpret_cast<TClonesArray*>(fObject);
1641 Int_t n = clones->GetEntriesFast();
1642 if (n > fMaximum) {
1643 fMaximum = n;
1644 }
1645 b << n;
1646}
1647
1648////////////////////////////////////////////////////////////////////////////////
1649/// Write leaves into i/o buffers for this branch.
1650/// Case of a data member within a TClonesArray (fType == 31).
1651
1653{
1655
1656 //
1657 // Silently do nothing if we have no user i/o buffer.
1658 //
1659
1660 if (!fObject) {
1661 return;
1662 }
1663
1664 TClonesArray* clones = reinterpret_cast<TClonesArray*>(fObject);
1665 Int_t n = clones->GetEntriesFast();
1666 TStreamerInfo* si = static_cast<TStreamerInfo*>(GetInfoImp());
1667 if (!si) {
1668 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1669 return;
1670 }
1671
1672 char **arr = reinterpret_cast<char **>(clones->GetObjectRef(nullptr));
1673 char **end = arr + n;
1674 b.ApplySequenceVecPtr(*fFillActionSequence,arr,end);
1675}
1676
1677////////////////////////////////////////////////////////////////////////////////
1678/// Write leaves into i/o buffers for this branch.
1679/// Case of a non TObject, non collection class with a custom streamer
1680
1682{
1684
1685 //
1686 // Silently do nothing if we have no user i/o buffer.
1687 //
1688
1689 if (!fObject) {
1690 return;
1691 }
1692
1693 //
1694 // Remember tobjects written to the buffer so that
1695 // pointers are handled correctly later.
1696
1697 if (TestBit(kBranchObject)) {
1698 b.MapObject(reinterpret_cast<TObject*>(fObject));
1699 } else if (TestBit(kBranchAny)) {
1700 b.MapObject(fObject, fBranchClass);
1701 }
1702
1704}
1705
1706////////////////////////////////////////////////////////////////////////////////
1707/// Write leaves into i/o buffers for this branch.
1708/// For split-class branch, base class branch, data member branch, or top-level branch.
1709/// which do have a branch count and are not a counter.
1710
1712{
1714 /*
1715 ValidateAddress();
1716
1717 //
1718 // Silently do nothing if we have no user i/o buffer.
1719 //
1720
1721 if (!fObject) {
1722 return;
1723 }
1724 */
1725}
1726
1727////////////////////////////////////////////////////////////////////////////////
1728/// Write leaves into i/o buffers for this branch.
1729/// For split-class branch, base class branch, data member branch, or top-level branch.
1730/// which do not have a branch count and are a counter.
1731
1733{
1735
1736 //
1737 // Silently do nothing if we have no user i/o buffer.
1738 //
1739
1740 if (!fObject) {
1741 return;
1742 }
1743 // -- Top-level, data member, base class, or split class branch.
1744 // 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.
1745 // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1746 // FIXME: What happens with a split base class branch,
1747 // or a split class branch???
1749 if (!si) {
1750 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1751 return;
1752 }
1753 // Since info is not null, fFillActionSequence is not null either.
1754 b.ApplySequence(*fFillActionSequence, fObject);
1755 // Int_t n = si->WriteBufferAux(b, &fObject, fID, 1, 0, 0);
1756
1757 Int_t n = *reinterpret_cast<Int_t*>(fObject + si->TStreamerInfo::GetElementOffset(fID)); // or GetInfoImp()->GetTypedValue<Int_t>(&fObject, fID, j, -1);
1758 if (n > fMaximum) {
1759 fMaximum = n;
1760 }
1761
1762}
1763
1764////////////////////////////////////////////////////////////////////////////////
1765/// Write leaves into i/o buffers for this branch.
1766/// For split-class branch, base class branch, data member branch, or top-level branch.
1767/// which do not have a branch count and are not a counter.
1768
1770{
1772
1773 //
1774 // Silently do nothing if we have no user i/o buffer.
1775 //
1776
1777 if (!fObject) {
1778 return;
1779 }
1780
1781 if (TestBit(kBranchObject)) {
1782 b.MapObject(reinterpret_cast<TObject*>(fObject));
1783 } else if (TestBit(kBranchAny)) {
1784 b.MapObject(fObject, fBranchClass);
1785 }
1786
1787 // -- Top-level, data member, base class, or split class branch.
1788 // 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.
1789 // Note: A split top-level branch (0, and fID == -2) should not happen here, see Fill().
1790 // FIXME: What happens with a split base class branch,
1791 // or a split class branch???
1793 if (!si) {
1794 Error("FillLeaves", "Cannot get streamer info for branch '%s'", GetName());
1795 return;
1796 }
1797 // Since info is not null, fFillActionSequence is not null either.
1798 b.ApplySequence(*fFillActionSequence, fObject);
1799
1800}
1801
1802////////////////////////////////////////////////////////////////////////////////
1803/// Remove trailing dimensions and make sure
1804/// there is a trailing dot.
1805
1806static void R__CleanName(std::string &name)
1807{
1808 if (name[name.length()-1]==']') {
1809 std::size_t dim = name.find_first_of('[');
1810 if (dim != std::string::npos) {
1811 name.erase(dim);
1812 }
1813 }
1814 if (name[name.size()-1] != '.') {
1815 name += '.';
1816 }
1817}
1818
1819////////////////////////////////////////////////////////////////////////////////
1820/// Find the immediate sub-branch with passed name.
1821
1823{
1824 // The default behavior of TBranch::FindBranch is sometimes
1825 // incorrect if this branch represent a base class, since
1826 // the base class name might or might not be in the name
1827 // of the sub-branches and might or might not be in the
1828 // name being passed.
1829
1830 if (fID >= 0) {
1832 TStreamerElement* se = si->GetElement(fID);
1833 if (se && se->IsBase()) {
1834 // We allow the user to pass only the last dotted component of the name.
1835 UInt_t len = strlen(name);
1836 std::string longnm;
1837 longnm.reserve(fName.Length()+len+3); // Enough space of fName + name + dots
1838 longnm = fName.Data();
1840 longnm += name;
1841 std::string longnm_parent;
1842 longnm_parent.reserve(fName.Length()+len+3);
1845 longnm_parent += name; // Name without the base class name
1846
1847 UInt_t namelen = strlen(name);
1848
1849 TBranch* branch = nullptr;
1851 for(Int_t i = 0; i < nbranches; ++i) {
1852 branch = static_cast<TBranch*>(fBranches.UncheckedAt(i));
1853
1854 const char *brname = branch->GetName();
1856 if (brname[brlen-1]==']') {
1857 const char *dim = strchr(brname,'[');
1858 if (dim) {
1859 brlen = dim - brname;
1860 }
1861 }
1862 if (namelen == brlen /* same effective size */
1863 && strncmp(name,brname,brlen) == 0) {
1864 return branch;
1865 }
1866 if (brlen == longnm.length()
1867 && strncmp(longnm.c_str(),brname,brlen) == 0) {
1868 return branch;
1869 }
1870 // This check is specific to base class
1871 if (brlen == longnm_parent.length()
1872 && strncmp(longnm_parent.c_str(),brname,brlen) == 0) {
1873 return branch;
1874 }
1875
1876 if (namelen>brlen && name[brlen]=='.' && strncmp(name,brname,brlen)==0) {
1877 // The prefix subbranch name match the branch name.
1878 return branch->FindBranch(name+brlen+1);
1879 }
1880 }
1881 }
1882 }
1884 if (!result) {
1885 // Look in base classes if any
1887 for(Int_t i = 0; i < nbranches; ++i) {
1888 TObject *obj = fBranches.UncheckedAt(i);
1889 if(obj->IsA() != TBranchElement :: Class() )
1890 continue;
1891 TBranchElement *br = static_cast<TBranchElement*>(obj);
1892 TVirtualStreamerInfo* si = br->GetInfoImp();
1893 if (si && br->GetID() >= 0) {
1894 TStreamerElement* se = si->GetElement(br->GetID());
1895 if (se && se->IsBase()) {
1896 result = br->FindBranch(name);
1897 }
1898 }
1899 }
1900 }
1901 return result;
1902}
1903
1904////////////////////////////////////////////////////////////////////////////////
1905/// Find the leaf corresponding to the name 'searchname'.
1906
1908{
1910
1911 if (leaf==nullptr && GetListOfLeaves()->GetEntries()==1) {
1912 TBranch *br = GetMother()->GetSubBranch( this );
1913 if( br->IsA() != TBranchElement::Class() )
1914 return nullptr;
1915
1916 TBranchElement *parent = static_cast<TBranchElement*>(br);
1917 if (parent==this || parent->GetID()<0 ) return nullptr;
1918
1919 TVirtualStreamerInfo* si = parent->GetInfoImp();
1920 TStreamerElement* se = si->GetElement(parent->GetID());
1921
1922 if (! se->IsBase() ) return nullptr;
1923
1924 br = GetMother()->GetSubBranch( parent );
1925 if( br->IsA() != TBranchElement::Class() )
1926 return nullptr;
1927
1928 TBranchElement *grand_parent = static_cast<TBranchElement*>(br);
1929
1930 std::string longname( grand_parent->GetName() );
1932 longname += name;
1933
1934 std::string leafname( GetListOfLeaves()->At(0)->GetName() );
1935
1936 if ( longname == leafname ) {
1937 return static_cast<TLeaf*>(GetListOfLeaves()->At(0));
1938 }
1939 }
1940 return leaf;
1941}
1942
1943////////////////////////////////////////////////////////////////////////////////
1944/// Get the branch address.
1945///
1946/// If we are *not* owned by a MakeClass() tree:
1947///
1948/// - If we are a top-level branch, return a pointer
1949/// - to the pointer to our object.
1950///
1951/// If we are *not* a top-level branch, return a pointer
1952/// to our object.
1953///
1954/// If we are owned by a MakeClass() tree:
1955///
1956/// - Return a pointer to our object.
1957
1959{
1961 return fAddress;
1962}
1963
1964
1965// For a mother branch of type 3 or 4, find the 'correct' StreamerInfo for the
1966// content of the collection by find a sub-branch corresponding to a direct data member
1967// of the containee class (valueClass)
1968// Default to the current StreamerInfo if none are found.
1970{
1972
1973 // Search for the correct version.
1975 if (!subbe->fInfo)
1976 subbe->SetupInfo();
1977 if (valueClass == subbe->fInfo->GetClass()) { // Use GetInfo to provoke its creation.
1978 localInfo = subbe->fInfo;
1979 break;
1980 }
1981 }
1982 if (!localInfo) {
1983 // This is likely sub-optimal as we really should call GetFile but it is non-const.
1984 auto file = fDirectory ? fDirectory->GetFile() : nullptr;
1985 if (file && file->GetSeekInfo()) {
1986 localInfo = static_cast<TStreamerInfo*>(file->GetStreamerInfoCache()->FindObject(valueClass->GetName()));
1987 if (localInfo) {
1988 if (valueClass->IsVersioned()) {
1989 localInfo = valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1990 } else {
1991 localInfo = valueClass->FindStreamerInfo(localInfo->GetCheckSum());
1992 if (localInfo) {
1993 // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
1994 localInfo = valueClass->GetStreamerInfo(localInfo->GetClassVersion());
1995 }
1996 }
1997 }
1998 }
1999 }
2000 if (!localInfo)
2001 localInfo = valueClass->GetStreamerInfo();
2002
2003 if (localInfo) {
2004 // See if we need any conversion.
2007 : nullptr;
2008 // For TClonesArray, the rest of the code probably does not support change in
2009 // value class, but if it does, we would have to look up the target value class
2010 // in the TClonesArray instance.
2011 // if (type == 3 && instance) targetValueClass = (reinterpret_cast<TClonesArray*>(instance))->GetClass();
2012
2013 if (targetValueClass && localInfo->GetClass() != targetValueClass) {
2014 localInfo = targetValueClass->GetConversionStreamerInfo(localInfo->GetClass(),
2015 localInfo->GetClassVersion());
2016 }
2017 }
2018 return static_cast<TStreamerInfo*>(localInfo);
2019}
2020
2021namespace {
2023 size_t ndata = info->GetNelement();
2024 for (size_t i =0; i < ndata; ++i) {
2025 TStreamerElement *nextel = info->GetElement(i);
2026
2027 if (nextel->GetType() == TStreamerInfo::kCacheDelete
2028 || nextel->GetType() == TStreamerInfo::kCacheNew) {
2029 continue;
2030 }
2031
2032 TString ename = prefix + nextel->GetName();
2033
2034 if (ename[0]=='*')
2035 ename.Remove(0,1);
2036
2037 Ssiz_t pos;
2038 while ((pos = ename.Last('[')) != TString::kNPOS) {
2039 ename = ename.Remove(pos);
2040 }
2041
2042 TBranchElement *be = static_cast<TBranchElement*>(branches.FindObject(ename));
2043 if (nextel->IsA() == TStreamerArtificial::Class()
2044 && be == nullptr) {
2045
2046 ids.push_back(i);
2047 ids.back().fElement = nextel;
2048 ids.back().fInfo = info;
2049 }
2050
2051 if (nextel->CannotSplit() || nextel->IsTransient() || nextel->GetOffset() == TStreamerInfo::kMissing)
2052 continue;
2053
2054 if (!be && nextel->IsBase()) {
2055 // We could be in the case of a branch created from a Folder or
2056 // a top level branch with a non-trailing dot in its name (case inadvertently confused with the folder case).
2057 // In those case, the name of the base class is *not* used to create the corresponding branch.
2058 TString subprefix(prefix);
2059 if (subprefix.Length() && subprefix[subprefix.Length()-1] == '.')
2060 subprefix.Remove(subprefix.Length()-1);
2061
2062 be = static_cast<TBranchElement*>(branches.FindObject(subprefix));
2063 if (be) {
2064 // There is at least 'one' base class branch all with the same name, so let's find the
2065 // right one.
2066 TClass *expectedClass = nullptr;
2068 if (0 != be->GetExpectedType(expectedClass,expectedType)
2069 || expectedClass != nextel->GetClassPointer())
2070 {
2071 be = nullptr;
2072 Int_t nbranches = branches.GetEntriesFast();
2073 for (Int_t bi = 0; bi < nbranches; ++bi) {
2074 TBranchElement* branch = static_cast<TBranchElement*>(branches[bi]);
2075 if (subprefix != branch->GetName())
2076 continue;
2077 if (0 == branch->GetExpectedType(expectedClass,expectedType)
2078 && expectedClass == nextel->GetClassPointer())
2079 {
2080 be = branch;
2081 break;
2082 }
2083 }
2084 } // else we have already found the right branch.
2085 }
2086 }
2087
2088 TClass *elementClass = nextel->GetClassPointer();
2089 if (elementClass && (!be || be->GetType() == -2)) {
2090 // Recurse on sub-objects.
2091 TStreamerInfo *nextinfo = nullptr;
2092
2093 // nextinfo_version = ....
2094 auto search = be ? be->GetListOfBranches() : &branches;
2095 TVirtualArray *onfileObject = nullptr;
2096
2098 if (prefix.Length() && nextel->IsA() == TStreamerBase::Class()) {
2099 // We skip the name of the base class if there is already a prefix.
2100 // See TBranchElement::Unroll
2101 subprefix = prefix;
2102 } else {
2103 subprefix = ename + ".";
2104 }
2105 auto nbranches = search->GetEntriesFast();
2106 bool foundRelatedSplit = false;
2107 for (Int_t bi = 0; bi < nbranches; ++bi) {
2108 TBranchElement* subbe = static_cast<TBranchElement*>(search->At(bi));
2109 bool matchSubPrefix = strncmp(subbe->GetFullName(), subprefix.Data(), subprefix.Length()) == 0;
2110 if (!foundRelatedSplit)
2112 if (elementClass == subbe->GetInfo()->GetClass() // Use GetInfo to provoke its creation.
2113 && subbe->GetOnfileObject()
2114 && matchSubPrefix)
2115 {
2116 nextinfo = subbe->GetInfo();
2117 onfileObject = subbe->GetOnfileObject();
2118 break;
2119 }
2120 }
2121
2122 if (!foundRelatedSplit) {
2123 continue;
2124 }
2125
2126 if (!nextinfo) {
2127 nextinfo = static_cast<TStreamerInfo *>(elementClass->GetStreamerInfo());
2128 if (elementClass->GetCollectionProxy() && elementClass->GetCollectionProxy()->GetValueClass()) {
2129 nextinfo = static_cast<TStreamerInfo *>(elementClass->GetCollectionProxy()->GetValueClass()->GetStreamerInfo()); // NOTE: need to find the right version
2130 }
2131 }
2132 ids.emplace_back(nextinfo, offset + nextel->GetOffset());
2133 if (!onfileObject && nextinfo && nextinfo->GetNelement() && nextinfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew) {
2134 onfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), 1 /* is that always right? */ );
2135 ids.back().fNestedIDs->fOwnOnfileObject = true;
2136 }
2137 ids.back().fNestedIDs->fOnfileObject = onfileObject;
2138 GatherArtificialElements(branches, ids.back().fNestedIDs->fIDs, subprefix, nextinfo, offset + nextel->GetOffset());
2139 if (ids.back().fNestedIDs->fIDs.empty())
2140 ids.pop_back();
2141 }
2142 }
2143};
2144} // Anonymous namespace.
2145
2146
2147////////////////////////////////////////////////////////////////////////////////
2148/// Set the value of fInfo. This is part one of InitInfo.
2149/// To be used as:
2150/// if (!fInfo)
2151/// SetupInfo();
2152/// It would only be used within InitInfo (and its callees)
2153
2155{
2156 // We did not already have streamer info, so now we must find it.
2158
2159 //------------------------------------------------------------------------
2160 // Check if we're dealing with the name change
2161 //////////////////////////////////////////////////////////////////////////
2162
2163 TClass* targetClass = nullptr;
2164 if( fTargetClass.GetClassName()[0] ) {
2166 if (!targetClass && GetCollectionProxy()) {
2167 // We are in the case where the branch holds a custom collection
2168 // proxy but the dictionary is not loaded, calling
2169 // GetCollectionProxy had the side effect of creating the TClass
2170 // corresponding to this emulated collection.
2172 }
2173 if ( !targetClass ) {
2174 Error("InitInfo", "Branch '%s': missing dictionary for target class '%s'!",
2176 return;
2177 }
2178 } else {
2179 targetClass = cl;
2180 }
2181 if (cl) {
2182 //---------------------------------------------------------------------
2183 // Get the streamer info for given version
2184 ///////////////////////////////////////////////////////////////////////
2185
2186 {
2187 if ( (cl->Property() & kIsAbstract) && cl == targetClass) {
2188 TBranchElement *parent = static_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
2189 if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
2190 // Our parent's class is emulated and we represent an abstract class.
2191 // and the target class has not been set explicitly.
2192 TString target = cl->GetName();
2193 target += "@@emulated";
2195
2196 if (!fTargetClass) {
2198 }
2200 }
2201 }
2202 if( targetClass != cl ) {
2203 fInfo = static_cast<TStreamerInfo*>(targetClass->GetConversionStreamerInfo( cl, fClassVersion ));
2204 } else {
2205 fInfo = static_cast<TStreamerInfo*>(cl->GetStreamerInfo(fClassVersion));
2206 }
2207 }
2208
2209 // FIXME: Check that the found streamer info checksum matches our branch class checksum here.
2210 // Check to see if the class code was unloaded/reloaded
2211 // since we were created.
2213 if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != static_cast<TVirtualStreamerInfo*>(cl->GetStreamerInfos()->At(1))->GetCheckSum())))) {
2214 // Try to compensate for a class that got unloaded on us.
2215 // Search through the streamer infos by checksum
2216 // and take the first match.
2217
2219 if( targetClass != cl )
2220 info = static_cast<TStreamerInfo*>(targetClass->FindConversionStreamerInfo( cl, fCheckSum ));
2221 else {
2222 info = static_cast<TStreamerInfo*>(cl->FindStreamerInfo( fCheckSum ));
2223 if (info) {
2224 // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
2225 info = static_cast<TStreamerInfo*>(cl->GetStreamerInfo(info->GetClassVersion()));
2226 }
2227 }
2228 if( info ) {
2229 fInfo = info;
2230 // We no longer reset the class version so that in case the user is passing us later
2231 // the address of a class that require (another) Conversion we can find the proper
2232 // StreamerInfo.
2233 // fClassVersion = fInfo->GetClassVersion();
2234 }
2235 }
2236 }
2237}
2238
2239
2240////////////////////////////////////////////////////////////////////////////////
2241/// Init the streamer info for the branch class, try to compensate for class
2242/// code unload/reload and schema evolution.
2243
2245{
2246 if (!fInfo)
2247 SetupInfo();
2248
2249 //
2250 // Fixup cached streamer info if necessary.
2251 //
2252 // FIXME: What if the class code was unloaded/reloaded since we were cached?
2253
2254 if (fInfo) {
2255
2256 if (!fInfo->IsCompiled()) {
2257 // Streamer info has not yet been compiled.
2258
2259 Error("InitInfo","StreamerInfo is not compiled.");
2260 }
2261 // return immediately if we are called recursively.
2262 if (fInInitInfo)
2263 return;
2264 fInInitInfo = true;
2265 if (!fInit) {
2266 // We were read in from a file, figure out what our fID should be,
2267 // schema evolution must be considered.
2268 //
2269 // Force our fID to be the id of the first streamer element that matches our name.
2270 //
2271 auto SetOnfileObject = [this](TStreamerInfo *info) {
2272 Int_t arrlen = 1;
2273 if (fType==31 || fType==41) {
2274 TLeaf *leaf = static_cast<TLeaf*>(fLeaves.At(0));
2275 if (leaf) {
2276 arrlen = leaf->GetMaximum();
2277 }
2278 }
2279 bool toplevel = (fType == 3 || fType == 4 || (fType == 0 && fID == -2));
2280 bool seenExisting = false;
2281
2282 fOnfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), arrlen );
2283 // Propagate this to all the other branches belonging to the same object.
2285 Int_t nbranches = branches->GetEntriesFast();
2286 TBranchElement *lastbranch = this;
2287
2290 if (toplevel) {
2291 // Note: Fragile/wrong when using conversion StreamerInfo?
2292 currentClass = info->GetClass();
2293 currentVersion = info->GetClassVersion();
2294 }
2295
2296 // First find the first branch corresponding to the same class as 'this'
2297 // branch
2298 Int_t index = branches->IndexOf(this);
2299 Int_t firstindex = 0;
2301 if (index >= 0) {
2302 TString fullname( GetFullName() );
2303 Ssiz_t lastdot = fullname.Last('.');
2304 if (lastdot == TString::kNPOS) {
2305 // No prefix or index, thus this is a first level branch
2306 TBranchElement* subbranch = static_cast<TBranchElement*>(branches->At(0));
2307 if (!subbranch->fInfo)
2308 subbranch->SetupInfo();
2309 } else {
2310 TString &thisprefix = fullname.Remove(lastdot + 1); // Mod fullname and 'rename' the variable.
2311 for(Int_t i = index - 1; i >= 0; --i) {
2312 TBranchElement* subbranch = static_cast<TBranchElement*>(branches->At(i));
2313 TString subbranch_name(subbranch->GetFullName());
2314 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2315 // We moved to another data member (of the enclosing class)
2316 firstindex = i + 1;
2317 break;
2318 }
2319 if (!subbranch->fInfo)
2320 subbranch->SetupInfo();
2321 }
2322 for(Int_t i = index; i < nbranches; ++i) {
2323 TBranchElement* subbranch = static_cast<TBranchElement*>(branches->At(i));
2324 TString subbranch_name(subbranch->GetFullName());
2325 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2326 lastindex = i - 1;
2327 break;
2328 }
2329 }
2330 }
2331 } else {
2332 // Case of a top level branch or 'empty node' (object marker for split sub-object)
2333 TString fullname( GetFullName() );
2334 Ssiz_t lastdot = fullname.Last('.');
2335 if (lastdot != TString::kNPOS) {
2336 TString &thisprefix = fullname.Remove(lastdot + 1); // Mod fullname and 'rename' the variable.
2337 for(Int_t i = 0; i < nbranches; ++i) {
2338 TBranchElement* subbranch = static_cast<TBranchElement*>(branches->At(i));
2339 TString subbranch_name(subbranch->GetFullName());
2340 if ( ! subbranch_name.BeginsWith(thisprefix)) {
2341 lastindex = i - 1;
2342 break;
2343 }
2344 }
2345 }
2346 }
2347 for (Int_t i = firstindex; i <= lastindex; ++i) {
2348 TBranchElement* subbranch = static_cast<TBranchElement*>(branches->At(i));
2349 bool match = false;
2350 if (this != subbranch) {
2351
2352 if (!subbranch->fInfo)
2353 subbranch->SetupInfo();
2354
2355 // We previously checked for subbranch->fInfo == info. However, this fails for split collections
2356 // where the value class was renamed. Eventually, the subbranch will get its target class properly
2357 // set and use the conversion streamer info. However, we hit the current code path from the collection
2358 // parent's TBranchElement::SetAddressImpl() _before_ we fix up the target class of the child branch.
2359 // So the previous call to subbranch->SetupInfo() doesn't return the conversion streamer info but
2360 // streamer info of the old class.
2361 if (strcmp(subbranch->fInfo->GetName(), info->GetName()) == 0 &&
2362 subbranch->fInfo->GetClassVersion() == info->GetClassVersion()) {
2363 match = true;
2364 } else if (subbranch->fInfo == nullptr && subbranch->fBranchClass == currentClass) {
2365 if (!toplevel) {
2366 if (subbranch->fCheckSum == fCheckSum)
2367 match = true;
2368 } else {
2369 if (!subbranch->fBranchClass->IsForeign() && subbranch->fClassVersion == currentVersion)
2370 match = true;
2371 else if (subbranch->fCheckSum == info->GetCheckSum()) {
2372 match = true;
2373 }
2374 }
2375 }
2376 }
2377 if (match) {
2378 if (subbranch->fOnfileObject && subbranch->fOnfileObject != fOnfileObject) {
2379 if (seenExisting) {
2380 Error("SetOnfileObject (lambda)", "2 distincts fOnfileObject are in the hierarchy of %s for type %s",
2381 toplevel ? GetName() : GetMother()->GetSubBranch(this)->GetName(), info->GetName());
2382 } else {
2383 delete fOnfileObject;
2384 fOnfileObject = subbranch->fOnfileObject;
2385 seenExisting = true;
2386 }
2387 }
2388 subbranch->fOnfileObject = fOnfileObject;
2390 }
2391 }
2392 if (toplevel) {
2394 if (lastbranch != this)
2395 lastbranch->ResetBit(kOwnOnfileObj);
2396 } else {
2397 lastbranch->SetBit(kOwnOnfileObj);
2398 }
2399 };
2400 if (GetID() > -1) {
2401 // We are *not* a top-level branch.
2402 std::string s(GetName());
2403 size_t pos = s.rfind('.');
2404 if (pos != std::string::npos) {
2405 s = s.substr(pos+1);
2406 }
2407 while ((pos = s.rfind('[')) != std::string::npos) {
2408 s = s.substr(0, pos);
2409 }
2410 int offset = 0;
2413 size_t ndata = fInfo->GetNelement();
2414 fNewIDs.clear();
2415 for (size_t i = 0; i < ndata; ++i) {
2416 if (fInfo->GetElement(i) == elt) {
2417 if (elt->TestBit (TStreamerElement::kCache)
2418 && (i+1) < ndata
2419 && s == fInfo->GetElement(i)->GetName())
2420 {
2421 // If the TStreamerElement we found is storing the information in the
2422 // cache and is a repeater, we need to use the real one (the next one).
2423 // (At least until the cache/repeat mechanism is properly handle by
2424 // ReadLeaves).
2425 // fID = i+1;
2426 fID = i;
2427 if (fType != 2) {
2428 if (elt->TestBit(TStreamerElement::kRepeat)) {
2429 fNewIDs.push_back(fID+1);
2430 fNewIDs.back().fElement = fInfo->GetElement(i+1);
2431 fNewIDs.back().fInfo = fInfo;
2432 } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) {
2433 fNewIDs.push_back(fID+1);
2434 fNewIDs.back().fElement = fInfo->GetElement(i+1);
2435 fNewIDs.back().fInfo = fInfo;
2436 }
2437 }
2438 } else {
2439 fID = i;
2440 }
2441 if (elt->TestBit (TStreamerElement::kCache)) {
2443 }
2444 break;
2445 }
2446 }
2447 for (size_t i = fID+1+(fNewIDs.size()); i < ndata; ++i) {
2449
2450 std::string ename = nextel->GetName();
2451 if (ename[0] == '*')
2452 ename = ename.substr(1);
2453
2454 while ((pos = ename.rfind('[')) != std::string::npos) {
2455 ename = ename.substr(0, pos);
2456 }
2457
2458 if (s != ename) {
2459 // We moved on to the next set
2460 break;
2461 }
2462 // Add all (and only) the Artificial Elements that follows this StreamerInfo.
2463 // fprintf(stderr,"%s/%d[%zu] passing through %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2464 if (fType==31||fType==41) {
2465 // The nested objects are unfolded and their branch can not be used to
2466 // execute StreamerElements of this StreamerInfo.
2467 if ((nextel->GetType() == TStreamerInfo::kObject
2468 || nextel->GetType() == TStreamerInfo::kAny)
2469 && nextel->GetClassPointer()->CanSplit())
2470 {
2471 continue;
2472 }
2473 }
2474 if (nextel->GetOffset() == TStreamerInfo::kMissing) {
2475 // This element will be 'skipped', it's TBranchElement's fObject will null
2476 // and thus can not be used to execute the artificial StreamerElements
2477 continue;
2478 }
2479 if (nextel->IsA() != TStreamerArtificial::Class()
2480 || nextel->GetType() == TStreamerInfo::kCacheDelete ) {
2481 continue;
2482 }
2483 // NOTE: We should verify that the rule's source are 'before'
2484 // or 'at' this branch.
2485 // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
2486 fNewIDs.push_back(i);
2487 fNewIDs.back().fElement = nextel;
2488 fNewIDs.back().fInfo = fInfo;
2489 }
2490 } else if (elt && offset==TStreamerInfo::kMissing) {
2491 // Still re-assign fID properly.
2492 fNewIDs.clear();
2493 size_t ndata = fInfo->GetNelement();
2494 for (size_t i = 0; i < ndata; ++i) {
2495 if (fInfo->GetElement(i) == elt) {
2496 fID = i;
2497 break;
2498 }
2499 }
2500 } else {
2501 // We have not even found the element .. this is strange :(
2502 // fNewIDs.clear();
2503 // fID = -3;
2504 // SetBit(kDoNotProcess);
2505 }
2506 if (fOnfileObject==nullptr && (fType==31 || fType==41 || (0 <= fType && fType <=2) ) && fInfo->GetNelement()
2508 {
2510 }
2511 }
2512 if (fType == 3 || fType == 4 || (fType == 0 && fID == -2) || fType == 2) {
2513 // Need to add the rule targeting transient members.
2515 if (fType == 3 || fType == 4) {
2516 // Don't we have real version information?
2517 // Not unless there is a subbranch with a non-split element of the class.
2518 // Search for the correct version.
2520 }
2521
2522 TString prefix(GetFullName());
2523 if (fType == 2 && fID >= 0) {
2524 auto start = prefix.Length();
2525 if (prefix[start - 1] == '.')
2526 --start;
2527 std::string_view view(prefix.Data(), start);
2528 auto cutoff = view.find_last_of('.');
2529 if (cutoff != std::string::npos) {
2530 prefix.Remove(cutoff + 1);
2531 }
2532 }
2533 if (prefix[prefix.Length()-1] != '.') {
2534 if (fType == 3 || fType == 4 || prefix.Index('.') != TString::kNPOS) {
2535 prefix += ".";
2536 } else {
2537 prefix = "";
2538 }
2539 }
2540 fNewIDs.clear();
2541
2543
2544 if (!fNewIDs.empty() && fOnfileObject == nullptr && localInfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew)
2545 {
2547 }
2548
2549 }
2550 fInit = true;
2551
2552 // Get the action sequence we need to copy for reading.
2555 } else if (!fReadActionSequence) {
2556 // Get the action sequence we need to copy for reading.
2559 }
2562 fInInitInfo = false;
2563 }
2564}
2565
2566////////////////////////////////////////////////////////////////////////////////
2567/// Return the collection proxy describing the branch content, if any.
2568
2570{
2571 if (fCollProxy) {
2572 return fCollProxy;
2573 }
2574 TBranchElement* thiscast = const_cast<TBranchElement*>(this);
2575 if (fType == 4) {
2576 // STL container top-level branch.
2577 const char* className = nullptr;
2578 TClass* cl = nullptr;
2579 if (fID < 0) {
2580 // We are a top-level branch.
2581 if (fBranchClass.GetClass()) {
2582 cl = fBranchClass.GetClass();
2583 }
2584 } else {
2585 // We are not a top-level branch.
2586 TVirtualStreamerInfo* si = thiscast->GetInfoImp();
2587 if (fCollProxy) {
2588 // The GetInfo set fProxy for us, let's not
2589 // redo it; the value of fCollProxy is possibly
2590 // used/recorded is the actions sequences, so
2591 // if we change it here, we would need to propagate
2592 // the change.
2593 return fCollProxy;
2594 }
2595 TStreamerElement* se = si->GetElement(fID);
2596 cl = se->GetClassPointer();
2597 }
2598 if (!cl) {
2599 // The TClass was not created but we do know (since it
2600 // is used as a collection) that it 'className' was a
2601 // class, so let's create it by hand!.
2602
2603 if (fID < 0) {
2605 className = cl->GetName();
2606 } else {
2607 cl = new TClass(className, fClassVersion);
2608 className = cl->GetName();
2609 }
2610 }
2612 if (!proxy) {
2613 // humm, we must have an older file with a custom collection
2614 // let's try to work-around it.
2615 TString equiv;
2616 equiv.Form("vector<%s>",fClonesName.Data());
2618 proxy = clequiv->GetCollectionProxy();
2619 if (!proxy) {
2620 Fatal("GetCollectionProxy",
2621 "Can not create a Collection Proxy of any kind for the class \"%s\" needed by the branch \"%s\" of the TTree \"%s\"!",
2622 className, GetName(), GetTree()->GetName());
2623 }
2624 if (gDebug > 0) Info("GetCollectionProxy",
2625 "Fixing the collection proxy of the class \"%s\" \n"
2626 "\tneeded by the branch \"%s\" of the TTree \"%s\" to be similar to \"%s\".",
2627 className, GetName(), GetTree()->GetName(),equiv.Data());
2628 cl->CopyCollectionProxy( *proxy );
2629 }
2630 fCollProxy = proxy->Generate();
2631 fSTLtype = proxy->GetCollectionType();
2632 } else if (fType == 41) {
2633 // STL container sub-branch.
2634 thiscast->fCollProxy = fBranchCount->GetCollectionProxy();
2635 }
2636 return fCollProxy;
2637}
2638
2639////////////////////////////////////////////////////////////////////////////////
2640/// Return a pointer to the current type of the data member corresponding to branch element.
2641
2643{
2644 TClass* cl = fCurrentClass;
2645 if (cl) {
2646 return cl;
2647 }
2648
2649 TStreamerInfo* brInfo = static_cast<TStreamerInfo*>(GetInfoImp());
2650 if (!brInfo) {
2652 R__ASSERT(cl && cl->GetCollectionProxy());
2653 fCurrentClass = cl;
2654 return cl;
2655 }
2656 TClass* motherCl = brInfo->GetClass();
2657 if (motherCl->GetCollectionProxy()) {
2658 cl = motherCl->GetCollectionProxy()->GetCollectionClass();
2659 if (cl) {
2660 fCurrentClass = cl;
2661 }
2662 return cl;
2663 }
2664 if (GetID() < 0 || GetID()>=brInfo->GetNelement()) {
2665 return nullptr;
2666 }
2668 TDataMember* dm = static_cast<TDataMember*>(motherCl->GetListOfDataMembers()->FindObject(currentStreamerElement->GetName()));
2669
2671 if (!dm) {
2672 // Either the class is not loaded or the data member is gone
2673 if (!motherCl->IsLoaded()) {
2674 TVirtualStreamerInfo* newInfo = motherCl->GetStreamerInfo();
2675 if (newInfo != brInfo) {
2676 TStreamerElement* newElems = static_cast<TStreamerElement*>(newInfo->GetElements()->FindObject(currentStreamerElement->GetName()));
2677 if (newElems) {
2678 if (newElems->GetClassPointer())
2679 newType = newElems->GetClassPointer()->GetName();
2680 else
2681 newType = newElems->GetTypeName();
2682 }
2683 }
2684 if (newType.Length()==0) {
2685 if (currentStreamerElement->GetClassPointer())
2686 newType = currentStreamerElement->GetClassPointer()->GetName();
2687 else
2688 newType = currentStreamerElement->GetTypeName();
2689 }
2690 }
2691 } else {
2692 newType = dm->GetTypeName();
2693 }
2695 if (cl) {
2696 fCurrentClass = cl;
2697 }
2698 return cl;
2699}
2700
2701////////////////////////////////////////////////////////////////////////////////
2702/// Read all branches of a BranchElement and return total number of bytes.
2703///
2704/// - If entry = 0, then use current entry number + 1.
2705/// - If entry < 0, then reset entry number to 0.
2706///
2707/// Returns the number of bytes read from the input buffer.
2708/// - If entry does not exist, then returns 0.
2709/// - If an I/O error occurs, then returns -1.
2710///
2711/// See IMPORTANT REMARKS in TTree::GetEntry.
2712
2714{
2715 // Remember which entry we are reading.
2716 auto prevEntry = fReadEntry;
2717 fReadEntry = entry;
2718
2719 // If our tree has a branch ref, make it remember the entry and
2720 // this branch. This allows a TRef::GetObject() call done during
2721 // the following I/O operation, for example in a custom streamer,
2722 // to search for the referenced object in the proper element of the
2723 // proper branch.
2725 if (R__unlikely(bref)) {
2726 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2727 fBranchID = bref->SetParent(this, fBranchID);
2728 bref->SetRequestedEntry(entry);
2729 }
2730
2731 Int_t nbytes = 0;
2732
2733 if (R__unlikely(IsAutoDelete())) {
2736 } else {
2738 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2740 }
2741 }
2742
2744 if (nbranches) {
2745 // -- Branch has daughters.
2746 // One must always read the branch counter.
2747 // In the case when one reads consecutively twice the same entry,
2748 // the user may have cleared the TClonesArray between the GetEntry calls.
2749 if ((fType == 3) || (fType == 4)) {
2751 if (nb < 0) {
2752 return nb;
2753 }
2754 nbytes += nb;
2755 }
2757 ValidateAddress(); // There is no ReadLeave for the node of a top level split object, so we need to do the
2758 // validation here.
2759 for (Int_t i = 0; i < nbranches; ++i) {
2760 TBranch* branch = static_cast<TBranch*>(fBranches.UncheckedAt(i));
2761 Int_t nb = branch->GetEntry(entry, getall);
2762 if (nb < 0) {
2763 return nb;
2764 }
2765 nbytes += nb;
2766 }
2767 }
2769 if (fType == 3) {
2770 // Apply the unattached rules; by definition they do not need any
2771 // input from a buffer.
2773
2774 auto ndata = GetNdata();
2775
2776 TClonesArray* clones = reinterpret_cast<TClonesArray*>(fObject);
2777 if (clones->IsZombie()) {
2778 return -1;
2779 }
2780 R__PushCache onfileObject(b, fOnfileObject, ndata);
2781
2782 char **arr = reinterpret_cast<char **>(clones->GetObjectRef());
2783 char **end = arr + fNdata;
2784
2785 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
2786 } else if (fType == 4) {
2787 // Apply the unattached rules; by definition they do not need any
2788 // input from a buffer.
2790
2791 auto ndata = GetNdata();
2792
2793 R__PushCache onfileObject(b, fOnfileObject, ndata);
2796
2798 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
2799 } else {
2800 // Apply the unattached rules; by definition they do not need any
2801 // input from a buffer.
2803 R__PushCache onfileObject(b, fOnfileObject, fNdata);
2804 b.ApplySequence(*fReadActionSequence, fObject);
2805 }
2806 }
2807 } else {
2808 // -- Terminal branch.
2809
2811 Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
2812 if (nb < 0)
2813 return nb;
2814 nbytes += nb;
2815 }
2816 // For associative containers, the count branch is actually
2817 // reading the subbranches (including this one) and in the case
2818 // of a compiled proxy the necessary staging area is only available
2819 // during the call to the count branch GetEntry.
2820 // We detect this code path by checking the position of the cursor,
2821 // which is explicitly reset by the count branch's GetEntry.
2822 // One down-side, if the user call twice GetEntry on the same entry,
2823 // the second call will not re-read the sub-branches (unlike all the other
2824 // types of branches).
2827 if (nb < 0) {
2828 return nb;
2829 }
2830 nbytes += nb;
2831 }
2832 }
2833
2834 if (R__unlikely(fTree->Debug() > 0)) {
2835 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
2836 Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
2837 }
2838 }
2839 return nbytes;
2840}
2841
2842////////////////////////////////////////////////////////////////////////////////
2843/// Fill expectedClass and expectedType with information on the data type of the
2844/// object/values contained in this branch (and thus the type of pointers
2845/// expected to be passed to Set[Branch]Address
2846/// return 0 in case of success and > 0 in case of failure.
2847
2849{
2850 expectedClass = nullptr;
2852
2854 if ((type == -1) || (fID == -1)) {
2856 } else {
2857 // Case of an object data member. Here we allow for the
2858 // variable name to be omitted. Eg, for Event.root with split
2859 // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
2861 if (element) {
2862 expectedClass = element->GetClassPointer();
2863 if (!expectedClass) {
2864 TDataType* data = gROOT->GetType(element->GetTypeNameBasic());
2865 if (!data) {
2866 Error("GetExpectedType", "Did not find the type number for %s", element->GetTypeNameBasic());
2867 return 1;
2868 } else {
2869 expectedType = (EDataType) data->GetType();
2870 }
2871 }
2872 } else {
2873 Error("GetExpectedType", "Did not find the type for %s",GetName());
2874 return 2;
2875 }
2876 }
2877 return 0;
2878}
2879
2880////////////////////////////////////////////////////////////////////////////////
2881/// Return the 'full' name of the branch. In particular prefix the mother's name
2882/// when it does not end in a trailing dot and thus is not part of the branch name
2884{
2885 TBranchElement* mother = static_cast<TBranchElement*>(GetMother());
2886 if (!mother || mother==this || mother->GetType() == 3 || mother->GetType() == 4) {
2887 // The parent's name is already included in the name for split TClonesArray and STL collections
2888 return fName;
2889 }
2890
2891 return TBranch::GetFullName();
2892}
2893
2894////////////////////////////////////////////////////////////////////////////////
2895/// Return icon name depending on type of branch element.
2896
2898{
2899 if (IsFolder()) {
2900 return "TBranchElement-folder";
2901 } else {
2902 return "TBranchElement-leaf";
2903 }
2904}
2905
2906////////////////////////////////////////////////////////////////////////////////
2907/// Return whether this branch is in a mode where the object are decomposed
2908/// or not (Also known as MakeClass mode).
2909
2911{
2912 return TestBit(kDecomposedObj); // Same as TestBit(kMakeClass)
2913}
2914
2915////////////////////////////////////////////////////////////////////////////////
2916/// Return maximum count value of the branchcount if any.
2917
2919{
2920 if (fBranchCount) {
2921 return fBranchCount->GetMaximum();
2922 }
2923 return fMaximum;
2924}
2925
2926////////////////////////////////////////////////////////////////////////////////
2927/// Return a pointer to our object.
2928
2930{
2932 return fObject;
2933}
2934
2935////////////////////////////////////////////////////////////////////////////////
2936/// Return a pointer to the parent class of the branch element.
2937
2942
2943////////////////////////////////////////////////////////////////////////////////
2944/// Return type name of element in the branch.
2945
2947{
2948 if (fType == 3 || fType == 4) {
2949 return "Int_t";
2950 }
2951 // FIXME: Use symbolic constants here.
2952 if ((fStreamerType < 1) || (fStreamerType > 59)) {
2953 if (fBranchClass.GetClass()) {
2954 if (fID>=0) {
2955 return GetInfoImp()->GetElement(fID)->GetTypeName();
2956 } else {
2957 return fBranchClass.GetClass()->GetName();
2958 }
2959 } else {
2960 return nullptr;
2961 }
2962 }
2963 const char *types[20] = {
2964 "",
2965 "Char_t",
2966 "Short_t",
2967 "Int_t",
2968 "Long_t",
2969 "Float_t",
2970 "Int_t",
2971 "char*",
2972 "Double_t",
2973 "Double32_t",
2974 "",
2975 "UChar_t",
2976 "UShort_t",
2977 "UInt_t",
2978 "ULong_t",
2979 "UInt_t",
2980 "Long64_t",
2981 "ULong64_t",
2982 "Bool_t",
2983 "Float16_t"
2984 };
2985 Int_t itype = fStreamerType % 20;
2986 return types[itype];
2987}
2988
2989////////////////////////////////////////////////////////////////////////////////
2990
2994
2995template <typename T>
2997{
2998 // -- Returns the branch value.
2999 //
3000 // If the leaf is an array, j is the index in the array.
3001 //
3002 // If leaf is an array inside a TClonesArray, len should be the length
3003 // of the array.
3004 //
3005 // If subarr is true, then len is actually the index within the sub-array.
3006 //
3007
3009
3010 Int_t prID = fID;
3011 char *object = fObject;
3012 if (TestBit(kCache)) {
3013 if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
3014 prID = fID+1;
3015 } else if (fOnfileObject) {
3016 object = fOnfileObject->GetObjectAt(0);
3017 }
3018 }
3019
3020 if (!j && fBranchCount) {
3022 // Since reloading the index, will reset the ClonesArray, let's
3023 // skip the load if we already read this entry.
3024 if (entry != fBranchCount->GetReadEntry()) {
3025 fBranchCount->TBranch::GetEntry(entry);
3026 }
3028 fBranchCount2->TBranch::GetEntry(entry);
3029 }
3030 }
3031
3032 if (TestBit(kDecomposedObj)) {
3033 if (!fAddress) {
3034 return 0;
3035 }
3036 if ((fType == 3) || (fType == 4)) {
3037 // Top-level branch of a TClonesArray.
3038 return fNdata;
3039 } else if ((fType == 31) || (fType == 41)) {
3040 // sub branch of a TClonesArray
3042 if (atype < 20) {
3043 atype += 20;
3044 }
3045 return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
3046 } else if (fType <= 2) {
3047 // branch in split mode
3048 // FIXME: This should probably be < 60 instead!
3049 if ((fStreamerType > 40) && (fStreamerType < 55)) {
3050 Int_t atype = fStreamerType - 20;
3051 return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
3052 } else {
3053 return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
3054 }
3055 }
3056 }
3057
3058 if (object == nullptr)
3059 {
3060 // We have nowhere to read the data from (probably because the data member was
3061 // 'dropped' from the current schema).
3062 return 0;
3063 }
3064
3065 if (fType == 31) {
3066 TClonesArray* clones = reinterpret_cast<TClonesArray*>(object);
3067 if (subarr) {
3069 }
3071 } else if (fType == 41) {
3074 {
3075 if (subarr)
3076 return GetInfoImp()->GetTypedValueSTL<T>(const_cast<TBranchElement*>(this)->GetCollectionProxy(), prID, j, len, fOffset);
3077
3078 return GetInfoImp()->GetTypedValueSTL<T>(const_cast<TBranchElement*>(this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
3079 }
3080 else
3081 {
3082 if (subarr)
3083 return GetInfoImp()->GetTypedValueSTLP<T>(const_cast<TBranchElement*>(this)->GetCollectionProxy(), prID, j, len, fOffset);
3084 return GetInfoImp()->GetTypedValueSTLP<T>(const_cast<TBranchElement*>(this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
3085 }
3086 } else {
3087 auto info = GetInfoImp();
3088 if (info) {
3089 return info->GetTypedValue<T>(object, prID, j, -1);
3090 }
3091 return 0;
3092 }
3093}
3094
3095////////////////////////////////////////////////////////////////////////////////
3096/// Returns pointer to first data element of this branch.
3097/// Currently used only for members of type character.
3098
3100{
3102
3103 TStreamerInfo *info = nullptr;
3104 Int_t prID = fID;
3105 char *object = fObject;
3106 if (TestBit(kCache)) {
3107 info = GetInfoImp();
3108 if (info->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
3109 prID = fID+1;
3110 } else if (fOnfileObject) {
3111 object = fOnfileObject->GetObjectAt(0);
3112 }
3113 }
3114
3115 if (fBranchCount) {
3117 fBranchCount->TBranch::GetEntry(entry);
3118 if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
3119 }
3120 if (TestBit(kDecomposedObj)) {
3121 if (!fAddress) {
3122 return nullptr;
3123 }
3124 if (fType == 3) { //top level branch of a TClonesArray
3125 //return &fNdata;
3126 return nullptr;
3127 } else if (fType == 4) { //top level branch of a TClonesArray
3128 //return &fNdata;
3129 return nullptr;
3130 } else if (fType == 31) { // sub branch of a TClonesArray
3131 //Int_t atype = fStreamerType;
3132 //if (atype < 20) atype += 20;
3133 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3134 return nullptr;
3135 } else if (fType == 41) { // sub branch of a TClonesArray
3136 //Int_t atype = fStreamerType;
3137 //if (atype < 20) atype += 20;
3138 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3139 return nullptr;
3140 } else if (fType <= 2) { // branch in split mode
3141 // FIXME: This should probably be < 60 instead!
3142 if (fStreamerType > 40 && fStreamerType < 55) {
3143 //Int_t atype = fStreamerType - 20;
3144 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3145 return nullptr;
3146 } else {
3147 //return GetInfoImp()->GetValue(object, fID, j, -1);
3148 return nullptr;
3149 }
3150 }
3151 }
3152
3153 if (fType == 31) {
3154 return nullptr;
3155 } else if (fType == 41) {
3156 return nullptr;
3157 } else if (prID < 0) {
3158 return object;
3159 } else {
3160 //return GetInfoImp()->GetValue(object,fID,j,-1);
3161 if (!info)
3162 info = GetInfoImp();
3163 if (!info || !object) return nullptr;
3164 char **val = reinterpret_cast<char **>(object+info->TStreamerInfo::GetElementOffset(prID));
3165 return *val;
3166 }
3167}
3168
3169////////////////////////////////////////////////////////////////////////////////
3170/// Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a container sub-branch.
3171///
3172/// Note: The offsets are zero for data members so that when
3173/// SetAddress recursively sets their address, they will get the
3174/// same address as their containing class because i/o is based
3175/// on streamer info offsets from the address of the containing
3176/// class.
3177///
3178/// Offsets are non-zero for base-class sub-branches that are
3179/// not the leftmost direct base class. They are laid out in
3180/// memory sequentially and only the leftmost direct base class
3181/// has the same address as the derived class. The streamer
3182/// offsets need to be added to the address of the base class
3183/// subobject which is not the same as the address of the
3184/// derived class for the non-leftmost direct base classes.
3185
3187{
3189
3190 // See https://sft.its.cern.ch/jira/browse/ROOT-8742
3191 // and https://sft.its.cern.ch/jira/browse/ROOT-9253
3192 // As of commit e21b4f1a3b, removing this lock lead to a failure
3193 // in the test testSetAddress[Loop].
3194 // As of commit 4f8b237849, removing this lock does not lead to
3195 // a visible failure in test. This might be due to the underlying
3196 // problem (missing lock or ?) being solved somewhere else or some
3197 // other perturbation reducing the failure rate.
3198 // Having the lock here is not too costly as InitializeOffsets is
3199 // one called once in the lifetime of the TBranch.
3201
3202 if (fID < 0) {
3203 // -- We are a top-level branch. Let's mark whether we need to use MapObject.
3205 if (fBranchClass.GetClass()->IsTObject()) {
3207 } else {
3209 }
3210 }
3211 }
3212 if (nbranches) {
3213 // Allocate space for the new sub-branch offsets.
3214 delete[] fBranchOffset;
3215 fBranchOffset = nullptr;
3217 // Make sure we can instantiate our class meta info.
3218 if (!fBranchClass.GetClass()) {
3219 Warning("InitializeOffsets", "No branch class set for branch: %s", GetName());
3220 fInitOffsets = true;
3221 return;
3222 }
3223 // Make sure we can instantiate our class streamer info.
3225 if (!info) {
3226 Warning("InitializeOffsets", "No streamer info available for branch: %s of class: %s", GetName(), fBranchClass.GetClass()->GetName());
3227 fInitOffsets = true;
3228 return;
3229 }
3230
3231 // Get the class we are a member of now (which is the
3232 // type of our containing subobject) and get our offset
3233 // inside of our containing subobject (our local offset).
3234 // Note: branchElem stays zero if we are a top-level branch,
3235 // we have to be careful about this later.
3236 TStreamerElement* branchElem = nullptr;
3237 Int_t localOffset = 0;
3239 bool renamed = false;
3240 if (fID > -1) {
3241 // -- Branch is *not* a top-level branch.
3242 // Instead of the streamer info class, we want the class of our
3243 // specific element in the streamer info. We could be a data
3244 // member of a base class or a split class, in which case our
3245 // streamer info will be for our containing sub-object, while
3246 // we are actually a different type.
3247 // Note: We tested to make sure the streamer info was available previously.
3248 if (!info->IsCompiled()) {
3249 Warning("InitializeOffsets", "Streamer info for branch: %s has no elements array!", GetName());
3250 fInitOffsets = true;
3251 return;
3252 }
3253 // FIXME: Check that fID is in range.
3254 branchElem = info->GetElement(fID);
3255 if (!branchElem) {
3256 Warning("InitializeOffsets", "Cannot get streamer element for branch: %s!", GetName());
3257 fInitOffsets = true;
3258 return;
3259 } else if (branchElem->TestBit(TStreamerElement::kRepeat)) {
3260 // If we have a repeating streamerElement, use the next
3261 // one as it actually hold the 'real' data member('s offset)
3262 if (info->GetElement(fID+1)) {
3263 branchElem = info->GetElement(fID+1);
3264 }
3265 }
3266 localOffset = branchElem->GetOffset();
3267 branchClass = branchElem->GetClassPointer();
3269 fObject = nullptr;
3270 } else {
3271 renamed = branchClass && branchElem->GetNewClass() && (branchClass != branchElem->GetNewClass());
3272 }
3273 } else {
3275 }
3276 if (!branchClass) {
3277 Error("InitializeOffsets", "Could not find class for branch: %s", GetName());
3278 fInitOffsets = true;
3279 return;
3280 }
3281
3282 //------------------------------------------------------------------------
3283 // Extract the name of the STL branch in case it has been split.
3284 //////////////////////////////////////////////////////////////////////////
3285
3287 bool stlParentNameUpdated = false;
3288 if( fType == 4 )
3289 {
3290 TBranch *br = GetMother()->GetSubBranch( this );
3291 stlParentName = br->GetName();
3293
3294 // We may ourself contain the 'Mother' branch name.
3295 // To avoid code duplication, we delegate the removal
3296 // of the mother's name to the first sub-branch loop.
3297 }
3298
3299 // Loop over our sub-branches and compute their offsets.
3301 bool alternateElement = false;
3302
3305 if (subBranch == nullptr) {
3306 // -- Skip sub-branches that are not TBranchElements.
3307 continue;
3308 }
3309
3310 if (renamed) {
3311 if (subBranch->fBranchClass == branchClass) {
3312 if (branchElem) subBranch->SetTargetClass(branchElem->GetNewClass()->GetName());
3313 else subBranch->SetTargetClass(fTargetClass->GetName());
3314 }
3315 }
3316
3317 TVirtualStreamerInfo* sinfo = subBranch->GetInfoImp();
3318 if (!sinfo) {
3319 Warning("InitializeOffsets", "No streamer info for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3321 continue;
3322 }
3323 if (!sinfo->IsCompiled()) {
3324 Warning("InitializeOffsets", "No elements array for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3326 continue;
3327 }
3328 // FIXME: Make sure subBranch->fID is in range.
3329 TStreamerElement* subBranchElement = sinfo->GetElement(subBranch->fID);
3330 if (!subBranchElement) {
3331 Warning("InitializeOffsets", "No streamer element for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3333 continue;
3334 } else if (subBranchElement->TestBit(TStreamerElement::kRepeat)) {
3335 // If we have a repeating streamerElement, use the next
3336 // one as it actually hold the 'real' data member('s offset)
3337 if (sinfo->GetElement(subBranch->fID+1)) {
3338 subBranchElement = sinfo->GetElement(subBranch->fID+1);
3339 }
3340 } else if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3341 // We have a cached item which is not a repeated but we might still
3342 // have some Actions triggered by a rule that affect real
3343 // data member(s).
3344 if (subBranch->fReadActionSequence && subBranch->fReadActionSequence->fActions.size() > 1) {
3345 typedef TStreamerInfoActions::ActionContainer_t::iterator iterator;
3346 iterator end = subBranch->fReadActionSequence->fActions.end();
3347 for(iterator iter = subBranch->fReadActionSequence->fActions.begin();
3348 iter != end; ++iter) {
3349 TStreamerInfoActions::TConfiguration *config = iter->fConfiguration;
3350 UInt_t id = config->fElemId;
3351 TStreamerElement *e = static_cast<TStreamerElement*>(config->fInfo->GetElements()->At(id));
3352 if (e && !e->TestBit(TStreamerElement::kCache)) {
3354 alternateElement = true;
3355 break;
3356 }
3357 }
3358 }
3359 }
3360
3361 localOffset = subBranchElement->GetOffset();
3363 subBranch->fObject = nullptr;
3364 }
3365 {
3366 Int_t streamerType = subBranchElement->GetType();
3368 && subBranch->GetListOfBranches()->GetEntriesFast()==0
3369 && CanSelfReference(subBranchElement->GetClass()))
3370 {
3371 subBranch->SetBit(kBranchAny);
3372 } else {
3373 subBranch->ResetBit(kBranchAny);
3374 }
3375 }
3376
3377 if (subBranchElement->GetNewType()<0) {
3378 subBranch->ResetBit(kBranchAny);
3379 subBranch->ResetBit(kBranchObject);
3380 }
3381
3382 // Note: This call is expensive, do it only once.
3384 if (!mother) {
3385 Warning("InitializeOffsets", "Branch '%s' has no mother!", GetName());
3387 continue;
3388 }
3389 TString motherName(mother->GetName());
3390 bool motherDot = false;
3391 if (motherName.Length() && strchr(motherName.Data(), '.')) {
3392 motherDot = true;
3393 }
3394 bool motherDotAtEnd = false;
3395 if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
3396 motherDotAtEnd = true;
3397 }
3398
3399 bool isBaseSubBranch = false;
3400 if ((subBranch->fType == 1) || (subBranchElement && subBranchElement->IsBase())) {
3401 // -- Base class sub-branch (1).
3402 //
3403 // Note: Our type will not be 1, even though we are
3404 // a base class branch, if we are not split (see the
3405 // constructor), or if we are an STL container master
3406 // branch and a base class branch at the same time
3407 // or an std::string.
3408 isBaseSubBranch = true;
3409 }
3410
3411 bool isContDataMember = false;
3412 if ((subBranch->fType == 31) || (subBranch->fType == 41)) {
3413 // -- Container data member sub-branch (31 or 41).
3414 isContDataMember = true;
3415 }
3416
3417 // I am either a data member sub-branch (0), or a base class
3418 // sub-branch (1), or TClonesArray master sub-branch (3),
3419 // or an STL container master sub-branch (4), or TClonesArray
3420 // data member sub-branch (31), or an STL container data member
3421 // sub-branch (41).
3422 //
3423 // My parent branch is either a top-level branch ((0), fID==(-2,-1)),
3424 // or a base class sub-branch (1), or a split-class branch (2),
3425 // or a TClonesArray master branch (3), or an STL container
3426 // master branch (4).
3427 //
3428
3429 //
3430 // We need to extract from our name the name
3431 // of the data member which contains us, so
3432 // that we may then do a by-name lookup in the
3433 // dictionary meta info of our parent class to
3434 // get our offset in our parent class.
3435 //
3436
3437 // Get our name.
3438 TString dataName(subBranch->GetName());
3439 if (motherDotAtEnd) {
3440 // -- Remove the top-level branch name from our name.
3441 dataName.Remove(0, motherName.Length());
3442 // stlParentNameUpdated is false the first time in this loop.
3443 if (!stlParentNameUpdated && stlParentName.Length()) {
3444 stlParentName.Remove(0, motherName.Length());
3445 stlParentNameUpdated = true;
3446 }
3447 } else if (fType == 4) {
3448 // This is a top-level branch of type STL collection. In this current
3449 // iteration, we are trying to calculate the offset of one of the
3450 // base classes of the element type of the STL collection. The
3451 // dataName string in this case will be akin to
3452 // "nameOfBranch.BaseClassName". Later logic in this function will
3453 // try to get the TRealData relative to "BaseClassName". But if the
3454 // base class is not splittable (i.e. it has a custom streamer), that
3455 // will not work anyway. The treatment of base classes follows a
3456 // different path: we remove the leading name of the branch, so only
3457 // the name of the base class is left. This will be later detected
3458 // and dataName will be stripped from the name of the base class,
3459 // leaving the string completely empty. Since the dataName string
3460 // will be empty, the logic of this function skips the part related
3461 // to finding the TRealData and directly computes the base class
3462 // offset.
3463 // Only perform the modification of the string if it looks as we
3464 // expect
3465 if (dataName == (motherName + '.' + subBranchElement->GetName()))
3466 dataName = subBranchElement->GetName();
3467 } else if (motherDot) {
3468 // -- Remove the top-level branch name from our name, folder case.
3469 //
3470 // Note: We are in the case where our mother was created
3471 // by the branch constructor which takes a folder
3472 // as an argument. The mother branch has internal
3473 // dots in its name to represent the folder hierarchy.
3474 // The TTree::Bronch() routine has handled us as a
3475 // special case, we must compensate.
3476 if ((fID < 0) && (subBranchElement->IsA() == TStreamerBase::Class())) {
3477 // -- Our name is the mother name, remove it.
3478 // Note: The test is our parent is a top-level branch
3479 // and our streamer is the base class streamer,
3480 // this matches the exact test in TTree::Bronch().
3481 if (dataName.Length() == motherName.Length()) {
3482 dataName.Remove(0, motherName.Length());
3483 // stlParentNameUpdated is false the first time in this loop.
3484 if (!stlParentNameUpdated && stlParentName.Length()) {
3485 stlParentName.Remove(0, motherName.Length());
3486 }
3487 }
3488 } else {
3489 // -- Remove the mother name and the dot.
3490 if (dataName.Length() > motherName.Length()) {
3491 dataName.Remove(0, motherName.Length() + 1);
3492 if (!stlParentNameUpdated && stlParentName.Length()) {
3493 stlParentName.Remove(0, motherName.Length());
3494 }
3495 }
3496 }
3497 }
3498 stlParentNameUpdated = true;
3499 if (isBaseSubBranch) {
3500 // -- Remove the base class name suffix from our name.
3501 // Note: The pattern is the name of the base class.
3502 TString pattern(subBranchElement->GetName());
3503 if (pattern.Length() <= dataName.Length()) {
3504 if (!strcmp(dataName.Data() + (dataName.Length() - pattern.Length()), pattern.Data())) {
3505 // The branch name contains the name of the base class in it.
3506 // This name is not reproduced in the sub-branches, so we need to
3507 // remove it.
3508 dataName.Remove(dataName.Length() - pattern.Length());
3509 }
3510 }
3511 // Remove any leading dot.
3512 if (dataName.Length()) {
3513 if (dataName[0] == '.') {
3514 dataName.Remove(0, 1);
3515 }
3516 }
3517 // Note: We intentionally leave any trailing dot
3518 // in our modified name here.
3519 }
3520
3521 // Get our parent branch's name.
3523 if (motherDotAtEnd) {
3524 // -- Remove the top-level branch name from our parent's name.
3525 parentName.Remove(0, motherName.Length());
3526 } else if (motherDot) {
3527 // -- Remove the top-level branch name from our parent's name, folder case.
3528 //
3529 // Note: We are in the case where our mother was created
3530 // by the branch constructor which takes a folder
3531 // as an argument. The mother branch has internal
3532 // dots in its name to represent the folder hierarchy.
3533 // The TTree::Bronch() routine has handled us as a
3534 // special case, we must compensate.
3535 if ((fID > -1) && (mother == mother->GetSubBranch(this)) && (branchElem->IsA() == TStreamerBase::Class())) {
3536 // -- Our parent's name is the mother name, remove it.
3537 // Note: The test is our parent's parent is a top-level branch
3538 // and our parent's streamer is the base class streamer,
3539 // this matches the exact test in TTree::Bronch().
3540 if (parentName.Length() == motherName.Length()) {
3541 parentName.Remove(0, motherName.Length());
3542 }
3543 } else {
3544 // -- Remove the mother name and the dot.
3545 if (parentName.Length() > motherName.Length()) {
3546 parentName.Remove(0, motherName.Length() + 1);
3547 }
3548 }
3549 }
3550 // FIXME: Do we need to use the other tests for a base class here?
3551 if (fType == 1) {
3552 // -- Our parent is a base class sub-branch, remove the base class name suffix from its name.
3553 if (mother != mother->GetSubBranch(this)) {
3554 // -- My parent's parent is not a top-level branch.
3555 // Remove the base class name suffix from the parent name.
3556 // Note: The pattern is the name of the base class.
3557 // coverity[var_deref_model] branchElem is non zero here since fType==1 and thus fID > -1
3558 TString pattern(branchElem->GetName());
3559 if (pattern.Length() <= parentName.Length()) {
3560 if (!strcmp(parentName.Data() + (parentName.Length() - pattern.Length()), pattern.Data())) {
3561 // The branch name contains the name of the base class in it.
3562 // This name is not reproduced in the sub-branches, so we need to
3563 // remove it.
3564 parentName.Remove(parentName.Length() - pattern.Length());
3565 }
3566 }
3567 }
3568 // Note: We intentionally leave any trailing dots
3569 // in the modified parent name here.
3570 }
3571
3572 // Remove the parent branch name part from our name,
3573 // but only if the parent branch is not a top-level branch.
3574 // FIXME: We should not assume parent name does not have length 0.
3575 if (fID > -1) {
3577 }
3578
3579 // Remove any leading dot.
3580 if (dataName.Length()) {
3581 if (dataName[0] == '.') {
3582 dataName.Remove(0, 1);
3583 }
3584 }
3585
3586 // Remove any trailing dot.
3587 if (dataName.Length()) {
3588 if (dataName[dataName.Length()-1] == '.') {
3589 dataName.Remove(dataName.Length() - 1, 1);
3590 }
3591 }
3592
3593 //
3594 // Now that we have our data member name, find our offset
3595 // in our parent class.
3596 //
3597 // Note: Our data member name can have many dots in it
3598 // if branches were elided between our parent branch
3599 // and us by Unroll().
3600 //
3601 // FIXME: This may not work if our member name is ambiguous.
3602 //
3603
3604 Int_t offset = 0;
3605 if (dataName.Length()) {
3606 // -- We have our data member name, do a lookup in the dictionary meta info of our parent class.
3607 // Get our parent class.
3608 TClass* pClass = nullptr;
3609 // First check whether this sub-branch is part of the 'cache' (because the data member it
3610 // represents is no longer in the current class layout.
3611 TStreamerInfo *subInfo = subBranch->GetInfoImp();
3612 //if (subInfo && subBranch->TestBit(kCache)) { // subInfo->GetElements()->At(subBranch->GetID())->TestBit(TStreamerElement::kCache)) {
3614 pClass = static_cast<TStreamerElement*>(subInfo->GetElements()->At(0))->GetClassPointer();
3615 }
3616 // FIXME: Do we need the other base class tests here?
3617 if (!pClass) {
3618 if (fType == 1) {
3619 // -- Parent branch is a base class branch.
3620 // FIXME: Is using branchElem here the right thing?
3621 pClass = branchElem->GetClassPointer();
3622 if (pClass->Property() & kIsAbstract) {
3623 // the class is abstract, let see if the
3624
3625 TBranchElement *parent = static_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3626 if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
3627 // Our parent's class is emulated and we represent an abstract class.
3628 // and the target class has not been set explicitly.
3629 TString target = pClass->GetName();
3630 target += "@@emulated";
3631
3633 }
3634 }
3635 } else {
3636 // -- Parent branch is *not* a base class branch.
3637 // FIXME: This sometimes returns a null pointer.
3638 pClass = subBranch->GetParentClass();
3639 }
3640 }
3641 if (!pClass) {
3642 // -- No parent class, fix it.
3643 // FIXME: This is probably wrong!
3644 // Assume parent class is our parent branch's clones class or value class.
3645 if (GetClonesName() && strlen(GetClonesName())) {
3647 if (!pClass) {
3648 Warning("InitializeOffsets", "subBranch: '%s' has no parent class, and cannot get class for clones class: '%s'!", subBranch->GetName(), GetClonesName());
3650 continue;
3651 }
3652 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3653 }
3656 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass ? pClass->GetName() : "unknown class");
3657 }
3658 if (!pClass) {
3659 // -- Still no parent class, assume our parent class is our parent branch's class.
3660 // FIXME: This is probably wrong!
3662 // FIXME: Enable this warning!
3663 //Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3664 }
3665 }
3666 if (renamed && pClass) {
3667 if (pClass == branchClass) {
3668 pClass = branchElem->GetNewClass();
3669 } else if (fCollProxy && pClass == branchClass->GetCollectionProxy()->GetValueClass()) {
3671 }
3672 }
3673
3674 //------------------------------------------------------------------
3675 // If we have the are the sub-branch of the TBranchSTL, we need
3676 // to remove it's name to get the correct real data offsets
3677 ////////////////////////////////////////////////////////////////////
3678
3679 const bool isToplevelCollection = (this == GetMother() && (fType == 3 || fType == 4));
3680 if( stlParentName.Length() && (dynamic_cast<TBranchSTL*>(fParent) || isToplevelCollection))
3681 {
3682 if( !strncmp( stlParentName.Data(), dataName.Data(), stlParentName.Length()-1 )
3683 && dataName[ stlParentName.Length() ] == '.' )
3684 dataName.Remove( 0, stlParentName.Length()+1 );
3685 }
3686
3687 // Find our offset in our parent class using
3688 // a lookup by name in the dictionary meta info
3689 // for our parent class.
3690
3691 if (alternateElement) {
3692 Ssiz_t dotpos = dataName.Last('.');
3693 Ssiz_t endpos = dataName.Length();
3694 if (dotpos != kNPOS) ++dotpos; else dotpos = 0;
3695 dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
3696 }
3697 TRealData* rd = pClass->GetRealData(dataName);
3698 if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
3699 // -- Data member exists in the dictionary meta info, get the offset.
3700 // If we are using an alternateElement, it is the target of a rule
3701 // and might be indeed transient.
3702 offset = rd->GetThisOffset();
3703 } else if (subBranchElement->TestBit(TStreamerElement::kWholeObject)) {
3704 // We are a rule with no specific target, it applies to the whole
3705 // object, let's set the offset to zero
3706 offset = 0;
3707 } else {
3708 // -- No dictionary meta info for this data member, it must no
3709 // longer exist
3710 if (fEntries == 0) {
3711 // ... unless we creating the branch in which case
3712 // we have an internal error.
3713 if (pClass->GetListOfRealData()->GetEntries() == 0) {
3714 // We are probably missing the ShowMember, let's
3715 // just issue an error.
3716 Error("InitializeOffsets",
3717 "Could not find the real data member '%s' when constructing the branch '%s' [Likely missing ShowMember].",
3718 dataName.Data(),GetName());
3719 } else if (subInfo && subInfo->GetClassVersion()!=subInfo->GetClass()->GetClassVersion()) {
3720 // In the case where we are cloning a TTree that was created with an older version of the layout, we may not
3721 // able to find all the members
3722 Info("InitializeOffsets",
3723 "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'. ",
3724 dataName.Data(),GetName());
3725 } else {
3726 // Something really bad happen.
3727 Fatal("InitializeOffsets",
3728 "Could not find the real data member '%s' when constructing the branch '%s' [Likely an internal error, please report to the developers].",
3729 dataName.Data(),GetName());
3730 }
3731 }
3733 }
3734 } else {
3735 // -- We have no data member name, ok for a base class, not good otherwise.
3736 if (isBaseSubBranch) {
3737 // I am a direct base class of my parent class, my local offset is enough.
3738 } else {
3739 Warning("InitializeOffsets", "Could not find the data member name for branch '%s' with parent branch '%s', assuming offset is zero!", subBranch->GetName(), GetName());
3740 }
3741 }
3742
3743 //
3744 // Ok, do final calculations for fOffset and fBranchOffset.
3745 //
3746
3747 if (isContDataMember) {
3748 // -- Container data members set fOffset instead of fBranchOffset.
3749 // The fOffset is what should be added to the start of the entry
3750 // in the collection (i.e., its current absolute address) to find
3751 // the beginning of the data member described by the current branch.
3752 //
3753 // Compensate for the i/o routines adding our local offset later.
3754 if (subBranch->fObject == nullptr && localOffset == TStreamerInfo::kMissing) {
3755 subBranch->SetMissing();
3756 // We stil need to set fBranchOffset in the case of a missing
3757 // element so that SetAddress is (as expected) not called
3758 // recursively in this case.
3760 } else {
3761 if (isBaseSubBranch) {
3762 // The value of 'offset' for a base class does not include its
3763 // 'localOffset'.
3764 subBranch->SetOffset(offset);
3765 } else {
3766 // The value of 'offset' for a regular data member does include its
3767 // 'localOffset', we need to remove it explicitly.
3768 subBranch->SetOffset(offset - localOffset);
3769 }
3770 }
3771 } else {
3772 // -- Set fBranchOffset for sub-branch.
3773 Int_t isSplit = 0 != subBranch->GetListOfBranches()->GetEntriesFast();
3774 if (subBranch->fObject == nullptr && localOffset == TStreamerInfo::kMissing) {
3775 // The branch is missing
3777
3778 } else if (isSplit) {
3779 if (isBaseSubBranch) {
3780 // We are split, so we need to add in our local offset
3781 // to get our absolute address for our children.
3783 } else {
3784 // We are split so our offset will never be
3785 // used in an i/o, so we do not have to subtract
3786 // off our local offset like below.
3788 }
3789 } else {
3790 if (isBaseSubBranch) {
3791 // We are not split, so our local offset will be
3792 // added later by the i/o routines.
3794 } else {
3795 // Compensate for the fact that the i/o routines
3796 // are going to add my local offset later.
3798 }
3799 }
3800 }
3801 }
3802 }
3803 else {
3804 if (fID > -1) {
3805 // Branch is *not* a top-level branch.
3806 // Let's check if the target member is still present in memory
3808 fObject = nullptr;
3809 }
3810 }
3811 }
3812 const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
3814 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3815 auto index = parent->fBranches.IndexOf(this);
3816 if (index >= 0) {
3818 }
3819 }
3820
3821 fInitOffsets = true;
3822}
3823
3824////////////////////////////////////////////////////////////////////////////////
3825/// Return true if more than one leaf, false otherwise.
3826
3828{
3830 if (nbranches >= 1) {
3831 return true;
3832 }
3833 TList* browsables = const_cast<TBranchElement*>(this)->GetBrowsables();
3834 return browsables && browsables->GetSize();
3835}
3836
3837////////////////////////////////////////////////////////////////////////////////
3838/// Detect a collection written using a zero pointer in old versions of root.
3839/// In versions of ROOT older than 4.00/03, if a collection (TClonesArray
3840/// or STL container) was split but the pointer to the collection was zeroed
3841/// out, nothing was saved. Hence there is no __easy__ way to detect the
3842/// case. In newer versions, a zero is written so that a 'missing' collection
3843/// appears to be an empty collection.
3844
3846{
3847 bool ismissing = false;
3849 if (basket && fTree) {
3852 Long64_t last;
3853 if (fReadBasket == fWriteBasket) {
3854 last = fEntryNumber - 1;
3855 } else {
3856 last = fBasketEntry[fReadBasket+1] - 1;
3857 }
3858 Int_t* entryOffset = basket->GetEntryOffset();
3860 Int_t bufnext;
3861 if (entryOffset) {
3862 bufbegin = entryOffset[entry-first];
3863
3864 if (entry < last) {
3865 bufnext = entryOffset[entry+1-first];
3866 } else {
3867 bufnext = basket->GetLast();
3868 }
3869 if (bufnext == bufbegin) {
3870 ismissing = true;
3871 } else {
3872 // fixed length buffer so this is not the case here.
3873 if (basket->GetNevBufSize() == 0) {
3874 ismissing = true;
3875 }
3876 }
3877 }
3878 }
3879 return ismissing;
3880}
3881
3882////////////////////////////////////////////////////////////////////////////////
3883/// Print branch parameters.
3884
3886{
3887 for(auto &cursor : ids) {
3888 auto id = cursor.fElemID;
3889 if (id >= 0) {
3890 auto el = info->GetElement(id);
3891 if (el)
3892 el->ls();
3893 else {
3894 Error("TBranchElement::Print", "Element for id #%d not found in StreamerInfo for %s",
3895 id, info->GetName());
3896 info->ls();
3897 }
3898 } else if (cursor.fNestedIDs) {
3899 Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
3900 PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
3901 }
3902 }
3903}
3904
3906{
3907 constexpr auto length = std::char_traits<char>::length;
3909 if (strncmp(option,"debugAddress",length("debugAddress"))==0) {
3910 if (strlen(option)==length("debugAddress")) {
3911 Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s %s\n",
3912 "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject", "fOnfileObject");
3913 }
3914 if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3915 else Printf("%-24s ", GetName());
3916
3917 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3918 Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3919 TVirtualStreamerInfo *info = const_cast<TBranchElement*>(this)->GetInfoImp();
3920
3921 Printf("%-16s %2d %4d %-16s %-16s %8x %8x %p %p%s\n",
3922 info ? info->GetName() : "StreamerInfo unavailable", GetID(), GetType(),
3924 (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3925 GetOffset(), GetObject(), fOnfileObject, TestBit(kOwnOnfileObj) ? " (owned)" : "");
3926 for (Int_t i = 0; i < nbranches; ++i) {
3927 TBranchElement* subbranch = static_cast<TBranchElement*>(fBranches.At(i));
3928 subbranch->Print("debugAddressSub");
3929 }
3930 return;
3931 }
3932 if (strncmp(option,"debugInfo",length("debugInfo"))==0) {
3933 Printf("Branch %s uses:",GetName());
3935 if (fID>= 0) {
3936 // GetInfoImp()->GetElement(fID)->ls();
3937 // for(UInt_t i=0; i< fIDs.size(); ++i) {
3938 // GetInfoImp()->GetElement(fIDs[i])->ls();
3939 // }
3940 if (fType == 3 || fType == 4) {
3941 // Search for the correct version.
3943 }
3944 Printf(" With elements:");
3945 if (fType != 3 && fType != 4)
3946 localInfo->GetElement(fID)->ls();
3948 Printf(" with read actions:");
3950 Printf(" with write actions:");
3952 } else if (!fNewIDs.empty() && localInfo) {
3953 if (fType == 3 || fType == 4) {
3954 // Search for the correct version.
3956 }
3958 Printf(" with read actions:");
3960 Printf(" with write actions:");
3962 }
3963 TString suboption = "debugInfoSub";
3964 suboption += (option+length("debugInfo"));
3965 for (Int_t i = 0; i < nbranches; ++i) {
3966 TBranchElement* subbranch = static_cast<TBranchElement*>(fBranches.At(i));
3967 subbranch->Print(suboption);
3968 }
3969 Printf(" ");
3970 return;
3971 }
3972 if (nbranches) {
3973 if (fID == -2) {
3974 if (strcmp(GetName(),GetTitle()) == 0) {
3975 Printf("*Branch :%-66s *",GetName());
3976 } else {
3977 Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3978 }
3979 Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3980 Printf("*............................................................................*");
3981 }
3982 if (fType >= 2) {
3984 }
3985 for (Int_t i=0;i<nbranches;i++) {
3986 TBranch *branch = static_cast<TBranch*>(fBranches.At(i));
3987 branch->Print(option);
3988 }
3989 } else {
3991 }
3992}
3993
3994////////////////////////////////////////////////////////////////////////////////
3995/// Prints values of leaves.
3996
3998{
4000
4002 Int_t prID = fID;
4003 char *object = fObject;
4004 if (TestBit(kCache)) {
4005 if (info->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
4006 prID = fID+1;
4007 } else if (fOnfileObject) {
4008 object = fOnfileObject->GetObjectAt(0);
4009 }
4010 }
4011
4012 if (TestBit(kDecomposedObj)) {
4013 if (!fAddress) {
4014 return;
4015 }
4016 if (fType == 3 || fType == 4) {
4017 // TClonesArray or STL container top-level branch.
4018 printf(" %-15s = %d\n", GetName(), fNdata);
4019 return;
4020 } else if (fType == 31 || fType == 41) {
4021 // TClonesArray or STL container sub-branch.
4022 Int_t n = TMath::Min(10, fNdata);
4025 // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
4026 // printed as a string and could print weird characters.
4027 // So we print an unsigned char instead (not perfect, but better).
4029 }
4030 if (atype > 54) {
4031 // FIXME: More logic required here (like in ReadLeaves)
4032 printf(" %-15s = %d\n", GetName(), fNdata);
4033 return;
4034 }
4035 if (fStreamerType > 20) {
4036 atype -= 20;
4037 TLeafElement* leaf = static_cast<TLeafElement*>(fLeaves.UncheckedAt(0));
4038 n = n * leaf->GetLenStatic();
4039 }
4040 if (info) {
4041 info->PrintValue(GetName(), fAddress, atype, n, lenmax);
4042 }
4043 return;
4044 } else if (fType <= 2) {
4045 // Branch in split mode.
4046 // FIXME: This should probably be < 60 instead.
4047 if ((fStreamerType > 40) && (fStreamerType < 55)) {
4048 Int_t atype = fStreamerType - 20;
4050 Int_t n = (Int_t) counterElement->GetValue(0, 0);
4051 if (info) {
4052 info->PrintValue(GetName(), fAddress, atype, n, lenmax);
4053 }
4054 } else {
4055 if (info) {
4056 info->PrintValue(GetName(), object, prID, -1, lenmax);
4057 }
4058 }
4059 return;
4060 }
4061 } else if (fType == 3) {
4062 printf(" %-15s = %d\n", GetName(), fNdata);
4063 } else if (fType == 31) {
4064 TClonesArray* clones = reinterpret_cast<TClonesArray*>(object);
4065 if (info) {
4066 info->PrintValueClones(GetName(), clones, prID, fOffset, lenmax);
4067 }
4068 } else if (fType == 41) {
4070 if (info) {
4071 info->PrintValueSTL(GetName(), const_cast<TBranchElement*>(this)->GetCollectionProxy(), prID, fOffset, lenmax);
4072 }
4073 } else {
4074 if (info) {
4075 info->PrintValue(GetName(), object, prID, -1, lenmax);
4076 }
4077 }
4078}
4079
4080////////////////////////////////////////////////////////////////////////////////
4081/// Unconfiguration Read Leave function.
4082
4084{
4085 Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
4086}
4087
4088////////////////////////////////////////////////////////////////////////////////
4089/// Read leaves into i/o buffers for this branch.
4090/// For the case where the branch is set in MakeClass mode (decomposed object).
4091
4093{
4095
4096 if (fType == 3 || fType == 4) {
4097 // Top level branch of a TClonesArray.
4098 Int_t *n = reinterpret_cast<Int_t*>(fAddress);
4099 b >> n[0];
4100 if ((n[0] < 0) || (n[0] > fMaximum)) {
4101 if (IsMissingCollection()) {
4102 n[0] = 0;
4103 b.SetBufferOffset(b.Length() - sizeof(n));
4104 } else {
4105 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());
4106 n[0] = 0;
4107 }
4108 }
4109 fNdata = n[0];
4110 if (fType == 4 && IsAssociativeContainer(fSTLtype)) {
4112 for (Int_t i=0; i<nbranches; i++) {
4113 TBranch *branch = static_cast<TBranch*>(fBranches[i]);
4114 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4115 if (nb < 0) {
4116 break;
4117 }
4118 }
4119 }
4120 return;
4121 } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
4124 // FIXME: This should probably be > 59 instead.
4125 if (atype > 54) return;
4126 if (!fAddress) {
4127 return;
4128 }
4129 Int_t n = fNdata;
4130 if (atype>40) {
4131 atype -= 40;
4132 if (!fBranchCount2) return;
4133 const char *len_where = fBranchCount2->fAddress;
4134 if (!len_where) return;
4136 Int_t length;
4137 Int_t k;
4139 for( k=0; k<n; k++) {
4140 char **where = &((reinterpret_cast<char**>(fAddress))[k]);
4141 delete [] *where;
4142 *where = nullptr;
4143 switch(len_atype) {
4144 case 1: {length = (reinterpret_cast<const Char_t* >(len_where))[k]; break;}
4145 case 2: {length = (reinterpret_cast<const Short_t* >(len_where))[k]; break;}
4146 case 3: {length = (reinterpret_cast<const Int_t* >(len_where))[k]; break;}
4147 case 4: {length = (reinterpret_cast<const Long_t* >(len_where))[k]; break;}
4148 //case 5: {length = (reinterpret_cast<Float_t*>(len_where))[k]; break;}
4149 case 6: {length = (reinterpret_cast<const Int_t* >(len_where))[k]; break;}
4150 //case 8: {length = (reinterpret_cast<Double_t*>(len_where))[k]; break;}
4151 case 11: {length = (reinterpret_cast<const UChar_t* >(len_where))[k]; break;}
4152 case 12: {length = (reinterpret_cast<const UShort_t* >(len_where))[k]; break;}
4153 case 13: {length = (reinterpret_cast<const UInt_t* >(len_where))[k]; break;}
4154 case 14: {length = (reinterpret_cast<const ULong_t* >(len_where))[k]; break;}
4155 case 15: {length = (reinterpret_cast<const ULong64_t*>(len_where))[k]; break;}
4156 case 16: {length = (reinterpret_cast<const Long64_t* >(len_where))[k]; break;}
4157 case 17: {length = (reinterpret_cast<const ULong64_t*>(len_where))[k]; break;}
4158 case 18: {length = (reinterpret_cast<const bool* >(len_where))[k]; break;}
4159 default: continue;
4160 }
4161 b >> isArray;
4162 if (length <= 0) continue;
4163 if (isArray == 0) continue;
4164 switch (atype) {
4165 case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray(reinterpret_cast<Char_t*>(*where), length); break;}
4166 case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray(reinterpret_cast<Short_t*>(*where), length); break;}
4167 case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray(reinterpret_cast<Int_t*>(*where), length); break;}
4168 case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray(reinterpret_cast<Long_t*>(*where), length); break;}
4169 case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray(reinterpret_cast<Float_t*>(*where), length); break;}
4170 case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray(reinterpret_cast<Int_t*>(*where), length); break;}
4171 case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray(reinterpret_cast<Double_t*>(*where), length); break;}
4172 case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray(reinterpret_cast<UChar_t*>(*where), length); break;}
4173 case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray(reinterpret_cast<UShort_t*>(*where), length); break;}
4174 case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray(reinterpret_cast<UInt_t*>(*where), length); break;}
4175 case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray(reinterpret_cast<ULong_t*>(*where), length); break;}
4176 case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray(reinterpret_cast<UInt_t*>(*where), length); break;}
4177 case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray(reinterpret_cast<Long64_t*>(*where), length); break;}
4178 case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray(reinterpret_cast<ULong64_t*>(*where), length); break;}
4179 case 18: {*where=new char[sizeof(bool)*length]; b.ReadFastArray(reinterpret_cast<bool*>(*where), length); break;}
4180 }
4181 }
4182 return;
4183 }
4184 if (atype > 20) {
4185 atype -= 20;
4186 TLeafElement *leaf = static_cast<TLeafElement*>(fLeaves.UncheckedAt(0));
4187 n *= leaf->GetLenStatic();
4188 }
4189 switch (atype) {
4190 case 1: {b.ReadFastArray(reinterpret_cast<Char_t*>(fAddress), n); break;}
4191 case 2: {b.ReadFastArray(reinterpret_cast<Short_t*>(fAddress), n); break;}
4192 case 3: {b.ReadFastArray(reinterpret_cast<Int_t*>(fAddress), n); break;}
4193 case 4: {b.ReadFastArray(reinterpret_cast<Long_t*>(fAddress), n); break;}
4194 case 5: {b.ReadFastArray(reinterpret_cast<Float_t*>(fAddress), n); break;}
4195 case 6: {b.ReadFastArray(reinterpret_cast<Int_t*>(fAddress), n); break;}
4196 case 8: {b.ReadFastArray(reinterpret_cast<Double_t*>(fAddress), n); break;}
4197 case 11: {b.ReadFastArray(reinterpret_cast<UChar_t*>(fAddress), n); break;}
4198 case 12: {b.ReadFastArray(reinterpret_cast<UShort_t*>(fAddress), n); break;}
4199 case 13: {b.ReadFastArray(reinterpret_cast<UInt_t*>(fAddress), n); break;}
4200 case 14: {b.ReadFastArray(reinterpret_cast<ULong_t*>(fAddress), n); break;}
4201 case 15: {b.ReadFastArray(reinterpret_cast<UInt_t*>(fAddress), n); break;}
4202 case 16: {b.ReadFastArray(reinterpret_cast<Long64_t*>(fAddress), n); break;}
4203 case 17: {b.ReadFastArray(reinterpret_cast<ULong64_t*>(fAddress), n); break;}
4204 case 18: {b.ReadFastArray(reinterpret_cast<bool*>(fAddress), n); break;}
4205 case 9: {
4207 TStreamerElement* se = static_cast<TStreamerElement*>(si->GetElement(fID));
4208 Double_t *xx = reinterpret_cast<Double_t*>(fAddress);
4209 for (Int_t ii=0;ii<n;ii++) {
4210 b.ReadDouble32(&(xx[ii]),se);
4211 }
4212 break;
4213 }
4214 case 19: {
4216 TStreamerElement* se = static_cast<TStreamerElement*>(si->GetElement(fID));
4217 Float_t *xx = reinterpret_cast<Float_t*>(fAddress);
4218 for (Int_t ii=0;ii<n;ii++) {
4219 b.ReadFloat16(&(xx[ii]),se);
4220 }
4221 break;
4222 }
4223 }
4224 return;
4225 } else if (fType <= 2) { // branch in split mode
4226 // FIXME: This should probably be < 60 instead.
4227 if (fStreamerType > 40 && fStreamerType < 55) {
4228 Int_t atype = fStreamerType - 40;
4229 Int_t n;
4230 if (fBranchCount==nullptr) {
4231 // Missing fBranchCount. let's attempts to recover.
4232
4234 Ssiz_t dot = countname.Last('.');
4235 if (dot>=0) {
4236 countname.Remove(dot+1);
4237 } else {
4238 countname = "";
4239 }
4240 TString counter( GetTitle() );
4241 Ssiz_t loc = counter.Last('[');
4242 if (loc>=0) {
4243 counter.Remove(0,loc+1);
4244 }
4245 loc = counter.Last(']');
4246 if (loc>=0) {
4247 counter.Remove(loc);
4248 }
4249 countname += counter;
4251 }
4252 if (fBranchCount) {
4253 n = (Int_t)fBranchCount->GetValue(0,0);
4254 } else {
4255 Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4256 n = 0;
4257 }
4258 fNdata = n;
4260 b >> isArray;
4261 switch (atype) {
4262 case 1: {b.ReadFastArray(reinterpret_cast<Char_t*>(fAddress), n); break;}
4263 case 2: {b.ReadFastArray(reinterpret_cast<Short_t*>(fAddress), n); break;}
4264 case 3: {b.ReadFastArray(reinterpret_cast<Int_t*>(fAddress), n); break;}
4265 case 4: {b.ReadFastArray(reinterpret_cast<Long_t*>(fAddress), n); break;}
4266 case 5: {b.ReadFastArray(reinterpret_cast<Float_t*>(fAddress), n); break;}
4267 case 6: {b.ReadFastArray(reinterpret_cast<Int_t*>(fAddress), n); break;}
4268 case 8: {b.ReadFastArray(reinterpret_cast<Double_t*>(fAddress), n); break;}
4269 case 11: {b.ReadFastArray(reinterpret_cast<UChar_t*>(fAddress), n); break;}
4270 case 12: {b.ReadFastArray(reinterpret_cast<UShort_t*>(fAddress), n); break;}
4271 case 13: {b.ReadFastArray(reinterpret_cast<UInt_t*>(fAddress), n); break;}
4272 case 14: {b.ReadFastArray(reinterpret_cast<ULong_t*>(fAddress), n); break;}
4273 case 15: {b.ReadFastArray(reinterpret_cast<UInt_t*>(fAddress), n); break;}
4274 case 16: {b.ReadFastArray(reinterpret_cast<Long64_t*>(fAddress), n); break;}
4275 case 17: {b.ReadFastArray(reinterpret_cast<ULong64_t*>(fAddress), n); break;}
4276 case 18: {b.ReadFastArray(reinterpret_cast<bool*>(fAddress), n); break;}
4277 case 9: {
4279 TStreamerElement* se = si->GetElement(fID);
4280 Double_t *xx = reinterpret_cast<Double_t*>(fAddress);
4281 for (Int_t ii=0;ii<n;ii++) {
4282 b.ReadDouble32(&(xx[ii]),se);
4283 }
4284 break;
4285 }
4286 case 19: {
4288 TStreamerElement* se = si->GetElement(fID);
4289 Float_t *xx = reinterpret_cast<Float_t*>(fAddress);
4290 for (Int_t ii=0;ii<n;ii++) {
4291 b.ReadFloat16(&(xx[ii]),se);
4292 }
4293 break;
4294 }
4295 }
4296 } else {
4297 fNdata = 1;
4298 if (fAddress) {
4299 if (fType<0) {
4300 // Non TObject, Non collection classes with a custom streamer.
4301
4302 // if (fObject)
4304 } else {
4306 if (!info) {
4307 return;
4308 }
4309 // Since info is not null, fReadActionSequence is not null either.
4310 b.ApplySequence(*fReadActionSequence, fObject);
4311 }
4313 fNdata = (Int_t) GetValue(0, 0);
4314 }
4315 } else {
4316 fNdata = 0;
4317 }
4318 }
4319 return;
4320 }
4321}
4322
4323////////////////////////////////////////////////////////////////////////////////
4324/// Read leaves into i/o buffers for this branch.
4325/// Case of a collection (fType == 4).
4326
4328{
4330 if (fObject == nullptr)
4331 {
4332 // We have nowhere to copy the data (probably because the data member was
4333 // 'dropped' from the current schema) so let's no copy it in a random place.
4334 return;
4335 }
4336
4337 // STL container master branch (has only the number of elements).
4338 Int_t n;
4339 b >> n;
4340 if ((n < 0) || (n > fMaximum)) {
4341 if (IsMissingCollection()) {
4342 n = 0;
4343 b.SetBufferOffset(b.Length()-sizeof(n));
4344 } else {
4345 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());
4346 n = 0;
4347 }
4348 }
4349 fNdata = n;
4350
4351 R__PushCache onfileObject(b, fOnfileObject, 1);
4352
4353 // Note: Proxy-helper needs to "embrace" the entire
4354 // streaming of this STL container if the container
4355 // is a set/multiset/map/multimap (what we do not
4356 // know here).
4357 // For vector/list/deque Allocate == Resize
4358 // and Commit == noop.
4359 // TODO: Exception safety a la TPushPop
4362 void* alternate = proxy->Allocate(fNdata, true);
4365 } else {
4367 }
4368
4370
4372 for (Int_t i = 0; i < nbranches; ++i) {
4373 TBranch *branch = static_cast<TBranch*>(fBranches[i]);
4374 // To ensure that the sub-branches are read, we need
4375 // reset their entry cursor.
4377 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4378 if (nb < 0) {
4379 // Give up on i/o failure.
4380 // FIXME: We need an error message here.
4381 break;
4382 }
4383 }
4384 }
4385 //------------------------------------------------------------------------
4386 // We have split this stuff, so we need to create the pointers
4387 /////////////////////////////////////////////////////////////////////////////
4388
4389 if( proxy->HasPointers() && fSplitLevel > TTree::kSplitCollectionOfPointers )
4390 {
4391 TClass *elClass = proxy->GetValueClass();
4392
4393 //--------------------------------------------------------------------
4394 // The allocation is done in this strange way because ReadLeaves
4395 // is being called many times by TTreeFormula!!!
4396 //////////////////////////////////////////////////////////////////////////
4397
4398 Int_t i = 0;
4399 // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4400 if( !fNdata || *reinterpret_cast<void**>(proxy->At( 0 )) != nullptr )
4401 i = fNdata;
4402
4403 for( ; i < fNdata; ++i )
4404 {
4405 void **el = reinterpret_cast<void**>(proxy->At( i ));
4406 // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4407 *el = elClass->New();
4408 }
4409 }
4410
4411 proxy->Commit(alternate);
4412}
4413
4414////////////////////////////////////////////////////////////////////////////////
4415/// Read leaves into i/o buffers for this branch.
4416/// Case of a data member within a collection (fType == 41).
4417
4419{
4421 if (fObject == nullptr)
4422 {
4423 // We have nowhere to copy the data (probably because the data member was
4424 // 'dropped' from the current schema) so let's no copy it in a random place.
4425 return;
4426 }
4427
4428 // STL container sub-branch (contains the elements).
4430 if (!fNdata) {
4431 return;
4432 }
4433
4434 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4435
4437 if (info == nullptr) return;
4438
4441
4442 // R__ASSERT(0);
4444 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4445}
4446
4447////////////////////////////////////////////////////////////////////////////////
4448/// Read leaves into i/o buffers for this branch.
4449/// Case of a data member within a collection (fType == 41).
4450
4452{
4454 if (fObject == nullptr)
4455 {
4456 // We have nowhere to copy the data (probably because the data member was
4457 // 'dropped' from the current schema) so let's no copy it in a random place.
4458 return;
4459 }
4460
4461 // STL container sub-branch (contains the elements).
4463 if (!fNdata) {
4464 return;
4465 }
4466 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4467
4469 if (info == nullptr) return;
4470
4473
4475 b.ApplySequenceVecPtr(*fReadActionSequence,iter->fBegin,iter->fEnd);
4476}
4477
4478////////////////////////////////////////////////////////////////////////////////
4479/// Read leaves into i/o buffers for this branch.
4480/// Case of a data member within a collection (fType == 41).
4481
4483{
4485 if (fObject == nullptr)
4486 {
4487 // We have nowhere to copy the data (probably because the data member was
4488 // 'dropped' from the current schema) so let's no copy it in a random place.
4489 return;
4490 }
4491
4492 // STL container sub-branch (contains the elements).
4494 if (!fNdata) {
4495 return;
4496 }
4497 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4498
4500 if (info == nullptr) return;
4501 // Since info is not null, fReadActionSequence is not null either.
4502
4503 // Still calling PushPop for the legacy entries.
4506
4508 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4509}
4510
4511////////////////////////////////////////////////////////////////////////////////
4512/// Read leaves into i/o buffers for this branch.
4513/// Case of a TClonesArray (fType == 3).
4514
4516{
4518 if (fObject == nullptr)
4519 {
4520 // We have nowhere to copy the data (probably because the data member was
4521 // 'dropped' from the current schema) so let's no copy it in a random place.
4522 return;
4523 }
4524
4525 // TClonesArray master branch (has only the number of elements).
4526 Int_t n;
4527 b >> n;
4528 if ((n < 0) || (n > fMaximum)) {
4529 if (IsMissingCollection()) {
4530 n = 0;
4531 b.SetBufferOffset(b.Length()-sizeof(n));
4532 } else {
4533 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());
4534 n = 0;
4535 }
4536 }
4537 fNdata = n;
4538 TClonesArray* clones = reinterpret_cast<TClonesArray*>(fObject);
4539 if (clones->IsZombie()) {
4540 return;
4541 }
4542 // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4543 // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4544 // clones->Clear();
4545 clones->ExpandCreateFast(fNdata);
4546}
4547
4548////////////////////////////////////////////////////////////////////////////////
4549/// Read leaves into i/o buffers for this branch.
4550/// Case of a data member within a TClonesArray (fType == 31).
4551
4553{
4554 // No need to validate the address here, if we are a member of a split ClonesArray,
4555 // fID is positive
4556 // ValidateAddress();
4557
4558 if (fObject == nullptr)
4559 {
4560 // We have nowhere to copy the data (probably because the data member was
4561 // 'dropped' from the current schema) so let's no copy it in a random place.
4562 return;
4563 }
4564
4565 // TClonesArray sub-branch (contains the elements).
4567 TClonesArray* clones = reinterpret_cast<TClonesArray*>(fObject);
4568 if (clones->IsZombie()) {
4569 return;
4570 }
4572 if (info==nullptr) return;
4573 // Since info is not null, fReadActionSequence is not null either.
4574
4575 // Note, we could (possibly) save some more, by configuring the action
4576 // based on the value of fOnfileObject rather than pushing in on a stack.
4577 R__PushCache onfileObject(b, fOnfileObject, fNdata);
4578
4579 char **arr = reinterpret_cast<char **>(clones->GetObjectRef());
4580 char **end = arr + fNdata;
4581 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
4582}
4583
4584////////////////////////////////////////////////////////////////////////////////
4585/// Read leaves into i/o buffers for this branch.
4586/// For split-class branch, base class branch, data member branch, or top-level branch.
4587/// which do not have a branch count and are not a counter.
4588
4590{
4591 R__ASSERT(fBranchCount==nullptr);
4593
4595 if (fObject == nullptr)
4596 {
4597 // We have nowhere to copy the data (probably because the data member was
4598 // 'dropped' from the current schema) so let's no copy it in a random place.
4599 return;
4600 }
4601
4602 R__PushCache onfileObject(b, fOnfileObject, 1);
4603 // If not a TClonesArray or STL container master branch
4604 // or sub-branch and branch inherits from tobject,
4605 // then register with the buffer so that pointers are
4606 // handled properly.
4607 if (TestBit(kBranchObject)) {
4608 b.MapObject(reinterpret_cast<TObject*>(fObject));
4609 } else if (TestBit(kBranchAny)) {
4610 b.MapObject(fObject, fBranchClass);
4611 }
4612
4613 fNdata = 1;
4615 if (!info) {
4616 return;
4617 }
4618 // Since info is not null, fReadActionSequence is not null either.
4619 b.ApplySequence(*fReadActionSequence, fObject);
4620}
4621
4622////////////////////////////////////////////////////////////////////////////////
4623/// Read leaves into i/o buffers for this branch.
4624/// For split-class branch, base class branch, data member branch, or top-level branch.
4625/// which do have a branch count and are not a counter.
4626
4628{
4630
4632 if (fObject == nullptr)
4633 {
4634 // We have nowhere to copy the data (probably because the data member was
4635 // 'dropped' from the current schema) so let's no copy it in a random place.
4636 return;
4637 }
4638
4639 // If not a TClonesArray or STL container master branch
4640 // or sub-branch and branch inherits from tobject,
4641 // then register with the buffer so that pointers are
4642 // handled properly.
4643 if (TestBit(kBranchObject)) {
4644 b.MapObject(reinterpret_cast<TObject*>(fObject));
4645 } else if (TestBit(kBranchAny)) {
4646 b.MapObject(fObject, fBranchClass);
4647 }
4648
4649 fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4651 if (!info) {
4652 return;
4653 }
4654 R__PushCache onfileObject(b, fOnfileObject,
4655 1); // Here we have a single object that contains a variable size C-style array.
4656 // Since info is not null, fReadActionSequence is not null either.
4657 b.ApplySequence(*fReadActionSequence, fObject);
4658}
4659
4660////////////////////////////////////////////////////////////////////////////////
4661/// Read leaves into i/o buffers for this branch.
4662/// For split-class branch, base class branch, data member branch, or top-level branch.
4663/// which do not have a branch count and are a counter.
4664
4666{
4668 if (fObject == nullptr)
4669 {
4670 // We have nowhere to copy the data (probably because the data member was
4671 // 'dropped' from the current schema) so let's no copy it in a random place.
4672 return;
4673 }
4674
4675 // If not a TClonesArray or STL container master branch
4676 // or sub-branch and branch inherits from tobject,
4677 // then register with the buffer so that pointers are
4678 // handled properly.
4679 if (TestBit(kBranchObject)) {
4680 b.MapObject(reinterpret_cast<TObject*>(fObject));
4681 } else if (TestBit(kBranchAny)) {
4682 b.MapObject(fObject, fBranchClass);
4683 }
4684
4686 if (!info) {
4687 return;
4688 }
4689
4690 R__PushCache onfileObject(b, fOnfileObject, 1);
4691
4692 // Since info is not null, fReadActionSequence is not null either.
4693 b.ApplySequence(*fReadActionSequence, fObject);
4694 fNdata = (Int_t) GetValue(0, 0);
4695}
4696
4697////////////////////////////////////////////////////////////////////////////////
4698/// Read leaves into i/o buffers for this branch.
4699/// Non TObject, Non collection classes with a custom streamer.
4700
4702{
4704 if (fObject == nullptr)
4705 {
4706 // We have nowhere to copy the data (probably because the data member was
4707 // 'dropped' from the current schema) so let's no copy it in a random place.
4708 return;
4709 }
4710
4711 R__PushCache onfileObject(b, fOnfileObject, 1);
4713}
4714
4715////////////////////////////////////////////////////////////////////////////////
4716/// Unconfiguration Fill Leave function.
4717
4719{
4720 Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4721}
4722
4723////////////////////////////////////////////////////////////////////////////////
4724/// Delete any object we may have allocated on a previous call to SetAddress.
4725
4727{
4728 if (fObject && TestBit(kDeleteObject)) {
4729 if (IsAutoDelete() && fAddress != reinterpret_cast<char*>(&fObject)) {
4730 *(reinterpret_cast<char**>(fAddress)) = nullptr;
4731 }
4733 if (fType == 3) {
4734 // -- We are a TClonesArray master branch.
4735 TClonesArray::Class()->Destructor(fObject);
4736 fObject = nullptr;
4739 // -- We are a pointer to a TClonesArray.
4740 // We must zero the pointer in the object.
4741 *(reinterpret_cast<char**>(fAddress)) = nullptr;
4742 }
4743 } else if (fType == 4) {
4744 // -- We are an STL container master branch.
4746
4747 if (!proxy) {
4748 Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4749 fObject = nullptr;
4750 } else {
4752 if (needDelete && fID >= 0) {
4754 TStreamerElement* se = si->GetElement(fID);
4756 }
4757 if (needDelete) {
4759 proxy->Clear("force");
4760 }
4761 proxy->Destructor(fObject);
4762 fObject = nullptr;
4763 }
4765 // -- We are a pointer to an STL container.
4766 // We must zero the pointer in the object.
4767 *(reinterpret_cast<char**>(fAddress)) = nullptr;
4768 }
4769 } else {
4770 // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4772 if (!cl) {
4773 Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4774 fObject = nullptr;
4775 } else {
4777
4778 if (proxy) {
4779 if (fID >= 0) {
4781 TStreamerElement* se = si->GetElement(fID);
4784 proxy->Clear("force");
4785 }
4786 } else if (proxy->GetProperties()&TVirtualCollectionProxy::kNeedDelete) {
4788 proxy->Clear("force");
4789 }
4790
4791 }
4792 cl->Destructor(fObject);
4793 fObject = nullptr;
4794 }
4795 }
4796 }
4797}
4798
4799////////////////////////////////////////////////////////////////////////////////
4800/// Reset a Branch.
4801///
4802/// Existing i/o buffers are deleted.
4803/// Entries, max and min are reset.
4804///
4805
4807{
4809 for (Int_t i = 0; i < nbranches; ++i) {
4810 TBranch* branch = static_cast<TBranch*>(fBranches[i]);
4811 branch->Reset(option);
4812 }
4813 fBranchID = -1;
4815}
4816
4817////////////////////////////////////////////////////////////////////////////////
4818/// Reset a Branch after a Merge operation (drop data but keep customizations)
4819///
4820
4822{
4824 for (Int_t i = 0; i < nbranches; ++i) {
4825 TBranch* branch = static_cast<TBranch*>(fBranches[i]);
4826 branch->ResetAfterMerge(info);
4827 }
4829}
4830
4831////////////////////////////////////////////////////////////////////////////////
4832/// Set branch address to zero and free all allocated memory.
4833
4835{
4836 for (Int_t i = 0; i < fNleaves; ++i) {
4837 TLeaf* leaf = static_cast<TLeaf*>(fLeaves.UncheckedAt(i));
4838 //if (leaf) leaf->SetAddress(0);
4839 leaf->SetAddress(nullptr);
4840 }
4841
4842 // Note: We *must* do the sub-branches first, otherwise
4843 // we may delete the object containing the sub-branches
4844 // before giving them a chance to cleanup.
4846 for (Int_t i = 0; i < nbranches; ++i) {
4847 TBranch* br = static_cast<TBranch*>(fBranches[i]);
4848 if (br) br->ResetAddress();
4849 }
4850
4851 //
4852 // SetAddress may have allocated an object.
4853 //
4854
4855 ReleaseObject();
4856
4858 fAddress = nullptr;
4859 fObject = nullptr;
4860}
4861
4862////////////////////////////////////////////////////////////////////////////////
4863/// Release ownership of any allocated objects.
4864///
4865/// Note: This interface was added so that clone trees could
4866/// be told they do not own the allocated objects.
4867
4869{
4872 for (Int_t i = 0; i < nb; ++i) {
4873 TBranch* br = static_cast<TBranch*>(fBranches[i]);
4874 if (br->InheritsFrom(TBranchElement::Class())) {
4875 static_cast<TBranchElement*>(br)->ResetDeleteObject();
4876 }
4877 }
4878}
4879
4880////////////////////////////////////////////////////////////////////////////////
4881/// \brief Reset offset and StreamerInfo information from this branch.
4882/// \param[in] recurse When true call ResetInitInfo on all subbranches.
4883///
4884
4886{
4887 fInfo = nullptr;
4888 fInit = false;
4889 fInitOffsets = false;
4890 fCurrentClass = nullptr;
4891 delete fReadActionSequence;
4892 fReadActionSequence = nullptr;
4893 delete fFillActionSequence;
4894 fFillActionSequence = nullptr;
4895
4896 if (recurse) {
4898 for (Int_t i = 0; i < nbranches; ++i) {
4899 TBranchElement *sub = static_cast<TBranchElement*>(fBranches[i]);
4900 sub->ResetInitInfo(true);
4901 }
4902 }
4903}
4904
4905////////////////////////////////////////////////////////////////////////////////
4906/// Point this branch at an object.
4907///
4908/// For a sub-branch, addr is a pointer to the branch object.
4909///
4910/// For a top-level branch the meaning of addr is as follows:
4911///
4912/// If addr is zero, then we allocate a branch object
4913/// internally and the branch is the owner of the allocated
4914/// object, not the caller. However the caller may obtain
4915/// a pointer to the branch object with GetObject().
4916/// The pointer is reset to zero (nullptr) when the relevant
4917/// branch object is destroyed.
4918///
4919/// Example:
4920/// ~~~ {.cpp}
4921/// branch->SetAddress(0);
4922/// Event* event = branch->GetObject();
4923/// ... Do some work.
4924/// ~~~
4925/// If addr is not zero, but the pointer addr points at is
4926/// zero, then we allocate a branch object and set the passed
4927/// pointer to point at the allocated object. The caller
4928/// owns the allocated object and is responsible for deleting
4929/// it when it is no longer needed.
4930///
4931/// Example:
4932/// ~~~ {.cpp}
4933/// Event* event = 0;
4934/// branch->SetAddress(&event);
4935/// ... Do some work.
4936/// delete event;
4937/// event = 0;
4938/// ~~~
4939/// If addr is not zero and the pointer addr points at is
4940/// also not zero, then the caller has allocated a branch
4941/// object and is asking us to use it. The caller owns it
4942/// and must delete it when it is no longer needed.
4943///
4944/// Example:
4945/// ~~~ {.cpp}
4946/// Event* event = new Event();
4947/// branch->SetAddress(&event);
4948/// ... Do some work.
4949/// delete event;
4950/// event = 0;
4951/// ~~~
4952/// These rules affect users of TTree::Branch(),
4953/// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4954/// as well because those routines call this one.
4955///
4956/// An example of a tree with branches with objects allocated
4957/// and owned by us:
4958/// ~~~ {.cpp}
4959/// TFile* f1 = new TFile("myfile_original.root");
4960/// TTree* t1 = f1->Get<TTree>("MyTree");
4961/// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4962/// TTree* t2 = t1->Clone(0);
4963/// for (Int_t i = 0; i < 10; ++i) {
4964/// t1->GetEntry(i);
4965/// t2->Fill();
4966/// }
4967/// t2->Write()
4968/// delete f2;
4969/// f2 = 0;
4970/// delete f1;
4971/// f1 = 0;
4972/// ~~~
4973/// An example of a branch with an object allocated by us,
4974/// but owned by the caller:
4975/// ~~~ {.cpp}
4976/// TFile* f = new TFile("myfile.root", "recreate");
4977/// TTree* t = new TTree("t", "A test tree.")
4978/// Event* event = 0;
4979/// TBranchElement* br = t->Branch("event.", &event);
4980/// for (Int_t i = 0; i < 10; ++i) {
4981/// ... Fill event with meaningful data in some way.
4982/// t->Fill();
4983/// }
4984/// t->Write();
4985/// delete event;
4986/// event = 0;
4987/// delete f;
4988/// f = 0;
4989/// ~~~
4990/// Notice that the only difference between this example
4991/// and the following example is that the event pointer
4992/// is zero when the branch is created.
4993///
4994/// An example of a branch with an object allocated and
4995/// owned by the caller:
4996/// ~~~ {.cpp}
4997/// TFile* f = new TFile("myfile.root", "recreate");
4998/// TTree* t = new TTree("t", "A test tree.")
4999/// Event* event = new Event();
5000/// TBranchElement* br = t->Branch("event.", &event);
5001/// for (Int_t i = 0; i < 10; ++i) {
5002/// ... Fill event with meaningful data in some way.
5003/// t->Fill();
5004/// }
5005/// t->Write();
5006/// delete event;
5007/// event = 0;
5008/// delete f;
5009/// f = 0;
5010/// ~~~
5011/// If AutoDelete is on (see TBranch::SetAutoDelete),
5012/// the top level objet will be deleted and recreate
5013/// each time an entry is read, whether or not the
5014/// TTree owns the object.
5015
5017{
5018 SetAddressImpl(addr, (addr == nullptr), 0);
5019}
5020
5021/// See TBranchElement::SetAddress.
5022/// If implied is true, we do not over-ride existing address for
5023/// sub-branches.
5024/// The `offset` is the offset of the sub-object within its parent,
5025/// it is already included in the addr but is still needed to be added
5026/// the OnfileObject address when/if we need to use that address.
5028{
5029 //
5030 // Don't bother if we are disabled.
5031 //
5032
5033 if (TestBit(kDoNotProcess)) {
5034 return;
5035 }
5036
5037 //
5038 // FIXME: When would this happen?
5039 //
5040
5041 if (fType < -1) {
5042 return;
5043 }
5044
5045 //
5046 // Special case when called from code generated by TTree::MakeClass.
5047 //
5048
5049 if (Longptr_t(addr) == -1) {
5050 // FIXME: Do we have to release an object here?
5051 // ReleaseObject();
5052 fAddress = reinterpret_cast<char*>(-1);
5053 fObject = reinterpret_cast<char*>(-1);
5056 return;
5057 }
5058
5059 //
5060 // Reset last read entry number, we have a new user object now.
5061 //
5062
5063 fReadEntry = -1;
5064
5065 //
5066 // Make sure our branch class is instantiated.
5067 //
5069 if( fTargetClass.GetClassName()[0] ) {
5071 }
5072
5073 //
5074 // Try to build the streamer info.
5075 //
5076
5078
5079 // FIXME: Warn about failure to get the streamer info here?
5080
5081 //
5082 // We may have allocated an object last time we were called.
5083 //
5084
5085 if (fObject && TestBit(kDeleteObject)){
5086 ReleaseObject();
5087 }
5088
5089 //
5090 // Remember the pointer to the pointer to our object.
5091 //
5092
5093 fAddress = reinterpret_cast<char*>(addr);
5094 if (fAddress != reinterpret_cast<char*>(&fObject)) {
5095 fObject = nullptr;
5096 }
5099
5100 //
5101 // Do special stuff if we got called from a MakeClass class.
5102 // Allow sub-branches to have independently set addresses.
5103 //
5104
5105 if (TestBit(kDecomposedObj)) {
5106 if (fID > -1) {
5107 // We are *not* a top-level branch.
5108 if (!info) {
5109 // No streamer info, give up.
5110 // FIXME: We should have an error message here.
5111 fObject = fAddress;
5112 } else {
5113 // Compensate for the fact that the i/o routines
5114 // will add the streamer offset to the address.
5115 fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
5116 }
5117 return;
5118 }
5119 }
5120
5121 //
5122 // Check whether the container type is still the same
5123 // to support schema evolution; what is written on the file
5124 // may no longer match the class code which is loaded.
5125 //
5126
5127 if (fType == 3) {
5128 // split TClonesArray, counter/master branch.
5130 if (clm) {
5131 // In case clm derives from an abstract class.
5132 clm->BuildRealData();
5133 clm->GetStreamerInfo();
5134 }
5136 if (newType && (newType != TClonesArray::Class())) {
5137 // The data type of the container has changed.
5138 //
5139 // Let's check if it is a compatible type:
5140 bool matched = false;
5141 if (newType->GetCollectionProxy()) {
5142 TClass *content = newType->GetCollectionProxy()->GetValueClass();
5143 if (clm == content) {
5144 matched = true;
5145 } else {
5146 Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
5147 }
5148 } else {
5149 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());
5150 }
5151 if (matched) {
5152 // Change from 3/31 to 4/41
5153 SetType(4);
5154 // Set the proxy.
5155 fSTLtype = newType->GetCollectionType();
5156 fCollProxy = newType->GetCollectionProxy()->Generate();
5157
5161
5164 } else if (IsAssociativeContainer(*fCollProxy)) {
5167 } else {
5169 }
5170 } else {
5171 // FIXME: Must maintain fObject here as well.
5172 fAddress = nullptr;
5174 }
5175 }
5176 } else if (fType == 4) {
5177 // split STL container, counter/master branch.
5179 if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
5180 // Let's check if it is a compatible type:
5181 TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
5183 if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
5184 delete fCollProxy;
5186 fCollProxy = newType->GetCollectionProxy()->Generate();
5188 for (Int_t i = 0; i < nbranches; ++i) {
5190 br->fCollProxy = nullptr;
5191 if (br->fReadActionSequence) {
5192 br->SetReadActionSequence();
5193 }
5194 if (br->fFillActionSequence) {
5195 br->SetFillActionSequence();
5196 }
5197 }
5202 delete fIterators;
5203 delete fPtrIterators;
5206 } else if (IsAssociativeContainer(*fCollProxy)) {
5209 } else {
5211 }
5212 }
5213 else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=nullptr) && (newProxy->GetValueClass()!=nullptr)) {
5214 // Let see if there is a rule to convert the content of the collection into each other.
5215 if (newType->GetSchemaRules()->HasRuleWithSourceClass( oldProxy->GetCollectionClass()->GetName())) {
5216 TClass *oldValueClass = oldProxy->GetValueClass();
5217 delete fCollProxy;
5219 fCollProxy = newType->GetCollectionProxy()->Generate();
5221 for (Int_t i = 0; i < nbranches; ++i) {
5223 br->fCollProxy = nullptr;
5224 if (br->fBranchClass == oldValueClass) {
5225 br->SetTargetClass(fCollProxy->GetValueClass()->GetName());
5226 }
5227 if (br->fReadActionSequence) {
5228 br->SetReadActionSequence();
5229 }
5230 if (br->fFillActionSequence) {
5231 br->SetFillActionSequence();
5232 }
5233 }
5238 delete fIterators;
5239 delete fPtrIterators;
5242 } else if (IsAssociativeContainer(*fCollProxy)) {
5245 } else {
5247 }
5248 } else {
5249 Error("SetAddress","For %s, we can not convert %s into %s\n",
5250 GetName(),oldProxy->GetCollectionClass()->GetName(),newType->GetName());
5251 fAddress = nullptr;
5252 fObject = nullptr;
5254 return;
5255 }
5256 }
5257 else if ((newType == TClonesArray::Class()) && (oldProxy->GetValueClass() && !oldProxy->HasPointers() && oldProxy->GetValueClass()->IsTObject()))
5258 {
5259 // The new collection and the old collection are not compatible,
5260 // we cannot use the new collection to read the data.
5261 // Actually we could check if the new collection is a
5262 // compatible ROOT collection.
5263
5264 // We cannot insure that the TClonesArray is set for the
5265 // proper class (oldProxy->GetValueClass()), so we assume that
5266 // the transformation was done properly by the class designer.
5267
5268 // Change from 4/41 to 3/31
5269 SetType(3);
5270 // Reset the proxy.
5271 fSTLtype = kNone;
5272 switch(fStreamerType) {
5276 break;
5280 break;
5283 break;
5284 }
5285 fClonesClass = oldProxy->GetValueClass();
5287 delete fCollProxy;
5288 fCollProxy = nullptr;
5290 if (clm) {
5291 clm->BuildRealData(); //just in case clm derives from an abstract class
5292 clm->GetStreamerInfo();
5293 }
5297 delete fIterators;
5298 fIterators = nullptr;
5299 delete fPtrIterators;
5300 fPtrIterators =nullptr;
5301 } else {
5302 // FIXME: We must maintain fObject here as well.
5303 Error("SetAddress","For %s can not convert %s into %s\n",GetName(),GetCurrentClass()->GetName(),newType->GetName());
5304 fAddress = nullptr;
5306 return;
5307 }
5308 } else {
5309 if (!fIterators && !fPtrIterators) {
5312 } else if (IsAssociativeContainer(*fCollProxy)) {
5315 } else {
5317 }
5318 }
5319 }
5320 }
5321
5322 //
5323 // Establish the semantics of fObject and fAddress.
5324 //
5325 // Top-level branch:
5326 // fObject is a ptr to the object,
5327 // fAddress is a ptr to a pointer to the object.
5328 //
5329 // Sub-branch:
5330 // fObject is a ptr to the object,
5331 // fAddress is the same as fObject.
5332 //
5333 //
5334 // There are special cases for TClonesArray and STL containers.
5335 // If there is no user-provided object, we allocate one. We must
5336 // also initialize any STL container proxy.
5337 //
5338
5339 if (fType == 3) {
5340 // -- We are a TClonesArray master branch.
5341 if (fAddress) {
5342 // -- We have been given a non-zero address, allocate if necessary.
5344 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5345 // Case of an embedded TClonesArray.
5346 fObject = fAddress;
5347 // Check if it has already been properly built.
5348 TClonesArray* clones = reinterpret_cast<TClonesArray*>(fObject);
5349 if (!clones->GetClass()) {
5351 }
5352 } else {
5353 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5354 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5355 if ((fStreamerType != -1) &&
5358 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5359 } else if (fStreamerType == -1) {
5360 // -- We are a top-level branch.
5361 TClonesArray** pp = reinterpret_cast<TClonesArray**>(fAddress);
5362 if (!*pp) {
5363 // -- Caller wants us to allocate the clones array, but they will own it.
5364 *pp = new TClonesArray(fClonesClass);
5365 }
5366 fObject = reinterpret_cast<char*>(*pp);
5367 } else {
5368 // -- We are a pointer to a TClonesArray.
5369 // Note: We do this so that the default constructor,
5370 // or the i/o constructor can be lazy.
5371 TClonesArray** pp = reinterpret_cast<TClonesArray**>(fAddress);
5372 if (!*pp) {
5373 // -- Caller wants us to allocate the clones array, but they will own it.
5374 *pp = new TClonesArray(fClonesClass);
5375 }
5376 fObject = reinterpret_cast<char*>(*pp);
5377 }
5378 }
5379 } else {
5380 // -- We have been given a zero address, allocate for top-level only.
5382 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5383 // Case of an embedded TClonesArray.
5384 Error("SetAddress", "Embedded TClonesArray given a zero address for branch '%s'", GetName());
5385 } else {
5386 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5387 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5388 if ((fStreamerType != -1) &&
5391 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5392 } else if (fStreamerType == -1) {
5393 // -- We are a top-level branch.
5394 // Idea: Consider making a zero address not allocate.
5396 fObject = reinterpret_cast<char*>(new TClonesArray(fClonesClass));
5397 fAddress = reinterpret_cast<char*>(&fObject);
5398 } else {
5399 // -- We are a sub-branch which is a pointer to a TClonesArray.
5400 Error("SetAddress", "Embedded pointer to a TClonesArray given a zero address for branch '%s'", GetName());
5401 }
5402 }
5403 }
5404 } else if (fType == 4) {
5405 // -- We are an STL container master branch.
5406 //
5407 // Initialize fCollProxy.
5409 if (fAddress) {
5410 // -- We have been given a non-zero address, allocate if necessary.
5414 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5415 // Case of an embedded STL container.
5416 // Note: We test for the kObject and kAny types to support
5417 // the (unwise) choice of inheriting from an STL container.
5418 fObject = fAddress;
5419 } else {
5420 // We are either a top-level branch or subbranch which is a pointer to an STL container.
5421 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5423 Error("SetAddress",
5424 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5426 } else if (fStreamerType == -1) {
5427 // -- We are a top-level branch.
5428 void** pp = reinterpret_cast<void**>(fAddress);
5429 if (!*pp) {
5430 // -- Caller wants us to allocate the STL container, but they will own it.
5431 *pp = proxy->New();
5432 if (!(*pp)) {
5433 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5434 // FIXME: Should we do this? Lots of other code wants
5435 // fAddress to be zero if no fObject, but is
5436 // that a good thing?
5437 fAddress = nullptr;
5439 }
5440 }
5441 fObject = reinterpret_cast<char*>(*pp);
5442 } else {
5443 // -- We are a pointer to an STL container.
5444 // Note: We do this so that the default constructor,
5445 // or the i/o constructor can be lazy.
5446 void** pp = reinterpret_cast<void**>(fAddress);
5447 if (!*pp) {
5448 // -- Caller wants us to allocate the STL container, but they will own it.
5449 *pp = proxy->New();
5450 if (!(*pp)) {
5451 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5452 // FIXME: Should we do this? Lots of other code wants
5453 // fAddress to be zero if no fObject, but is
5454 // that a good thing?
5455 fAddress = nullptr;
5457 }
5458 }
5459 fObject = reinterpret_cast<char*>(*pp);
5460 }
5461 }
5462 } else {
5463 // -- We have been given a zero address, allocate for top-level only.
5467 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5468 // Case of an embedded STL container.
5469 // Note: We test for the kObject and kAny types to support
5470 // the (unwise) choice of inheriting from an STL container.
5471 Error("SetAddress", "Embedded STL container given a zero address for branch '%s'", GetName());
5472 } else {
5473 // We are either a top-level branch or sub-branch which is a pointer to an STL container.
5474 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5476 Error("SetAddress",
5477 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5479 } else if (fStreamerType == -1) {
5480 // -- We are a top-level branch, allocate.
5482 fObject = reinterpret_cast<char*>(proxy->New());
5483 if (fObject) {
5484 fAddress = reinterpret_cast<char*>(&fObject);
5485 } else {
5486 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5487 // FIXME: Should we do this? Lots of other code wants
5488 // fAddress to be zero if no fObject, but is
5489 // that a good thing?
5490 fAddress = nullptr;
5492 }
5493 } else {
5494 // -- We are a sub-branch which is a pointer to an STL container.
5495 Error("SetAddress", "Embedded pointer to an STL container given a zero address for branch '%s'", GetName());
5496 }
5497 }
5498 }
5499 } else if (fType == 41) {
5500 // -- We are an STL container sub-branch.
5501 // Initialize fCollProxy.
5503 // We are not at top-level branch.
5504 fObject = fAddress;
5505 } else if (fID < 0) {
5506 // -- We are a top-level branch.
5507 char** pp = reinterpret_cast<char**>(fAddress);
5508 if (pp && *pp) {
5509 // -- Caller provided an i/o buffer for us to use.
5510 fObject = *pp;
5511 } else {
5512 // -- Caller did not provide an i/o buffer for us to use, we must make one for ourselves.
5513 if (clOfBranch) {
5514 if (!pp) {
5515 // -- Caller wants us to own the object.
5517 }
5518 fObject = reinterpret_cast<char*>(clOfBranch->New());
5519 if (pp) {
5520 *pp = fObject;
5521 } else {
5522 fAddress = reinterpret_cast<char*>(&fObject);
5523 }
5524 } else {
5525 Error("SetAddress", "I have no TClass for branch %s, so I cannot allocate an I/O buffer!", GetName());
5526 if (pp) {
5527 fObject = nullptr;
5528 *pp = nullptr;
5529 }
5530 }
5531 }
5532 } else {
5533 // -- We are *not* a top-level branch.
5534 fObject = fAddress;
5535 }
5536
5537 if (!info) {
5538 // FIXME: We need and error message here, no streamer info, so cannot set offsets.
5539 return;
5540 }
5541
5542 // We do this only once because it depends only on
5543 // the type of our object, not on its address.
5544 if (!fInitOffsets) {
5546 }
5547
5548 // We are split, recurse down to our sub-branches.
5549 //
5550 // FIXME: This is a tail recursion, we burn stack.
5552 char *localObject = fObject;
5553 if (fOnfileObject && this != GetMother()) {
5555 }
5556 for (Int_t i = 0; i < nbranches; ++i) {
5557 TBranch *abranch = static_cast<TBranch*>(fBranches.UncheckedAt(i));
5558 // FIXME: This is a tail recursion!
5559 if (fBranchOffset[i] != TStreamerInfo::kMissing && !(implied && abranch->TestBit(kAddressSet))) {
5560 abranch->SetAddressImpl(localObject + fBranchOffset[i], implied, fBranchOffset[i]);
5561 abranch->SetBit(kAddressSet);
5562 if (TestBit(kDecomposedObj) != abranch->TestBit(kDecomposedObj))
5563 abranch->SetMakeClass(TestBit(kDecomposedObj));
5564 } else {
5565 // When the member is missing, just leave the address alone
5566 // (since setting explicitly to 0 would trigger error/warning
5567 // messages).
5568 // abranch->SetAddress(0);
5569 abranch->SetBit(kAddressSet);
5570 }
5571 }
5572}
5573
5574////////////////////////////////////////////////////////////////////////////////
5575/// Reset the basket size for all sub-branches of this branch element.
5576
5578{
5581 for (Int_t i = 0; i < nbranches; ++i) {
5582 TBranch* branch = static_cast<TBranch*>(fBranches[i]);
5583 branch->SetBasketSize(fBasketSize);
5584 }
5585}
5586
5587////////////////////////////////////////////////////////////////////////////////
5588/// Set the branch counter for this branch.
5589
5591{
5593 if (fBranchCount==nullptr) return;
5594
5595 TLeafElement* leafOfCounter = static_cast<TLeafElement*>(brOfCounter->GetListOfLeaves()->At(0));
5596 TLeafElement* leaf = static_cast<TLeafElement*>(GetListOfLeaves()->At(0));
5597 if (leafOfCounter && leaf) {
5598 leaf->SetLeafCount(leafOfCounter);
5599 } else {
5600 if (!leafOfCounter) {
5601 Warning("SetBranchCount", "Counter branch %s for branch %s has no leaves!", brOfCounter->GetName(), GetName());
5602 }
5603 if (!leaf) {
5604 Warning("SetBranchCount", "Branch %s has no leaves!", GetName());
5605 }
5606 }
5607}
5608
5609////////////////////////////////////////////////////////////////////////////////
5610/// Set the branch in a mode where the object are decomposed
5611/// (Also known as MakeClass mode).
5612/// Return whether the setting was possible (it is not possible for
5613/// TBranch and TBranchObject).
5614
5616{
5617 if (decomposeObj)
5618 SetBit(kDecomposedObj); // Same as SetBit(kMakeClass)
5619 else
5621
5623 for (Int_t i = 0; i < nbranches; ++i) {
5624 TBranchElement* branch = static_cast<TBranchElement*>(fBranches[i]);
5625 branch->SetMakeClass(decomposeObj);
5626 }
5629
5630 return true;
5631}
5632
5633////////////////////////////////////////////////////////////////////////////////
5634/// Set object this branch is pointing to.
5635
5637{
5638 if (TestBit(kDoNotProcess)) {
5639 return;
5640 }
5641 fObject = reinterpret_cast<char*>(obj);
5642 SetAddress( &fObject );
5643}
5644
5645////////////////////////////////////////////////////////////////////////////////
5646/// Set offset of the object (to which the data member represented by this
5647/// branch belongs) inside its containing object (if any).
5648
5650{
5651 // We need to make sure that the Read and Write action's configuration
5652 // properly reflect this value.
5653
5655 SetMissing();
5656 return;
5657 }
5658
5659 if (fReadActionSequence) {
5661 }
5662 if (fFillActionSequence) {
5664 }
5665 fOffset = offset;
5666}
5667
5668////////////////////////////////////////////////////////////////////////////////
5669/// Set offset of the object (to which the data member represented by this
5670/// branch belongs) inside its containing object (if any) to mark it as missing.
5671
5673{
5674 // We need to make sure that the Read and Write action's configuration
5675 // properly reflect this value.
5676
5677 if (fReadActionSequence) {
5679 }
5680 if (fFillActionSequence) {
5682 }
5684}
5685
5686
5687////////////////////////////////////////////////////////////////////////////////
5688/// Set the sequence of actions needed to read the data out of the buffer.
5690{
5691 // A 'split' node does not store data itself (it has not associated baskets)
5692 const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
5693
5694 if (!isSplitNode) {
5695 fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
5696 }
5697
5698 if (actionSequence) delete actionSequence;
5700
5701 actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
5702
5703 if (!isSplitNode)
5704 fNewIDs.erase(fNewIDs.begin());
5705
5706 else if (fInitOffsets && fType != 3 && fType != 4) {
5707 // fObject has the address of the sub-object but the streamer action have
5708 // offset relative to the parent.
5709
5710 // Note: We skipped this for the top node of split collection because the
5711 // sequence is about the content, we need to review what happens where an
5712 // action related to the collection itself will land.
5713 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
5714
5715 auto index = parent->fBranches.IndexOf(this);
5716 if (index >= 0) {
5717 actionSequence->AddToOffset( - parent->fBranchOffset[index] );
5718 }
5719 } // else it will be done by InitOffsets
5720}
5721
5722////////////////////////////////////////////////////////////////////////////////
5723/// Set the sequence of actions needed to read the data out of the buffer.
5725{
5726 if (fInfo == nullptr) {
5727 // We are called too soon. We will be called again by InitInfo
5728 return;
5729 }
5730
5732 TClass *originalClass = nullptr;
5734 if (fType == 41) {
5737 } else {
5739 if (GetParentClass() == info->GetClass()) {
5743 } else {
5745 }
5746 } else if (GetCollectionProxy()) {
5747 // Base class and embedded objects.
5749 }
5750 }
5751 } else if (fType == 31) {
5753 } else if (0<=fType && fType<=2) {
5754 // Note: this still requires the ObjectWise sequence to not be optimized!
5756 } else if ( fType == 4 && !fNewIDs.empty()) {
5759 } else if ( fType == 3 && !fNewIDs.empty()) {
5762 }
5763
5764 if (create) {
5766 }
5767}
5768
5769////////////////////////////////////////////////////////////////////////////////
5770/// Set the ReadLeaves pointer to execute the expected operations.
5771
5773{
5774 if (TestBit(kDecomposedObj)) {
5776 } else if (fType == 4) {
5778 } else if (fType == 41) {
5782 } else {
5784 }
5785 } else {
5787 }
5788 } else if (fType == 3) {
5790 } else if (fType == 31) {
5792 } else if (fType < 0) {
5794 } else if (fType == 0 && fID == -1) {
5795 // top-level branch.
5797 if (hasCustomStreamer) {
5798 // We are in the case where the object did *not* have a custom
5799 // Streamer when the TTree was written but now *does* have a custom
5800 // Streamer thus we must use it.
5802 } else {
5804 }
5805 } else if (fType <= 2) {
5806 // split-class branch, base class branch or data member branch.
5807 if (fBranchCount) {
5811 } else {
5813 }
5814 } else {
5815 Fatal("SetReadLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5816 }
5817
5819}
5820
5821////////////////////////////////////////////////////////////////////////////////
5822/// Set the sequence of actions needed to write the data out from the buffer.
5823
5825{
5826 if (fInfo == nullptr) {
5827 // We are called too soon. We will be called again by InitInfo
5828 return;
5829 }
5830
5832 TClass *originalClass = nullptr;
5834 if (fType == 41) {
5837 } else {
5839 if (GetParentClass() == info->GetClass()) {
5840 // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
5841 // originalClass = fBranchClass;
5842 // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter;
5843 // } else {
5845 // }
5846 } else if (GetCollectionProxy()) {
5847 // Base class and embedded objects.
5849 }
5850 }
5851 } else if (fType == 31) {
5853 } else if (0<=fType && fType<=2) {
5854 // Note: this still requires the ObjectWise sequence to not be optimized!
5856 } else if ( fType == 4 && !fNewIDs.empty()) {
5859 } else if ( fType == 3 && !fNewIDs.empty()) {
5862 }
5863
5864 if (create) {
5866 }
5867}
5868
5869////////////////////////////////////////////////////////////////////////////////
5870/// Set the FillLeaves pointer to execute the expected operations.
5871
5873{
5874 if (TestBit(kDecomposedObj) && ((fType==3)||(fType==31))) {
5876 } else if (fType == 4) {
5878 } else if (fType == 41) {
5882 } else {
5884 }
5887 } else {
5889 }
5890 } else if (fType == 3) {
5892 } else if (fType == 31) {
5894 } else if (fType < 0) {
5896 } else if (fType <=2) {
5897 //split-class branch, base class branch, data member branch, or top-level branch.
5898 if (fBranchCount) {
5902 } else {
5904 }
5905 } else {
5906 Fatal("SetFillLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5907 }
5908
5910}
5911
5912////////////////////////////////////////////////////////////////////////////////
5913/// Set the name of the class of the in-memory object into which the data will
5914/// loaded.
5915
5917{
5918 if (name == nullptr) return;
5919
5920 if (strcmp(fTargetClass.GetClassName(),name) != 0 )
5921 {
5922 // We are changing target class, let's reset the meta information and
5923 // the sub-branches.
5924
5925 ResetInitInfo(/*recurse=*/ false);
5926
5928 for (Int_t i = 0; i < nbranches; ++i) {
5929 TBranchElement *sub = static_cast<TBranchElement*>(fBranches[i]);
5930
5931 if (sub->fTargetClass == fTargetClass ) {
5932 sub->SetTargetClass(name);
5933 } else {
5934 // Since the top level changes, the StreamerInfo (in particular for split collection)
5935 // may still need to change (and the info might be updated else (see for example SetAddress for the
5936 // the case fType 4/41)
5937 sub->ResetInitInfo(true);
5938 }
5939 if (sub->fParentClass == fTargetClass ) {
5941 }
5942 }
5944 }
5945
5946}
5947
5948////////////////////////////////////////////////////////////////////////////////
5949/// If the branch address is not set, we set all addresses starting with
5950/// the top level parent branch. This is required to be done in order for
5951/// GetOffset to be correct and for GetEntry to run.
5952
5954{
5955 // Check to see if the user changed the branch address on us.
5957
5959 // -- Do nothing if already setup or if we are a MakeClass branch.
5960 return;
5961 }
5963}
5964
5965////////////////////////////////////////////////////////////////////////////////
5966/// If the branch address is not set, we set all addresses starting with
5967/// the top level parent branch. This is required to be done in order for
5968/// GetOffset to be correct and for GetEntry to run.
5969
5971{
5972 if (TestBit((long)kDoNotProcess|(long)kAddressSet)) {
5973 // -- Do nothing if we have been told not to.
5974 // Or the data member in this branch is not longer part of the
5975 // parent's layout.
5976 return;
5977 }
5978
5979 //--------------------------------------------------------------------------
5980 // Check if we are splited STL collection of pointers
5981 /////////////////////////////////////////////////////////////////////////////
5982
5984 {
5985 TBranchElement *parent = static_cast<TBranchElement*>(GetMother()->GetSubBranch( this ));
5986
5987 // Make sure the StreamerInfo is loaded and initialized.
5988 GetInfoImp();
5989
5990 if( !parent->GetAddress() )
5991 parent->SetAddress( nullptr );
5992 return;
5993 }
5994
5995 //--------------------------------------------------------------------------
5996 // Any other case
5997 /////////////////////////////////////////////////////////////////////////////
5998
5999 TBranchElement* mother = static_cast<TBranchElement*>(GetMother());
6000 if (!mother) {
6001 return;
6002 }
6003 TClass* cl = TClass::GetClass(mother->GetClassName());
6004
6005 // Make sure the StreamerInfo is loaded and initialized.
6006 GetInfoImp();
6007
6008 if (!cl) {
6009 return;
6010 }
6011
6012 if (!mother->GetAddress()) {
6013 // -- Our top-level branch has no address.
6014 bool motherStatus = mother->TestBit(kDoNotProcess);
6015 mother->ResetBit(kDoNotProcess);
6016 // Note: This will allocate an object.
6017 mother->SetAddress(nullptr);
6019 }
6020}
6021
6022////////////////////////////////////////////////////////////////////////////////
6023/// Stream an object of class TBranchElement.
6024
6026{
6027 if (R__b.IsReading()) {
6028 R__b.ReadClassBuffer(TBranchElement::Class(), this);
6033 // The fAddress and fObject data members are not persistent,
6034 // therefore we do not own anything.
6035 // Also clear the bit possibly set by the schema evolution.
6037 // Fixup a case where the TLeafElement was missing
6038 if ((fType == 0) && (fLeaves.GetEntriesFast() == 0)) {
6039 TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
6040 leaf->SetTitle(GetTitle());
6041 fNleaves = 1;
6042 fLeaves.Add(leaf);
6043 fTree->GetListOfLeaves()->Add(leaf);
6044 }
6045
6046 // SetReadLeavesPtr();
6047 }
6048 else {
6050 fDirectory = nullptr; // to avoid recursive calls
6051 {
6052 // Save class version.
6054 // Record only positive 'version number'
6055 if (fClassVersion < 0) {
6057 }
6058 // TODO: Should we clear the kDeleteObject bit before writing?
6059 // If we did we would have to remember the old value and
6060 // put it back, we wouldn't want to forget that we owned
6061 // something just because we got written to disk.
6062 R__b.WriteClassBuffer(TBranchElement::Class(), this);
6063 // Restore class version.
6065 }
6066 //
6067 // Mark all streamer infos used by this branch element
6068 // to be written to our output file.
6069 //
6070 {
6071 R__b.ForceWriteInfo(GetInfoImp(), true);
6072 }
6073 //
6074 // If we are a clones array master branch, or an
6075 // STL container master branch, we must also mark
6076 // the streamer infos used by the value class to
6077 // be written to our output file.
6078 //
6079 if (fType == 3) {
6080 // -- TClonesArray, counter/master branch
6081 //
6082 // We must mark the streamer info for the
6083 // value class to be written to the file.
6084 //
6085 TClass* cl = fClonesClass;
6086 if (cl) {
6087 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6088 }
6089 }
6090 else if (fType == 4) {
6091 // -- STL container, counter/master branch
6092 //
6093 // We must mark the streamer info for the
6094 // value class to be written to the file.
6095 //
6097 if (cp) {
6098 TClass* cl = cp->GetValueClass();
6099 if (cl) {
6100 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6101 }
6102 }
6103 }
6104 // If we are in a separate file, then save
6105 // ourselves as an independent key.
6106 if (!dirsav) {
6107 // Note: No need to restore fDirectory, it was already zero.
6108 return;
6109 }
6110 if (!dirsav->IsWritable()) {
6112 return;
6113 }
6115 if (!pdirectory) {
6117 return;
6118 }
6119 const char* treeFileName = pdirectory->GetFile()->GetName();
6121 const char* motherFileName = treeFileName;
6122 if (mother && (mother != this)) {
6123 motherFileName = mother->GetFileName();
6124 }
6125 if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
6126 dirsav->WriteTObject(this);
6127 }
6129 }
6130}
6131
6132
6133////////////////////////////////////////////////////////////////////////////////
6134/// Split class cl into sub-branches of this branch.
6135///
6136/// This version of Unroll was formerly embedded in TTree::BronchExec
6137/// It is moved here so we can make sure to call SetReadActionSequence.
6138
6140{
6141 //
6142 // Do we have a final dot in our name?
6143 //
6144
6145 // Note: The branch constructor which takes a folder as input
6146 // creates top-level branch names with dots in them to
6147 // indicate the folder hierarchy.
6148 const char* dot = strchr(name, '.');
6149 Int_t nch = strlen(name);
6150 bool dotlast = false;
6151 if (nch && (name[nch-1] == '.')) {
6152 dotlast = true;
6153 }
6154
6155 // Loop on all public data members of the class and its base classes and create branches for each one.
6156 TObjArray* blist = this->GetListOfBranches();
6157 TIter next(sinfo->GetElements());
6158 TStreamerElement* element = nullptr;
6159 TString bname;
6160 for (Int_t id = 0; (element = static_cast<TStreamerElement*>(next())); ++id) {
6161 if (element->IsA() == TStreamerArtificial::Class()) {
6162 continue;
6163 }
6164 if (element->TestBit(TStreamerElement::kRepeat)) {
6165 continue;
6166 }
6168 continue;
6169 }
6170 char* pointer = (objptr + element->GetOffset());
6171 // FIXME: This is not good enough, an STL container can be
6172 // a base, and the test will fail.
6173 // See TBranchElement::InitializeOffsets() for the
6174 // correct test.
6175 bool isBase = (element->IsA() == TStreamerBase::Class());
6176 if (isBase) {
6177 TClass* clbase = element->GetClassPointer();
6178 if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) {
6179 // Note: TStreamerInfo::Compile() leaves this element
6180 // out of the optimized info, although it does
6181 // exists in the non-compiled and non-optimized info.
6182 // FIXME: The test that TStreamerInfo::Compile() uses
6183 // is element->GetType() < 0, so that is what
6184 // we should do as well.
6185 continue;
6186 }
6187 if (clbase->GetListOfRealData()->GetSize() == 0) {
6188 // Do not create a branch for empty bases.
6189 continue;
6190 }
6191 }
6192 if (dot) {
6193 if (dotlast) {
6194 bname.Form("%s%s", name, element->GetFullName());
6195 } else {
6196 // FIXME: We are in the case where we have a top-level
6197 // branch name that was created by the branch
6198 // constructor which takes a folder as input.
6199 // The internal dots in the name are in place of
6200 // of the original slashes and represent the
6201 // folder hierarchy.
6202 if (isBase) {
6203 // FIXME: This is very strange, this is the only case where
6204 // we create a branch for a base class that does
6205 // not have the base class name in the branch name.
6206 // FIXME: This is also quite bad since classes with two
6207 // or more base classes end up with sub-branches
6208 // that have the same name.
6209 bname = name;
6210 } else {
6211 bname.Form("%s.%s", name, element->GetFullName());
6212 }
6213 }
6214 } else {
6215 // Note: For a base class element, this results in the branchname
6216 // being the name of the base class.
6217 bname.Form("%s", element->GetFullName());
6218 }
6219
6221 element->GetClass()->GetCollectionProxy() &&
6222 element->GetClass()->GetCollectionProxy()->HasPointers() )
6223 {
6224 TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id );
6225 blist->Add(brSTL);
6226 }
6227 else
6228 {
6229 TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1);
6230 bre->SetParentClass(cl);
6231 blist->Add(bre);
6232 }
6233 }
6234 // Now that we know that this branch is split, let's redo the actions.
6237}
6238
6239////////////////////////////////////////////////////////////////////////////////
6240/// Split class cl into sub-branches of this branch.
6241///
6242/// Create a sub-branch of this branch for each non-empty,
6243/// non-abstract base class of cl (unless we are a sub-branch
6244/// of a TClonesArray or an STL container, in which case we
6245/// do *not* create a sub-branch), and for each non-split data
6246/// member of cl.
6247///
6248/// Note: We do *not* create sub-branches for base classes of cl
6249/// if we are a sub-branch of a TClonesArray or an STL container.
6250///
6251/// Note: We do *not* create sub-branches for data members which
6252/// have a class type and which we are splitting.
6253///
6254/// Note: The above rules imply that the branch hierarchy increases
6255/// in depth only for base classes of cl (unless we are inside
6256/// of a TClonesArray or STL container, in which case the depth
6257/// does *not* increase, the base class is elided) and for
6258/// TClonesArray or STL container data members (which have one
6259/// additional level of sub-branches). The only other way the
6260/// depth increases is when the top-level branch has a split
6261/// class data member, in that case the constructor will create
6262/// a sub-branch for it. In other words, the interior nodes of
6263/// the branch tree are all either: base class nodes; split
6264/// class nodes which are direct sub-branches of top-level nodes
6265/// (created by TClass::Bronch usually); or TClonesArray or STL
6266/// container master nodes.
6267///
6268/// Note: The exception to the above is for the top-level branches,
6269/// Tree::Bronch creates nodes for everything in that case,
6270/// except for a TObject base class of a class which has the
6271/// can ignore tobject streamer flag set.
6272
6274{
6275 //----------------------------------------------------------------------------
6276 // Handling the case of STL collections of pointers
6277 /////////////////////////////////////////////////////////////////////////////
6278
6281
6283
6284 if ((cl == TObject::Class()) && clParent->CanIgnoreTObjectStreamer()) {
6285 return 0;
6286 }
6287
6289
6290 //
6291 // Do nothing if we couldn't build the streamer info for cl.
6292 //
6293
6294 if (!sinfo) {
6295 return 0;
6296 }
6297
6298 const auto namelen = strlen(name);
6299 bool dotlast = (namelen && (name[namelen-1] == '.'));
6300
6301 Int_t ndata = sinfo->GetNelement();
6302
6303 if ((ndata == 1) && cl->GetCollectionProxy() && !strcmp(sinfo->GetElement(0)->GetName(), "This")) {
6304 // -- Class cl is an STL collection, refuse to split it.
6305 // Question: Why? We certainly could by switching to the value class.
6306 // Partial Answer: Only the branch element constructor can split STL containers.
6307 return 1;
6308 }
6309
6310 for (Int_t elemID = 0; elemID < ndata; ++elemID) {
6311 // -- Loop over all the streamer elements and create sub-branches as needed.
6312 TStreamerElement* elem = sinfo->GetElement(elemID);
6313 if (elem->IsA() == TStreamerArtificial::Class()) {
6314 continue;
6315 }
6316 if (elem->TestBit(TStreamerElement::kRepeat)) {
6317 continue;
6318 }
6319 if (elem->TestBit(TStreamerElement::kCache) && !elem->TestBit(TStreamerElement::kWrite)) {
6320 continue;
6321 }
6322 Int_t offset = elem->GetOffset();
6323 // FIXME: An STL container as a base class gets TStreamerSTL as its class, so this test is not enough.
6324 // See InitializeOffsets() for the proper test.
6325 if (elem->IsA() == TStreamerBase::Class()) {
6326 // -- This is a base class of cl.
6327 TClass* clOfBase = elem->GetClassPointer();
6328 if (!clOfBase || ((clOfBase->Property() & kIsAbstract) && cl->InheritsFrom(TCollection::Class()))) {
6329 // -- Do nothing if we are one of the abstract collection (we know they have no data).
6330 return -1;
6331 }
6332 if ((btype == 31) || (btype == 41)) {
6333 // -- Elide the base-class sub-branches of a split TClonesArray or STL container.
6334 //
6335 // Note: We are eliding the base class here, that is, we never
6336 // create a branch for it, so the branch hierarchy is not
6337 // complete.
6338 // Note: The clParent parameter is the value class of the
6339 // container which we are splitting. It does not
6340 // appear in the branch hierarchy either.
6341 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6342 Int_t unroll = -1;
6343 if (!elem->CannotSplit() || clOfBase == TObject::Class()) {
6345 }
6346 if (unroll < 0) {
6347 // FIXME: We could not split because we are abstract, should we be doing this?
6348 if (namelen) {
6349 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6350 } else {
6351 branchname.Form("%s", elem->GetFullName());
6352 }
6353 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, nullptr, basketsize, 0, btype);
6354 branch->SetParentClass(clParent);
6356 }
6357 } else if (clOfBase->GetListOfRealData()->GetSize()) {
6358 // -- Create a branch for a non-empty base class.
6359 if (namelen) {
6360 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6361 // Elide the base class name when creating the sub-branches.
6362 // Note: The branch names for sub-branches of a base class branch
6363 // do not represent the full class hierarchy because we do
6364 // this, however it does keep the branch names for the
6365 // inherited data members simple.
6367 // Then reset it to the proper name.
6368 branch->SetName(branchname);
6369 branch->SetTitle(branchname);
6370 branch->SetParentClass(clParent);
6372 } else {
6373 branchname.Form("%s", elem->GetFullName());
6375 branch->SetParentClass(clParent);
6377 }
6378 }
6379 } else {
6380 // -- This is a data member of cl.
6381 if (namelen) {
6382 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6383 } else {
6384 branchname.Form("%s", elem->GetFullName());
6385 }
6386 if ((splitlevel > 1) && ((elem->IsA() == TStreamerObject::Class()) || (elem->IsA() == TStreamerObjectAny::Class()))) {
6387 // -- We are splitting a non-TClonesArray (may inherit from TClonesArray though), non-STL container object.
6388 //
6389 // Ignore an abstract class.
6390 // FIXME: How could an abstract class get here?
6391 // Partial answer: It is a base class. But this is a data member!
6392 TClass* elemClass = elem->GetClassPointer();
6393 if (!elemClass || elemClass->Property() & kIsAbstract) {
6394 return -1;
6395 }
6396 if (elem->CannotSplit()) {
6397 // We are not splitting.
6398 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6399 branch->SetParentClass(clParent);
6401 } else if (elemClass->InheritsFrom(TClonesArray::Class())) {
6402 // Splitting something derived from TClonesArray.
6404 if (btype == 31 || btype == 41 || elem->CannotSplit()) {
6405 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6406 subSplitlevel = 0;
6407 }
6409 branch->SetParentClass(clParent);
6411 } else {
6412 // Splitting a normal class.
6413 // FIXME: We are eliding the class we are splitting here,
6414 // i.e., we do not create a branch for it, so the
6415 // branch hierarchy does not match the class hierarchy.
6416 // Note: clParent is the class which contains a data member of
6417 // the class type which we are splitting.
6418 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6420 if (unroll < 0) {
6421 // FIXME: We could not split because we are abstract, should we be doing this?
6422 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6423 branch->SetParentClass(clParent);
6425 }
6426 }
6427 }
6428 else if( elem->GetClassPointer() &&
6429 elem->GetClassPointer()->GetCollectionProxy() &&
6430 elem->GetClassPointer()->GetCollectionProxy()->HasPointers() &&
6431 splitSTLP && fType != 4 )
6432 {
6433
6434 TBranchSTL* branch = new TBranchSTL( this, branchname,
6435 elem->GetClassPointer()->GetCollectionProxy(),
6437 branch->SetAddress( ptr+offset );
6438 fBranches.Add( branch );
6439 }
6440 else if ((elem->IsA() == TStreamerSTL::Class()) && !elem->IsaPointer()) {
6441 // -- We have an STL container.
6442 // Question: What if splitlevel == 0 here?
6443 // Answer: then we should not be here.
6445 if ((btype == 31) || (btype == 41) || elem->CannotSplit()) {
6446 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6447 subSplitlevel = 0;
6448 }
6450 branch->SetParentClass(clParent);
6452 } else if (((btype != 31) && (btype != 41)) && ptr && ((elem->GetClassPointer() == TClonesArray::Class()) || ((elem->IsA() == TStreamerSTL::Class()) && !elem->CannotSplit()))) {
6453 // -- We have a TClonesArray.
6454 // FIXME: We could get a ptr to a TClonesArray here by mistake.
6455 // Question: What if splitlevel == 0 here?
6456 // Answer: then we should not be here.
6457 // Note: ptr may be null in case of a TClonesArray inside another
6458 // TClonesArray or STL container, see the else clause.
6460 branch->SetParentClass(clParent);
6462 } else {
6463 // -- We are not going to split this element any farther.
6465 branch->SetType(btype);
6466 branch->SetParentClass(clParent);
6468 }
6469 }
6470 }
6471
6472 if (!fBranches.IsEmpty()) {
6473 // Refresh this branch's action now that we know whether it is split or not.
6476 }
6477 return 1;
6478}
6479
6480////////////////////////////////////////////////////////////////////////////////
6481/// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
6482/// with the current value of fTree->GetCurrentFile unless this branch has been
6483/// redirected to a different file. Also update the sub-branches.
6484
6486{
6487 // The BranchCount and BranchCount2 are part of higher level branches' list of
6488 // branches.
6489 // if (fBranchCount) fBranchCount->UpdateFile();
6490 // if (fBranchCount2) fBranchCount2->UpdateFile();
6492}
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 or (STL) collection (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.
@ 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.
virtual UInt_t GetCheckSum() const =0
@ 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