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