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) {
2564 className = cl->GetName();
2565 } else {
2566 cl = new TClass(className, fClassVersion);
2568 className = cl->GetName();
2569 }
2570 }
2572 if (!proxy) {
2573 // humm, we must have an older file with a custom collection
2574 // let's try to work-around it.
2575 TString equiv;
2576 equiv.Form("vector<%s>",fClonesName.Data());
2577 TClass *clequiv = TClass::GetClass(equiv);
2578 proxy = clequiv->GetCollectionProxy();
2579 if (!proxy) {
2580 Fatal("GetCollectionProxy",
2581 "Can not create a Collection Proxy of any kind for the class \"%s\" needed by the branch \"%s\" of the TTree \"%s\"!",
2582 className, GetName(), GetTree()->GetName());
2583 }
2584 if (gDebug > 0) Info("GetCollectionProxy",
2585 "Fixing the collection proxy of the class \"%s\" \n"
2586 "\tneeded by the branch \"%s\" of the TTree \"%s\" to be similar to \"%s\".",
2587 className, GetName(), GetTree()->GetName(),equiv.Data());
2588 cl->CopyCollectionProxy( *proxy );
2589 }
2590 fCollProxy = proxy->Generate();
2591 fSTLtype = proxy->GetCollectionType();
2592 } else if (fType == 41) {
2593 // STL container sub-branch.
2595 }
2596 return fCollProxy;
2597}
2598
2599////////////////////////////////////////////////////////////////////////////////
2600/// Return a pointer to the current type of the data member corresponding to branch element.
2601
2603{
2604 TClass* cl = fCurrentClass;
2605 if (cl) {
2606 return cl;
2607 }
2608
2610 if (!brInfo) {
2612 R__ASSERT(cl && cl->GetCollectionProxy());
2613 fCurrentClass = cl;
2614 return cl;
2615 }
2616 TClass* motherCl = brInfo->GetClass();
2617 if (motherCl->GetCollectionProxy()) {
2618 cl = motherCl->GetCollectionProxy()->GetCollectionClass();
2619 if (cl) {
2620 fCurrentClass = cl;
2621 }
2622 return cl;
2623 }
2624 if (GetID() < 0 || GetID()>=brInfo->GetNelement()) {
2625 return nullptr;
2626 }
2627 TStreamerElement* currentStreamerElement = brInfo->GetElement(GetID());
2628 TDataMember* dm = (TDataMember*) motherCl->GetListOfDataMembers()->FindObject(currentStreamerElement->GetName());
2629
2630 TString newType;
2631 if (!dm) {
2632 // Either the class is not loaded or the data member is gone
2633 if (!motherCl->IsLoaded()) {
2634 TVirtualStreamerInfo* newInfo = motherCl->GetStreamerInfo();
2635 if (newInfo != brInfo) {
2636 TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(currentStreamerElement->GetName());
2637 if (newElems) {
2638 if (newElems->GetClassPointer())
2639 newType = newElems->GetClassPointer()->GetName();
2640 else
2641 newType = newElems->GetTypeName();
2642 }
2643 }
2644 if (newType.Length()==0) {
2645 if (currentStreamerElement->GetClassPointer())
2646 newType = currentStreamerElement->GetClassPointer()->GetName();
2647 else
2648 newType = currentStreamerElement->GetTypeName();
2649 }
2650 }
2651 } else {
2652 newType = dm->GetTypeName();
2653 }
2654 cl = TClass::GetClass(newType);
2655 if (cl) {
2656 fCurrentClass = cl;
2657 }
2658 return cl;
2659}
2660
2661////////////////////////////////////////////////////////////////////////////////
2662/// Read all branches of a BranchElement and return total number of bytes.
2663///
2664/// - If entry = 0, then use current entry number + 1.
2665/// - If entry < 0, then reset entry number to 0.
2666///
2667/// Returns the number of bytes read from the input buffer.
2668/// - If entry does not exist, then returns 0.
2669/// - If an I/O error occurs, then returns -1.
2670///
2671/// See IMPORTANT REMARKS in TTree::GetEntry.
2672
2674{
2675 // Remember which entry we are reading.
2676 fReadEntry = entry;
2677
2678 // If our tree has a branch ref, make it remember the entry and
2679 // this branch. This allows a TRef::GetObject() call done during
2680 // the following I/O operation, for example in a custom streamer,
2681 // to search for the referenced object in the proper element of the
2682 // proper branch.
2683 TBranchRef* bref = fTree->GetBranchRef();
2684 if (R__unlikely(bref)) {
2685 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2686 fBranchID = bref->SetParent(this, fBranchID);
2687 bref->SetRequestedEntry(entry);
2688 }
2689
2690 Int_t nbytes = 0;
2691
2692 if (R__unlikely(IsAutoDelete())) {
2695 } else {
2697 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
2699 }
2700 }
2701
2702 Int_t nbranches = fBranches.GetEntriesFast();
2703 if (nbranches) {
2704 // -- Branch has daughters.
2705 // One must always read the branch counter.
2706 // In the case when one reads consecutively twice the same entry,
2707 // the user may have cleared the TClonesArray between the GetEntry calls.
2708 if ((fType == 3) || (fType == 4)) {
2709 Int_t nb = TBranch::GetEntry(entry, getall);
2710 if (nb < 0) {
2711 return nb;
2712 }
2713 nbytes += nb;
2714 }
2715 switch(fSTLtype) {
2716 case ROOT::kSTLset:
2717 case ROOT::kSTLmultiset:
2720 case ROOT::kSTLmap:
2721 case ROOT::kSTLmultimap:
2724 break;
2725 default:
2726 ValidateAddress(); // There is no ReadLeave for this node, so we need to do the validation here.
2727 for (Int_t i = 0; i < nbranches; ++i) {
2728 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2729 Int_t nb = branch->GetEntry(entry, getall);
2730 if (nb < 0) {
2731 return nb;
2732 }
2733 nbytes += nb;
2734 }
2735 break;
2736 }
2738 if (fType == 3) {
2739 // Apply the unattached rules; by definition they do not need any
2740 // input from a buffer.
2742
2743 auto ndata = GetNdata();
2744
2745 TClonesArray* clones = (TClonesArray*) fObject;
2746 if (clones->IsZombie()) {
2747 return -1;
2748 }
2749 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2750
2751 char **arr = (char **)clones->GetObjectRef();
2752 char **end = arr + fNdata;
2753
2754 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
2755 } else if (fType == 4) {
2756 // Apply the unattached rules; by definition they do not need any
2757 // input from a buffer.
2759
2760 auto ndata = GetNdata();
2761
2762 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
2765
2767 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
2768 } else {
2769 // Apply the unattached rules; by definition they do not need any
2770 // input from a buffer.
2772 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
2773 b.ApplySequence(*fReadActionSequence, fObject);
2774 }
2775 }
2776 } else {
2777 // -- Terminal branch.
2778 if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
2779 Int_t nb = fBranchCount->TBranch::GetEntry(entry, getall);
2780 if (nb < 0) {
2781 return nb;
2782 }
2783 nbytes += nb;
2784 }
2785 Int_t nb = TBranch::GetEntry(entry, getall);
2786 if (nb < 0) {
2787 return nb;
2788 }
2789 nbytes += nb;
2790 }
2791
2792 if (R__unlikely(fTree->Debug() > 0)) {
2793 if ((entry >= fTree->GetDebugMin()) && (entry <= fTree->GetDebugMax())) {
2794 Info("GetEntry", "%lld, branch=%s, nbytes=%d", entry, GetName(), nbytes);
2795 }
2796 }
2797 return nbytes;
2798}
2799
2800////////////////////////////////////////////////////////////////////////////////
2801/// Fill expectedClass and expectedType with information on the data type of the
2802/// object/values contained in this branch (and thus the type of pointers
2803/// expected to be passed to Set[Branch]Address
2804/// return 0 in case of success and > 0 in case of failure.
2805
2807{
2808 expectedClass = nullptr;
2809 expectedType = kOther_t;
2810
2812 if ((type == -1) || (fID == -1)) {
2813 expectedClass = fBranchClass;
2814 } else {
2815 // Case of an object data member. Here we allow for the
2816 // variable name to be omitted. Eg, for Event.root with split
2817 // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
2819 if (element) {
2820 expectedClass = element->GetClassPointer();
2821 if (!expectedClass) {
2822 TDataType* data = gROOT->GetType(element->GetTypeNameBasic());
2823 if (!data) {
2824 Error("GetExpectedType", "Did not find the type number for %s", element->GetTypeNameBasic());
2825 return 1;
2826 } else {
2827 expectedType = (EDataType) data->GetType();
2828 }
2829 }
2830 } else {
2831 Error("GetExpectedType", "Did not find the type for %s",GetName());
2832 return 2;
2833 }
2834 }
2835 return 0;
2836}
2837
2838////////////////////////////////////////////////////////////////////////////////
2839/// Return the 'full' name of the branch. In particular prefix the mother's name
2840/// when it does not end in a trailing dot and thus is not part of the branch name
2842{
2843 TBranchElement* mother = static_cast<TBranchElement*>(GetMother());
2844 if (!mother || mother==this || mother->GetType() == 3 || mother->GetType() == 4) {
2845 // The parent's name is already included in the name for split TClonesArray and STL collections
2846 return fName;
2847 }
2848
2849 return TBranch::GetFullName();
2850}
2851
2852////////////////////////////////////////////////////////////////////////////////
2853/// Return icon name depending on type of branch element.
2854
2856{
2857 if (IsFolder()) {
2858 return "TBranchElement-folder";
2859 } else {
2860 return "TBranchElement-leaf";
2861 }
2862}
2863
2864////////////////////////////////////////////////////////////////////////////////
2865/// Return whether this branch is in a mode where the object are decomposed
2866/// or not (Also known as MakeClass mode).
2867
2869{
2870 return TestBit(kDecomposedObj); // Same as TestBit(kMakeClass)
2871}
2872
2873////////////////////////////////////////////////////////////////////////////////
2874/// Return maximum count value of the branchcount if any.
2875
2877{
2878 if (fBranchCount) {
2879 return fBranchCount->GetMaximum();
2880 }
2881 return fMaximum;
2882}
2883
2884////////////////////////////////////////////////////////////////////////////////
2885/// Return a pointer to our object.
2886
2888{
2890 return fObject;
2891}
2892
2893////////////////////////////////////////////////////////////////////////////////
2894/// Return a pointer to the parent class of the branch element.
2895
2897{
2898 return fParentClass.GetClass();
2899}
2900
2901////////////////////////////////////////////////////////////////////////////////
2902/// Return type name of element in the branch.
2903
2905{
2906 if (fType == 3 || fType == 4) {
2907 return "Int_t";
2908 }
2909 // FIXME: Use symbolic constants here.
2910 if ((fStreamerType < 1) || (fStreamerType > 59)) {
2911 if (fBranchClass.GetClass()) {
2912 if (fID>=0) {
2913 return GetInfoImp()->GetElement(fID)->GetTypeName();
2914 } else {
2915 return fBranchClass.GetClass()->GetName();
2916 }
2917 } else {
2918 return nullptr;
2919 }
2920 }
2921 const char *types[20] = {
2922 "",
2923 "Char_t",
2924 "Short_t",
2925 "Int_t",
2926 "Long_t",
2927 "Float_t",
2928 "Int_t",
2929 "char*",
2930 "Double_t",
2931 "Double32_t",
2932 "",
2933 "UChar_t",
2934 "UShort_t",
2935 "UInt_t",
2936 "ULong_t",
2937 "UInt_t",
2938 "Long64_t",
2939 "ULong64_t",
2940 "Bool_t",
2941 "Float16_t"
2942 };
2943 Int_t itype = fStreamerType % 20;
2944 return types[itype];
2945}
2946
2947////////////////////////////////////////////////////////////////////////////////
2948
2949template Double_t TBranchElement::GetTypedValue(Int_t j, Int_t len, bool subarr) const;
2950template Long64_t TBranchElement::GetTypedValue(Int_t j, Int_t len, bool subarr) const;
2951template LongDouble_t TBranchElement::GetTypedValue(Int_t j, Int_t len, bool subarr) const;
2952
2953template <typename T>
2955{
2956 // -- Returns the branch value.
2957 //
2958 // If the leaf is an array, j is the index in the array.
2959 //
2960 // If leaf is an array inside a TClonesArray, len should be the length
2961 // of the array.
2962 //
2963 // If subarr is true, then len is actually the index within the sub-array.
2964 //
2965
2967
2968 Int_t prID = fID;
2969 char *object = fObject;
2970 if (TestBit(kCache)) {
2971 if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
2972 prID = fID+1;
2973 } else if (fOnfileObject) {
2974 object = fOnfileObject->GetObjectAt(0);
2975 }
2976 }
2977
2978 if (!j && fBranchCount) {
2979 Long64_t entry = fTree->GetReadEntry();
2980 // Since reloading the index, will reset the ClonesArray, let's
2981 // skip the load if we already read this entry.
2982 if (entry != fBranchCount->GetReadEntry()) {
2983 fBranchCount->TBranch::GetEntry(entry);
2984 }
2985 if (fBranchCount2 && entry != fBranchCount2->GetReadEntry()) {
2986 fBranchCount2->TBranch::GetEntry(entry);
2987 }
2988 }
2989
2990 if (TestBit(kDecomposedObj)) {
2991 if (!fAddress) {
2992 return 0;
2993 }
2994 if ((fType == 3) || (fType == 4)) {
2995 // Top-level branch of a TClonesArray.
2996 return fNdata;
2997 } else if ((fType == 31) || (fType == 41)) {
2998 // sub branch of a TClonesArray
2999 Int_t atype = fStreamerType;
3000 if (atype < 20) {
3001 atype += 20;
3002 }
3003 return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
3004 } else if (fType <= 2) {
3005 // branch in split mode
3006 // FIXME: This should probably be < 60 instead!
3007 if ((fStreamerType > 40) && (fStreamerType < 55)) {
3008 Int_t atype = fStreamerType - 20;
3009 return GetInfoImp()->GetTypedValue<T>(fAddress, atype, j, 1);
3010 } else {
3011 return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
3012 }
3013 }
3014 }
3015
3016 if (object == nullptr)
3017 {
3018 // We have nowhere to read the data from (probably because the data member was
3019 // 'dropped' from the current schema).
3020 return 0;
3021 }
3022
3023 if (fType == 31) {
3024 TClonesArray* clones = (TClonesArray*) object;
3025 if (subarr) {
3026 return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j, len, fOffset);
3027 }
3028 return GetInfoImp()->GetTypedValueClones<T>(clones, prID, j/len, j%len, fOffset);
3029 } else if (fType == 41) {
3032 {
3033 if (subarr)
3034 return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
3035
3036 return GetInfoImp()->GetTypedValueSTL<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
3037 }
3038 else
3039 {
3040 if (subarr)
3041 return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j, len, fOffset);
3042 return GetInfoImp()->GetTypedValueSTLP<T>(((TBranchElement*) this)->GetCollectionProxy(), prID, j/len, j%len, fOffset);
3043 }
3044 } else {
3045 if (GetInfoImp()) {
3046 return GetInfoImp()->GetTypedValue<T>(object, prID, j, -1);
3047 }
3048 return 0;
3049 }
3050}
3051
3052////////////////////////////////////////////////////////////////////////////////
3053/// Returns pointer to first data element of this branch.
3054/// Currently used only for members of type character.
3055
3057{
3059
3060 Int_t prID = fID;
3061 char *object = fObject;
3062 if (TestBit(kCache)) {
3063 if (GetInfoImp()->GetElements()->At(fID)->TestBit(TStreamerElement::kRepeat)) {
3064 prID = fID+1;
3065 } else if (fOnfileObject) {
3066 object = fOnfileObject->GetObjectAt(0);
3067 }
3068 }
3069
3070 if (fBranchCount) {
3071 Long64_t entry = fTree->GetReadEntry();
3072 fBranchCount->TBranch::GetEntry(entry);
3073 if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
3074 }
3075 if (TestBit(kDecomposedObj)) {
3076 if (!fAddress) {
3077 return nullptr;
3078 }
3079 if (fType == 3) { //top level branch of a TClonesArray
3080 //return &fNdata;
3081 return nullptr;
3082 } else if (fType == 4) { //top level branch of a TClonesArray
3083 //return &fNdata;
3084 return nullptr;
3085 } else if (fType == 31) { // sub branch of a TClonesArray
3086 //Int_t atype = fStreamerType;
3087 //if (atype < 20) atype += 20;
3088 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3089 return nullptr;
3090 } else if (fType == 41) { // sub branch of a TClonesArray
3091 //Int_t atype = fStreamerType;
3092 //if (atype < 20) atype += 20;
3093 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3094 return nullptr;
3095 } else if (fType <= 2) { // branch in split mode
3096 // FIXME: This should probably be < 60 instead!
3097 if (fStreamerType > 40 && fStreamerType < 55) {
3098 //Int_t atype = fStreamerType - 20;
3099 //return GetInfoImp()->GetValue(fAddress, atype, j, 1);
3100 return nullptr;
3101 } else {
3102 //return GetInfoImp()->GetValue(object, fID, j, -1);
3103 return nullptr;
3104 }
3105 }
3106 }
3107
3108 if (fType == 31) {
3109 return nullptr;
3110 } else if (fType == 41) {
3111 return nullptr;
3112 } else if (prID < 0) {
3113 return object;
3114 } else {
3115 //return GetInfoImp()->GetValue(object,fID,j,-1);
3116 if (!GetInfoImp() || !object) return nullptr;
3117 char **val = (char**)(object+GetInfoImp()->TStreamerInfo::GetElementOffset(prID));
3118 return *val;
3119 }
3120}
3121
3122////////////////////////////////////////////////////////////////////////////////
3123/// Initialize the base class subobjects offsets of our sub-branches and set fOffset if we are a container sub-branch.
3124///
3125/// Note: The offsets are zero for data members so that when
3126/// SetAddress recursively sets their address, they will get the
3127/// same address as their containing class because i/o is based
3128/// on streamer info offsets from the address of the containing
3129/// class.
3130///
3131/// Offsets are non-zero for base-class sub-branches that are
3132/// not the leftmost direct base class. They are laid out in
3133/// memory sequentially and only the leftmost direct base class
3134/// has the same address as the derived class. The streamer
3135/// offsets need to be added to the address of the base class
3136/// subobject which is not the same as the address of the
3137/// derived class for the non-leftmost direct base classes.
3138
3140{
3141 Int_t nbranches = fBranches.GetEntriesFast();
3142
3143 // See https://sft.its.cern.ch/jira/browse/ROOT-8742
3144 // and https://sft.its.cern.ch/jira/browse/ROOT-9253
3145 // As of commit e21b4f1a3b, removing this lock lead to a failure
3146 // in the test testSetAddress[Loop].
3147 // As of commit 4f8b237849, removing this lock does not lead to
3148 // a visible failure in test. This might be due to the underlying
3149 // problem (missing lock or ?) being solved somewhere else or some
3150 // other perturbation reducing the failure rate.
3151 // Having the lock here is not too costly as InitializeOffsets is
3152 // one called once in the lifetime of the TBranch.
3154
3155 if (fID < 0) {
3156 // -- We are a top-level branch. Let's mark whether we need to use MapObject.
3157 if (CanSelfReference(fBranchClass)) {
3158 if (fBranchClass.GetClass()->IsTObject()) {
3160 } else {
3162 }
3163 }
3164 }
3165 if (nbranches) {
3166 // Allocate space for the new sub-branch offsets.
3167 delete[] fBranchOffset;
3168 fBranchOffset = nullptr;
3169 fBranchOffset = new Int_t[nbranches];
3170 // Make sure we can instantiate our class meta info.
3171 if (!fBranchClass.GetClass()) {
3172 Warning("InitializeOffsets", "No branch class set for branch: %s", GetName());
3173 fInitOffsets = true;
3174 return;
3175 }
3176 // Make sure we can instantiate our class streamer info.
3177 if (!GetInfoImp()) {
3178 Warning("InitializeOffsets", "No streamer info available for branch: %s of class: %s", GetName(), fBranchClass.GetClass()->GetName());
3179 fInitOffsets = true;
3180 return;
3181 }
3182
3183 // Get the class we are a member of now (which is the
3184 // type of our containing subobject) and get our offset
3185 // inside of our containing subobject (our local offset).
3186 // Note: branchElem stays zero if we are a top-level branch,
3187 // we have to be careful about this later.
3188 TStreamerElement* branchElem = nullptr;
3189 Int_t localOffset = 0;
3190 TClass* branchClass = fBranchClass.GetClass();
3191 bool renamed = false;
3192 if (fID > -1) {
3193 // -- Branch is *not* a top-level branch.
3194 // Instead of the streamer info class, we want the class of our
3195 // specific element in the streamer info. We could be a data
3196 // member of a base class or a split class, in which case our
3197 // streamer info will be for our containing sub-object, while
3198 // we are actually a different type.
3200 // Note: We tested to make sure the streamer info was available previously.
3201 if (!si->IsCompiled()) {
3202 Warning("InitializeOffsets", "Streamer info for branch: %s has no elements array!", GetName());
3203 fInitOffsets = true;
3204 return;
3205 }
3206 // FIXME: Check that fID is in range.
3207 branchElem = si->GetElement(fID);
3208 if (!branchElem) {
3209 Warning("InitializeOffsets", "Cannot get streamer element for branch: %s!", GetName());
3210 fInitOffsets = true;
3211 return;
3212 } else if (branchElem->TestBit(TStreamerElement::kRepeat)) {
3213 // If we have a repeating streamerElement, use the next
3214 // one as it actually hold the 'real' data member('s offset)
3215 if (si->GetElement(fID+1)) {
3216 branchElem = si->GetElement(fID+1);
3217 }
3218 }
3219 localOffset = branchElem->GetOffset();
3220 branchClass = branchElem->GetClassPointer();
3221 if (localOffset == TStreamerInfo::kMissing) {
3222 fObject = nullptr;
3223 } else {
3224 renamed = branchClass && branchElem->GetNewClass() && (branchClass != branchElem->GetNewClass());
3225 }
3226 } else {
3227 renamed = fTargetClass != fBranchClass;
3228 }
3229 if (!branchClass) {
3230 Error("InitializeOffsets", "Could not find class for branch: %s", GetName());
3231 fInitOffsets = true;
3232 return;
3233 }
3234
3235 //------------------------------------------------------------------------
3236 // Extract the name of the STL branch in case it has been split.
3237 //////////////////////////////////////////////////////////////////////////
3238
3239 TString stlParentName;
3240 bool stlParentNameUpdated = false;
3241 if( fType == 4 )
3242 {
3243 TBranch *br = GetMother()->GetSubBranch( this );
3244 stlParentName = br->GetName();
3245 stlParentName = stlParentName.Strip( TString::kTrailing, '.' );
3246
3247 // We may ourself contain the 'Mother' branch name.
3248 // To avoid code duplication, we delegate the removal
3249 // of the mother's name to the first sub-branch loop.
3250 }
3251
3252 // Loop over our sub-branches and compute their offsets.
3253 for (Int_t subBranchIdx = 0; subBranchIdx < nbranches; ++subBranchIdx) {
3254 bool alternateElement = false;
3255
3256 fBranchOffset[subBranchIdx] = 0;
3257 TBranchElement* subBranch = dynamic_cast<TBranchElement*> (fBranches[subBranchIdx]);
3258 if (subBranch == nullptr) {
3259 // -- Skip sub-branches that are not TBranchElements.
3260 continue;
3261 }
3262
3263 if (renamed) {
3264 if (subBranch->fBranchClass == branchClass) {
3265 if (branchElem) subBranch->SetTargetClass(branchElem->GetNewClass()->GetName());
3266 else subBranch->SetTargetClass(fTargetClass->GetName());
3267 }
3268 }
3269
3270 TVirtualStreamerInfo* sinfo = subBranch->GetInfoImp();
3271 if (!sinfo) {
3272 Warning("InitializeOffsets", "No streamer info for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3273 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3274 continue;
3275 }
3276 if (!sinfo->IsCompiled()) {
3277 Warning("InitializeOffsets", "No elements array for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3278 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3279 continue;
3280 }
3281 // FIXME: Make sure subBranch->fID is in range.
3282 TStreamerElement* subBranchElement = sinfo->GetElement(subBranch->fID);
3283 if (!subBranchElement) {
3284 Warning("InitializeOffsets", "No streamer element for branch: %s subbranch: %s", GetName(), subBranch->GetName());
3285 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3286 continue;
3287 } else if (subBranchElement->TestBit(TStreamerElement::kRepeat)) {
3288 // If we have a repeating streamerElement, use the next
3289 // one as it actually hold the 'real' data member('s offset)
3290 if (sinfo->GetElement(subBranch->fID+1)) {
3291 subBranchElement = sinfo->GetElement(subBranch->fID+1);
3292 }
3293 } else if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3294 // We have a cached item which is not a repeated but we might still
3295 // have some Actions triggered by a rule that affect real
3296 // data member(s).
3297 if (subBranch->fReadActionSequence && subBranch->fReadActionSequence->fActions.size() > 1) {
3298 typedef TStreamerInfoActions::ActionContainer_t::iterator iterator;
3299 iterator end = subBranch->fReadActionSequence->fActions.end();
3300 for(iterator iter = subBranch->fReadActionSequence->fActions.begin();
3301 iter != end; ++iter) {
3302 TStreamerInfoActions::TConfiguration *config = iter->fConfiguration;
3303 UInt_t id = config->fElemId;
3305 if (e && !e->TestBit(TStreamerElement::kCache)) {
3306 subBranchElement = e;
3307 alternateElement = true;
3308 break;
3309 }
3310 }
3311 }
3312 }
3313
3314 localOffset = subBranchElement->GetOffset();
3315 if (localOffset == TStreamerInfo::kMissing) {
3316 subBranch->fObject = nullptr;
3317 }
3318 {
3319 Int_t streamerType = subBranchElement->GetType();
3320 if (streamerType > TStreamerInfo::kObject
3321 && subBranch->GetListOfBranches()->GetEntriesFast()==0
3322 && CanSelfReference(subBranchElement->GetClass()))
3323 {
3324 subBranch->SetBit(kBranchAny);
3325 } else {
3326 subBranch->ResetBit(kBranchAny);
3327 }
3328 }
3329
3330 if (subBranchElement->GetNewType()<0) {
3331 subBranch->ResetBit(kBranchAny);
3332 subBranch->ResetBit(kBranchObject);
3333 }
3334
3335 // Note: This call is expensive, do it only once.
3336 TBranch* mother = GetMother();
3337 if (!mother) {
3338 Warning("InitializeOffsets", "Branch '%s' has no mother!", GetName());
3339 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3340 continue;
3341 }
3342 TString motherName(mother->GetName());
3343 bool motherDot = false;
3344 if (motherName.Length() && strchr(motherName.Data(), '.')) {
3345 motherDot = true;
3346 }
3347 bool motherDotAtEnd = false;
3348 if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
3349 motherDotAtEnd = true;
3350 }
3351
3352 bool isBaseSubBranch = false;
3353 if ((subBranch->fType == 1) || (subBranchElement && subBranchElement->IsBase())) {
3354 // -- Base class sub-branch (1).
3355 //
3356 // Note: Our type will not be 1, even though we are
3357 // a base class branch, if we are not split (see the
3358 // constructor), or if we are an STL container master
3359 // branch and a base class branch at the same time
3360 // or an std::string.
3361 isBaseSubBranch = true;
3362 }
3363
3364 bool isContDataMember = false;
3365 if ((subBranch->fType == 31) || (subBranch->fType == 41)) {
3366 // -- Container data member sub-branch (31 or 41).
3367 isContDataMember = true;
3368 }
3369
3370 // I am either a data member sub-branch (0), or a base class
3371 // sub-branch (1), or TClonesArray master sub-branch (3),
3372 // or an STL container master sub-branch (4), or TClonesArray
3373 // data member sub-branch (31), or an STL container data member
3374 // sub-branch (41).
3375 //
3376 // My parent branch is either a top-level branch ((0), fID==(-2,-1)),
3377 // or a base class sub-branch (1), or a split-class branch (2),
3378 // or a TClonesArray master branch (3), or an STL container
3379 // master branch (4).
3380 //
3381
3382 //
3383 // We need to extract from our name the name
3384 // of the data member which contains us, so
3385 // that we may then do a by-name lookup in the
3386 // dictionary meta info of our parent class to
3387 // get our offset in our parent class.
3388 //
3389
3390 // Get our name.
3391 TString dataName(subBranch->GetName());
3392 if (motherDotAtEnd) {
3393 // -- Remove the top-level branch name from our name.
3394 dataName.Remove(0, motherName.Length());
3395 // stlParentNameUpdated is false the first time in this loop.
3396 if (!stlParentNameUpdated && stlParentName.Length()) {
3397 stlParentName.Remove(0, motherName.Length());
3398 stlParentNameUpdated = true;
3399 }
3400 } else if (motherDot) {
3401 // -- Remove the top-level branch name from our name, folder case.
3402 //
3403 // Note: We are in the case where our mother was created
3404 // by the branch constructor which takes a folder
3405 // as an argument. The mother branch has internal
3406 // dots in its name to represent the folder hierarchy.
3407 // The TTree::Bronch() routine has handled us as a
3408 // special case, we must compensate.
3409 if ((fID < 0) && (subBranchElement->IsA() == TStreamerBase::Class())) {
3410 // -- Our name is the mother name, remove it.
3411 // Note: The test is our parent is a top-level branch
3412 // and our streamer is the base class streamer,
3413 // this matches the exact test in TTree::Bronch().
3414 if (dataName.Length() == motherName.Length()) {
3415 dataName.Remove(0, motherName.Length());
3416 // stlParentNameUpdated is false the first time in this loop.
3417 if (!stlParentNameUpdated && stlParentName.Length()) {
3418 stlParentName.Remove(0, motherName.Length());
3419 }
3420 }
3421 } else {
3422 // -- Remove the mother name and the dot.
3423 if (dataName.Length() > motherName.Length()) {
3424 dataName.Remove(0, motherName.Length() + 1);
3425 if (!stlParentNameUpdated && stlParentName.Length()) {
3426 stlParentName.Remove(0, motherName.Length());
3427 }
3428 }
3429 }
3430 }
3431 stlParentNameUpdated = true;
3432 if (isBaseSubBranch) {
3433 // -- Remove the base class name suffix from our name.
3434 // Note: The pattern is the name of the base class.
3435 TString pattern(subBranchElement->GetName());
3436 if (pattern.Length() <= dataName.Length()) {
3437 if (!strcmp(dataName.Data() + (dataName.Length() - pattern.Length()), pattern.Data())) {
3438 // The branch name contains the name of the base class in it.
3439 // This name is not reproduced in the sub-branches, so we need to
3440 // remove it.
3441 dataName.Remove(dataName.Length() - pattern.Length());
3442 }
3443 }
3444 // Remove any leading dot.
3445 if (dataName.Length()) {
3446 if (dataName[0] == '.') {
3447 dataName.Remove(0, 1);
3448 }
3449 }
3450 // Note: We intentionally leave any trailing dot
3451 // in our modified name here.
3452 }
3453
3454 // Get our parent branch's name.
3455 TString parentName(GetName());
3456 if (motherDotAtEnd) {
3457 // -- Remove the top-level branch name from our parent's name.
3458 parentName.Remove(0, motherName.Length());
3459 } else if (motherDot) {
3460 // -- Remove the top-level branch name from our parent's name, folder case.
3461 //
3462 // Note: We are in the case where our mother was created
3463 // by the branch constructor which takes a folder
3464 // as an argument. The mother branch has internal
3465 // dots in its name to represent the folder hierarchy.
3466 // The TTree::Bronch() routine has handled us as a
3467 // special case, we must compensate.
3468 if ((fID > -1) && (mother == mother->GetSubBranch(this)) && (branchElem->IsA() == TStreamerBase::Class())) {
3469 // -- Our parent's name is the mother name, remove it.
3470 // Note: The test is our parent's parent is a top-level branch
3471 // and our parent's streamer is the base class streamer,
3472 // this matches the exact test in TTree::Bronch().
3473 if (parentName.Length() == motherName.Length()) {
3474 parentName.Remove(0, motherName.Length());
3475 }
3476 } else {
3477 // -- Remove the mother name and the dot.
3478 if (parentName.Length() > motherName.Length()) {
3479 parentName.Remove(0, motherName.Length() + 1);
3480 }
3481 }
3482 }
3483 // FIXME: Do we need to use the other tests for a base class here?
3484 if (fType == 1) {
3485 // -- Our parent is a base class sub-branch, remove the base class name suffix from its name.
3486 if (mother != mother->GetSubBranch(this)) {
3487 // -- My parent's parent is not a top-level branch.
3488 // Remove the base class name suffix from the parent name.
3489 // Note: The pattern is the name of the base class.
3490 // coverity[var_deref_model] branchElem is non zero here since fType==1 and thus fID > -1
3491 TString pattern(branchElem->GetName());
3492 if (pattern.Length() <= parentName.Length()) {
3493 if (!strcmp(parentName.Data() + (parentName.Length() - pattern.Length()), pattern.Data())) {
3494 // The branch name contains the name of the base class in it.
3495 // This name is not reproduced in the sub-branches, so we need to
3496 // remove it.
3497 parentName.Remove(parentName.Length() - pattern.Length());
3498 }
3499 }
3500 }
3501 // Note: We intentionally leave any trailing dots
3502 // in the modified parent name here.
3503 }
3504
3505 // Remove the parent branch name part from our name,
3506 // but only if the parent branch is not a top-level branch.
3507 // FIXME: We should not assume parent name does not have length 0.
3508 if (fID > -1) {
3509 RemovePrefix(dataName, parentName);
3510 }
3511
3512 // Remove any leading dot.
3513 if (dataName.Length()) {
3514 if (dataName[0] == '.') {
3515 dataName.Remove(0, 1);
3516 }
3517 }
3518
3519 // Remove any trailing dot.
3520 if (dataName.Length()) {
3521 if (dataName[dataName.Length()-1] == '.') {
3522 dataName.Remove(dataName.Length() - 1, 1);
3523 }
3524 }
3525
3526 //
3527 // Now that we have our data member name, find our offset
3528 // in our parent class.
3529 //
3530 // Note: Our data member name can have many dots in it
3531 // if branches were elided between our parent branch
3532 // and us by Unroll().
3533 //
3534 // FIXME: This may not work if our member name is ambiguous.
3535 //
3536
3537 Int_t offset = 0;
3538 if (dataName.Length()) {
3539 // -- We have our data member name, do a lookup in the dictionary meta info of our parent class.
3540 // Get our parent class.
3541 TClass* pClass = nullptr;
3542 // First check whether this sub-branch is part of the 'cache' (because the data member it
3543 // represents is no longer in the current class layout.
3544 TStreamerInfo *subInfo = subBranch->GetInfoImp();
3545 //if (subInfo && subBranch->TestBit(kCache)) { // subInfo->GetElements()->At(subBranch->GetID())->TestBit(TStreamerElement::kCache)) {
3546 if (subBranchElement->TestBit(TStreamerElement::kCache)) {
3547 pClass = ((TStreamerElement*)subInfo->GetElements()->At(0))->GetClassPointer();
3548 }
3549 // FIXME: Do we need the other base class tests here?
3550 if (!pClass) {
3551 if (fType == 1) {
3552 // -- Parent branch is a base class branch.
3553 // FIXME: Is using branchElem here the right thing?
3554 pClass = branchElem->GetClassPointer();
3555 if (pClass->Property() & kIsAbstract) {
3556 // the class is abstract, let see if the
3557
3559 if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
3560 // Our parent's class is emulated and we represent an abstract class.
3561 // and the target class has not been set explicitly.
3562 TString target = pClass->GetName();
3563 target += "@@emulated";
3564
3565 pClass = TClass::GetClass(target);
3566 }
3567 }
3568 } else {
3569 // -- Parent branch is *not* a base class branch.
3570 // FIXME: This sometimes returns a null pointer.
3571 pClass = subBranch->GetParentClass();
3572 }
3573 }
3574 if (!pClass) {
3575 // -- No parent class, fix it.
3576 // FIXME: This is probably wrong!
3577 // Assume parent class is our parent branch's clones class or value class.
3578 if (GetClonesName() && strlen(GetClonesName())) {
3579 pClass = fClonesClass;
3580 if (!pClass) {
3581 Warning("InitializeOffsets", "subBranch: '%s' has no parent class, and cannot get class for clones class: '%s'!", subBranch->GetName(), GetClonesName());
3582 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3583 continue;
3584 }
3585 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3586 }
3589 Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass ? pClass->GetName() : "unknown class");
3590 }
3591 if (!pClass) {
3592 // -- Still no parent class, assume our parent class is our parent branch's class.
3593 // FIXME: This is probably wrong!
3594 pClass = branchClass;
3595 // FIXME: Enable this warning!
3596 //Warning("InitializeOffsets", "subBranch: '%s' has no parent class! Assuming parent class is: '%s'.", subBranch->GetName(), pClass->GetName());
3597 }
3598 }
3599 if (renamed && pClass) {
3600 if (pClass == branchClass) {
3601 pClass = branchElem->GetNewClass();
3602 } else if (fCollProxy && pClass == branchClass->GetCollectionProxy()->GetValueClass()) {
3603 pClass = fCollProxy->GetValueClass();
3604 }
3605 }
3606
3607 //------------------------------------------------------------------
3608 // If we have the are the sub-branch of the TBranchSTL, we need
3609 // to remove it's name to get the correct real data offsets
3610 ////////////////////////////////////////////////////////////////////
3611
3612 const bool isToplevelCollection = (this == GetMother() && (fType == 3 || fType == 4));
3613 if( stlParentName.Length() && (dynamic_cast<TBranchSTL*>(fParent) || isToplevelCollection))
3614 {
3615 if( !strncmp( stlParentName.Data(), dataName.Data(), stlParentName.Length()-1 )
3616 && dataName[ stlParentName.Length() ] == '.' )
3617 dataName.Remove( 0, stlParentName.Length()+1 );
3618 }
3619
3620 // Find our offset in our parent class using
3621 // a lookup by name in the dictionary meta info
3622 // for our parent class.
3623
3624 if (alternateElement) {
3625 Ssiz_t dotpos = dataName.Last('.');
3626 Ssiz_t endpos = dataName.Length();
3627 if (dotpos != kNPOS) ++dotpos; else dotpos = 0;
3628 dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
3629 }
3630 TRealData* rd = pClass->GetRealData(dataName);
3631 if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
3632 // -- Data member exists in the dictionary meta info, get the offset.
3633 // If we are using an alternateElement, it is the target of a rule
3634 // and might be indeed transient.
3635 offset = rd->GetThisOffset();
3636 } else if (subBranchElement->TestBit(TStreamerElement::kWholeObject)) {
3637 // We are a rule with no specific target, it applies to the whole
3638 // object, let's set the offset to zero
3639 offset = 0;
3640 } else {
3641 // -- No dictionary meta info for this data member, it must no
3642 // longer exist
3643 if (fEntries == 0) {
3644 // ... unless we creating the branch in which case
3645 // we have an internal error.
3646 if (pClass->GetListOfRealData()->GetEntries() == 0) {
3647 // We are probably missing the ShowMember, let's
3648 // just issue an error.
3649 Error("InitializeOffsets",
3650 "Could not find the real data member '%s' when constructing the branch '%s' [Likely missing ShowMember].",
3651 dataName.Data(),GetName());
3652 } else if (subInfo && subInfo->GetClassVersion()!=subInfo->GetClass()->GetClassVersion()) {
3653 // In the case where we are cloning a TTree that was created with an older version of the layout, we may not
3654 // able to find all the members
3655 Info("InitializeOffsets",
3656 "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'. ",
3657 dataName.Data(),GetName());
3658 } else {
3659 // Something really bad happen.
3660 Fatal("InitializeOffsets",
3661 "Could not find the real data member '%s' when constructing the branch '%s' [Likely an internal error, please report to the developers].",
3662 dataName.Data(),GetName());
3663 }
3664 }
3665 localOffset = TStreamerInfo::kMissing;
3666 }
3667 } else {
3668 // -- We have no data member name, ok for a base class, not good otherwise.
3669 if (isBaseSubBranch) {
3670 // I am a direct base class of my parent class, my local offset is enough.
3671 } else {
3672 Warning("InitializeOffsets", "Could not find the data member name for branch '%s' with parent branch '%s', assuming offset is zero!", subBranch->GetName(), GetName());
3673 }
3674 }
3675
3676 //
3677 // Ok, do final calculations for fOffset and fBranchOffset.
3678 //
3679
3680 if (isContDataMember) {
3681 // -- Container data members set fOffset instead of fBranchOffset.
3682 // The fOffset is what should be added to the start of the entry
3683 // in the collection (i.e., its current absolute address) to find
3684 // the beginning of the data member described by the current branch.
3685 //
3686 // Compensate for the i/o routines adding our local offset later.
3687 if (subBranch->fObject == nullptr && localOffset == TStreamerInfo::kMissing) {
3688 subBranch->SetMissing();
3689 // We stil need to set fBranchOffset in the case of a missing
3690 // element so that SetAddress is (as expected) not called
3691 // recursively in this case.
3692 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3693 } else {
3694 if (isBaseSubBranch) {
3695 // The value of 'offset' for a base class does not include its
3696 // 'localOffset'.
3697 subBranch->SetOffset(offset);
3698 } else {
3699 // The value of 'offset' for a regular data member does include its
3700 // 'localOffset', we need to remove it explicitly.
3701 subBranch->SetOffset(offset - localOffset);
3702 }
3703 }
3704 } else {
3705 // -- Set fBranchOffset for sub-branch.
3706 Int_t isSplit = 0 != subBranch->GetListOfBranches()->GetEntriesFast();
3707 if (subBranch->fObject == nullptr && localOffset == TStreamerInfo::kMissing) {
3708 // The branch is missing
3709 fBranchOffset[subBranchIdx] = TStreamerInfo::kMissing;
3710
3711 } else if (isSplit) {
3712 if (isBaseSubBranch) {
3713 // We are split, so we need to add in our local offset
3714 // to get our absolute address for our children.
3715 fBranchOffset[subBranchIdx] = offset + localOffset;
3716 } else {
3717 // We are split so our offset will never be
3718 // used in an i/o, so we do not have to subtract
3719 // off our local offset like below.
3720 fBranchOffset[subBranchIdx] = offset;
3721 }
3722 } else {
3723 if (isBaseSubBranch) {
3724 // We are not split, so our local offset will be
3725 // added later by the i/o routines.
3726 fBranchOffset[subBranchIdx] = offset;
3727 } else {
3728 // Compensate for the fact that the i/o routines
3729 // are going to add my local offset later.
3730 fBranchOffset[subBranchIdx] = offset - localOffset;
3731 }
3732 }
3733 }
3734 }
3735 }
3736 else {
3737 if (fID > -1) {
3738 // Branch is *not* a top-level branch.
3739 // Let's check if the target member is still present in memory
3741 fObject = nullptr;
3742 }
3743 }
3744 }
3745 const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
3746 if (fReadActionSequence && isSplitNode) {
3747 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3748 auto index = parent->fBranches.IndexOf(this);
3749 if (index >= 0) {
3751 }
3752 }
3753
3754 fInitOffsets = true;
3755}
3756
3757////////////////////////////////////////////////////////////////////////////////
3758/// Return true if more than one leaf, false otherwise.
3759
3761{
3762 Int_t nbranches = fBranches.GetEntriesFast();
3763 if (nbranches >= 1) {
3764 return true;
3765 }
3766 TList* browsables = const_cast<TBranchElement*>(this)->GetBrowsables();
3767 return browsables && browsables->GetSize();
3768}
3769
3770////////////////////////////////////////////////////////////////////////////////
3771/// Detect a collection written using a zero pointer in old versions of root.
3772/// In versions of ROOT older than 4.00/03, if a collection (TClonesArray
3773/// or STL container) was split but the pointer to the collection was zeroed
3774/// out, nothing was saved. Hence there is no __easy__ way to detect the
3775/// case. In newer versions, a zero is written so that a 'missing' collection
3776/// appears to be an empty collection.
3777
3779{
3780 bool ismissing = false;
3782 if (basket && fTree) {
3783 Long64_t entry = fTree->GetReadEntry();
3785 Long64_t last;
3786 if (fReadBasket == fWriteBasket) {
3787 last = fEntryNumber - 1;
3788 } else {
3789 last = fBasketEntry[fReadBasket+1] - 1;
3790 }
3791 Int_t* entryOffset = basket->GetEntryOffset();
3792 Int_t bufbegin;
3793 Int_t bufnext;
3794 if (entryOffset) {
3795 bufbegin = entryOffset[entry-first];
3796
3797 if (entry < last) {
3798 bufnext = entryOffset[entry+1-first];
3799 } else {
3800 bufnext = basket->GetLast();
3801 }
3802 if (bufnext == bufbegin) {
3803 ismissing = true;
3804 } else {
3805 // fixed length buffer so this is not the case here.
3806 if (basket->GetNevBufSize() == 0) {
3807 ismissing = true;
3808 }
3809 }
3810 }
3811 }
3812 return ismissing;
3813}
3814
3815////////////////////////////////////////////////////////////////////////////////
3816/// Print branch parameters.
3817
3818static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids)
3819{
3820 for(auto &cursor : ids) {
3821 auto id = cursor.fElemID;
3822 if (id >= 0) {
3823 auto el = info->GetElement(id);
3824 if (el)
3825 el->ls();
3826 else {
3827 Error("TBranchElement::Print", "Element for id #%d not found in StreamerInfo for %s",
3828 id, info->GetName());
3829 info->ls();
3830 }
3831 } else if (cursor.fNestedIDs) {
3832 Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
3833 PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
3834 }
3835 }
3836}
3837
3839{
3840 Int_t nbranches = fBranches.GetEntriesFast();
3841 if (strncmp(option,"debugAddress",strlen("debugAddress"))==0) {
3842 if (strlen(option)==strlen("debugAddress")) {
3843 Printf("%-24s %-16s %2s %4s %-16s %-16s %8s %8s %s %s\n",
3844 "Branch Name", "Streamer Class", "ID", "Type", "Class", "Parent", "pOffset", "fOffset", "fObject", "fOnfileObject");
3845 }
3846 if (strlen(GetName())>24) Printf("%-24s\n%-24s ", GetName(),"");
3847 else Printf("%-24s ", GetName());
3848
3849 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
3850 Int_t ind = parent ? parent->GetListOfBranches()->IndexOf(this) : -1;
3851 TVirtualStreamerInfo *info = ((TBranchElement*)this)->GetInfoImp();
3852
3853 Printf("%-16s %2d %4d %-16s %-16s %8x %8x %p %p%s\n",
3854 info ? info->GetName() : "StreamerInfo unavailable", GetID(), GetType(),
3856 (fBranchOffset&&parent && ind>=0) ? parent->fBranchOffset[ind] : 0,
3857 GetOffset(), GetObject(), fOnfileObject, TestBit(kOwnOnfileObj) ? " (owned)" : "");
3858 for (Int_t i = 0; i < nbranches; ++i) {
3859 TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3860 subbranch->Print("debugAddressSub");
3861 }
3862 return;
3863 }
3864 if (strncmp(option,"debugInfo",strlen("debugInfo"))==0) {
3865 Printf("Branch %s uses:",GetName());
3866 if (fID>=0) {
3867 // GetInfoImp()->GetElement(fID)->ls();
3868 // for(UInt_t i=0; i< fIDs.size(); ++i) {
3869 // GetInfoImp()->GetElement(fIDs[i])->ls();
3870 // }
3871 TStreamerInfo *localInfo = GetInfoImp();
3872 if (fType == 3 || fType == 4) {
3873 // Search for the correct version.
3875 }
3876 Printf(" With elements:");
3877 if (fType != 3 && fType != 4)
3878 localInfo->GetElement(fID)->ls();
3879 PrintElements(localInfo, fNewIDs);
3880 Printf(" with read actions:");
3882 Printf(" with write actions:");
3884 } else if (!fNewIDs.empty() && GetInfoImp()) {
3885 TStreamerInfo *localInfo = GetInfoImp();
3886 if (fType == 3 || fType == 4) {
3887 // Search for the correct version.
3889 }
3890 PrintElements(localInfo, fNewIDs);
3891 Printf(" with read actions:");
3893 Printf(" with write actions:");
3895 }
3896 TString suboption = "debugInfoSub";
3897 suboption += (option+strlen("debugInfo"));
3898 for (Int_t i = 0; i < nbranches; ++i) {
3899 TBranchElement* subbranch = (TBranchElement*)fBranches.At(i);
3900 subbranch->Print(suboption);
3901 }
3902 Printf(" ");
3903 return;
3904 }
3905 if (nbranches) {
3906 if (fID == -2) {
3907 if (strcmp(GetName(),GetTitle()) == 0) {
3908 Printf("*Branch :%-66s *",GetName());
3909 } else {
3910 Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
3911 }
3912 Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
3913 Printf("*............................................................................*");
3914 }
3915 if (fType >= 2) {
3917 }
3918 for (Int_t i=0;i<nbranches;i++) {
3919 TBranch *branch = (TBranch*)fBranches.At(i);
3920 branch->Print(option);
3921 }
3922 } else {
3924 }
3925}
3926
3927////////////////////////////////////////////////////////////////////////////////
3928/// Prints values of leaves.
3929
3931{
3933
3934 TStreamerInfo *info = GetInfoImp();
3935 Int_t prID = fID;
3936 char *object = fObject;
3937 if (TestBit(kCache)) {
3939 prID = fID+1;
3940 } else if (fOnfileObject) {
3941 object = fOnfileObject->GetObjectAt(0);
3942 }
3943 }
3944
3945 if (TestBit(kDecomposedObj)) {
3946 if (!fAddress) {
3947 return;
3948 }
3949 if (fType == 3 || fType == 4) {
3950 // TClonesArray or STL container top-level branch.
3951 printf(" %-15s = %d\n", GetName(), fNdata);
3952 return;
3953 } else if (fType == 31 || fType == 41) {
3954 // TClonesArray or STL container sub-branch.
3955 Int_t n = TMath::Min(10, fNdata);
3958 // TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar is
3959 // printed as a string and could print weird characters.
3960 // So we print an unsigned char instead (not perfect, but better).
3962 }
3963 if (atype > 54) {
3964 // FIXME: More logic required here (like in ReadLeaves)
3965 printf(" %-15s = %d\n", GetName(), fNdata);
3966 return;
3967 }
3968 if (fStreamerType > 20) {
3969 atype -= 20;
3971 n = n * leaf->GetLenStatic();
3972 }
3973 if (GetInfoImp()) {
3974 GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3975 }
3976 return;
3977 } else if (fType <= 2) {
3978 // Branch in split mode.
3979 // FIXME: This should probably be < 60 instead.
3980 if ((fStreamerType > 40) && (fStreamerType < 55)) {
3981 Int_t atype = fStreamerType - 20;
3982 TBranchElement* counterElement = (TBranchElement*) fBranchCount;
3983 Int_t n = (Int_t) counterElement->GetValue(0, 0);
3984 if (GetInfoImp()) {
3985 GetInfoImp()->PrintValue(GetName(), fAddress, atype, n, lenmax);
3986 }
3987 } else {
3988 if (GetInfoImp()) {
3989 GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
3990 }
3991 }
3992 return;
3993 }
3994 } else if (fType == 3) {
3995 printf(" %-15s = %d\n", GetName(), fNdata);
3996 } else if (fType == 31) {
3997 TClonesArray* clones = (TClonesArray*) object;
3998 if (GetInfoImp()) {
3999 GetInfoImp()->PrintValueClones(GetName(), clones, prID, fOffset, lenmax);
4000 }
4001 } else if (fType == 41) {
4003 if (GetInfoImp()) {
4004 GetInfoImp()->PrintValueSTL(GetName(), ((TBranchElement*) this)->GetCollectionProxy(), prID, fOffset, lenmax);
4005 }
4006 } else {
4007 if (GetInfoImp()) {
4008 GetInfoImp()->PrintValue(GetName(), object, prID, -1, lenmax);
4009 }
4010 }
4011}
4012
4013////////////////////////////////////////////////////////////////////////////////
4014/// Unconfiguration Read Leave function.
4015
4017{
4018 Fatal("ReadLeaves","The ReadLeaves function has not been configured for %s",GetName());
4019}
4020
4021////////////////////////////////////////////////////////////////////////////////
4022/// Read leaves into i/o buffers for this branch.
4023/// For the case where the branch is set in MakeClass mode (decomposed object).
4024
4026{
4028
4029 if (fType == 3 || fType == 4) {
4030 // Top level branch of a TClonesArray.
4031 Int_t *n = (Int_t*) fAddress;
4032 b >> n[0];
4033 if ((n[0] < 0) || (n[0] > fMaximum)) {
4034 if (IsMissingCollection()) {
4035 n[0] = 0;
4036 b.SetBufferOffset(b.Length() - sizeof(n));
4037 } else {
4038 Error("ReadLeaves", "Incorrect size read for the container in %s\nThe size read is %d when the maximum is %d\nThe size is reset to 0 for this entry (%lld)", GetName(), n[0], fMaximum, GetReadEntry());
4039 n[0] = 0;
4040 }
4041 }
4042 fNdata = n[0];
4043 if (fType == 4) {
4044 Int_t nbranches = fBranches.GetEntriesFast();
4045 switch(fSTLtype) {
4046 case ROOT::kSTLset:
4047 case ROOT::kSTLmultiset:
4048 case ROOT::kSTLmap:
4049 case ROOT::kSTLmultimap:
4050 for (Int_t i=0; i<nbranches; i++) {
4051 TBranch *branch = (TBranch*)fBranches[i];
4052 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4053 if (nb < 0) {
4054 break;
4055 }
4056 }
4057 break;
4058 default:
4059 break;
4060 }
4061 }
4062 return;
4063 } else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
4065 Int_t atype = fStreamerType;
4066 // FIXME: This should probably be > 59 instead.
4067 if (atype > 54) return;
4068 if (!fAddress) {
4069 return;
4070 }
4071 Int_t n = fNdata;
4072 if (atype>40) {
4073 atype -= 40;
4074 if (!fBranchCount2) return;
4075 const char *len_where = (char*)fBranchCount2->fAddress;
4076 if (!len_where) return;
4077 Int_t len_atype = fBranchCount2->fStreamerType;
4078 Int_t length;
4079 Int_t k;
4080 Char_t isArray;
4081 for( k=0; k<n; k++) {
4082 char **where = &(((char**)fAddress)[k]);
4083 delete [] *where;
4084 *where = nullptr;
4085 switch(len_atype) {
4086 case 1: {length = ((Char_t*) len_where)[k]; break;}
4087 case 2: {length = ((Short_t*) len_where)[k]; break;}
4088 case 3: {length = ((Int_t*) len_where)[k]; break;}
4089 case 4: {length = ((Long_t*) len_where)[k]; break;}
4090 //case 5: {length = ((Float_t*) len_where)[k]; break;}
4091 case 6: {length = ((Int_t*) len_where)[k]; break;}
4092 //case 8: {length = ((Double_t*)len_where)[k]; break;}
4093 case 11: {length = ((UChar_t*) len_where)[k]; break;}
4094 case 12: {length = ((UShort_t*) len_where)[k]; break;}
4095 case 13: {length = ((UInt_t*) len_where)[k]; break;}
4096 case 14: {length = ((ULong_t*) len_where)[k]; break;}
4097 case 15: {length = ((UInt_t*) len_where)[k]; break;}
4098 case 16: {length = ((Long64_t*) len_where)[k]; break;}
4099 case 17: {length = ((ULong64_t*)len_where)[k]; break;}
4100 case 18: {length = ((bool*) len_where)[k]; break;}
4101 default: continue;
4102 }
4103 b >> isArray;
4104 if (length <= 0) continue;
4105 if (isArray == 0) continue;
4106 switch (atype) {
4107 case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
4108 case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
4109 case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4110 case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
4111 case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
4112 case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
4113 case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
4114 case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
4115 case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
4116 case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4117 case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
4118 case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
4119 case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
4120 case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
4121 case 18: {*where=new char[sizeof(bool)*length]; b.ReadFastArray((bool*) *where, length); break;}
4122 }
4123 }
4124 return;
4125 }
4126 if (atype > 20) {
4127 atype -= 20;
4129 n *= leaf->GetLenStatic();
4130 }
4131 switch (atype) {
4132 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4133 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4134 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4135 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4136 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4137 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4138 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4139 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4140 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4141 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4142 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4143 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4144 case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
4145 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4146 case 18: {b.ReadFastArray((bool*) fAddress, n); break;}
4147 case 9: {
4150 Double_t *xx = (Double_t*) fAddress;
4151 for (Int_t ii=0;ii<n;ii++) {
4152 b.ReadDouble32(&(xx[ii]),se);
4153 }
4154 break;
4155 }
4156 case 19: {
4159 Float_t *xx = (Float_t*) fAddress;
4160 for (Int_t ii=0;ii<n;ii++) {
4161 b.ReadFloat16(&(xx[ii]),se);
4162 }
4163 break;
4164 }
4165 }
4166 return;
4167 } else if (fType <= 2) { // branch in split mode
4168 // FIXME: This should probably be < 60 instead.
4169 if (fStreamerType > 40 && fStreamerType < 55) {
4170 Int_t atype = fStreamerType - 40;
4171 Int_t n;
4172 if (fBranchCount==nullptr) {
4173 // Missing fBranchCount. let's attempts to recover.
4174
4175 TString countname( GetName() );
4176 Ssiz_t dot = countname.Last('.');
4177 if (dot>=0) {
4178 countname.Remove(dot+1);
4179 } else {
4180 countname = "";
4181 }
4182 TString counter( GetTitle() );
4183 Ssiz_t loc = counter.Last('[');
4184 if (loc>=0) {
4185 counter.Remove(0,loc+1);
4186 }
4187 loc = counter.Last(']');
4188 if (loc>=0) {
4189 counter.Remove(loc);
4190 }
4191 countname += counter;
4193 }
4194 if (fBranchCount) {
4195 n = (Int_t)fBranchCount->GetValue(0,0);
4196 } else {
4197 Warning("ReadLeaves","Missing fBranchCount for %s. Data will not be read correctly by the MakeClass mode.",GetName());
4198 n = 0;
4199 }
4200 fNdata = n;
4201 Char_t isArray;
4202 b >> isArray;
4203 switch (atype) {
4204 case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
4205 case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
4206 case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4207 case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
4208 case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
4209 case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
4210 case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
4211 case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
4212 case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
4213 case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4214 case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
4215 case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
4216 case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
4217 case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
4218 case 18: {b.ReadFastArray((bool*) fAddress, n); break;}
4219 case 9: {
4222 Double_t *xx = (Double_t*) fAddress;
4223 for (Int_t ii=0;ii<n;ii++) {
4224 b.ReadDouble32(&(xx[ii]),se);
4225 }
4226 break;
4227 }
4228 case 19: {
4231 Float_t *xx = (Float_t*) fAddress;
4232 for (Int_t ii=0;ii<n;ii++) {
4233 b.ReadFloat16(&(xx[ii]),se);
4234 }
4235 break;
4236 }
4237 }
4238 } else {
4239 fNdata = 1;
4240 if (fAddress) {
4241 if (fType<0) {
4242 // Non TObject, Non collection classes with a custom streamer.
4243
4244 // if (fObject)
4246 } else {
4247 TStreamerInfo *info = GetInfoImp();
4248 if (!info) {
4249 return;
4250 }
4251 // Since info is not null, fReadActionSequence is not null either.
4252 b.ApplySequence(*fReadActionSequence, fObject);
4253 }
4255 fNdata = (Int_t) GetValue(0, 0);
4256 }
4257 } else {
4258 fNdata = 0;
4259 }
4260 }
4261 return;
4262 }
4263}
4264
4265////////////////////////////////////////////////////////////////////////////////
4266/// Read leaves into i/o buffers for this branch.
4267/// Case of a collection (fType == 4).
4268
4270{
4272 if (fObject == nullptr)
4273 {
4274 // We have nowhere to copy the data (probably because the data member was
4275 // 'dropped' from the current schema) so let's no copy it in a random place.
4276 return;
4277 }
4278
4279 // STL container master branch (has only the number of elements).
4280 Int_t n;
4281 b >> n;
4282 if ((n < 0) || (n > fMaximum)) {
4283 if (IsMissingCollection()) {
4284 n = 0;
4285 b.SetBufferOffset(b.Length()-sizeof(n));
4286 } else {
4287 Error("ReadLeaves", "Incorrect size read for the container in %s\n\tThe size read is %d while the maximum is %d\n\tThe size is reset to 0 for this entry (%lld)", GetName(), n, fMaximum, GetReadEntry());
4288 n = 0;
4289 }
4290 }
4291 fNdata = n;
4292
4293 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4294
4295 // Note: Proxy-helper needs to "embrace" the entire
4296 // streaming of this STL container if the container
4297 // is a set/multiset/map/multimap (what we do not
4298 // know here).
4299 // For vector/list/deque Allocate == Resize
4300 // and Commit == noop.
4301 // TODO: Exception safety a la TPushPop
4304 void* alternate = proxy->Allocate(fNdata, true);
4306 fPtrIterators->CreateIterators(alternate, proxy);
4307 } else {
4308 fIterators->CreateIterators(alternate, proxy);
4309 }
4310
4311 Int_t nbranches = fBranches.GetEntriesFast();
4312 switch (fSTLtype) {
4313 case ROOT::kSTLset:
4316 case ROOT::kSTLmultiset:
4317 case ROOT::kSTLmap:
4318 case ROOT::kSTLmultimap:
4321 for (Int_t i = 0; i < nbranches; ++i) {
4322 TBranch *branch = (TBranch*) fBranches[i];
4323 Int_t nb = branch->GetEntry(GetReadEntry(), 1);
4324 if (nb < 0) {
4325 // Give up on i/o failure.
4326 // FIXME: We need an error message here.
4327 break;
4328 }
4329 }
4330 break;
4331 default:
4332 break;
4333 }
4334 //------------------------------------------------------------------------
4335 // We have split this stuff, so we need to create the pointers
4336 /////////////////////////////////////////////////////////////////////////////
4337
4339 {
4340 TClass *elClass = proxy->GetValueClass();
4341
4342 //--------------------------------------------------------------------
4343 // The allocation is done in this strange way because ReadLeaves
4344 // is being called many times by TTreeFormula!!!
4345 //////////////////////////////////////////////////////////////////////////
4346
4347 Int_t i = 0;
4348 // coverity[returned_null] the fNdata is check enough to prevent the use of null value of At(0)
4349 if( !fNdata || *(void**)proxy->At( 0 ) != nullptr )
4350 i = fNdata;
4351
4352 for( ; i < fNdata; ++i )
4353 {
4354 void **el = (void**)proxy->At( i );
4355 // coverity[dereference] since this is a member streaming action by definition the collection contains objects and elClass is not null.
4356 *el = elClass->New();
4357 }
4358 }
4359
4360 proxy->Commit(alternate);
4361}
4362
4363////////////////////////////////////////////////////////////////////////////////
4364/// Read leaves into i/o buffers for this branch.
4365/// Case of a data member within a collection (fType == 41).
4366
4368{
4370 if (fObject == nullptr)
4371 {
4372 // We have nowhere to copy the data (probably because the data member was
4373 // 'dropped' from the current schema) so let's no copy it in a random place.
4374 return;
4375 }
4376
4377 // STL container sub-branch (contains the elements).
4379 if (!fNdata) {
4380 return;
4381 }
4382
4383 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4384
4385 TStreamerInfo *info = GetInfoImp();
4386 if (info == nullptr) return;
4387
4390
4391 // R__ASSERT(0);
4393 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4394}
4395
4396////////////////////////////////////////////////////////////////////////////////
4397/// Read leaves into i/o buffers for this branch.
4398/// Case of a data member within a collection (fType == 41).
4399
4401{
4403 if (fObject == nullptr)
4404 {
4405 // We have nowhere to copy the data (probably because the data member was
4406 // 'dropped' from the current schema) so let's no copy it in a random place.
4407 return;
4408 }
4409
4410 // STL container sub-branch (contains the elements).
4412 if (!fNdata) {
4413 return;
4414 }
4415 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4416
4417 TStreamerInfo *info = GetInfoImp();
4418 if (info == nullptr) return;
4419
4422
4424 b.ApplySequenceVecPtr(*fReadActionSequence,iter->fBegin,iter->fEnd);
4425}
4426
4427////////////////////////////////////////////////////////////////////////////////
4428/// Read leaves into i/o buffers for this branch.
4429/// Case of a data member within a collection (fType == 41).
4430
4432{
4434 if (fObject == nullptr)
4435 {
4436 // We have nowhere to copy the data (probably because the data member was
4437 // 'dropped' from the current schema) so let's no copy it in a random place.
4438 return;
4439 }
4440
4441 // STL container sub-branch (contains the elements).
4443 if (!fNdata) {
4444 return;
4445 }
4446 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4447
4448 TStreamerInfo *info = GetInfoImp();
4449 if (info == nullptr) return;
4450 // Since info is not null, fReadActionSequence is not null either.
4451
4452 // Still calling PushPop for the legacy entries.
4455
4457 b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
4458}
4459
4460////////////////////////////////////////////////////////////////////////////////
4461/// Read leaves into i/o buffers for this branch.
4462/// Case of a TClonesArray (fType == 3).
4463
4465{
4467 if (fObject == nullptr)
4468 {
4469 // We have nowhere to copy the data (probably because the data member was
4470 // 'dropped' from the current schema) so let's no copy it in a random place.
4471 return;
4472 }
4473
4474 // TClonesArray master branch (has only the number of elements).
4475 Int_t n;
4476 b >> n;
4477 if ((n < 0) || (n > fMaximum)) {
4478 if (IsMissingCollection()) {
4479 n = 0;
4480 b.SetBufferOffset(b.Length()-sizeof(n));
4481 } else {
4482 Error("ReadLeaves", "Incorrect size read for the container in %s\n\tThe size read is %d while the maximum is %d\n\tThe size is reset to 0 for this entry (%lld)", GetName(), n, fMaximum, GetReadEntry());
4483 n = 0;
4484 }
4485 }
4486 fNdata = n;
4487 TClonesArray* clones = (TClonesArray*) fObject;
4488 if (clones->IsZombie()) {
4489 return;
4490 }
4491 // The salient part of Clear is now 'duplicated in ExpandCreateFast (i.e. the
4492 // setting to zero of the unused slots), so we no longer need to call Clear explicitly
4493 // clones->Clear();
4494 clones->ExpandCreateFast(fNdata);
4495}
4496
4497////////////////////////////////////////////////////////////////////////////////
4498/// Read leaves into i/o buffers for this branch.
4499/// Case of a data member within a TClonesArray (fType == 31).
4500
4502{
4503 // No need to validate the address here, if we are a member of a split ClonesArray,
4504 // fID is positive
4505 // ValidateAddress();
4506
4507 if (fObject == nullptr)
4508 {
4509 // We have nowhere to copy the data (probably because the data member was
4510 // 'dropped' from the current schema) so let's no copy it in a random place.
4511 return;
4512 }
4513
4514 // TClonesArray sub-branch (contains the elements).
4516 TClonesArray* clones = (TClonesArray*) fObject;
4517 if (clones->IsZombie()) {
4518 return;
4519 }
4520 TStreamerInfo *info = GetInfoImp();
4521 if (info==nullptr) return;
4522 // Since info is not null, fReadActionSequence is not null either.
4523
4524 // Note, we could (possibly) save some more, by configuring the action
4525 // based on the value of fOnfileObject rather than pushing in on a stack.
4526 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
4527
4528 char **arr = (char **)clones->GetObjectRef();
4529 char **end = arr + fNdata;
4530 b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
4531}
4532
4533////////////////////////////////////////////////////////////////////////////////
4534/// Read leaves into i/o buffers for this branch.
4535/// For split-class branch, base class branch, data member branch, or top-level branch.
4536/// which do not have a branch count and are not a counter.
4537
4539{
4540 R__ASSERT(fBranchCount==nullptr);
4542
4544 if (fObject == nullptr)
4545 {
4546 // We have nowhere to copy the data (probably because the data member was
4547 // 'dropped' from the current schema) so let's no copy it in a random place.
4548 return;
4549 }
4550
4551 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4552 // If not a TClonesArray or STL container master branch
4553 // or sub-branch and branch inherits from tobject,
4554 // then register with the buffer so that pointers are
4555 // handled properly.
4556 if (TestBit(kBranchObject)) {
4557 b.MapObject((TObject*) fObject);
4558 } else if (TestBit(kBranchAny)) {
4559 b.MapObject(fObject, fBranchClass);
4560 }
4561
4562 fNdata = 1;
4563 TStreamerInfo *info = GetInfoImp();
4564 if (!info) {
4565 return;
4566 }
4567 // Since info is not null, fReadActionSequence is not null either.
4568 b.ApplySequence(*fReadActionSequence, fObject);
4569}
4570
4571////////////////////////////////////////////////////////////////////////////////
4572/// Read leaves into i/o buffers for this branch.
4573/// For split-class branch, base class branch, data member branch, or top-level branch.
4574/// which do have a branch count and are not a counter.
4575
4577{
4579
4581 if (fObject == nullptr)
4582 {
4583 // We have nowhere to copy the data (probably because the data member was
4584 // 'dropped' from the current schema) so let's no copy it in a random place.
4585 return;
4586 }
4587
4588 // If not a TClonesArray or STL container master branch
4589 // or sub-branch and branch inherits from tobject,
4590 // then register with the buffer so that pointers are
4591 // handled properly.
4592 if (TestBit(kBranchObject)) {
4593 b.MapObject((TObject*) fObject);
4594 } else if (TestBit(kBranchAny)) {
4595 b.MapObject(fObject, fBranchClass);
4596 }
4597
4598 fNdata = (Int_t) fBranchCount->GetValue(0, 0);
4599 TStreamerInfo *info = GetInfoImp();
4600 if (!info) {
4601 return;
4602 }
4603 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1); // Here we have a single object that contains a variable size C-style array.
4604 // Since info is not null, fReadActionSequence is not null either.
4605 b.ApplySequence(*fReadActionSequence, fObject);
4606}
4607
4608////////////////////////////////////////////////////////////////////////////////
4609/// Read leaves into i/o buffers for this branch.
4610/// For split-class branch, base class branch, data member branch, or top-level branch.
4611/// which do not have a branch count and are a counter.
4612
4614{
4616 if (fObject == nullptr)
4617 {
4618 // We have nowhere to copy the data (probably because the data member was
4619 // 'dropped' from the current schema) so let's no copy it in a random place.
4620 return;
4621 }
4622
4623 // If not a TClonesArray or STL container master branch
4624 // or sub-branch and branch inherits from tobject,
4625 // then register with the buffer so that pointers are
4626 // handled properly.
4627 if (TestBit(kBranchObject)) {
4628 b.MapObject((TObject*) fObject);
4629 } else if (TestBit(kBranchAny)) {
4630 b.MapObject(fObject, fBranchClass);
4631 }
4632
4633 TStreamerInfo *info = GetInfoImp();
4634 if (!info) {
4635 return;
4636 }
4637
4638 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4639
4640 // Since info is not null, fReadActionSequence is not null either.
4641 b.ApplySequence(*fReadActionSequence, fObject);
4642 fNdata = (Int_t) GetValue(0, 0);
4643}
4644
4645////////////////////////////////////////////////////////////////////////////////
4646/// Read leaves into i/o buffers for this branch.
4647/// Non TObject, Non collection classes with a custom streamer.
4648
4650{
4652 if (fObject == nullptr)
4653 {
4654 // We have nowhere to copy the data (probably because the data member was
4655 // 'dropped' from the current schema) so let's no copy it in a random place.
4656 return;
4657 }
4658
4659 R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,1);
4661}
4662
4663////////////////////////////////////////////////////////////////////////////////
4664/// Unconfiguration Fill Leave function.
4665
4667{
4668 Fatal("FillLeaves","The FillLeaves function has not been configured for %s",GetName());
4669}
4670
4671////////////////////////////////////////////////////////////////////////////////
4672/// Delete any object we may have allocated on a previous call to SetAddress.
4673
4675{
4676 if (fObject && TestBit(kDeleteObject)) {
4677 if (IsAutoDelete() && fAddress != (char*)&fObject) {
4678 *((char**) fAddress) = nullptr;
4679 }
4681 if (fType == 3) {
4682 // -- We are a TClonesArray master branch.
4684 fObject = nullptr;
4687 // -- We are a pointer to a TClonesArray.
4688 // We must zero the pointer in the object.
4689 *((char**) fAddress) = nullptr;
4690 }
4691 } else if (fType == 4) {
4692 // -- We are an STL container master branch.
4694
4695 if (!proxy) {
4696 Warning("ReleaseObject", "Cannot delete allocated STL container because I do not have a proxy! branch: %s", GetName());
4697 fObject = nullptr;
4698 } else {
4699 bool needDelete = proxy->GetProperties()&TVirtualCollectionProxy::kNeedDelete;
4700 if (needDelete && fID >= 0) {
4703 needDelete = !se->TestBit(TStreamerElement::kDoNotDelete);
4704 }
4705 if (needDelete) {
4707 proxy->Clear("force");
4708 }
4709 proxy->Destructor(fObject);
4710 fObject = nullptr;
4711 }
4713 // -- We are a pointer to an STL container.
4714 // We must zero the pointer in the object.
4715 *((char**) fAddress) = nullptr;
4716 }
4717 } else {
4718 // We are *not* a TClonesArray master branch and we are *not* an STL container master branch.
4720 if (!cl) {
4721 Warning("ReleaseObject", "Cannot delete allocated object because I cannot instantiate a TClass object for its class! branch: '%s' class: '%s'", GetName(), fBranchClass.GetClassName());
4722 fObject = nullptr;
4723 } else {
4725
4726 if (proxy) {
4727 if (fID >= 0) {
4729 TStreamerElement* se = si->GetElement(fID);
4732 proxy->Clear("force");
4733 }
4736 proxy->Clear("force");
4737 }
4738
4739 }
4740 cl->Destructor(fObject);
4741 fObject = nullptr;
4742 }
4743 }
4744 }
4745}
4746
4747////////////////////////////////////////////////////////////////////////////////
4748/// Reset a Branch.
4749///
4750/// Existing i/o buffers are deleted.
4751/// Entries, max and min are reset.
4752///
4753
4755{
4756 Int_t nbranches = fBranches.GetEntriesFast();
4757 for (Int_t i = 0; i < nbranches; ++i) {
4758 TBranch* branch = (TBranch*) fBranches[i];
4759 branch->Reset(option);
4760 }
4761 fBranchID = -1;
4763}
4764
4765////////////////////////////////////////////////////////////////////////////////
4766/// Reset a Branch after a Merge operation (drop data but keep customizations)
4767///
4768
4770{
4771 Int_t nbranches = fBranches.GetEntriesFast();
4772 for (Int_t i = 0; i < nbranches; ++i) {
4773 TBranch* branch = (TBranch*) fBranches[i];
4774 branch->ResetAfterMerge(info);
4775 }
4777}
4778
4779////////////////////////////////////////////////////////////////////////////////
4780/// Set branch address to zero and free all allocated memory.
4781
4783{
4784 for (Int_t i = 0; i < fNleaves; ++i) {
4785 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
4786 //if (leaf) leaf->SetAddress(0);
4787 leaf->SetAddress(nullptr);
4788 }
4789
4790 // Note: We *must* do the sub-branches first, otherwise
4791 // we may delete the object containing the sub-branches
4792 // before giving them a chance to cleanup.
4793 Int_t nbranches = fBranches.GetEntriesFast();
4794 for (Int_t i = 0; i < nbranches; ++i) {
4795 TBranch* br = (TBranch*) fBranches[i];
4796 if (br) br->ResetAddress();
4797 }
4798
4799 //
4800 // SetAddress may have allocated an object.
4801 //
4802
4803 ReleaseObject();
4804
4806 fAddress = nullptr;
4807 fObject = nullptr;
4808}
4809
4810////////////////////////////////////////////////////////////////////////////////
4811/// Release ownership of any allocated objects.
4812///
4813/// Note: This interface was added so that clone trees could
4814/// be told they do not own the allocated objects.
4815
4817{
4820 for (Int_t i = 0; i < nb; ++i) {
4821 TBranch* br = (TBranch*) fBranches[i];
4823 ((TBranchElement*) br)->ResetDeleteObject();
4824 }
4825 }
4826}
4827
4828////////////////////////////////////////////////////////////////////////////////
4829/// \brief Reset offset and StreamerInfo information from this branch.
4830/// \param[in] recurse When true call ResetInitInfo on all subbranches.
4831///
4832
4834{
4835 fInfo = nullptr;
4836 fInit = false;
4837 fInitOffsets = false;
4838 fCurrentClass = nullptr;
4839 delete fReadActionSequence;
4840 fReadActionSequence = nullptr;
4841 delete fFillActionSequence;
4842 fFillActionSequence = nullptr;
4843
4844 if (recurse) {
4845 Int_t nbranches = fBranches.GetEntriesFast();
4846 for (Int_t i = 0; i < nbranches; ++i) {
4848 sub->ResetInitInfo(true);
4849 }
4850 }
4851}
4852
4853////////////////////////////////////////////////////////////////////////////////
4854/// Point this branch at an object.
4855///
4856/// For a sub-branch, addr is a pointer to the branch object.
4857///
4858/// For a top-level branch the meaning of addr is as follows:
4859///
4860/// If addr is zero, then we allocate a branch object
4861/// internally and the branch is the owner of the allocated
4862/// object, not the caller. However the caller may obtain
4863/// a pointer to the branch object with GetObject().
4864/// The pointer is reset to zero (nullptr) when the relevant
4865/// branch object is destroyed.
4866///
4867/// Example:
4868/// ~~~ {.cpp}
4869/// branch->SetAddress(0);
4870/// Event* event = branch->GetObject();
4871/// ... Do some work.
4872/// ~~~
4873/// If addr is not zero, but the pointer addr points at is
4874/// zero, then we allocate a branch object and set the passed
4875/// pointer to point at the allocated object. The caller
4876/// owns the allocated object and is responsible for deleting
4877/// it when it is no longer needed.
4878///
4879/// Example:
4880/// ~~~ {.cpp}
4881/// Event* event = 0;
4882/// branch->SetAddress(&event);
4883/// ... Do some work.
4884/// delete event;
4885/// event = 0;
4886/// ~~~
4887/// If addr is not zero and the pointer addr points at is
4888/// also not zero, then the caller has allocated a branch
4889/// object and is asking us to use it. The caller owns it
4890/// and must delete it when it is no longer needed.
4891///
4892/// Example:
4893/// ~~~ {.cpp}
4894/// Event* event = new Event();
4895/// branch->SetAddress(&event);
4896/// ... Do some work.
4897/// delete event;
4898/// event = 0;
4899/// ~~~
4900/// These rules affect users of TTree::Branch(),
4901/// TTree::SetBranchAddress(), and TChain::SetBranchAddress()
4902/// as well because those routines call this one.
4903///
4904/// An example of a tree with branches with objects allocated
4905/// and owned by us:
4906/// ~~~ {.cpp}
4907/// TFile* f1 = new TFile("myfile_original.root");
4908/// TTree* t1 = (TTree*) f->Get("MyTree");
4909/// TFile* f2 = new TFile("myfile_copy.root", "recreate");
4910/// TTree* t2 = t1->Clone(0);
4911/// for (Int_t i = 0; i < 10; ++i) {
4912/// t1->GetEntry(i);
4913/// t2->Fill();
4914/// }
4915/// t2->Write()
4916/// delete f2;
4917/// f2 = 0;
4918/// delete f1;
4919/// f1 = 0;
4920/// ~~~
4921/// An example of a branch with an object allocated by us,
4922/// but owned by the caller:
4923/// ~~~ {.cpp}
4924/// TFile* f = new TFile("myfile.root", "recreate");
4925/// TTree* t = new TTree("t", "A test tree.")
4926/// Event* event = 0;
4927/// TBranchElement* br = t->Branch("event.", &event);
4928/// for (Int_t i = 0; i < 10; ++i) {
4929/// ... Fill event with meaningful data in some way.
4930/// t->Fill();
4931/// }
4932/// t->Write();
4933/// delete event;
4934/// event = 0;
4935/// delete f;
4936/// f = 0;
4937/// ~~~
4938/// Notice that the only difference between this example
4939/// and the following example is that the event pointer
4940/// is zero when the branch is created.
4941///
4942/// An example of a branch with an object allocated and
4943/// owned by the caller:
4944/// ~~~ {.cpp}
4945/// TFile* f = new TFile("myfile.root", "recreate");
4946/// TTree* t = new TTree("t", "A test tree.")
4947/// Event* event = new Event();
4948/// TBranchElement* br = t->Branch("event.", &event);
4949/// for (Int_t i = 0; i < 10; ++i) {
4950/// ... Fill event with meaningful data in some way.
4951/// t->Fill();
4952/// }
4953/// t->Write();
4954/// delete event;
4955/// event = 0;
4956/// delete f;
4957/// f = 0;
4958/// ~~~
4959/// If AutoDelete is on (see TBranch::SetAutoDelete),
4960/// the top level objet will be deleted and recreate
4961/// each time an entry is read, whether or not the
4962/// TTree owns the object.
4963
4965{
4966 SetAddressImpl(addr, (addr == nullptr));
4967}
4968
4969/// See TBranchElement::SetAddress.
4970/// If implied is true, we do not over-ride existing address for
4971/// sub-branches.
4972void TBranchElement::SetAddressImpl(void* addr, bool implied)
4973{
4974 //
4975 // Don't bother if we are disabled.
4976 //
4977
4978 if (TestBit(kDoNotProcess)) {
4979 return;
4980 }
4981
4982 //
4983 // FIXME: When would this happen?
4984 //
4985
4986 if (fType < -1) {
4987 return;
4988 }
4989
4990 //
4991 // Special case when called from code generated by TTree::MakeClass.
4992 //
4993
4994 if (Longptr_t(addr) == -1) {
4995 // FIXME: Do we have to release an object here?
4996 // ReleaseObject();
4997 fAddress = (char*) -1;
4998 fObject = (char*) -1;
5001 return;
5002 }
5003
5004 //
5005 // Reset last read entry number, we have a new user object now.
5006 //
5007
5008 fReadEntry = -1;
5009
5010 //
5011 // Make sure our branch class is instantiated.
5012 //
5013 TClass* clOfBranch = fBranchClass.GetClass();
5014 if( fTargetClass.GetClassName()[0] ) {
5015 clOfBranch = fTargetClass;
5016 }
5017
5018 //
5019 // Try to build the streamer info.
5020 //
5021
5022 TStreamerInfo *info = GetInfoImp();
5023
5024 // FIXME: Warn about failure to get the streamer info here?
5025
5026 //
5027 // We may have allocated an object last time we were called.
5028 //
5029
5030 if (fObject && TestBit(kDeleteObject)){
5031 ReleaseObject();
5032 }
5033
5034 //
5035 // Remember the pointer to the pointer to our object.
5036 //
5037
5038 fAddress = (char*) addr;
5039 if (fAddress != (char*)(&fObject)) {
5040 fObject = nullptr;
5041 }
5044
5045 //
5046 // Do special stuff if we got called from a MakeClass class.
5047 // Allow sub-branches to have independently set addresses.
5048 //
5049
5050 if (TestBit(kDecomposedObj)) {
5051 if (fID > -1) {
5052 // We are *not* a top-level branch.
5053 if (!info) {
5054 // No streamer info, give up.
5055 // FIXME: We should have an error message here.
5056 fObject = fAddress;
5057 } else {
5058 // Compensate for the fact that the i/o routines
5059 // will add the streamer offset to the address.
5060 fObject = fAddress - info->TStreamerInfo::GetElementOffset(fID);
5061 }
5062 return;
5063 }
5064 }
5065
5066 //
5067 // Check whether the container type is still the same
5068 // to support schema evolution; what is written on the file
5069 // may no longer match the class code which is loaded.
5070 //
5071
5072 if (fType == 3) {
5073 // split TClonesArray, counter/master branch.
5074 TClass* clm = fClonesClass;
5075 if (clm) {
5076 // In case clm derives from an abstract class.
5077 clm->BuildRealData();
5078 clm->GetStreamerInfo();
5079 }
5080 TClass* newType = GetCurrentClass();
5081 if (newType && (newType != TClonesArray::Class())) {
5082 // The data type of the container has changed.
5083 //
5084 // Let's check if it is a compatible type:
5085 bool matched = false;
5086 if (newType->GetCollectionProxy()) {
5087 TClass *content = newType->GetCollectionProxy()->GetValueClass();
5088 if (clm == content) {
5089 matched = true;
5090 } else {
5091 Warning("SetAddress", "The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!", GetName(), newType->GetName(), GetClonesName());
5092 }
5093 } else {
5094 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());
5095 }
5096 if (matched) {
5097 // Change from 3/31 to 4/41
5098 SetType(4);
5099 // Set the proxy.
5100 fSTLtype = newType->GetCollectionType();
5101 fCollProxy = newType->GetCollectionProxy()->Generate();
5102
5106
5112 } else {
5114 }
5115 } else {
5116 // FIXME: Must maintain fObject here as well.
5117 fAddress = nullptr;
5119 }
5120 }
5121 } else if (fType == 4) {
5122 // split STL container, counter/master branch.
5123 TClass* newType = GetCurrentClass();
5124 if (newType && (newType != GetCollectionProxy()->GetCollectionClass())) {
5125 // Let's check if it is a compatible type:
5126 TVirtualCollectionProxy* newProxy = newType->GetCollectionProxy();
5128 if (newProxy && (oldProxy->GetValueClass() == newProxy->GetValueClass()) && ((!oldProxy->GetValueClass() && (oldProxy->GetType() == newProxy->GetType())) || (oldProxy->GetValueClass() && (oldProxy->HasPointers() == newProxy->HasPointers())))) {
5129 delete fCollProxy;
5130 Int_t nbranches = GetListOfBranches()->GetEntries();
5131 fCollProxy = newType->GetCollectionProxy()->Generate();
5133 for (Int_t i = 0; i < nbranches; ++i) {
5135 br->fCollProxy = nullptr;
5136 if (br->fReadActionSequence) {
5138 }
5139 if (br->fFillActionSequence) {
5141 }
5142 }
5147 delete fIterators;
5148 delete fPtrIterators;
5154 } else {
5156 }
5157 }
5158 else if (newProxy && (oldProxy->HasPointers() == newProxy->HasPointers()) && (oldProxy->GetValueClass()!=nullptr) && (newProxy->GetValueClass()!=nullptr)) {
5159 // Let see if there is a rule to convert the content of the collection into each other.
5160 if (newType->GetSchemaRules()->HasRuleWithSourceClass( oldProxy->GetCollectionClass()->GetName())) {
5161 TClass *oldValueClass = oldProxy->GetValueClass();
5162 delete fCollProxy;
5163 Int_t nbranches = GetListOfBranches()->GetEntries();
5164 fCollProxy = newType->GetCollectionProxy()->Generate();
5166 for (Int_t i = 0; i < nbranches; ++i) {
5168 br->fCollProxy = nullptr;
5169 if (br->fBranchClass == oldValueClass) {
5171 }
5172 if (br->fReadActionSequence) {
5174 }
5175 if (br->fFillActionSequence) {
5177 }
5178 }
5183 delete fIterators;
5184 delete fPtrIterators;
5190 } else {
5192 }
5193 } else {
5194 Error("SetAddress","For %s, we can not convert %s into %s\n",
5195 GetName(),oldProxy->GetCollectionClass()->GetName(),newType->GetName());
5196 fAddress = nullptr;
5197 fObject = nullptr;
5199 return;
5200 }
5201 }
5202 else if ((newType == TClonesArray::Class()) && (oldProxy->GetValueClass() && !oldProxy->HasPointers() && oldProxy->GetValueClass()->IsTObject()))
5203 {
5204 // The new collection and the old collection are not compatible,
5205 // we cannot use the new collection to read the data.
5206 // Actually we could check if the new collection is a
5207 // compatible ROOT collection.
5208
5209 // We cannot insure that the TClonesArray is set for the
5210 // proper class (oldProxy->GetValueClass()), so we assume that
5211 // the transformation was done properly by the class designer.
5212
5213 // Change from 4/41 to 3/31
5214 SetType(3);
5215 // Reset the proxy.
5216 fSTLtype = kNone;
5217 switch(fStreamerType) {
5221 break;
5225 break;
5228 break;
5229 }
5230 fClonesClass = oldProxy->GetValueClass();
5232 delete fCollProxy;
5233 fCollProxy = nullptr;
5234 TClass* clm = fClonesClass;
5235 if (clm) {
5236 clm->BuildRealData(); //just in case clm derives from an abstract class
5237 clm->GetStreamerInfo();
5238 }
5242 delete fIterators;
5243 fIterators = nullptr;
5244 delete fPtrIterators;
5245 fPtrIterators =nullptr;
5246 } else {
5247 // FIXME: We must maintain fObject here as well.
5248 Error("SetAddress","For %s can not convert %s into %s\n",GetName(),GetCurrentClass()->GetName(),newType->GetName());
5249 fAddress = nullptr;
5251 return;
5252 }
5253 } else {
5254 if (!fIterators && !fPtrIterators) {
5260 } else {
5262 }
5263 }
5264 }
5265 }
5266
5267 //
5268 // Establish the semantics of fObject and fAddress.
5269 //
5270 // Top-level branch:
5271 // fObject is a ptr to the object,
5272 // fAddress is a ptr to a pointer to the object.
5273 //
5274 // Sub-branch:
5275 // fObject is a ptr to the object,
5276 // fAddress is the same as fObject.
5277 //
5278 //
5279 // There are special cases for TClonesArray and STL containers.
5280 // If there is no user-provided object, we allocate one. We must
5281 // also initialize any STL container proxy.
5282 //
5283
5284 if (fType == 3) {
5285 // -- We are a TClonesArray master branch.
5286 if (fAddress) {
5287 // -- We have been given a non-zero address, allocate if necessary.
5289 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5290 // Case of an embedded TClonesArray.
5291 fObject = fAddress;
5292 // Check if it has already been properly built.
5293 TClonesArray* clones = (TClonesArray*) fObject;
5294 if (!clones->GetClass()) {
5296 }
5297 } else {
5298 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5299 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5300 if ((fStreamerType != -1) &&
5303 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5304 } else if (fStreamerType == -1) {
5305 // -- We are a top-level branch.
5307 if (!*pp) {
5308 // -- Caller wants us to allocate the clones array, but they will own it.
5309 *pp = new TClonesArray(fClonesClass);
5310 }
5311 fObject = (char*) *pp;
5312 } else {
5313 // -- We are a pointer to a TClonesArray.
5314 // Note: We do this so that the default constructor,
5315 // or the i/o constructor can be lazy.
5317 if (!*pp) {
5318 // -- Caller wants us to allocate the clones array, but they will own it.
5319 *pp = new TClonesArray(fClonesClass);
5320 }
5321 fObject = (char*) *pp;
5322 }
5323 }
5324 } else {
5325 // -- We have been given a zero address, allocate for top-level only.
5327 // -- We are *not* a top-level branch and we are *not* a pointer to a TClonesArray.
5328 // Case of an embedded TClonesArray.
5329 Error("SetAddress", "Embedded TClonesArray given a zero address for branch '%s'", GetName());
5330 } else {
5331 // -- We are either a top-level branch or we are a subbranch which is a pointer to a TClonesArray.
5332 // Streamer type should be -1 (for a top-level branch) or kObject(p|P) here.
5333 if ((fStreamerType != -1) &&
5336 Error("SetAddress", "TClonesArray with fStreamerType: %d", fStreamerType);
5337 } else if (fStreamerType == -1) {
5338 // -- We are a top-level branch.
5339 // Idea: Consider making a zero address not allocate.
5341 fObject = (char*) new TClonesArray(fClonesClass);
5342 fAddress = (char*) &fObject;
5343 } else {
5344 // -- We are a sub-branch which is a pointer to a TClonesArray.
5345 Error("SetAddress", "Embedded pointer to a TClonesArray given a zero address for branch '%s'", GetName());
5346 }
5347 }
5348 }
5349 } else if (fType == 4) {
5350 // -- We are an STL container master branch.
5351 //
5352 // Initialize fCollProxy.
5354 if (fAddress) {
5355 // -- We have been given a non-zero address, allocate if necessary.
5359 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5360 // Case of an embedded STL container.
5361 // Note: We test for the kObject and kAny types to support
5362 // the (unwise) choice of inheriting from an STL container.
5363 fObject = fAddress;
5364 } else {
5365 // We are either a top-level branch or subbranch which is a pointer to an STL container.
5366 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5368 Error("SetAddress",
5369 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5371 } else if (fStreamerType == -1) {
5372 // -- We are a top-level branch.
5373 void** pp = (void**) fAddress;
5374 if (!*pp) {
5375 // -- Caller wants us to allocate the STL container, but they will own it.
5376 *pp = proxy->New();
5377 if (!(*pp)) {
5378 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5379 // FIXME: Should we do this? Lots of other code wants
5380 // fAddress to be zero if no fObject, but is
5381 // that a good thing?
5382 fAddress = nullptr;
5384 }
5385 }
5386 fObject = (char*) *pp;
5387 } else {
5388 // -- We are a pointer to an STL container.
5389 // Note: We do this so that the default constructor,
5390 // or the i/o constructor can be lazy.
5391 void** pp = (void**) fAddress;
5392 if (!*pp) {
5393 // -- Caller wants us to allocate the STL container, but they will own it.
5394 *pp = proxy->New();
5395 if (!(*pp)) {
5396 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5397 // FIXME: Should we do this? Lots of other code wants
5398 // fAddress to be zero if no fObject, but is
5399 // that a good thing?
5400 fAddress = nullptr;
5402 }
5403 }
5404 fObject = (char*) *pp;
5405 }
5406 }
5407 } else {
5408 // -- We have been given a zero address, allocate for top-level only.
5412 // We are *not* a top-level branch and we are *not* a pointer to an STL container.
5413 // Case of an embedded STL container.
5414 // Note: We test for the kObject and kAny types to support
5415 // the (unwise) choice of inheriting from an STL container.
5416 Error("SetAddress", "Embedded STL container given a zero address for branch '%s'", GetName());
5417 } else {
5418 // We are either a top-level branch or sub-branch which is a pointer to an STL container.
5419 // Streamer type should be -1 (for a top-level branch) or kSTLp here.
5421 Error("SetAddress",
5422 "Branch %s is a split STL container (fStreamerType is: %d), the address can not be set directly.",
5424 } else if (fStreamerType == -1) {
5425 // -- We are a top-level branch, allocate.
5427 fObject = (char*) proxy->New();
5428 if (fObject) {
5429 fAddress = (char*) &fObject;
5430 } else {
5431 Error("SetAddress", "Failed to allocate STL container for branch '%s'", GetName());
5432 // FIXME: Should we do this? Lots of other code wants
5433 // fAddress to be zero if no fObject, but is
5434 // that a good thing?
5435 fAddress = nullptr;
5437 }
5438 } else {
5439 // -- We are a sub-branch which is a pointer to an STL container.
5440 Error("SetAddress", "Embedded pointer to an STL container given a zero address for branch '%s'", GetName());
5441 }
5442 }
5443 }
5444 } else if (fType == 41) {
5445 // -- We are an STL container sub-branch.
5446 // Initialize fCollProxy.
5448 // We are not at top-level branch.
5449 fObject = fAddress;
5450 } else if (fID < 0) {
5451 // -- We are a top-level branch.
5452 char** pp = (char**) fAddress;
5453 if (pp && *pp) {
5454 // -- Caller provided an i/o buffer for us to use.
5455 fObject = *pp;
5456 } else {
5457 // -- Caller did not provide an i/o buffer for us to use, we must make one for ourselves.
5458 if (clOfBranch) {
5459 if (!pp) {
5460 // -- Caller wants us to own the object.
5462 }
5463 fObject = (char*) clOfBranch->New();
5464 if (pp) {
5465 *pp = fObject;
5466 } else {
5467 fAddress = (char*) &fObject;
5468 }
5469 } else {
5470 Error("SetAddress", "I have no TClass for branch %s, so I cannot allocate an I/O buffer!", GetName());
5471 if (pp) {
5472 fObject = nullptr;
5473 *pp = nullptr;
5474 }
5475 }
5476 }
5477 } else {
5478 // -- We are *not* a top-level branch.
5479 fObject = fAddress;
5480 }
5481
5482 if (!info) {
5483 // FIXME: We need and error message here, no streamer info, so cannot set offsets.
5484 return;
5485 }
5486
5487 // We do this only once because it depends only on
5488 // the type of our object, not on its address.
5489 if (!fInitOffsets) {
5491 }
5492
5493 // We are split, recurse down to our sub-branches.
5494 //
5495 // FIXME: This is a tail recursion, we burn stack.
5496 Int_t nbranches = fBranches.GetEntriesFast();
5497 for (Int_t i = 0; i < nbranches; ++i) {
5498 TBranch *abranch = (TBranch*) fBranches.UncheckedAt(i);
5499 // FIXME: This is a tail recursion!
5500 if (fBranchOffset[i] != TStreamerInfo::kMissing && !(implied && abranch->TestBit(kAddressSet))) {
5501 abranch->SetAddressImpl(fObject + fBranchOffset[i], implied);
5502 abranch->SetBit(kAddressSet);
5503 if (TestBit(kDecomposedObj) != abranch->TestBit(kDecomposedObj))
5505 } else {
5506 // When the member is missing, just leave the address alone
5507 // (since setting explicitly to 0 would trigger error/warning
5508 // messages).
5509 // abranch->SetAddress(0);
5510 abranch->SetBit(kAddressSet);
5511 }
5512 }
5513}
5514
5515////////////////////////////////////////////////////////////////////////////////
5516/// Reset the basket size for all sub-branches of this branch element.
5517
5519{
5520 TBranch::SetBasketSize(buffsize);
5521 Int_t nbranches = fBranches.GetEntriesFast();
5522 for (Int_t i = 0; i < nbranches; ++i) {
5523 TBranch* branch = (TBranch*) fBranches[i];
5524 branch->SetBasketSize(fBasketSize);
5525 }
5526}
5527
5528////////////////////////////////////////////////////////////////////////////////
5529/// Set the branch counter for this branch.
5530
5532{
5533 fBranchCount = brOfCounter;
5534 if (fBranchCount==nullptr) return;
5535
5536 TLeafElement* leafOfCounter = (TLeafElement*) brOfCounter->GetListOfLeaves()->At(0);
5538 if (leafOfCounter && leaf) {
5539 leaf->SetLeafCount(leafOfCounter);
5540 } else {
5541 if (!leafOfCounter) {
5542 Warning("SetBranchCount", "Counter branch %s for branch %s has no leaves!", brOfCounter->GetName(), GetName());
5543 }
5544 if (!leaf) {
5545 Warning("SetBranchCount", "Branch %s has no leaves!", GetName());
5546 }
5547 }
5548}
5549
5550////////////////////////////////////////////////////////////////////////////////
5551/// Set the branch in a mode where the object are decomposed
5552/// (Also known as MakeClass mode).
5553/// Return whether the setting was possible (it is not possible for
5554/// TBranch and TBranchObject).
5555
5556bool TBranchElement::SetMakeClass(bool decomposeObj)
5557{
5558 if (decomposeObj)
5559 SetBit(kDecomposedObj); // Same as SetBit(kMakeClass)
5560 else
5562
5563 Int_t nbranches = fBranches.GetEntriesFast();
5564 for (Int_t i = 0; i < nbranches; ++i) {
5565 TBranchElement* branch = (TBranchElement*) fBranches[i];
5566 branch->SetMakeClass(decomposeObj);
5567 }
5570
5571 return true;
5572}
5573
5574////////////////////////////////////////////////////////////////////////////////
5575/// Set object this branch is pointing to.
5576
5578{
5579 if (TestBit(kDoNotProcess)) {
5580 return;
5581 }
5582 fObject = (char*)obj;
5583 SetAddress( &fObject );
5584}
5585
5586////////////////////////////////////////////////////////////////////////////////
5587/// Set offset of the object (to which the data member represented by this
5588/// branch belongs) inside its containing object (if any).
5589
5591{
5592 // We need to make sure that the Read and Write action's configuration
5593 // properly reflect this value.
5594
5596 SetMissing();
5597 return;
5598 }
5599
5600 if (fReadActionSequence) {
5602 }
5603 if (fFillActionSequence) {
5605 }
5606 fOffset = offset;
5607}
5608
5609////////////////////////////////////////////////////////////////////////////////
5610/// Set offset of the object (to which the data member represented by this
5611/// branch belongs) inside its containing object (if any) to mark it as missing.
5612
5614{
5615 // We need to make sure that the Read and Write action's configuration
5616 // properly reflect this value.
5617
5618 if (fReadActionSequence) {
5620 }
5621 if (fFillActionSequence) {
5623 }
5625}
5626
5627
5628////////////////////////////////////////////////////////////////////////////////
5629/// Set the sequence of actions needed to read the data out of the buffer.
5631{
5632 // A 'split' node does not store data itself (it has not associated baskets)
5633 const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
5634
5635 if (!isSplitNode) {
5636 fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
5637 }
5638
5639 if (actionSequence) delete actionSequence;
5640 auto original = create(localInfo, GetCollectionProxy(), originalClass);
5641
5642 actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
5643
5644 if (!isSplitNode)
5645 fNewIDs.erase(fNewIDs.begin());
5646
5647 else if (fInitOffsets && fType != 3 && fType != 4) {
5648 // fObject has the address of the sub-object but the streamer action have
5649 // offset relative to the parent.
5650
5651 // Note: We skipped this for the top node of split collection because the
5652 // sequence is about the content, we need to review what happens where an
5653 // action related to the collection itself will land.
5654 TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
5655
5656 auto index = parent->fBranches.IndexOf(this);
5657 if (index >= 0) {
5658 actionSequence->AddToOffset( - parent->fBranchOffset[index] );
5659 }
5660 } // else it will be done by InitOffsets
5661}
5662
5663////////////////////////////////////////////////////////////////////////////////
5664/// Set the sequence of actions needed to read the data out of the buffer.
5666{
5667 if (fInfo == nullptr) {
5668 // We are called too soon. We will be called again by InitInfo
5669 return;
5670 }
5671
5673 TClass *originalClass = nullptr;
5674 TStreamerInfo *localInfo = fInfo;
5675 if (fType == 41) {
5678 } else {
5680 if (GetParentClass() == info->GetClass()) {
5682 originalClass = fBranchClass;
5684 } else {
5686 }
5687 } else if (GetCollectionProxy()) {
5688 // Base class and embedded objects.
5690 }
5691 }
5692 } else if (fType == 31) {
5694 } else if (0<=fType && fType<=2) {
5695 // Note: this still requires the ObjectWise sequence to not be optimized!
5697 } else if ( fType == 4 && !fNewIDs.empty()) {
5700 } else if ( fType == 3 && !fNewIDs.empty()) {
5703 }
5704
5705 if (create) {
5706 SetActionSequence(originalClass, localInfo, create, fReadActionSequence);
5707 }
5708}
5709
5710////////////////////////////////////////////////////////////////////////////////
5711/// Set the ReadLeaves pointer to execute the expected operations.
5712
5714{
5715 if (TestBit(kDecomposedObj)) {
5717 } else if (fType == 4) {
5719 } else if (fType == 41) {
5723 } else {
5725 }
5726 } else {
5728 }
5729 } else if (fType == 3) {
5731 } else if (fType == 31) {
5733 } else if (fType < 0) {
5735 } else if (fType == 0 && fID == -1) {
5736 // top-level branch.
5738 if (hasCustomStreamer) {
5739 // We are in the case where the object did *not* have a custom
5740 // Streamer when the TTree was written but now *does* have a custom
5741 // Streamer thus we must use it.
5743 } else {
5745 }
5746 } else if (fType <= 2) {
5747 // split-class branch, base class branch or data member branch.
5748 if (fBranchCount) {
5752 } else {
5754 }
5755 } else {
5756 Fatal("SetReadLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5757 }
5758
5760}
5761
5762////////////////////////////////////////////////////////////////////////////////
5763/// Set the sequence of actions needed to write the data out from the buffer.
5764
5766{
5767 if (fInfo == nullptr) {
5768 // We are called too soon. We will be called again by InitInfo
5769 return;
5770 }
5771
5773 TClass *originalClass = nullptr;
5774 TStreamerInfo *localInfo = fInfo;
5775 if (fType == 41) {
5778 } else {
5780 if (GetParentClass() == info->GetClass()) {
5781 // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
5782 // originalClass = fBranchClass;
5783 // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter;
5784 // } else {
5786 // }
5787 } else if (GetCollectionProxy()) {
5788 // Base class and embedded objects.
5790 }
5791 }
5792 } else if (fType == 31) {
5794 } else if (0<=fType && fType<=2) {
5795 // Note: this still requires the ObjectWise sequence to not be optimized!
5797 } else if ( fType == 4 && !fNewIDs.empty()) {
5800 } else if ( fType == 3 && !fNewIDs.empty()) {
5803 }
5804
5805 if (create) {
5806 SetActionSequence(originalClass, localInfo, create, fFillActionSequence);
5807 }
5808}
5809
5810////////////////////////////////////////////////////////////////////////////////
5811/// Set the FillLeaves pointer to execute the expected operations.
5812
5814{
5815 if (TestBit(kDecomposedObj) && ((fType==3)||(fType==31))) {
5817 } else if (fType == 4) {
5819 } else if (fType == 41) {
5823 } else {
5825 }
5828 } else {
5830 }
5831 } else if (fType == 3) {
5833 } else if (fType == 31) {
5835 } else if (fType < 0) {
5837 } else if (fType <=2) {
5838 //split-class branch, base class branch, data member branch, or top-level branch.
5839 if (fBranchCount) {
5843 } else {
5845 }
5846 } else {
5847 Fatal("SetFillLeavePtr","Unexpected branch type %d for %s",fType,GetName());
5848 }
5849
5851}
5852
5853////////////////////////////////////////////////////////////////////////////////
5854/// Set the name of the class of the in-memory object into which the data will
5855/// loaded.
5856
5858{
5859 if (name == nullptr) return;
5860
5861 if (strcmp(fTargetClass.GetClassName(),name) != 0 )
5862 {
5863 // We are changing target class, let's reset the meta information and
5864 // the sub-branches.
5865
5866 ResetInitInfo(/*recurse=*/ false);
5867
5868 Int_t nbranches = fBranches.GetEntriesFast();
5869 for (Int_t i = 0; i < nbranches; ++i) {
5871
5872 if (sub->fTargetClass == fTargetClass ) {
5873 sub->SetTargetClass(name);
5874 } else {
5875 // Since the top level changes, the StreamerInfo (in particular for split collection)
5876 // may still need to change (and the info might be updated else (see for example SetAddress for the
5877 // the case fType 4/41)
5878 sub->ResetInitInfo(true);
5879 }
5880 if (sub->fParentClass == fTargetClass ) {
5882 }
5883 }
5885 }
5886
5887}
5888
5889////////////////////////////////////////////////////////////////////////////////
5890/// If the branch address is not set, we set all addresses starting with
5891/// the top level parent branch. This is required to be done in order for
5892/// GetOffset to be correct and for GetEntry to run.
5893
5895{
5896 // Check to see if the user changed the branch address on us.
5898
5900 // -- Do nothing if already setup or if we are a MakeClass branch.
5901 return;
5902 }
5904}
5905
5906////////////////////////////////////////////////////////////////////////////////
5907/// If the branch address is not set, we set all addresses starting with
5908/// the top level parent branch. This is required to be done in order for
5909/// GetOffset to be correct and for GetEntry to run.
5910
5912{
5913 if (TestBit((long)kDoNotProcess|(long)kAddressSet)) {
5914 // -- Do nothing if we have been told not to.
5915 // Or the data member in this branch is not longer part of the
5916 // parent's layout.
5917 return;
5918 }
5919
5920 //--------------------------------------------------------------------------
5921 // Check if we are splited STL collection of pointers
5922 /////////////////////////////////////////////////////////////////////////////
5923
5925 {
5926 TBranchElement *parent = (TBranchElement *)GetMother()->GetSubBranch( this );
5927
5928 // Make sure the StreamerInfo is loaded and initialized.
5929 GetInfoImp();
5930
5931 if( !parent->GetAddress() )
5932 parent->SetAddress( nullptr );
5933 return;
5934 }
5935
5936 //--------------------------------------------------------------------------
5937 // Any other case
5938 /////////////////////////////////////////////////////////////////////////////
5939
5941 if (!mother) {
5942 return;
5943 }
5944 TClass* cl = TClass::GetClass(mother->GetClassName());
5945
5946 // Make sure the StreamerInfo is loaded and initialized.
5947 GetInfoImp();
5948
5949 if (!cl) {
5950 return;
5951 }
5952
5953 if (!mother->GetAddress()) {
5954 // -- Our top-level branch has no address.
5955 bool motherStatus = mother->TestBit(kDoNotProcess);
5956 mother->ResetBit(kDoNotProcess);
5957 // Note: This will allocate an object.
5958 mother->SetAddress(nullptr);
5959 mother->SetBit(kDoNotProcess, motherStatus);
5960 }
5961}
5962
5963////////////////////////////////////////////////////////////////////////////////
5964/// Stream an object of class TBranchElement.
5965
5967{
5968 if (R__b.IsReading()) {
5974 // The fAddress and fObject data members are not persistent,
5975 // therefore we do not own anything.
5976 // Also clear the bit possibly set by the schema evolution.
5978 // Fixup a case where the TLeafElement was missing
5979 if ((fType == 0) && (fLeaves.GetEntriesFast() == 0)) {
5980 TLeaf* leaf = new TLeafElement(this, GetTitle(), fID, fStreamerType);
5981 leaf->SetTitle(GetTitle());
5982 fNleaves = 1;
5983 fLeaves.Add(leaf);
5984 fTree->GetListOfLeaves()->Add(leaf);
5985 }
5986
5987 // SetReadLeavesPtr();
5988 }
5989 else {
5990 TDirectory* dirsav = fDirectory;
5991 fDirectory = nullptr; // to avoid recursive calls
5992 {
5993 // Save class version.
5994 Int_t classVersion = fClassVersion;
5995 // Record only positive 'version number'
5996 if (fClassVersion < 0) {
5998 }
5999 // TODO: Should we clear the kDeleteObject bit before writing?
6000 // If we did we would have to remember the old value and
6001 // put it back, we wouldn't want to forget that we owned
6002 // something just because we got written to disk.
6004 // Restore class version.
6005 fClassVersion = classVersion;
6006 }
6007 //
6008 // Mark all streamer infos used by this branch element
6009 // to be written to our output file.
6010 //
6011 {
6012 R__b.ForceWriteInfo(GetInfoImp(), true);
6013 }
6014 //
6015 // If we are a clones array master branch, or an
6016 // STL container master branch, we must also mark
6017 // the streamer infos used by the value class to
6018 // be written to our output file.
6019 //
6020 if (fType == 3) {
6021 // -- TClonesArray, counter/master branch
6022 //
6023 // We must mark the streamer info for the
6024 // value class to be written to the file.
6025 //
6026 TClass* cl = fClonesClass;
6027 if (cl) {
6028 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6029 }
6030 }
6031 else if (fType == 4) {
6032 // -- STL container, counter/master branch
6033 //
6034 // We must mark the streamer info for the
6035 // value class to be written to the file.
6036 //
6038 if (cp) {
6039 TClass* cl = cp->GetValueClass();
6040 if (cl) {
6041 R__b.ForceWriteInfo(cl->GetStreamerInfo(), true);
6042 }
6043 }
6044 }
6045 // If we are in a separate file, then save
6046 // ourselves as an independent key.
6047 if (!dirsav) {
6048 // Note: No need to restore fDirectory, it was already zero.
6049 return;
6050 }
6051 if (!dirsav->IsWritable()) {
6052 fDirectory = dirsav;
6053 return;
6054 }
6055 TDirectory* pdirectory = fTree->GetDirectory();
6056 if (!pdirectory) {
6057 fDirectory = dirsav;
6058 return;
6059 }
6060 const char* treeFileName = pdirectory->GetFile()->GetName();
6061 TBranch* mother = GetMother();
6062 const char* motherFileName = treeFileName;
6063 if (mother && (mother != this)) {
6064 motherFileName = mother->GetFileName();
6065 }
6066 if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
6067 dirsav->WriteTObject(this);
6068 }
6069 fDirectory = dirsav;
6070 }
6071}
6072
6073
6074////////////////////////////////////////////////////////////////////////////////
6075/// Split class cl into sub-branches of this branch.
6076///
6077/// This version of Unroll was formerly embedded in TTree::BronchExec
6078/// It is moved here so we can make sure to call SetReadActionSequence.
6079
6080void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Int_t bufsize, Int_t splitlevel)
6081{
6082 //
6083 // Do we have a final dot in our name?
6084 //
6085
6086 // Note: The branch constructor which takes a folder as input
6087 // creates top-level branch names with dots in them to
6088 // indicate the folder hierarchy.
6089 char* dot = (char*) strchr(name, '.');
6090 Int_t nch = strlen(name);
6091 bool dotlast = false;
6092 if (nch && (name[nch-1] == '.')) {
6093 dotlast = true;
6094 }
6095
6096 // Loop on all public data members of the class and its base classes and create branches for each one.
6097 TObjArray* blist = this->GetListOfBranches();
6098 TIter next(sinfo->GetElements());
6099 TStreamerElement* element = nullptr;
6100 TString bname;
6101 for (Int_t id = 0; (element = (TStreamerElement*) next()); ++id) {
6102 if (element->IsA() == TStreamerArtificial::Class()) {
6103 continue;
6104 }
6105 if (element->TestBit(TStreamerElement::kRepeat)) {
6106 continue;
6107 }
6109 continue;
6110 }
6111 char* pointer = (char*) (objptr + element->GetOffset());
6112 // FIXME: This is not good enough, an STL container can be
6113 // a base, and the test will fail.
6114 // See TBranchElement::InitializeOffsets() for the
6115 // correct test.
6116 bool isBase = (element->IsA() == TStreamerBase::Class());
6117 if (isBase) {
6118 TClass* clbase = element->GetClassPointer();
6119 if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) {
6120 // Note: TStreamerInfo::Compile() leaves this element
6121 // out of the optimized info, although it does
6122 // exists in the non-compiled and non-optimized info.
6123 // FIXME: The test that TStreamerInfo::Compile() uses
6124 // is element->GetType() < 0, so that is what
6125 // we should do as well.
6126 continue;
6127 }
6128 if (clbase->GetListOfRealData()->GetSize() == 0) {
6129 // Do not create a branch for empty bases.
6130 continue;
6131 }
6132 }
6133 if (dot) {
6134 if (dotlast) {
6135 bname.Form("%s%s", name, element->GetFullName());
6136 } else {
6137 // FIXME: We are in the case where we have a top-level
6138 // branch name that was created by the branch
6139 // constructor which takes a folder as input.
6140 // The internal dots in the name are in place of
6141 // of the original slashes and represent the
6142 // folder hierarchy.
6143 if (isBase) {
6144 // FIXME: This is very strange, this is the only case where
6145 // we create a branch for a base class that does
6146 // not have the base class name in the branch name.
6147 // FIXME: This is also quite bad since classes with two
6148 // or more base classes end up with sub-branches
6149 // that have the same name.
6150 bname = name;
6151 } else {
6152 bname.Form("%s.%s", name, element->GetFullName());
6153 }
6154 }
6155 } else {
6156 // Note: For a base class element, this results in the branchname
6157 // being the name of the base class.
6158 bname.Form("%s", element->GetFullName());
6159 }
6160
6161 if( splitlevel > TTree::kSplitCollectionOfPointers && element->GetClass() &&
6162 element->GetClass()->GetCollectionProxy() &&
6163 element->GetClass()->GetCollectionProxy()->HasPointers() )
6164 {
6165 TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id );
6166 blist->Add(brSTL);
6167 }
6168 else
6169 {
6170 TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1);
6171 bre->SetParentClass(cl);
6172 blist->Add(bre);
6173 }
6174 }
6175 // Now that we know that this branch is split, let's redo the actions.
6178}
6179
6180////////////////////////////////////////////////////////////////////////////////
6181/// Split class cl into sub-branches of this branch.
6182///
6183/// Create a sub-branch of this branch for each non-empty,
6184/// non-abstract base class of cl (unless we are a sub-branch
6185/// of a TClonesArray or an STL container, in which case we
6186/// do *not* create a sub-branch), and for each non-split data
6187/// member of cl.
6188///
6189/// Note: We do *not* create sub-branches for base classes of cl
6190/// if we are a sub-branch of a TClonesArray or an STL container.
6191///
6192/// Note: We do *not* create sub-branches for data members which
6193/// have a class type and which we are splitting.
6194///
6195/// Note: The above rules imply that the branch hierarchy increases
6196/// in depth only for base classes of cl (unless we are inside
6197/// of a TClonesArray or STL container, in which case the depth
6198/// does *not* increase, the base class is elided) and for
6199/// TClonesArray or STL container data members (which have one
6200/// additional level of sub-branches). The only other way the
6201/// depth increases is when the top-level branch has a split
6202/// class data member, in that case the constructor will create
6203/// a sub-branch for it. In other words, the interior nodes of
6204/// the branch tree are all either: base class nodes; split
6205/// class nodes which are direct sub-branches of top-level nodes
6206/// (created by TClass::Bronch usually); or TClonesArray or STL
6207/// container master nodes.
6208///
6209/// Note: The exception to the above is for the top-level branches,
6210/// Tree::Bronch creates nodes for everything in that case,
6211/// except for a TObject base class of a class which has the
6212/// can ignore tobject streamer flag set.
6213
6214Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype)
6215{
6216 //----------------------------------------------------------------------------
6217 // Handling the case of STL collections of pointers
6218 /////////////////////////////////////////////////////////////////////////////
6219
6220 Int_t splitSTLP = splitlevel - (splitlevel%TTree::kSplitCollectionOfPointers);
6222
6223 TString branchname;
6224
6225 if ((cl == TObject::Class()) && clParent->CanIgnoreTObjectStreamer()) {
6226 return 0;
6227 }
6228
6230
6231 //
6232 // Do nothing if we couldn't build the streamer info for cl.
6233 //
6234
6235 if (!sinfo) {
6236 return 0;
6237 }
6238
6239 const auto namelen = strlen(name);
6240 bool dotlast = (namelen && (name[namelen-1] == '.'));
6241
6242 Int_t ndata = sinfo->GetNelement();
6243
6244 if ((ndata == 1) && cl->GetCollectionProxy() && !strcmp(sinfo->GetElement(0)->GetName(), "This")) {
6245 // -- Class cl is an STL collection, refuse to split it.
6246 // Question: Why? We certainly could by switching to the value class.
6247 // Partial Answer: Only the branch element constructor can split STL containers.
6248 return 1;
6249 }
6250
6251 for (Int_t elemID = 0; elemID < ndata; ++elemID) {
6252 // -- Loop over all the streamer elements and create sub-branches as needed.
6253 TStreamerElement* elem = sinfo->GetElement(elemID);
6254 if (elem->IsA() == TStreamerArtificial::Class()) {
6255 continue;
6256 }
6258 continue;
6259 }
6261 continue;
6262 }
6263 Int_t offset = elem->GetOffset();
6264 // FIXME: An STL container as a base class gets TStreamerSTL as its class, so this test is not enough.
6265 // See InitializeOffsets() for the proper test.
6266 if (elem->IsA() == TStreamerBase::Class()) {
6267 // -- This is a base class of cl.
6268 TClass* clOfBase = elem->GetClassPointer();
6269 if (!clOfBase || ((clOfBase->Property() & kIsAbstract) && cl->InheritsFrom(TCollection::Class()))) {
6270 // -- Do nothing if we are one of the abstract collection (we know they have no data).
6271 return -1;
6272 }
6273 if ((btype == 31) || (btype == 41)) {
6274 // -- Elide the base-class sub-branches of a split TClonesArray or STL container.
6275 //
6276 // Note: We are eliding the base class here, that is, we never
6277 // create a branch for it, so the branch hierarchy is not
6278 // complete.
6279 // Note: The clParent parameter is the value class of the
6280 // container which we are splitting. It does not
6281 // appear in the branch hierarchy either.
6282 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6283 Int_t unroll = -1;
6284 if (!elem->CannotSplit() || clOfBase == TObject::Class()) {
6285 unroll = Unroll(name, clParent, clOfBase, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6286 }
6287 if (unroll < 0) {
6288 // FIXME: We could not split because we are abstract, should we be doing this?
6289 if (namelen) {
6290 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6291 } else {
6292 branchname.Form("%s", elem->GetFullName());
6293 }
6294 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, nullptr, basketsize, 0, btype);
6295 branch->SetParentClass(clParent);
6296 fBranches.Add(branch);
6297 }
6298 } else if (clOfBase->GetListOfRealData()->GetSize()) {
6299 // -- Create a branch for a non-empty base class.
6300 if (namelen) {
6301 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6302 // Elide the base class name when creating the sub-branches.
6303 // Note: The branch names for sub-branches of a base class branch
6304 // do not represent the full class hierarchy because we do
6305 // this, however it does keep the branch names for the
6306 // inherited data members simple.
6307 TBranchElement* branch = new TBranchElement(this, name, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6308 // Then reset it to the proper name.
6309 branch->SetName(branchname);
6310 branch->SetTitle(branchname);
6311 branch->SetParentClass(clParent);
6312 fBranches.Add(branch);
6313 } else {
6314 branchname.Form("%s", elem->GetFullName());
6315 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel+splitSTLP, btype);
6316 branch->SetParentClass(clParent);
6317 fBranches.Add(branch);
6318 }
6319 }
6320 } else {
6321 // -- This is a data member of cl.
6322 if (namelen) {
6323 branchname.Form("%s%s%s", name, dotlast ? "" : ".", elem->GetFullName());
6324 } else {
6325 branchname.Form("%s", elem->GetFullName());
6326 }
6327 if ((splitlevel > 1) && ((elem->IsA() == TStreamerObject::Class()) || (elem->IsA() == TStreamerObjectAny::Class()))) {
6328 // -- We are splitting a non-TClonesArray (may inherit from TClonesArray though), non-STL container object.
6329 //
6330 // Ignore an abstract class.
6331 // FIXME: How could an abstract class get here?
6332 // Partial answer: It is a base class. But this is a data member!
6333 TClass* elemClass = elem->GetClassPointer();
6334 if (!elemClass || elemClass->Property() & kIsAbstract) {
6335 return -1;
6336 }
6337 if (elem->CannotSplit()) {
6338 // We are not splitting.
6339 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6340 branch->SetParentClass(clParent);
6341 fBranches.Add(branch);
6342 } else if (elemClass->InheritsFrom(TClonesArray::Class())) {
6343 // Splitting something derived from TClonesArray.
6344 Int_t subSplitlevel = splitlevel-1;
6345 if (btype == 31 || btype == 41 || elem->CannotSplit()) {
6346 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6347 subSplitlevel = 0;
6348 }
6349 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel, btype);
6350 branch->SetParentClass(clParent);
6351 fBranches.Add(branch);
6352 } else {
6353 // Splitting a normal class.
6354 // FIXME: We are eliding the class we are splitting here,
6355 // i.e., we do not create a branch for it, so the
6356 // branch hierarchy does not match the class hierarchy.
6357 // Note: clParent is the class which contains a data member of
6358 // the class type which we are splitting.
6359 // Note: We can use parent class (clParent) != branch class (elemClass) to detection elision.
6360 Int_t unroll = Unroll(branchname, clParent, elemClass, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6361 if (unroll < 0) {
6362 // FIXME: We could not split because we are abstract, should we be doing this?
6363 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, 0, btype);
6364 branch->SetParentClass(clParent);
6365 fBranches.Add(branch);
6366 }
6367 }
6368 }
6369 else if( elem->GetClassPointer() &&
6372 splitSTLP && fType != 4 )
6373 {
6374
6375 TBranchSTL* branch = new TBranchSTL( this, branchname,
6377 basketsize, splitlevel - 1+splitSTLP, sinfo, elemID );
6378 branch->SetAddress( ptr+offset );
6379 fBranches.Add( branch );
6380 }
6381 else if ((elem->IsA() == TStreamerSTL::Class()) && !elem->IsaPointer()) {
6382 // -- We have an STL container.
6383 // Question: What if splitlevel == 0 here?
6384 // Answer: then we should not be here.
6385 Int_t subSplitlevel = splitlevel - 1;
6386 if ((btype == 31) || (btype == 41) || elem->CannotSplit()) {
6387 // -- We split the sub-branches of a TClonesArray or an STL container only once.
6388 subSplitlevel = 0;
6389 }
6390 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, subSplitlevel+splitSTLP, btype);
6391 branch->SetParentClass(clParent);
6392 fBranches.Add(branch);
6393 } else if (((btype != 31) && (btype != 41)) && ptr && ((elem->GetClassPointer() == TClonesArray::Class()) || ((elem->IsA() == TStreamerSTL::Class()) && !elem->CannotSplit()))) {
6394 // -- We have a TClonesArray.
6395 // FIXME: We could get a ptr to a TClonesArray here by mistake.
6396 // Question: What if splitlevel == 0 here?
6397 // Answer: then we should not be here.
6398 // Note: ptr may be null in case of a TClonesArray inside another
6399 // TClonesArray or STL container, see the else clause.
6400 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, ptr + offset, basketsize, splitlevel-1+splitSTLP, btype);
6401 branch->SetParentClass(clParent);
6402 fBranches.Add(branch);
6403 } else {
6404 // -- We are not going to split this element any farther.
6405 TBranchElement* branch = new TBranchElement(this, branchname, sinfo, elemID, nullptr, basketsize, splitSTLP, btype);
6406 branch->SetType(btype);
6407 branch->SetParentClass(clParent);
6408 fBranches.Add(branch);
6409 }
6410 }
6411 }
6412
6413 if (!fBranches.IsEmpty()) {
6414 // Refresh this branch's action now that we know whether it is split or not.
6417 }
6418 return 1;
6419}
6420
6421////////////////////////////////////////////////////////////////////////////////
6422/// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
6423/// with the current value of fTree->GetCurrentFile unless this branch has been
6424/// redirected to a different file. Also update the sub-branches.
6425
6427{
6428 // The BranchCount and BranchCount2 are part of higher level branches' list of
6429 // branches.
6430 // if (fBranchCount) fBranchCount->UpdateFile();
6431 // if (fBranchCount2) fBranchCount2->UpdateFile();
6433}
std::string fBuffer
const Handle_t kNone
Definition GuiTypes.h:88
#define R__unlikely(expr)
Definition RConfig.hxx:611
#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:595
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:65
TClass * GetClass() const
Definition TClassRef.h:70
const char * GetClassName()
Definition TClassRef.h:69
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:603
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
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:451
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:391
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:490
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:518
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:418
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3503
@ kHasCustomStreamerMember
Definition TClass.h:106
@ kIsEmulation
Definition TClass.h:102
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 composed of a header, followed by consecutive data records (TKey instances) with a wel...
Definition TFile.h:53
Int_t GetCompressionSettings() const
Definition TFile.h:396
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:578
void Add(TObject *obj) override
Definition TList.h:81
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
TString fName
Definition TNamed.h:32
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:140
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
Int_t IndexOf(const TObject *obj) const override
TObject ** GetObjectRef() const
Definition TObjArray.h:63
Int_t GetEntries() const override
Return the number of objects in array (i.e.
TObject * At(Int_t idx) const override
Definition TObjArray.h:164
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
Bool_t IsEmpty() const override
Definition TObjArray.h:65
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
void Add(TObject *obj) override
Definition TObjArray.h:68
Mother of all ROOT objects.
Definition TObject.h:41
friend class TClonesArray
Definition TObject.h:242
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:201
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:962
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:976
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1004
virtual TClass * IsA() const
Definition TObject.h:245
void ResetBit(UInt_t f)
Definition TObject.h:200
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:950
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:419
static constexpr Ssiz_t kNPOS
Definition TString.h:280
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:696
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition TString.cxx:538
const char * Data() const
Definition TString.h:378
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:706
@ kTrailing
Definition TString.h:278
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:625
TString & Prepend(const char *cs)
Definition TString.h:675
TString & Remove(Ssiz_t pos)
Definition TString.h:687
TString & Append(const char *cs)
Definition TString.h:574
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:634
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:653
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
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
@ 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