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