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 Int_t nbranches = fBranches.GetEntriesFast();
3839 if (strncmp(option,"debugAddress",strlen("debugAddress"))==0) {
3840 if (strlen(option)==strlen("debugAddress")) {
3841 Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s %s\n",
3842 "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject", "fOnfileObject");
3843 }
3844 if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3845 else Printf("%-24s ", GetName());
3846
3847 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3848 Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3849 TVirtualStreamerInfo *info = ((TBranchElement*)this)->GetInfoImp();
3850
3851 Printf("%-16s %2d %4d %-16s %-16s %8x %8x %p %p%s\n",
3852 info ? info->GetName() : "StreamerInfo unavailable", GetID(), GetType(),
3854 (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3855 GetOffset(), GetObject(), fOnfileObject, TestBit(kOwnOnfileObj) ? " (owned)" : "");
3856 for (Int_t i = 0; i < nbranches; ++i) {
3857 TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3858 subbranch->Print("debugAddressSub");
3859 }
3860 return;
3861 }
3862 if (strncmp(option,"debugInfo",strlen("debugInfo"))==0) {
3863 Printf("Branch %s uses:",GetName());
3864 if (fID>=0) {
3865 // GetInfoImp()->GetElement(fID)->ls();
3866 // for(UInt_t i=0; i< fIDs.size(); ++i) {
3867 // GetInfoImp()->GetElement(fIDs[i])->ls();
3868 // }
3869 TStreamerInfo *localInfo = GetInfoImp();
3870 if (fType == 3 || fType == 4) {
3871 // Search for the correct version.
3873 }
3874 Printf(" With elements:");
3875 if (fType != 3 && fType != 4)
3876 localInfo->GetElement(fID)->ls();
3877 PrintElements(localInfo, fNewIDs);
3878 Printf(" with read actions:");
3880 Printf(" with write actions:");
3882 } else if (!fNewIDs.empty() && GetInfoImp()) {
3883 TStreamerInfo *localInfo = GetInfoImp();
3884 if (fType == 3 || fType == 4) {
3885 // Search for the correct version.
3887 }
3888 PrintElements(localInfo, fNewIDs);
3889 Printf(" with read actions:");
3891 Printf(" with write actions:");
3893 }
3894 TString suboption = "debugInfoSub";
3895 suboption += (option+strlen("debugInfo"));
3896 for (Int_t i = 0; i < nbranches; ++i) {
3897 TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3898 subbranch->Print(suboption);
3899 }
3900 Printf(" ");
3901 return;
3902 }
3903 if (nbranches) {
3904 if (fID == -2) {
3905 if (strcmp(GetName(),GetTitle()) == 0) {
3906 Printf("*Branch :%-66s *",GetName());
3907 } else {
3908 Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3909 }
3910 Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3911 Printf("*............................................................................*");
3912 }
3913 if (fType >= 2) {
3915 }
3916 for (Int_t i=0;i<nbranches;i++) {
3917 TBranch *branch = (TBranch*)fBranches.At(i);
3918 branch->Print(option);
3919 }
3920 } else {
3922 }
3923}
3924
3925////////////////////////////////////////////////////////////////////////////////
3926/// Prints values of leaves.
3927
3929{
3931
3932 TStreamerInfo *info = GetInfoImp();
3933 Int_t prID = fID;
3934 char *object = fObject;
3935 if (TestBit(kCache)) {
3937 prID = fID+1;
3938 } else if (fOnfileObject) {
3939 object = fOnfileObject->GetObjectAt(0);
3940 }
3941 }
3942
3943 if (TestBit(kDecomposedObj)) {
3944 if (!fAddress) {
3945 return;
3946 }
3947 if (fType == 3 || fType == 4) {
3948 // TClonesArray or STL container top-level branch.
3949 printf(" %-15s = %d\n", GetName(), fNdata);
3950 return;
3951 } else if (fType == 31 || fType == 41) {
3952 // TClonesArray or STL container sub-branch.
3953 Int_t n = TMath::Min(10, fNdata);
3956 // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
3957 // printed as a string and could print weird characters.
3958 // So we print an unsigned char instead (not perfect, but better).
3960 }
3961 if (atype > 54) {
3962 // FIXME: More logic required here (like in ReadLeaves)
3963 printf(" %-15s = %d\n", GetName(), fNdata);
3964 return;
3965 }
3966 if (fStreamerType > 20) {
3967 atype -= 20;
3969 n = n * leaf->GetLenStatic();
3970 }
3971 if (GetInfoImp()) {
3972 GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3973 }
3974 return;
3975 } else if (fType <= 2) {
3976 // Branch in split mode.
3977 // FIXME: This should probably be < 60 instead.
3978 if ((fStreamerType > 40) && (fStreamerType < 55)) {
3979 Int_t atype = fStreamerType - 20;
3980 TBranchElement* counterElement = (TBranchElement*) fBranchCount;
3981 Int_t n = (Int_t) counterElement->GetValue(0, 0);
3982 if (GetInfoImp()) {
3983 GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3984 }
3985 } else {
3986 if (GetInfoImp()) {
3987 GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3988 }
3989 }
3990 return;
3991 }
3992 } else if (fType == 3) {
3993 printf(" %-15s = %d\n", GetName(), fNdata);
3994 } else if (fType == 31) {
3995 TClonesArray* clones = (TClonesArray*) object;
3996 if (GetInfoImp()) {
3997 GetInfoImp()->PrintValueClones(GetName(), clones, prID, fOffset, lenmax);
3998 }
3999 } else if (fType == 41) {
4001 if (GetInfoImp()) {
4002 GetInfoImp()->PrintValueSTL(GetName(), ((TBranchElement*) this)->GetCollectionProxy(), prID, fOffset, lenmax);
4003 }
4004 } else {
4005 if (GetInfoImp()) {
4006 GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
4007 }
4008 }
4009}
4010
4011////////////////////////////////////////////////////////////////////////////////
4012/// Unconfiguration Read Leave function.
4013
4015{
4016 Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
4017}
4018
4019////////////////////////////////////////////////////////////////////////////////
4020/// Read leaves into i/o buffers for this branch.
4021/// For the case where the branch is set in MakeClass mode (decomposed object).
4022
4024{
4026
4027 if (fType == 3 || fType == 4) {
4028 // Top level branch of a TClonesArray.
4029 Int_t *n = (Int_t*) fAddress;
4030 b >> n[0];
4031 if ((n[0] < 0) || (n[0] > fMaximum)) {
4032 if (IsMissingCollection()) {
4033 n[0] = 0;
4034 b.SetBufferOffset(b.Length() - sizeof(n));
4035 } else {
4036 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());
4037 n[0] = 0;
4038 }
4039 }
4040 fNdata = n[0];
4041 if (fType == 4) {
4042 Int_t nbranches = fBranches.GetEntriesFast();
4043 switch(fSTLtype) {
4044 case ROOT::kSTLset:
4045 case ROOT::kSTLmultiset:
4046 case ROOT::kSTLmap:
4047 case ROOT::kSTLmultimap:
4048 for (Int_t i=0; i<nbranches; i++) {
4049 TBranch *branch = (TBranch*)fBranches[i];
4050 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4051 if (nb < 0) {
4052 break;
4053 }
4054 }
4055 break;
4056 default:
4057 break;
4058 }
4059 }
4060 return;
4061 } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
4063 Int_t atype = fStreamerType;
4064 // FIXME: This should probably be > 59 instead.
4065 if (atype > 54) return;
4066 if (!fAddress) {
4067 return;
4068 }
4069 Int_t n = fNdata;
4070 if (atype>40) {
4071 atype -= 40;
4072 if (!fBranchCount2) return;
4073 const char *len_where = (char*)fBranchCount2->fAddress;
4074 if (!len_where) return;
4075 Int_t len_atype = fBranchCount2->fStreamerType;
4076 Int_t length;
4077 Int_t k;
4078 Char_t isArray;
4079 for( k=0; k<n; k++) {
4080 char **where = &(((char**)fAddress)[k]);
4081 delete [] *where;
4082 *where = nullptr;
4083 switch(len_atype) {
4084 case 1: {length = ((Char_t*) len_where)[k]; break;}
4085 case 2: {length = ((Short_t*) len_where)[k]; break;}
4086 case 3: {length = ((Int_t*) len_where)[k]; break;}
4087 case 4: {length = ((Long_t*) len_where)[k]; break;}
4088 //case 5: {length = ((Float_t*) len_where)[k]; break;}
4089 case 6: {length = ((Int_t*) len_where)[k]; break;}
4090 //case 8: {length = ((Double_t*)len_where)[k]; break;}
4091 case 11: {length = ((UChar_t*) len_where)[k]; break;}
4092 case 12: {length = ((UShort_t*) len_where)[k]; break;}
4093 case 13: {length = ((UInt_t*) len_where)[k]; break;}
4094 case 14: {length = ((ULong_t*) len_where)[k]; break;}
4095 case 15: {length = ((UInt_t*) len_where)[k]; break;}
4096 case 16: {length = ((Long64_t*) len_where)[k]; break;}
4097 case 17: {length = ((ULong64_t*)len_where)[k]; break;}
4098 case 18: {length = ((bool*) len_where)[k]; break;}
4099 default: continue;
4100 }
4101 b >> isArray;
4102 if (length <= 0) continue;
4103 if (isArray == 0) continue;
4104 switch (atype) {
4105 case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
4106 case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
4107 case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4108 case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
4109 case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
4110 case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4111 case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
4112 case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
4113 case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
4114 case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4115 case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
4116 case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4117 case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
4118 case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
4119 case 18: {*where=new char[sizeof(bool)*length]; b.ReadFastArray((bool*) *where, length); break;}
4120 }
4121 }
4122 return;
4123 }
4124 if (atype > 20) {
4125 atype -= 20;
4127 n *= leaf->GetLenStatic();
4128 }
4129 switch (atype) {
4130 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4131 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4132 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4133 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4134 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4135 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4136 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4137 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4138 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4139 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4140 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4141 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4142 case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
4143 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4144 case 18: {b.ReadFastArray((bool*) fAddress, n); break;}
4145 case 9: {
4148 Double_t *xx = (Double_t*) fAddress;
4149 for (Int_t ii=0;ii<n;ii++) {
4150 b.ReadDouble32(&(xx[ii]),se);
4151 }
4152 break;
4153 }
4154 case 19: {
4157 Float_t *xx = (Float_t*) fAddress;
4158 for (Int_t ii=0;ii<n;ii++) {
4159 b.ReadFloat16(&(xx[ii]),se);
4160 }
4161 break;
4162 }
4163 }
4164 return;
4165 } else if (fType <= 2) { // branch in split mode
4166 // FIXME: This should probably be < 60 instead.
4167 if (fStreamerType > 40 && fStreamerType < 55) {
4168 Int_t atype = fStreamerType - 40;
4169 Int_t n;
4170 if (fBranchCount==nullptr) {
4171 // Missing fBranchCount. let's attempts to recover.
4172
4173 TString countname( GetName() );
4174 Ssiz_t dot = countname.Last('.');
4175 if (dot>=0) {
4176 countname.Remove(dot+1);
4177 } else {
4178 countname = "";
4179 }
4180 TString counter( GetTitle() );
4181 Ssiz_t loc = counter.Last('[');
4182 if (loc>=0) {
4183 counter.Remove(0,loc+1);
4184 }
4185 loc = counter.Last(']');
4186 if (loc>=0) {
4187 counter.Remove(loc);
4188 }
4189 countname += counter;
4191 }
4192 if (fBranchCount) {
4193 n = (Int_t)fBranchCount->GetValue(0,0);
4194 } else {
4195 Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4196 n = 0;
4197 }
4198 fNdata = n;
4199 Char_t isArray;
4200 b >> isArray;
4201 switch (atype) {
4202 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4203 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4204 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4205 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4206 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4207 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4208 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4209 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4210 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4211 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4212 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4213 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4214 case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
4215 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4216 case 18: {b.ReadFastArray((bool*) fAddress, n); break;}
4217 case 9: {
4220 Double_t *xx = (Double_t*) fAddress;
4221 for (Int_t ii=0;ii<n;ii++) {
4222 b.ReadDouble32(&(xx[ii]),se);
4223 }
4224 break;
4225 }
4226 case 19: {
4229 Float_t *xx = (Float_t*) fAddress;
4230 for (Int_t ii=0;ii<n;ii++) {
4231 b.ReadFloat16(&(xx[ii]),se);
4232 }
4233 break;
4234 }
4235 }
4236 } else {
4237 fNdata = 1;
4238 if (fAddress) {
4239 if (fType<0) {
4240 // Non TObject, Non collection classes with a custom streamer.
4241
4242 // if (fObject)
4244 } else {
4245 TStreamerInfo *info = GetInfoImp();
4246 if (!info) {
4247 return;
4248 }
4249 // Since info is not null, fReadActionSequence is not null either.
4250 b.ApplySequence(*fReadActionSequence, fObject);
4251 }
4253 fNdata = (Int_t) GetValue(0, 0);
4254 }
4255 } else {
4256 fNdata = 0;
4257 }
4258 }
4259 return;
4260 }
4261}
4262
4263////////////////////////////////////////////////////////////////////////////////
4264/// Read leaves into i/o buffers for this branch.
4265/// Case of a collection (fType == 4).
4266
4268{
4270 if (fObject == nullptr)
4271 {
4272 // We have nowhere to copy the data (probably because the data member was
4273 // 'dropped' from the current schema) so let's no copy it in a random place.
4274 return;
4275 }
4276
4277 // STL container master branch (has only the number of elements).
4278 Int_t n;
4279 b >> n;
4280 if ((n < 0) || (n > fMaximum)) {
4281 if (IsMissingCollection()) {
4282 n = 0;
4283 b.SetBufferOffset(b.Length()-sizeof(n));
4284 } else {
4285 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());
4286 n = 0;
4287 }
4288 }
4289 fNdata = n;
4290
4291 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4292
4293 // Note: Proxy-helper needs to "embrace" the entire
4294 // streaming of this STL container if the container
4295 // is a set/multiset/map/multimap (what we do not
4296 // know here).
4297 // For vector/list/deque Allocate == Resize
4298 // and Commit == noop.
4299 // TODO: Exception safety a la TPushPop
4302 void* alternate = proxy->Allocate(fNdata, true);
4304 fPtrIterators->CreateIterators(alternate, proxy);
4305 } else {
4306 fIterators->CreateIterators(alternate, proxy);
4307 }
4308
4309 Int_t nbranches = fBranches.GetEntriesFast();
4310 switch (fSTLtype) {
4311 case ROOT::kSTLset:
4314 case ROOT::kSTLmultiset:
4315 case ROOT::kSTLmap:
4316 case ROOT::kSTLmultimap:
4319 for (Int_t i = 0; i < nbranches; ++i) {
4320 TBranch *branch = (TBranch*) fBranches[i];
4321 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4322 if (nb < 0) {
4323 // Give up on i/o failure.
4324 // FIXME: We need an error message here.
4325 break;
4326 }
4327 }
4328 break;
4329 default:
4330 break;
4331 }
4332 //------------------------------------------------------------------------
4333 // We have split this stuff, so we need to create the pointers
4334 /////////////////////////////////////////////////////////////////////////////
4335
4337 {
4338 TClass *elClass = proxy->GetValueClass();
4339
4340 //--------------------------------------------------------------------
4341 // The allocation is done in this strange way because ReadLeaves
4342 // is being called many times by TTreeFormula!!!
4343 //////////////////////////////////////////////////////////////////////////
4344
4345 Int_t i = 0;
4346 // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4347 if( !fNdata || *(void**)proxy->At( 0 ) != nullptr )
4348 i = fNdata;
4349
4350 for( ; i < fNdata; ++i )
4351 {
4352 void **el = (void**)proxy->At( i );
4353 // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4354 *el = elClass->New();
4355 }
4356 }
4357
4358 proxy->Commit(alternate);
4359}
4360
4361////////////////////////////////////////////////////////////////////////////////
4362/// Read leaves into i/o buffers for this branch.
4363/// Case of a data member within a collection (fType == 41).
4364
4366{
4368 if (fObject == nullptr)
4369 {
4370 // We have nowhere to copy the data (probably because the data member was
4371 // 'dropped' from the current schema) so let's no copy it in a random place.
4372 return;
4373 }
4374
4375 // STL container sub-branch (contains the elements).
4377 if (!fNdata) {
4378 return;
4379 }
4380
4381 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4382
4383 TStreamerInfo *info = GetInfoImp();
4384 if (info == nullptr) return;
4385
4388
4389 // R__ASSERT(0);
4391 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4392}
4393
4394////////////////////////////////////////////////////////////////////////////////
4395/// Read leaves into i/o buffers for this branch.
4396/// Case of a data member within a collection (fType == 41).
4397
4399{
4401 if (fObject == nullptr)
4402 {
4403 // We have nowhere to copy the data (probably because the data member was
4404 // 'dropped' from the current schema) so let's no copy it in a random place.
4405 return;
4406 }
4407
4408 // STL container sub-branch (contains the elements).
4410 if (!fNdata) {
4411 return;
4412 }
4413 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4414
4415 TStreamerInfo *info = GetInfoImp();
4416 if (info == nullptr) return;
4417
4420
4422 b.ApplySequenceVecPtr(*fReadActionSequence,iter->fBegin,iter->fEnd);
4423}
4424
4425////////////////////////////////////////////////////////////////////////////////
4426/// Read leaves into i/o buffers for this branch.
4427/// Case of a data member within a collection (fType == 41).
4428
4430{
4432 if (fObject == nullptr)
4433 {
4434 // We have nowhere to copy the data (probably because the data member was
4435 // 'dropped' from the current schema) so let's no copy it in a random place.
4436 return;
4437 }
4438
4439 // STL container sub-branch (contains the elements).
4441 if (!fNdata) {
4442 return;
4443 }
4444 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4445
4446 TStreamerInfo *info = GetInfoImp();
4447 if (info == nullptr) return;
4448 // Since info is not null, fReadActionSequence is not null either.
4449
4450 // Still calling PushPop for the legacy entries.
4453
4455 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4456}
4457
4458////////////////////////////////////////////////////////////////////////////////
4459/// Read leaves into i/o buffers for this branch.
4460/// Case of a TClonesArray (fType == 3).
4461
4463{
4465 if (fObject == nullptr)
4466 {
4467 // We have nowhere to copy the data (probably because the data member was
4468 // 'dropped' from the current schema) so let's no copy it in a random place.
4469 return;
4470 }
4471
4472 // TClonesArray master branch (has only the number of elements).
4473 Int_t n;
4474 b >> n;
4475 if ((n < 0) || (n > fMaximum)) {
4476 if (IsMissingCollection()) {
4477 n = 0;
4478 b.SetBufferOffset(b.Length()-sizeof(n));
4479 } else {
4480 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());
4481 n = 0;
4482 }
4483 }
4484 fNdata = n;
4485 TClonesArray* clones = (TClonesArray*) fObject;
4486 if (clones->IsZombie()) {
4487 return;
4488 }
4489 // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4490 // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4491 // clones->Clear();
4492 clones->ExpandCreateFast(fNdata);
4493}
4494
4495////////////////////////////////////////////////////////////////////////////////
4496/// Read leaves into i/o buffers for this branch.
4497/// Case of a data member within a TClonesArray (fType == 31).
4498
4500{
4501 // No need to validate the address here, if we are a member of a split ClonesArray,
4502 // fID is positive
4503 // ValidateAddress();
4504
4505 if (fObject == nullptr)
4506 {
4507 // We have nowhere to copy the data (probably because the data member was
4508 // 'dropped' from the current schema) so let's no copy it in a random place.
4509 return;
4510 }
4511
4512 // TClonesArray sub-branch (contains the elements).
4514 TClonesArray* clones = (TClonesArray*) fObject;
4515 if (clones->IsZombie()) {
4516 return;
4517 }
4518 TStreamerInfo *info = GetInfoImp();
4519 if (info==nullptr) return;
4520 // Since info is not null, fReadActionSequence is not null either.
4521
4522 // Note, we could (possibly) save some more, by configuring the action
4523 // based on the value of fOnfileObject rather than pushing in on a stack.
4524 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4525
4526 char **arr = (char **)clones->GetObjectRef();
4527 char **end = arr + fNdata;
4528 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
4529}
4530
4531////////////////////////////////////////////////////////////////////////////////
4532/// Read leaves into i/o buffers for this branch.
4533/// For split-class branch, base class branch, data member branch, or top-level branch.
4534/// which do not have a branch count and are not a counter.
4535
4537{
4538 R__ASSERT(fBranchCount==nullptr);
4540
4542 if (fObject == nullptr)
4543 {
4544 // We have nowhere to copy the data (probably because the data member was
4545 // 'dropped' from the current schema) so let's no copy it in a random place.
4546 return;
4547 }
4548
4549 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4550 // If not a TClonesArray or STL container master branch
4551 // or sub-branch and branch inherits from tobject,
4552 // then register with the buffer so that pointers are
4553 // handled properly.
4554 if (TestBit(kBranchObject)) {
4555 b.MapObject((TObject*) fObject);
4556 } else if (TestBit(kBranchAny)) {
4557 b.MapObject(fObject, fBranchClass);
4558 }
4559
4560 fNdata = 1;
4561 TStreamerInfo *info = GetInfoImp();
4562 if (!info) {
4563 return;
4564 }
4565 // Since info is not null, fReadActionSequence is not null either.
4566 b.ApplySequence(*fReadActionSequence, fObject);
4567}
4568
4569////////////////////////////////////////////////////////////////////////////////
4570/// Read leaves into i/o buffers for this branch.
4571/// For split-class branch, base class branch, data member branch, or top-level branch.
4572/// which do have a branch count and are not a counter.
4573
4575{
4577
4579 if (fObject == nullptr)
4580 {
4581 // We have nowhere to copy the data (probably because the data member was
4582 // 'dropped' from the current schema) so let's no copy it in a random place.
4583 return;
4584 }
4585
4586 // If not a TClonesArray or STL container master branch
4587 // or sub-branch and branch inherits from tobject,
4588 // then register with the buffer so that pointers are
4589 // handled properly.
4590 if (TestBit(kBranchObject)) {
4591 b.MapObject((TObject*) fObject);
4592 } else if (TestBit(kBranchAny)) {
4593 b.MapObject(fObject, fBranchClass);
4594 }
4595
4596 fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4597 TStreamerInfo *info = GetInfoImp();
4598 if (!info) {
4599 return;
4600 }
4601 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1); // Here we have a single object that contains a variable size C-style array.
4602 // Since info is not null, fReadActionSequence is not null either.
4603 b.ApplySequence(*fReadActionSequence, fObject);
4604}
4605
4606////////////////////////////////////////////////////////////////////////////////
4607/// Read leaves into i/o buffers for this branch.
4608/// For split-class branch, base class branch, data member branch, or top-level branch.
4609/// which do not have a branch count and are a counter.
4610
4612{
4614 if (fObject == nullptr)
4615 {
4616 // We have nowhere to copy the data (probably because the data member was
4617 // 'dropped' from the current schema) so let's no copy it in a random place.
4618 return;
4619 }
4620
4621 // If not a TClonesArray or STL container master branch
4622 // or sub-branch and branch inherits from tobject,
4623 // then register with the buffer so that pointers are
4624 // handled properly.
4625 if (TestBit(kBranchObject)) {
4626 b.MapObject((TObject*) fObject);
4627 } else if (TestBit(kBranchAny)) {
4628 b.MapObject(fObject, fBranchClass);
4629 }
4630
4631 TStreamerInfo *info = GetInfoImp();
4632 if (!info) {
4633 return;
4634 }
4635
4636 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4637
4638 // Since info is not null, fReadActionSequence is not null either.
4639 b.ApplySequence(*fReadActionSequence, fObject);
4640 fNdata = (Int_t) GetValue(0, 0);
4641}
4642
4643////////////////////////////////////////////////////////////////////////////////
4644/// Read leaves into i/o buffers for this branch.
4645/// Non TObject, Non collection classes with a custom streamer.
4646
4648{
4650 if (fObject == nullptr)
4651 {
4652 // We have nowhere to copy the data (probably because the data member was
4653 // 'dropped' from the current schema) so let's no copy it in a random place.
4654 return;
4655 }
4656
4657 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4659}
4660
4661////////////////////////////////////////////////////////////////////////////////
4662/// Unconfiguration Fill Leave function.
4663
4665{
4666 Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4667}
4668
4669////////////////////////////////////////////////////////////////////////////////
4670/// Delete any object we may have allocated on a previous call to SetAddress.
4671
4673{
4674 if (fObject && TestBit(kDeleteObject)) {
4675 if (IsAutoDelete() && fAddress != (char*)&fObject) {
4676 *((char**) fAddress) = nullptr;
4677 }
4679 if (fType == 3) {
4680 // -- We are a TClonesArray master branch.
4682 fObject = nullptr;
4685 // -- We are a pointer to a TClonesArray.
4686 // We must zero the pointer in the object.
4687 *((char**) fAddress) = nullptr;
4688 }
4689 } else if (fType == 4) {
4690 // -- We are an STL container master branch.
4692
4693 if (!proxy) {
4694 Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4695 fObject = nullptr;
4696 } else {
4697 bool needDelete = proxy->GetProperties()&TVirtualCollectionProxy::kNeedDelete;
4698 if (needDelete && fID >= 0) {
4701 needDelete = !se->TestBit(TStreamerElement::kDoNotDelete);
4702 }
4703 if (needDelete) {
4705 proxy->Clear("force");
4706 }
4707 proxy->Destructor(fObject);
4708 fObject = nullptr;
4709 }
4711 // -- We are a pointer to an STL container.
4712 // We must zero the pointer in the object.
4713 *((char**) fAddress) = nullptr;
4714 }
4715 } else {
4716 // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4718 if (!cl) {
4719 Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4720 fObject = nullptr;
4721 } else {
4723
4724 if (proxy) {
4725 if (fID >= 0) {
4727 TStreamerElement* se = si->GetElement(fID);
4730 proxy->Clear("force");
4731 }
4734 proxy->Clear("force");
4735 }
4736
4737 }
4738 cl->Destructor(fObject);
4739 fObject = nullptr;
4740 }
4741 }
4742 }
4743}
4744
4745////////////////////////////////////////////////////////////////////////////////
4746/// Reset a Branch.
4747///
4748/// Existing i/o buffers are deleted.
4749/// Entries, max and min are reset.
4750///
4751
4753{
4754 Int_t nbranches = fBranches.GetEntriesFast();
4755 for (Int_t i = 0; i < nbranches; ++i) {
4756 TBranch* branch = (TBranch*) fBranches[i];
4757 branch->Reset(option);
4758 }
4759 fBranchID = -1;
4761}
4762
4763////////////////////////////////////////////////////////////////////////////////
4764/// Reset a Branch after a Merge operation (drop data but keep customizations)
4765///
4766
4768{
4769 Int_t nbranches = fBranches.GetEntriesFast();
4770 for (Int_t i = 0; i < nbranches; ++i) {
4771 TBranch* branch = (TBranch*) fBranches[i];
4772 branch->ResetAfterMerge(info);
4773 }
4775}
4776
4777////////////////////////////////////////////////////////////////////////////////
4778/// Set branch address to zero and free all allocated memory.
4779
4781{
4782 for (Int_t i = 0; i < fNleaves; ++i) {
4783 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
4784 //if (leaf) leaf->SetAddress(0);
4785 leaf->SetAddress(nullptr);
4786 }
4787
4788 // Note: We *must* do the sub-branches first, otherwise
4789 // we may delete the object containing the sub-branches
4790 // before giving them a chance to cleanup.
4791 Int_t nbranches = fBranches.GetEntriesFast();
4792 for (Int_t i = 0; i < nbranches; ++i) {
4793 TBranch* br = (TBranch*) fBranches[i];
4794 if (br) br->ResetAddress();
4795 }
4796
4797 //
4798 // SetAddress may have allocated an object.
4799 //
4800
4801 ReleaseObject();
4802
4804 fAddress = nullptr;
4805 fObject = nullptr;
4806}
4807
4808////////////////////////////////////////////////////////////////////////////////
4809/// Release ownership of any allocated objects.
4810///
4811/// Note: This interface was added so that clone trees could
4812/// be told they do not own the allocated objects.
4813
4815{
4818 for (Int_t i = 0; i < nb; ++i) {
4819 TBranch* br = (TBranch*) fBranches[i];
4821 ((TBranchElement*) br)->ResetDeleteObject();
4822 }
4823 }
4824}
4825
4826////////////////////////////////////////////////////////////////////////////////
4827/// \brief Reset offset and StreamerInfo information from this branch.
4828/// \param[in] recurse When true call ResetInitInfo on all subbranches.
4829///
4830
4832{
4833 fInfo = nullptr;
4834 fInit = false;
4835 fInitOffsets = false;
4836 fCurrentClass = nullptr;
4837 delete fReadActionSequence;
4838 fReadActionSequence = nullptr;
4839 delete fFillActionSequence;
4840 fFillActionSequence = nullptr;
4841
4842 if (recurse) {
4843 Int_t nbranches = fBranches.GetEntriesFast();
4844 for (Int_t i = 0; i < nbranches; ++i) {
4846 sub->ResetInitInfo(true);
4847 }
4848 }
4849}
4850
4851////////////////////////////////////////////////////////////////////////////////
4852/// Point this branch at an object.
4853///
4854/// For a sub-branch, addr is a pointer to the branch object.
4855///
4856/// For a top-level branch the meaning of addr is as follows:
4857///
4858/// If addr is zero, then we allocate a branch object
4859/// internally and the branch is the owner of the allocated
4860/// object, not the caller. However the caller may obtain
4861/// a pointer to the branch object with GetObject().
4862/// The pointer is reset to zero (nullptr) when the relevant
4863/// branch object is destroyed.
4864///
4865/// Example:
4866/// ~~~ {.cpp}
4867/// branch->SetAddress(0);
4868/// Event* event = branch->GetObject();
4869/// ... Do some work.
4870/// ~~~
4871/// If addr is not zero, but the pointer addr points at is
4872/// zero, then we allocate a branch object and set the passed
4873/// pointer to point at the allocated object. The caller
4874/// owns the allocated object and is responsible for deleting
4875/// it when it is no longer needed.
4876///
4877/// Example:
4878/// ~~~ {.cpp}
4879/// Event* event = 0;
4880/// branch->SetAddress(&event);
4881/// ... Do some work.
4882/// delete event;
4883/// event = 0;
4884/// ~~~
4885/// If addr is not zero and the pointer addr points at is
4886/// also not zero, then the caller has allocated a branch
4887/// object and is asking us to use it. The caller owns it
4888/// and must delete it when it is no longer needed.
4889///
4890/// Example:
4891/// ~~~ {.cpp}
4892/// Event* event = new Event();
4893/// branch->SetAddress(&event);
4894/// ... Do some work.
4895/// delete event;
4896/// event = 0;
4897/// ~~~
4898/// These rules affect users of TTree::Branch(),
4899/// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4900/// as well because those routines call this one.
4901///
4902/// An example of a tree with branches with objects allocated
4903/// and owned by us:
4904/// ~~~ {.cpp}
4905/// TFile* f1 = new TFile("myfile_original.root");
4906/// TTree* t1 = (TTree*) f->Get("MyTree");
4907/// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4908/// TTree* t2 = t1->Clone(0);
4909/// for (Int_t i = 0; i < 10; ++i) {
4910/// t1->GetEntry(i);
4911/// t2->Fill();
4912/// }
4913/// t2->Write()
4914/// delete f2;
4915/// f2 = 0;
4916/// delete f1;
4917/// f1 = 0;
4918/// ~~~
4919/// An example of a branch with an object allocated by us,
4920/// but owned by the caller:
4921/// ~~~ {.cpp}
4922/// TFile* f = new TFile("myfile.root", "recreate");
4923/// TTree* t = new TTree("t", "A test tree.")
4924/// Event* event = 0;
4925/// TBranchElement* br = t->Branch("event.", &event);
4926/// for (Int_t i = 0; i < 10; ++i) {
4927/// ... Fill event with meaningful data in some way.
4928/// t->Fill();
4929/// }
4930/// t->Write();
4931/// delete event;
4932/// event = 0;
4933/// delete f;
4934/// f = 0;
4935/// ~~~
4936/// Notice that the only difference between this example
4937/// and the following example is that the event pointer
4938/// is zero when the branch is created.
4939///
4940/// An example of a branch with an object allocated and
4941/// owned by the caller:
4942/// ~~~ {.cpp}
4943/// TFile* f = new TFile("myfile.root", "recreate");
4944/// TTree* t = new TTree("t", "A test tree.")
4945/// Event* event = new Event();
4946/// TBranchElement* br = t->Branch("event.", &event);
4947/// for (Int_t i = 0; i < 10; ++i) {
4948/// ... Fill event with meaningful data in some way.
4949/// t->Fill();
4950/// }
4951/// t->Write();
4952/// delete event;
4953/// event = 0;
4954/// delete f;
4955/// f = 0;
4956/// ~~~
4957/// If AutoDelete is on (see TBranch::SetAutoDelete),
4958/// the top level objet will be deleted and recreate
4959/// each time an entry is read, whether or not the
4960/// TTree owns the object.
4961
4963{
4964 SetAddressImpl(addr, (addr == nullptr));
4965}
4966
4967/// See TBranchElement::SetAddress.
4968/// If implied is true, we do not over-ride existing address for
4969/// sub-branches.
4970void TBranchElement::SetAddressImpl(void* addr, bool implied)
4971{
4972 //
4973 // Don't bother if we are disabled.
4974 //
4975
4976 if (TestBit(kDoNotProcess)) {
4977 return;
4978 }
4979
4980 //
4981 // FIXME: When would this happen?
4982 //
4983
4984 if (fType < -1) {
4985 return;
4986 }
4987
4988 //
4989 // Special case when called from code generated by TTree::MakeClass.
4990 //
4991
4992 if (Longptr_t(addr) == -1) {
4993 // FIXME: Do we have to release an object here?
4994 // ReleaseObject();
4995 fAddress = (char*) -1;
4996 fObject = (char*) -1;
4999 return;
5000 }
5001
5002 //
5003 // Reset last read entry number, we have a new user object now.
5004 //
5005
5006 fReadEntry = -1;
5007
5008 //
5009 // Make sure our branch class is instantiated.
5010 //
5011 TClass* clOfBranch = fBranchClass.GetClass();
5012 if( fTargetClass.GetClassName()[0] ) {
5013 clOfBranch = fTargetClass;
5014 }
5015
5016 //
5017 // Try to build the streamer info.
5018 //
5019
5020 TStreamerInfo *info = GetInfoImp();
5021
5022 // FIXME: Warn about failure to get the streamer info here?
5023
5024 //
5025 // We may have allocated an object last time we were called.
5026 //
5027
5028 if (fObject && TestBit(kDeleteObject)){
5029 ReleaseObject();
5030 }
5031
5032 //
5033 // Remember the pointer to the pointer to our object.
5034 //
5035
5036 fAddress = (char*) addr;
5037 if (fAddress != (char*)(&fObject)) {
5038 fObject = nullptr;
5039 }
5042
5043 //
5044 // Do special stuff if we got called from a MakeClass class.
5045 // Allow sub-branches to have independently set addresses.
5046 //
5047
5048 if (TestBit(kDecomposedObj)) {
5049 if (fID > -1) {
5050 // We are *not* a top-level branch.
5051 if (!info) {
5052 // No streamer info, give up.
5053 // FIXME: We should have an error message here.
5054 fObject = fAddress;
5055 } else {
5056 // Compensate for the fact that the i/o routines
5057 // will add the streamer offset to the address.
5058 fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
5059 }
5060 return;
5061 }
5062 }
5063
5064 //
5065 // Check whether the container type is still the same
5066 // to support schema evolution; what is written on the file
5067 // may no longer match the class code which is loaded.
5068 //
5069
5070 if (fType == 3) {
5071 // split TClonesArray, counter/master branch.
5072 TClass* clm = fClonesClass;
5073 if (clm) {
5074 // In case clm derives from an abstract class.
5075 clm->BuildRealData();
5076 clm->GetStreamerInfo();
5077 }
5078 TClass* newType = GetCurrentClass();
5079 if (newType && (newType != TClonesArray::Class())) {
5080 // The data type of the container has changed.
5081 //
5082 // Let's check if it is a compatible type:
5083 bool matched = false;
5084 if (newType->GetCollectionProxy()) {
5085 TClass *content = newType->GetCollectionProxy()->GetValueClass();
5086 if (clm == content) {
5087 matched = true;
5088 } else {
5089 Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
5090 }
5091 } else {
5092 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());
5093 }
5094 if (matched) {
5095 // Change from 3/31 to 4/41
5096 SetType(4);
5097 // Set the proxy.
5098 fSTLtype = newType->GetCollectionType();
5099 fCollProxy = newType->GetCollectionProxy()->Generate();
5100
5104
5110 } else {
5112 }
5113 } else {
5114 // FIXME: Must maintain fObject here as well.
5115 fAddress = nullptr;
5117 }
5118 }
5119 } else if (fType == 4) {
5120 // split STL container, counter/master branch.
5121 TClass* newType = GetCurrentClass();
5122 if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
5123 // Let's check if it is a compatible type:
5124 TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
5126 if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
5127 delete fCollProxy;
5128 Int_t nbranches = GetListOfBranches()->GetEntries();
5129 fCollProxy = newType->GetCollectionProxy()->Generate();
5131 for (Int_t i = 0; i < nbranches; ++i) {
5133 br->fCollProxy = nullptr;
5134 if (br->fReadActionSequence) {
5136 }
5137 if (br->fFillActionSequence) {
5139 }
5140 }
5145 delete fIterators;
5146 delete fPtrIterators;
5152 } else {
5154 }
5155 }
5156 else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=nullptr) && (newProxy->GetValueClass()!=nullptr)) {
5157 // Let see if there is a rule to convert the content of the collection into each other.
5158 if (newType->GetSchemaRules()->HasRuleWithSourceClass( oldProxy->GetCollectionClass()->GetName())) {
5159 TClass *oldValueClass = oldProxy->GetValueClass();
5160 delete fCollProxy;
5161 Int_t nbranches = GetListOfBranches()->GetEntries();
5162 fCollProxy = newType->GetCollectionProxy()->Generate();
5164 for (Int_t i = 0; i < nbranches; ++i) {
5166 br->fCollProxy = nullptr;
5167 if (br->fBranchClass == oldValueClass) {
5169 }
5170 if (br->fReadActionSequence) {
5172 }
5173 if (br->fFillActionSequence) {
5175 }
5176 }
5181 delete fIterators;
5182 delete fPtrIterators;
5188 } else {
5190 }
5191 } else {
5192 Error("SetAddress","For %s, we can not convert %s into %s\n",
5193 GetName(),oldProxy->GetCollectionClass()->GetName(),newType->GetName());
5194 fAddress = nullptr;
5195 fObject = nullptr;
5197 return;
5198 }
5199 }
5200 else if ((newType == TClonesArray::Class()) && (oldProxy->GetValueClass() && !oldProxy->HasPointers() && oldProxy->GetValueClass()->IsTObject()))
5201 {
5202 // The new collection and the old collection are not compatible,
5203 // we cannot use the new collection to read the data.
5204 // Actually we could check if the new collection is a
5205 // compatible ROOT collection.
5206
5207 // We cannot insure that the TClonesArray is set for the
5208 // proper class (oldProxy->GetValueClass()), so we assume that
5209 // the transformation was done properly by the class designer.
5210
5211 // Change from 4/41 to 3/31
5212 SetType(3);
5213 // Reset the proxy.
5214 fSTLtype = kNone;
5215 switch(fStreamerType) {
5219 break;
5223 break;
5226 break;
5227 }
5228 fClonesClass = oldProxy->GetValueClass();
5230 delete fCollProxy;
5231 fCollProxy = nullptr;
5232 TClass* clm = fClonesClass;
5233 if (clm) {
5234 clm->BuildRealData(); //just in case clm derives from an abstract class
5235 clm->GetStreamerInfo();
5236 }
5240 delete fIterators;
5241 fIterators = nullptr;
5242 delete fPtrIterators;
5243 fPtrIterators =nullptr;
5244 } else {
5245 // FIXME: We must maintain fObject here as well.
5246 Error("SetAddress","For %s can not convert %s into %s\n",GetName(),GetCurrentClass()->GetName(),newType->GetName());
5247 fAddress = nullptr;
5249 return;
5250 }
5251 } else {
5252 if (!fIterators && !fPtrIterators) {
5258 } else {
5260 }
5261 }
5262 }
5263 }
5264
5265 //
5266 // Establish the semantics of fObject and fAddress.
5267 //
5268 // Top-level branch:
5269 // fObject is a ptr to the object,
5270 // fAddress is a ptr to a pointer to the object.
5271 //
5272 // Sub-branch:
5273 // fObject is a ptr to the object,
5274 // fAddress is the same as fObject.
5275 //
5276 //
5277 // There are special cases for TClonesArray and STL containers.
5278 // If there is no user-provided object, we allocate one. We must
5279 // also initialize any STL container proxy.
5280 //
5281
5282 if (fType == 3) {
5283 // -- We are a TClonesArray master branch.
5284 if (fAddress) {
5285 // -- We have been given a non-zero address, allocate if necessary.
5287 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5288 // Case of an embedded TClonesArray.
5289 fObject = fAddress;
5290 // Check if it has already been properly built.
5291 TClonesArray* clones = (TClonesArray*) fObject;
5292 if (!clones->GetClass()) {
5294 }
5295 } else {
5296 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5297 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5298 if ((fStreamerType != -1) &&
5301 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5302 } else if (fStreamerType == -1) {
5303 // -- We are a top-level branch.
5305 if (!*pp) {
5306 // -- Caller wants us to allocate the clones array, but they will own it.
5307 *pp = new TClonesArray(fClonesClass);
5308 }
5309 fObject = (char*) *pp;
5310 } else {
5311 // -- We are a pointer to a TClonesArray.
5312 // Note: We do this so that the default constructor,
5313 // or the i/o constructor can be lazy.
5315 if (!*pp) {
5316 // -- Caller wants us to allocate the clones array, but they will own it.
5317 *pp = new TClonesArray(fClonesClass);
5318 }
5319 fObject = (char*) *pp;
5320 }
5321 }
5322 } else {
5323 // -- We have been given a zero address, allocate for top-level only.
5325 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5326 // Case of an embedded TClonesArray.
5327 Error("SetAddress", "Embedded TClonesArray given a zero address for branch '%s'", GetName());
5328 } else {
5329 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5330 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5331 if ((fStreamerType != -1) &&
5334 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5335 } else if (fStreamerType == -1) {
5336 // -- We are a top-level branch.
5337 // Idea: Consider making a zero address not allocate.
5339 fObject = (char*) new TClonesArray(fClonesClass);
5340 fAddress = (char*) &fObject;
5341 } else {
5342 // -- We are a sub-branch which is a pointer to a TClonesArray.
5343 Error("SetAddress", "Embedded pointer to a TClonesArray given a zero address for branch '%s'", GetName());
5344 }
5345 }
5346 }
5347 } else if (fType == 4) {
5348 // -- We are an STL container master branch.
5349 //
5350 // Initialize fCollProxy.
5352 if (fAddress) {
5353 // -- We have been given a non-zero address, allocate if necessary.
5357 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5358 // Case of an embedded STL container.
5359 // Note: We test for the kObject and kAny types to support
5360 // the (unwise) choice of inheriting from an STL container.
5361 fObject = fAddress;
5362 } else {
5363 // We are either a top-level branch or subbranch which is a pointer to an STL container.
5364 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5366 Error("SetAddress",
5367 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5369 } else if (fStreamerType == -1) {
5370 // -- We are a top-level branch.
5371 void** pp = (void**) fAddress;
5372 if (!*pp) {
5373 // -- Caller wants us to allocate the STL container, but they will own it.
5374 *pp = proxy->New();
5375 if (!(*pp)) {
5376 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5377 // FIXME: Should we do this? Lots of other code wants
5378 // fAddress to be zero if no fObject, but is
5379 // that a good thing?
5380 fAddress = nullptr;
5382 }
5383 }
5384 fObject = (char*) *pp;
5385 } else {
5386 // -- We are a pointer to an STL container.
5387 // Note: We do this so that the default constructor,
5388 // or the i/o constructor can be lazy.
5389 void** pp = (void**) fAddress;
5390 if (!*pp) {
5391 // -- Caller wants us to allocate the STL container, but they will own it.
5392 *pp = proxy->New();
5393 if (!(*pp)) {
5394 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5395 // FIXME: Should we do this? Lots of other code wants
5396 // fAddress to be zero if no fObject, but is
5397 // that a good thing?
5398 fAddress = nullptr;
5400 }
5401 }
5402 fObject = (char*) *pp;
5403 }
5404 }
5405 } else {
5406 // -- We have been given a zero address, allocate for top-level only.
5410 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5411 // Case of an embedded STL container.
5412 // Note: We test for the kObject and kAny types to support
5413 // the (unwise) choice of inheriting from an STL container.
5414 Error("SetAddress", "Embedded STL container given a zero address for branch '%s'", GetName());
5415 } else {
5416 // We are either a top-level branch or sub-branch which is a pointer to an STL container.
5417 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5419 Error("SetAddress",
5420 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5422 } else if (fStreamerType == -1) {
5423 // -- We are a top-level branch, allocate.
5425 fObject = (char*) proxy->New();
5426 if (fObject) {
5427 fAddress = (char*) &fObject;
5428 } else {
5429 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5430 // FIXME: Should we do this? Lots of other code wants
5431 // fAddress to be zero if no fObject, but is
5432 // that a good thing?
5433 fAddress = nullptr;
5435 }
5436 } else {
5437 // -- We are a sub-branch which is a pointer to an STL container.
5438 Error("SetAddress", "Embedded pointer to an STL container given a zero address for branch '%s'", GetName());
5439 }
5440 }
5441 }
5442 } else if (fType == 41) {
5443 // -- We are an STL container sub-branch.
5444 // Initialize fCollProxy.
5446 // We are not at top-level branch.
5447 fObject = fAddress;
5448 } else if (fID < 0) {
5449 // -- We are a top-level branch.
5450 char** pp = (char**) fAddress;
5451 if (pp && *pp) {
5452 // -- Caller provided an i/o buffer for us to use.
5453 fObject = *pp;
5454 } else {
5455 // -- Caller did not provide an i/o buffer for us to use, we must make one for ourselves.
5456 if (clOfBranch) {
5457 if (!pp) {
5458 // -- Caller wants us to own the object.
5460 }
5461 fObject = (char*) clOfBranch->New();
5462 if (pp) {
5463 *pp = fObject;
5464 } else {
5465 fAddress = (char*) &fObject;
5466 }
5467 } else {
5468 Error("SetAddress", "I have no TClass for branch %s, so I cannot allocate an I/O buffer!", GetName());
5469 if (pp) {
5470 fObject = nullptr;
5471 *pp = nullptr;
5472 }
5473 }
5474 }
5475 } else {
5476 // -- We are *not* a top-level branch.
5477 fObject = fAddress;
5478 }
5479
5480 if (!info) {
5481 // FIXME: We need and error message here, no streamer info, so cannot set offsets.
5482 return;
5483 }
5484
5485 // We do this only once because it depends only on
5486 // the type of our object, not on its address.
5487 if (!fInitOffsets) {
5489 }
5490
5491 // We are split, recurse down to our sub-branches.
5492 //
5493 // FIXME: This is a tail recursion, we burn stack.
5494 Int_t nbranches = fBranches.GetEntriesFast();
5495 for (Int_t i = 0; i < nbranches; ++i) {
5496 TBranch *abranch = (TBranch*) fBranches.UncheckedAt(i);
5497 // FIXME: This is a tail recursion!
5498 if (fBranchOffset[i] != TStreamerInfo::kMissing && !(implied && abranch->TestBit(kAddressSet))) {
5499 abranch->SetAddressImpl(fObject + fBranchOffset[i], implied);
5500 abranch->SetBit(kAddressSet);
5501 if (TestBit(kDecomposedObj) != abranch->TestBit(kDecomposedObj))
5503 } else {
5504 // When the member is missing, just leave the address alone
5505 // (since setting explicitly to 0 would trigger error/warning
5506 // messages).
5507 // abranch->SetAddress(0);
5508 abranch->SetBit(kAddressSet);
5509 }
5510 }
5511}
5512
5513////////////////////////////////////////////////////////////////////////////////
5514/// Reset the basket size for all sub-branches of this branch element.
5515
5517{
5518 TBranch::SetBasketSize(buffsize);
5519 Int_t nbranches = fBranches.GetEntriesFast();
5520 for (Int_t i = 0; i < nbranches; ++i) {
5521 TBranch* branch = (TBranch*) fBranches[i];
5522 branch->SetBasketSize(fBasketSize);
5523 }
5524}
5525
5526////////////////////////////////////////////////////////////////////////////////
5527/// Set the branch counter for this branch.
5528
5530{
5531 fBranchCount = brOfCounter;
5532 if (fBranchCount==nullptr) return;
5533
5534 TLeafElement* leafOfCounter = (TLeafElement*) brOfCounter->GetListOfLeaves()->At(0);
5536 if (leafOfCounter && leaf) {
5537 leaf->SetLeafCount(leafOfCounter);
5538 } else {
5539 if (!leafOfCounter) {
5540 Warning("SetBranchCount", "Counter branch %s for branch %s has no leaves!", brOfCounter->GetName(), GetName());
5541 }
5542 if (!leaf) {
5543 Warning("SetBranchCount", "Branch %s has no leaves!", GetName());
5544 }
5545 }
5546}
5547
5548////////////////////////////////////////////////////////////////////////////////
5549/// Set the branch in a mode where the object are decomposed
5550/// (Also known as MakeClass mode).
5551/// Return whether the setting was possible (it is not possible for
5552/// TBranch and TBranchObject).
5553
5554bool TBranchElement::SetMakeClass(bool decomposeObj)
5555{
5556 if (decomposeObj)
5557 SetBit(kDecomposedObj); // Same as SetBit(kMakeClass)
5558 else
5560
5561 Int_t nbranches = fBranches.GetEntriesFast();
5562 for (Int_t i = 0; i < nbranches; ++i) {
5563 TBranchElement* branch = (TBranchElement*) fBranches[i];
5564 branch->SetMakeClass(decomposeObj);
5565 }
5568
5569 return true;
5570}
5571
5572////////////////////////////////////////////////////////////////////////////////
5573/// Set object this branch is pointing to.
5574
5576{
5577 if (TestBit(kDoNotProcess)) {
5578 return;
5579 }
5580 fObject = (char*)obj;
5581 SetAddress( &fObject );
5582}
5583
5584////////////////////////////////////////////////////////////////////////////////
5585/// Set offset of the object (to which the data member represented by this
5586/// branch belongs) inside its containing object (if any).
5587
5589{
5590 // We need to make sure that the Read and Write action's configuration
5591 // properly reflect this value.
5592
5594 SetMissing();
5595 return;
5596 }
5597
5598 if (fReadActionSequence) {
5600 }
5601 if (fFillActionSequence) {
5603 }
5604 fOffset = offset;
5605}
5606
5607////////////////////////////////////////////////////////////////////////////////
5608/// Set offset of the object (to which the data member represented by this
5609/// branch belongs) inside its containing object (if any) to mark it as missing.
5610
5612{
5613 // We need to make sure that the Read and Write action's configuration
5614 // properly reflect this value.
5615
5616 if (fReadActionSequence) {
5618 }
5619 if (fFillActionSequence) {
5621 }
5623}
5624
5625
5626////////////////////////////////////////////////////////////////////////////////
5627/// Set the sequence of actions needed to read the data out of the buffer.
5629{
5630 // A 'split' node does not store data itself (it has not associated baskets)
5631 const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
5632
5633 if (!isSplitNode) {
5634 fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
5635 }
5636
5637 if (actionSequence) delete actionSequence;
5638 auto original = create(localInfo, GetCollectionProxy(), originalClass);
5639
5640 actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
5641
5642 if (!isSplitNode)
5643 fNewIDs.erase(fNewIDs.begin());
5644
5645 else if (fInitOffsets && fType != 3 && fType != 4) {
5646 // fObject has the address of the sub-object but the streamer action have
5647 // offset relative to the parent.
5648
5649 // Note: We skipped this for the top node of split collection because the
5650 // sequence is about the content, we need to review what happens where an
5651 // action related to the collection itself will land.
5652 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
5653
5654 auto index = parent->fBranches.IndexOf(this);
5655 if (index >= 0) {
5656 actionSequence->AddToOffset( - parent->fBranchOffset[index] );
5657 }
5658 } // else it will be done by InitOffsets
5659}
5660
5661////////////////////////////////////////////////////////////////////////////////
5662/// Set the sequence of actions needed to read the data out of the buffer.
5664{
5665 if (fInfo == nullptr) {
5666 // We are called too soon. We will be called again by InitInfo
5667 return;
5668 }
5669
5671 TClass *originalClass = nullptr;
5672 TStreamerInfo *localInfo = fInfo;
5673 if (fType == 41) {
5676 } else {
5678 if (GetParentClass() == info->GetClass()) {
5680 originalClass = fBranchClass;
5682 } else {
5684 }
5685 } else if (GetCollectionProxy()) {
5686 // Base class and embedded objects.
5688 }
5689 }
5690 } else if (fType == 31) {
5692 } else if (0<=fType && fType<=2) {
5693 // Note: this still requires the ObjectWise sequence to not be optimized!
5695 } else if ( fType == 4 && !fNewIDs.empty()) {
5698 } else if ( fType == 3 && !fNewIDs.empty()) {
5701 }
5702
5703 if (create) {
5704 SetActionSequence(originalClass, localInfo, create, fReadActionSequence);
5705 }
5706}
5707
5708////////////////////////////////////////////////////////////////////////////////
5709/// Set the ReadLeaves pointer to execute the expected operations.
5710
5712{
5713 if (TestBit(kDecomposedObj)) {
5715 } else if (fType == 4) {
5717 } else if (fType == 41) {
5721 } else {
5723 }
5724 } else {
5726 }
5727 } else if (fType == 3) {
5729 } else if (fType == 31) {
5731 } else if (fType < 0) {
5733 } else if (fType == 0 && fID == -1) {
5734 // top-level branch.
5736 if (hasCustomStreamer) {
5737 // We are in the case where the object did *not* have a custom
5738 // Streamer when the TTree was written but now *does* have a custom
5739 // Streamer thus we must use it.
5741 } else {
5743 }
5744 } else if (fType <= 2) {
5745 // split-class branch, base class branch or data member branch.
5746 if (fBranchCount) {
5750 } else {
5752 }
5753 } else {
5754 Fatal("SetReadLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5755 }
5756
5758}
5759
5760////////////////////////////////////////////////////////////////////////////////
5761/// Set the sequence of actions needed to write the data out from the buffer.
5762
5764{
5765 if (fInfo == nullptr) {
5766 // We are called too soon. We will be called again by InitInfo
5767 return;
5768 }
5769
5771 TClass *originalClass = nullptr;
5772 TStreamerInfo *localInfo = fInfo;
5773 if (fType == 41) {
5776 } else {
5778 if (GetParentClass() == info->GetClass()) {
5779 // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
5780 // originalClass = fBranchClass;
5781 // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter;
5782 // } else {
5784 // }
5785 } else if (GetCollectionProxy()) {
5786 // Base class and embedded objects.
5788 }
5789 }
5790 } else if (fType == 31) {
5792 } else if (0<=fType && fType<=2) {
5793 // Note: this still requires the ObjectWise sequence to not be optimized!
5795 } else if ( fType == 4 && !fNewIDs.empty()) {
5798 } else if ( fType == 3 && !fNewIDs.empty()) {
5801 }
5802
5803 if (create) {
5804 SetActionSequence(originalClass, localInfo, create, fFillActionSequence);
5805 }
5806}
5807
5808////////////////////////////////////////////////////////////////////////////////
5809/// Set the FillLeaves pointer to execute the expected operations.
5810
5812{
5813 if (TestBit(kDecomposedObj) && ((fType==3)||(fType==31))) {
5815 } else if (fType == 4) {
5817 } else if (fType == 41) {
5821 } else {
5823 }
5826 } else {
5828 }
5829 } else if (fType == 3) {
5831 } else if (fType == 31) {
5833 } else if (fType < 0) {
5835 } else if (fType <=2) {
5836 //split-class branch, base class branch, data member branch, or top-level branch.
5837 if (fBranchCount) {
5841 } else {
5843 }
5844 } else {
5845 Fatal("SetFillLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5846 }
5847
5849}
5850
5851////////////////////////////////////////////////////////////////////////////////
5852/// Set the name of the class of the in-memory object into which the data will
5853/// loaded.
5854
5856{
5857 if (name == nullptr) return;
5858
5859 if (strcmp(fTargetClass.GetClassName(),name) != 0 )
5860 {
5861 // We are changing target class, let's reset the meta information and
5862 // the sub-branches.
5863
5864 ResetInitInfo(/*recurse=*/ false);
5865
5866 Int_t nbranches = fBranches.GetEntriesFast();
5867 for (Int_t i = 0; i < nbranches; ++i) {
5869
5870 if (sub->fTargetClass == fTargetClass ) {
5871 sub->SetTargetClass(name);
5872 } else {
5873 // Since the top level changes, the StreamerInfo (in particular for split collection)
5874 // may still need to change (and the info might be updated else (see for example SetAddress for the
5875 // the case fType 4/41)
5876 sub->ResetInitInfo(true);
5877 }
5878 if (sub->fParentClass == fTargetClass ) {
5880 }
5881 }
5883 }
5884
5885}
5886
5887////////////////////////////////////////////////////////////////////////////////
5888/// If the branch address is not set, we set all addresses starting with
5889/// the top level parent branch. This is required to be done in order for
5890/// GetOffset to be correct and for GetEntry to run.
5891
5893{
5894 // Check to see if the user changed the branch address on us.
5896
5898 // -- Do nothing if already setup or if we are a MakeClass branch.
5899 return;
5900 }
5902}
5903
5904////////////////////////////////////////////////////////////////////////////////
5905/// If the branch address is not set, we set all addresses starting with
5906/// the top level parent branch. This is required to be done in order for
5907/// GetOffset to be correct and for GetEntry to run.
5908
5910{
5911 if (TestBit((long)kDoNotProcess|(long)kAddressSet)) {
5912 // -- Do nothing if we have been told not to.
5913 // Or the data member in this branch is not longer part of the
5914 // parent's layout.
5915 return;
5916 }
5917
5918 //--------------------------------------------------------------------------
5919 // Check if we are splited STL collection of pointers
5920 /////////////////////////////////////////////////////////////////////////////
5921
5923 {
5924 TBranchElement *parent = (TBranchElement *)GetMother()->GetSubBranch( this );
5925
5926 // Make sure the StreamerInfo is loaded and initialized.
5927 GetInfoImp();
5928
5929 if( !parent->GetAddress() )
5930 parent->SetAddress( nullptr );
5931 return;
5932 }
5933
5934 //--------------------------------------------------------------------------
5935 // Any other case
5936 /////////////////////////////////////////////////////////////////////////////
5937
5939 if (!mother) {
5940 return;
5941 }
5942 TClass* cl = TClass::GetClass(mother->GetClassName());
5943
5944 // Make sure the StreamerInfo is loaded and initialized.
5945 GetInfoImp();
5946
5947 if (!cl) {
5948 return;
5949 }
5950
5951 if (!mother->GetAddress()) {
5952 // -- Our top-level branch has no address.
5953 bool motherStatus = mother->TestBit(kDoNotProcess);
5954 mother->ResetBit(kDoNotProcess);
5955 // Note: This will allocate an object.
5956 mother->SetAddress(nullptr);
5957 mother->SetBit(kDoNotProcess, motherStatus);
5958 }
5959}
5960
5961////////////////////////////////////////////////////////////////////////////////
5962/// Stream an object of class TBranchElement.
5963
5965{
5966 if (R__b.IsReading()) {
5972 // The fAddress and fObject data members are not persistent,
5973 // therefore we do not own anything.
5974 // Also clear the bit possibly set by the schema evolution.
5976 // Fixup a case where the TLeafElement was missing
5977 if ((fType == 0) && (fLeaves.GetEntriesFast() == 0)) {
5978 TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
5979 leaf->SetTitle(GetTitle());
5980 fNleaves = 1;
5981 fLeaves.Add(leaf);
5982 fTree->GetListOfLeaves()->Add(leaf);
5983 }
5984
5985 // SetReadLeavesPtr();
5986 }
5987 else {
5988 TDirectory* dirsav = fDirectory;
5989 fDirectory = nullptr; // to avoid recursive calls
5990 {
5991 // Save class version.
5992 Int_t classVersion = fClassVersion;
5993 // Record only positive 'version number'
5994 if (fClassVersion < 0) {
5996 }
5997 // TODO: Should we clear the kDeleteObject bit before writing?
5998 // If we did we would have to remember the old value and
5999 // put it back, we wouldn't want to forget that we owned
6000 // something just because we got written to disk.
6002 // Restore class version.
6003 fClassVersion = classVersion;
6004 }
6005 //
6006 // Mark all streamer infos used by this branch element
6007 // to be written to our output file.
6008 //
6009 {
6010 R__b.ForceWriteInfo(GetInfoImp(), true);
6011 }
6012 //
6013 // If we are a clones array master branch, or an
6014 // STL container master branch, we must also mark
6015 // the streamer infos used by the value class to
6016 // be written to our output file.
6017 //
6018 if (fType == 3) {
6019 // -- TClonesArray, counter/master branch
6020 //
6021 // We must mark the streamer info for the
6022 // value class to be written to the file.
6023 //
6024 TClass* cl = fClonesClass;
6025 if (cl) {
6026 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6027 }
6028 }
6029 else if (fType == 4) {
6030 // -- STL container, counter/master branch
6031 //
6032 // We must mark the streamer info for the
6033 // value class to be written to the file.
6034 //
6036 if (cp) {
6037 TClass* cl = cp->GetValueClass();
6038 if (cl) {
6039 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6040 }
6041 }
6042 }
6043 // If we are in a separate file, then save
6044 // ourselves as an independent key.
6045 if (!dirsav) {
6046 // Note: No need to restore fDirectory, it was already zero.
6047 return;
6048 }
6049 if (!dirsav->IsWritable()) {
6050 fDirectory = dirsav;
6051 return;
6052 }
6053 TDirectory* pdirectory = fTree->GetDirectory();
6054 if (!pdirectory) {
6055 fDirectory = dirsav;
6056 return;
6057 }
6058 const char* treeFileName = pdirectory->GetFile()->GetName();
6059 TBranch* mother = GetMother();
6060 const char* motherFileName = treeFileName;
6061 if (mother && (mother != this)) {
6062 motherFileName = mother->GetFileName();
6063 }
6064 if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
6065 dirsav->WriteTObject(this);
6066 }
6067 fDirectory = dirsav;
6068 }
6069}
6070
6071
6072////////////////////////////////////////////////////////////////////////////////
6073/// Split class cl into sub-branches of this branch.
6074///
6075/// This version of Unroll was formerly embedded in TTree::BronchExec
6076/// It is moved here so we can make sure to call SetReadActionSequence.
6077
6078void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Int_t bufsize, Int_t splitlevel)
6079{
6080 //
6081 // Do we have a final dot in our name?
6082 //
6083
6084 // Note: The branch constructor which takes a folder as input
6085 // creates top-level branch names with dots in them to
6086 // indicate the folder hierarchy.
6087 char* dot = (char*) strchr(name, '.');
6088 Int_t nch = strlen(name);
6089 bool dotlast = false;
6090 if (nch && (name[nch-1] == '.')) {
6091 dotlast = true;
6092 }
6093
6094 // Loop on all public data members of the class and its base classes and create branches for each one.
6095 TObjArray* blist = this->GetListOfBranches();
6096 TIter next(sinfo->GetElements());
6097 TStreamerElement* element = nullptr;
6098 TString bname;
6099 for (Int_t id = 0; (element = (TStreamerElement*) next()); ++id) {
6100 if (element->IsA() == TStreamerArtificial::Class()) {
6101 continue;
6102 }
6103 if (element->TestBit(TStreamerElement::kRepeat)) {
6104 continue;
6105 }
6107 continue;
6108 }
6109 char* pointer = (char*) (objptr + element->GetOffset());
6110 // FIXME: This is not good enough, an STL container can be
6111 // a base, and the test will fail.
6112 // See TBranchElement::InitializeOffsets() for the
6113 // correct test.
6114 bool isBase = (element->IsA() == TStreamerBase::Class());
6115 if (isBase) {
6116 TClass* clbase = element->GetClassPointer();
6117 if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) {
6118 // Note: TStreamerInfo::Compile() leaves this element
6119 // out of the optimized info, although it does
6120 // exists in the non-compiled and non-optimized info.
6121 // FIXME: The test that TStreamerInfo::Compile() uses
6122 // is element->GetType() < 0, so that is what
6123 // we should do as well.
6124 continue;
6125 }
6126 if (clbase->GetListOfRealData()->GetSize() == 0) {
6127 // Do not create a branch for empty bases.
6128 continue;
6129 }
6130 }
6131 if (dot) {
6132 if (dotlast) {
6133 bname.Form("%s%s", name, element->GetFullName());
6134 } else {
6135 // FIXME: We are in the case where we have a top-level
6136 // branch name that was created by the branch
6137 // constructor which takes a folder as input.
6138 // The internal dots in the name are in place of
6139 // of the original slashes and represent the
6140 // folder hierarchy.
6141 if (isBase) {
6142 // FIXME: This is very strange, this is the only case where
6143 // we create a branch for a base class that does
6144 // not have the base class name in the branch name.
6145 // FIXME: This is also quite bad since classes with two
6146 // or more base classes end up with sub-branches
6147 // that have the same name.
6148 bname = name;
6149 } else {
6150 bname.Form("%s.%s", name, element->GetFullName());
6151 }
6152 }
6153 } else {
6154 // Note: For a base class element, this results in the branchname
6155 // being the name of the base class.
6156 bname.Form("%s", element->GetFullName());
6157 }
6158
6159 if( splitlevel > TTree::kSplitCollectionOfPointers && element->GetClass() &&
6160 element->GetClass()->GetCollectionProxy() &&
6161 element->GetClass()->GetCollectionProxy()->HasPointers() )
6162 {
6163 TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id );
6164 blist->Add(brSTL);
6165 }
6166 else
6167 {
6168 TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1);
6169 bre->SetParentClass(cl);
6170 blist->Add(bre);
6171 }
6172 }
6173 // Now that we know that this branch is split, let's redo the actions.
6176}
6177
6178////////////////////////////////////////////////////////////////////////////////
6179/// Split class cl into sub-branches of this branch.
6180///
6181/// Create a sub-branch of this branch for each non-empty,
6182/// non-abstract base class of cl (unless we are a sub-branch
6183/// of a TClonesArray or an STL container, in which case we
6184/// do *not* create a sub-branch), and for each non-split data
6185/// member of cl.
6186///
6187/// Note: We do *not* create sub-branches for base classes of cl
6188/// if we are a sub-branch of a TClonesArray or an STL container.
6189///
6190/// Note: We do *not* create sub-branches for data members which
6191/// have a class type and which we are splitting.
6192///
6193/// Note: The above rules imply that the branch hierarchy increases
6194/// in depth only for base classes of cl (unless we are inside
6195/// of a TClonesArray or STL container, in which case the depth
6196/// does *not* increase, the base class is elided) and for
6197/// TClonesArray or STL container data members (which have one
6198/// additional level of sub-branches). The only other way the
6199/// depth increases is when the top-level branch has a split
6200/// class data member, in that case the constructor will create
6201/// a sub-branch for it. In other words, the interior nodes of
6202/// the branch tree are all either: base class nodes; split
6203/// class nodes which are direct sub-branches of top-level nodes
6204/// (created by TClass::Bronch usually); or TClonesArray or STL
6205/// container master nodes.
6206///
6207/// Note: The exception to the above is for the top-level branches,
6208/// Tree::Bronch creates nodes for everything in that case,
6209/// except for a TObject base class of a class which has the
6210/// can ignore tobject streamer flag set.
6211
6212Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype)
6213{
6214 //----------------------------------------------------------------------------
6215 // Handling the case of STL collections of pointers
6216 /////////////////////////////////////////////////////////////////////////////
6217
6218 Int_t splitSTLP = splitlevel - (splitlevel%TTree::kSplitCollectionOfPointers);
6220
6221 TString branchname;
6222
6223 if ((cl == TObject::Class()) && clParent->CanIgnoreTObjectStreamer()) {
6224 return 0;
6225 }
6226
6228
6229 //
6230 // Do nothing if we couldn't build the streamer info for cl.
6231 //
6232
6233 if (!sinfo) {
6234 return 0;
6235 }
6236
6237 const auto namelen = strlen(name);
6238 bool dotlast = (namelen && (name[namelen-1] == '.'));
6239
6240 Int_t ndata = sinfo->GetNelement();
6241
6242 if ((ndata == 1) && cl->GetCollectionProxy() && !strcmp(sinfo->GetElement(0)->GetName(), "This")) {
6243 // -- Class cl is an STL collection, refuse to split it.
6244 // Question: Why? We certainly could by switching to the value class.
6245 // Partial Answer: Only the branch element constructor can split STL containers.
6246 return 1;
6247 }
6248
6249 for (Int_t elemID = 0; elemID < ndata; ++elemID) {
6250 // -- Loop over all the streamer elements and create sub-branches as needed.
6251 TStreamerElement* elem = sinfo->GetElement(elemID);
6252 if (elem->IsA() == TStreamerArtificial::Class()) {
6253 continue;
6254 }
6256 continue;
6257 }
6259 continue;
6260 }
6261 Int_t offset = elem->GetOffset();
6262 // FIXME: An STL container as a base class gets TStreamerSTL as its class, so this test is not enough.
6263 // See InitializeOffsets() for the proper test.
6264 if (elem->IsA() == TStreamerBase::Class()) {
6265 // -- This is a base class of cl.
6266 TClass* clOfBase = elem->GetClassPointer();
6267 if (!clOfBase || ((clOfBase->Property() & kIsAbstract) && cl->InheritsFrom(TCollection::Class()))) {
6268 // -- Do nothing if we are one of the abstract collection (we know they have no data).
6269 return -1;
6270 }
6271 if ((btype == 31) || (btype == 41)) {
6272 // -- Elide the base-class sub-branches of a split TClonesArray or STL container.
6273 //
6274 // Note: We are eliding the base class here, that is, we never
6275 // create a branch for it, so the branch hierarchy is not
6276 // complete.
6277 // Note: The clParent parameter is the value class of the
6278 // container which we are splitting. It does not
6279 // appear in the branch hierarchy either.
6280 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6281 Int_t unroll = -1;
6282 if (!elem->CannotSplit() || clOfBase == TObject::Class()) {
6283 unroll = Unroll(name, clParent, clOfBase, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6284 }
6285 if (unroll < 0) {
6286 // FIXME: We could not split because we are abstract, should we be doing this?
6287 if (namelen) {
6288 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6289 } else {
6290 branchname.Form("%s", elem->GetFullName());
6291 }
6292 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, nullptr, basketsize, 0, btype);
6293 branch->SetParentClass(clParent);
6294 fBranches.Add(branch);
6295 }
6296 } else if (clOfBase->GetListOfRealData()->GetSize()) {
6297 // -- Create a branch for a non-empty base class.
6298 if (namelen) {
6299 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6300 // Elide the base class name when creating the sub-branches.
6301 // Note: The branch names for sub-branches of a base class branch
6302 // do not represent the full class hierarchy because we do
6303 // this, however it does keep the branch names for the
6304 // inherited data members simple.
6305 TBranchElement* branch = new TBranchElement(this, name, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6306 // Then reset it to the proper name.
6307 branch->SetName(branchname);
6308 branch->SetTitle(branchname);
6309 branch->SetParentClass(clParent);
6310 fBranches.Add(branch);
6311 } else {
6312 branchname.Form("%s", elem->GetFullName());
6313 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6314 branch->SetParentClass(clParent);
6315 fBranches.Add(branch);
6316 }
6317 }
6318 } else {
6319 // -- This is a data member of cl.
6320 if (namelen) {
6321 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6322 } else {
6323 branchname.Form("%s", elem->GetFullName());
6324 }
6325 if ((splitlevel > 1) && ((elem->IsA() == TStreamerObject::Class()) || (elem->IsA() == TStreamerObjectAny::Class()))) {
6326 // -- We are splitting a non-TClonesArray (may inherit from TClonesArray though), non-STL container object.
6327 //
6328 // Ignore an abstract class.
6329 // FIXME: How could an abstract class get here?
6330 // Partial answer: It is a base class. But this is a data member!
6331 TClass* elemClass = elem->GetClassPointer();
6332 if (!elemClass || elemClass->Property() & kIsAbstract) {
6333 return -1;
6334 }
6335 if (elem->CannotSplit()) {
6336 // We are not splitting.
6337 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6338 branch->SetParentClass(clParent);
6339 fBranches.Add(branch);
6340 } else if (elemClass->InheritsFrom(TClonesArray::Class())) {
6341 // Splitting something derived from TClonesArray.
6342 Int_t subSplitlevel = splitlevel-1;
6343 if (btype == 31 || btype == 41 || elem->CannotSplit()) {
6344 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6345 subSplitlevel = 0;
6346 }
6347 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel, btype);
6348 branch->SetParentClass(clParent);
6349 fBranches.Add(branch);
6350 } else {
6351 // Splitting a normal class.
6352 // FIXME: We are eliding the class we are splitting here,
6353 // i.e., we do not create a branch for it, so the
6354 // branch hierarchy does not match the class hierarchy.
6355 // Note: clParent is the class which contains a data member of
6356 // the class type which we are splitting.
6357 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6358 Int_t unroll = Unroll(branchname, clParent, elemClass, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6359 if (unroll < 0) {
6360 // FIXME: We could not split because we are abstract, should we be doing this?
6361 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6362 branch->SetParentClass(clParent);
6363 fBranches.Add(branch);
6364 }
6365 }
6366 }
6367 else if( elem->GetClassPointer() &&
6370 splitSTLP && fType != 4 )
6371 {
6372
6373 TBranchSTL* branch = new TBranchSTL( this, branchname,
6375 basketsize, splitlevel - 1+splitSTLP, sinfo, elemID );
6376 branch->SetAddress( ptr+offset );
6377 fBranches.Add( branch );
6378 }
6379 else if ((elem->IsA() == TStreamerSTL::Class()) && !elem->IsaPointer()) {
6380 // -- We have an STL container.
6381 // Question: What if splitlevel == 0 here?
6382 // Answer: then we should not be here.
6383 Int_t subSplitlevel = splitlevel - 1;
6384 if ((btype == 31) || (btype == 41) || elem->CannotSplit()) {
6385 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6386 subSplitlevel = 0;
6387 }
6388 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel+splitSTLP, btype);
6389 branch->SetParentClass(clParent);
6390 fBranches.Add(branch);
6391 } else if (((btype != 31) && (btype != 41)) && ptr && ((elem->GetClassPointer() == TClonesArray::Class()) || ((elem->IsA() == TStreamerSTL::Class()) && !elem->CannotSplit()))) {
6392 // -- We have a TClonesArray.
6393 // FIXME: We could get a ptr to a TClonesArray here by mistake.
6394 // Question: What if splitlevel == 0 here?
6395 // Answer: then we should not be here.
6396 // Note: ptr may be null in case of a TClonesArray inside another
6397 // TClonesArray or STL container, see the else clause.
6398 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6399 branch->SetParentClass(clParent);
6400 fBranches.Add(branch);
6401 } else {
6402 // -- We are not going to split this element any farther.
6403 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, nullptr, basketsize, splitSTLP, btype);
6404 branch->SetType(btype);
6405 branch->SetParentClass(clParent);
6406 fBranches.Add(branch);
6407 }
6408 }
6409 }
6410
6411 if (!fBranches.IsEmpty()) {
6412 // Refresh this branch's action now that we know whether it is split or not.
6415 }
6416 return 1;
6417}
6418
6419////////////////////////////////////////////////////////////////////////////////
6420/// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
6421/// with the current value of fTree->GetCurrentFile unless this branch has been
6422/// redirected to a different file. Also update the sub-branches.
6423
6425{
6426 // The BranchCount and BranchCount2 are part of higher level branches' list of
6427 // branches.
6428 // if (fBranchCount) fBranchCount->UpdateFile();
6429 // if (fBranchCount2) fBranchCount2->UpdateFile();
6431}
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:578
#define b(i)
Definition RSha256.hxx:100
#define e(i)
Definition RSha256.hxx:103
virtual RooAbsTestStatistic * create(const char *name, const char *title, RooAbsReal &real, RooAbsData &data, const RooArgSet &projDeps, Configuration const &cfg)=0
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:96
long Longptr_t
Definition RtypesCore.h:82
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:124
long long Long64_t
Definition RtypesCore.h:80
unsigned long long ULong64_t
Definition RtypesCore.h:81
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:377
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)
Definition TError.h:118
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 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 data
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:6505
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=nullptr) const
Definition TClass.h:607
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition TClass.cxx:3439
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2319
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2886
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:4709
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:4978
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Replaces the collection proxy for this class.
Definition TClass.cxx:2470
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:508
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5400
TClassStreamer * GetStreamer() const
Return the Streamer Class allowing streaming (if any).
Definition TClass.cxx:2914
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2031
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3770
TList * GetListOfRealData() const
Definition TClass.h:453
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:1932
const TObjArray * GetStreamerInfos() const
Definition TClass.h:492
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:5912
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:5938
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method).
Definition TClass.cxx:5947
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:4599
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4874
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2897
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6086
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:7086
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:7193
Bool_t IsVersioned() const
Definition TClass.h:522
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition TClass.cxx:7066
Version_t GetClassVersion() const
Definition TClass.h:420
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3503
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:2968
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:83
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:973
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:403
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:780
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:525
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:987
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1015
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:961
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:2652
@ kSplitCollectionOfPointers
Definition TTree.h:266
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5294
Int_t GetDefaultEntryOffsetLen() const
Definition TTree.h:459
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:489
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:509
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.
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