Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TTree.cxx
Go to the documentation of this file.
1// @(#)root/tree:$Id$
2// Author: Rene Brun 12/01/96
3
4/*************************************************************************
5 * Copyright (C) 1995-2024, 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 \defgroup tree Tree Library
13
14 RNTuple is the modern way of storing columnar datasets: please consider to use it
15 before starting new projects based on TTree and related classes.
16
17 In order to store columnar datasets, ROOT historically provides the TTree, TChain,
18 TNtuple and TNtupleD classes.
19 The TTree class represents a columnar dataset. Any C++ type can be stored in the
20 columns. The TTree has allowed to store about **1 EB** of data coming from the LHC alone:
21 it is demonstrated to scale and it's battle tested. It has been optimized during the years
22 to reduce dataset sizes on disk and to deliver excellent runtime performance.
23 It allows to access only part of the columns of the datasets, too.
24 The TNtuple and TNtupleD classes are specialisations of the TTree class which can
25 only hold single precision and double precision floating-point numbers respectively;
26 The TChain is a collection of TTrees, which can be located also in different files.
27
28*/
29
30/** \class TTree
31\ingroup tree
32
33A TTree represents a columnar dataset. Any C++ type can be stored in its columns. The modern
34version of TTree is RNTuple: please consider using it before opting for TTree.
35
36A TTree, often called in jargon *tree*, consists of a list of independent columns or *branches*,
37represented by the TBranch class.
38Behind each branch, buffers are allocated automatically by ROOT.
39Such buffers are automatically written to disk or kept in memory until the size stored in the
40attribute fMaxVirtualSize is reached.
41Variables of one branch are written to the same buffer. A branch buffer is
42automatically compressed if the file compression attribute is set (default).
43Branches may be written to different files (see TBranch::SetFile).
44
45The ROOT user can decide to make one single branch and serialize one object into
46one single I/O buffer or to make several branches.
47Making several branches is particularly interesting in the data analysis phase,
48when it is desirable to have a high reading rate and not all columns are equally interesting
49
50\anchor creatingattreetoc
51## Create a TTree to store columnar data
52- [Construct a TTree](\ref creatingattree)
53- [Add a column of Fundamental Types and Arrays thereof](\ref addcolumnoffundamentaltypes)
54- [Add a column of a STL Collection instances](\ref addingacolumnofstl)
55- [Add a column holding an object](\ref addingacolumnofobjs)
56- [Add a column holding a TObjectArray](\ref addingacolumnofobjs)
57- [Fill the tree](\ref fillthetree)
58- [Add a column to an already existing Tree](\ref addcoltoexistingtree)
59- [An Example](\ref fullexample)
60
61\anchor creatingattree
62## Construct a TTree
63
64~~~ {.cpp}
65 TTree tree(name, title)
66~~~
67Creates a Tree with name and title.
68
69Various kinds of branches can be added to a tree:
70- Variables representing fundamental types, simple classes/structures or list of variables: for example for C or Fortran
71structures.
72- Any C++ object or collection, provided by the STL or ROOT.
73
74In the following, the details about the creation of different types of branches are given.
75
76\anchor addcolumnoffundamentaltypes
77## Add a column ("branch") holding fundamental types and arrays thereof
78This strategy works also for lists of variables, e.g. to describe simple structures.
79It is strongly recommended to persistify those as objects rather than lists of leaves.
80
81~~~ {.cpp}
82 auto branch = tree.Branch(branchname, address, leaflist, bufsize)
83~~~
84- `address` is the address of the first item of a structure
85- `leaflist` is the concatenation of all the variable names and types
86 separated by a colon character :
87 The variable name and the variable type are separated by a
88 slash (/). The variable type must be 1 character. (Characters
89 after the first are legal and will be appended to the visible
90 name of the leaf, but have no effect.) If no type is given, the
91 type of the variable is assumed to be the same as the previous
92 variable. If the first variable does not have a type, it is
93 assumed of type F by default. The list of currently supported
94 types is given below:
95 - `C` : a character string terminated by the 0 character
96 - `B` : an 8 bit signed integer (`Char_t`); Treated as a character when in an array.
97 - `b` : an 8 bit unsigned integer (`UChar_t`)
98 - `S` : a 16 bit signed integer (`Short_t`)
99 - `s` : a 16 bit unsigned integer (`UShort_t`)
100 - `I` : a 32 bit signed integer (`Int_t`)
101 - `i` : a 32 bit unsigned integer (`UInt_t`)
102 - `F` : a 32 bit floating point (`Float_t`)
103 - `f` : a 21 bit floating point with truncated mantissa (`Float16_t`): 1 for the sign, 8 for the exponent and 12 for the mantissa.
104 - `D` : a 64 bit floating point (`Double_t`)
105 - `d` : a 32 bit truncated floating point (`Double32_t`): 1 for the sign, 8 for the exponent and 23 for the mantissa.
106 - `L` : a 64 bit signed integer (`Long64_t`)
107 - `l` : a 64 bit unsigned integer (`ULong64_t`)
108 - `G` : a long signed integer, stored as 64 bit (`Long_t`)
109 - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
110 - `O` : [the letter `o`, not a zero] a boolean (`bool`)
111
112 Examples:
113 - A int: "myVar/I"
114 - A float array with fixed size: "myArrfloat[42]/F"
115 - An double array with variable size, held by the `myvar` column: "myArrdouble[myvar]/D"
116 - An Double32_t array with variable size, held by the `myvar` column , with values between 0 and 16: "myArr[myvar]/d[0,10]"
117 - The `myvar` column, which holds the variable size, **MUST** be an `Int_t` (/I).
118
119- If the address points to a single numerical variable, the leaflist is optional:
120~~~ {.cpp}
121 int value;
122 tree->Branch(branchname, &value);
123~~~
124- If the address points to more than one numerical variable, we strongly recommend
125 that the variable be sorted in decreasing order of size. Any other order will
126 result in a non-portable TTree (i.e. you will not be able to read it back on a
127 platform with a different padding strategy).
128 We recommend to persistify objects rather than composite leaflists.
129- In case of the truncated floating point types (`Float16_t` and `Double32_t`) you can
130 also specify the range in the style `[xmin,xmax]` or `[xmin,xmax,nbits]` after
131 the type character. For example, for storing a variable size array `myArr` of
132 `Double32_t` with values within a range of `[0, 2*pi]` and the size of which is stored
133 in an `Int_t` (/I) branch called `myArrSize`, the syntax for the `leaflist` string would
134 be: `myArr[myArrSize]/d[0,twopi]`. Of course the number of bits could be specified,
135 the standard rules of opaque typedefs annotation are valid. For example, if only
136 18 bits were sufficient, the syntax would become: `myArr[myArrSize]/d[0,twopi,18]`
137
138\anchor addingacolumnofstl
139## Adding a column holding STL collection instances (e.g. std::vector or std::list)
140
141~~~ {.cpp}
142 auto branch = tree.Branch( branchname, STLcollection, buffsize, splitlevel);
143~~~
144`STLcollection` is the address of a pointer to a container of the standard
145library such as `std::vector`, `std::list`, containing pointers, fundamental types
146or objects.
147If the splitlevel is a value bigger than 100 (`TTree::kSplitCollectionOfPointers`)
148then the collection will be written in split mode, i.e. transparently storing
149individual data members as arrays, therewith potentially increasing compression ratio.
150
151### Note
152In case of dynamic structures changing with each entry, see e.g.
153~~~ {.cpp}
154 branch->SetAddress(void *address)
155~~~
156one must redefine the branch address before filling the branch
157again. This is done via the `TBranch::SetAddress` member function.
158
159\anchor addingacolumnofobjs
160## Add a column holding objects
161
162~~~ {.cpp}
163 MyClass object;
164 auto branch = tree.Branch(branchname, &object, bufsize, splitlevel)
165~~~
166Note: The 2nd parameter must be the address of a valid object.
167 The object must not be destroyed (i.e. be deleted) until the TTree
168 is deleted or TTree::ResetBranchAddress is called.
169
170- if splitlevel=0, the object is serialized in the branch buffer.
171- if splitlevel=1 (default), this branch will automatically be split
172 into subbranches, with one subbranch for each data member or object
173 of the object itself. In case the object member is a TClonesArray,
174 the mechanism described in case C is applied to this array.
175- if splitlevel=2 ,this branch will automatically be split
176 into subbranches, with one subbranch for each data member or object
177 of the object itself. In case the object member is a TClonesArray,
178 it is processed as a TObject*, only one branch.
179
180Another available syntax is the following:
181
182~~~ {.cpp}
183 auto branch_a = tree.Branch(branchname, &p_object, bufsize, splitlevel)
184 auto branch_b = tree.Branch(branchname, className, &p_object, bufsize, splitlevel)
185~~~
186- `p_object` is a pointer to an object.
187- If `className` is not specified, the `Branch` method uses the type of `p_object`
188 to determine the type of the object.
189- If `className` is used to specify explicitly the object type, the `className`
190 must be of a type related to the one pointed to by the pointer. It should be
191 either a parent or derived class.
192
193Note: The pointer whose address is passed to `TTree::Branch` must not
194 be destroyed (i.e. go out of scope) until the TTree is deleted or
195 TTree::ResetBranchAddress is called.
196
197Note: The pointer `p_object` can be initialized before calling `TTree::Branch`
198~~~ {.cpp}
199 auto p_object = new MyDataClass;
200 tree.Branch(branchname, &p_object);
201~~~
202or not
203~~~ {.cpp}
204 MyDataClass* p_object = nullptr;
205 tree.Branch(branchname, &p_object);
206~~~
207In either case, the ownership of the object is not taken over by the `TTree`.
208Even though in the first case an object is be allocated by `TTree::Branch`,
209the object will <b>not</b> be deleted when the `TTree` is deleted.
210
211\anchor addingacolumnoftclonesarray
212## Add a column holding TClonesArray instances
213
214*The usage of `TClonesArray` should be abandoned in favour of `std::vector`,
215for which `TTree` has been heavily optimised, as well as `RNTuple`.*
216
217~~~ {.cpp}
218 // clonesarray is the address of a pointer to a TClonesArray.
219 auto branch = tree.Branch(branchname,clonesarray, bufsize, splitlevel)
220~~~
221The TClonesArray is a direct access list of objects of the same class.
222For example, if the TClonesArray is an array of TTrack objects,
223this function will create one subbranch for each data member of
224the object TTrack.
225
226\anchor fillthetree
227## Fill the Tree
228
229A TTree instance is filled with the invocation of the TTree::Fill method:
230~~~ {.cpp}
231 tree.Fill()
232~~~
233Upon its invocation, a loop on all defined branches takes place that for each branch invokes
234the TBranch::Fill method.
235
236\anchor addcoltoexistingtree
237## Add a column to an already existing Tree
238
239You may want to add a branch to an existing tree. For example,
240if one variable in the tree was computed with a certain algorithm,
241you may want to try another algorithm and compare the results.
242One solution is to add a new branch, fill it, and save the tree.
243The code below adds a simple branch to an existing tree.
244Note the `kOverwrite` option in the `Write` method: it overwrites the
245existing tree. If it is not specified, two copies of the tree headers
246are saved.
247~~~ {.cpp}
248 void addBranchToTree() {
249 TFile f("tree.root", "update");
250
251 Float_t new_v;
252 auto mytree = f->Get<TTree>("mytree");
253 auto newBranch = mytree->Branch("new_v", &new_v, "new_v/F");
254
255 auto nentries = mytree->GetEntries(); // read the number of entries in the mytree
256
257 for (Long64_t i = 0; i < nentries; i++) {
258 new_v = gRandom->Gaus(0, 1);
259 newBranch->Fill();
260 }
261
262 mytree->Write("", TObject::kOverwrite); // save only the new version of the tree
263 }
264~~~
265It is not always possible to add branches to existing datasets stored in TFiles: for example,
266these files might not be writeable, just readable. In addition, modifying in place a TTree
267causes a new TTree instance to be written and the previous one to be deleted.
268For this reasons, ROOT offers the concept of friends for TTree and TChain.
269
270\anchor fullexample
271## A Complete Example
272
273~~~ {.cpp}
274// A simple example creating a tree
275// Compile it with: `g++ myTreeExample.cpp -o myTreeExample `root-config --cflags --libs`
276
277#include "TFile.h"
278#include "TH1D.h"
279#include "TRandom3.h"
280#include "TTree.h"
281
282int main()
283{
284 // Create a new ROOT binary machine independent file.
285 // Note that this file may contain any kind of ROOT objects, histograms,trees
286 // pictures, graphics objects, detector geometries, tracks, events, etc..
287 TFile hfile("htree.root", "RECREATE", "Demo ROOT file with trees");
288
289 // Define a histogram and some simple structures
290 TH1D hpx("hpx", "This is the px distribution", 100, -4, 4);
291
292 typedef struct {
293 Float_t x, y, z;
294 } Point;
295
296 typedef struct {
297 Int_t ntrack, nseg, nvertex;
298 UInt_t flag;
299 Float_t temperature;
300 } Event;
301 Point point;
302 Event event;
303
304 // Create a ROOT Tree
305 TTree tree("T", "An example of ROOT tree with a few branches");
306 tree.Branch("point", &point, "x:y:z");
307 tree.Branch("event", &event, "ntrack/I:nseg:nvertex:flag/i:temperature/F");
308 tree.Branch("hpx", &hpx);
309
310 float px, py;
311
312 TRandom3 myGenerator;
313
314 // Here we start a loop on 1000 events
315 for (Int_t i = 0; i < 1000; i++) {
316 myGenerator.Rannor(px, py);
317 const auto random = myGenerator.Rndm(1);
318
319 // Fill histogram
320 hpx.Fill(px);
321
322 // Fill structures
323 point.x = 10 * (random - 1);
324 point.y = 5 * random;
325 point.z = 20 * random;
326 event.ntrack = int(100 * random);
327 event.nseg = int(2 * event.ntrack);
328 event.nvertex = 1;
329 event.flag = int(random + 0.5);
330 event.temperature = 20 + random;
331
332 // Fill the tree. For each event, save the 2 structures and object.
333 // In this simple example, the objects hpx, hprof and hpxpy are only slightly
334 // different from event to event. We expect a big compression factor!
335 tree.Fill();
336 }
337
338 // Save all objects in this file
339 hfile.Write();
340
341 // Close the file. Note that this is automatically done when you leave
342 // the application upon file destruction.
343 hfile.Close();
344
345 return 0;
346}
347~~~
348## TTree Diagram
349
350The following diagram shows the organisation of the federation of classes related to TTree.
351
352Begin_Macro
353../../../tutorials/legacy/tree/tree.C
354End_Macro
355*/
356
357#include <ROOT/RConfig.hxx>
358#include "TTree.h"
359
360#include "ROOT/TIOFeatures.hxx"
361#include "TArrayC.h"
362#include "TBufferFile.h"
363#include "TBaseClass.h"
364#include "TBasket.h"
365#include "TBranchClones.h"
366#include "TBranchElement.h"
367#include "TBranchObject.h"
368#include "TBranchRef.h"
369#include "TBrowser.h"
370#include "TClass.h"
371#include "TClassEdit.h"
372#include "TClonesArray.h"
373#include "TCut.h"
374#include "TDataMember.h"
375#include "TDataType.h"
376#include "TDirectory.h"
377#include "TError.h"
378#include "TEntryList.h"
379#include "TEnv.h"
380#include "TEventList.h"
381#include "TFile.h"
382#include "TFolder.h"
383#include "TFriendElement.h"
384#include "TInterpreter.h"
385#include "TLeaf.h"
386#include "TLeafB.h"
387#include "TLeafC.h"
388#include "TLeafD.h"
389#include "TLeafElement.h"
390#include "TLeafF.h"
391#include "TLeafI.h"
392#include "TLeafL.h"
393#include "TLeafObject.h"
394#include "TLeafS.h"
395#include "TList.h"
396#include "TMath.h"
397#include "TMemFile.h"
398#include "TROOT.h"
399#include "TRealData.h"
400#include "TRegexp.h"
401#include "TRefTable.h"
402#include "TStreamerElement.h"
403#include "TStreamerInfo.h"
404#include "TStyle.h"
405#include "TSystem.h"
406#include "TTreeCloner.h"
407#include "TTreeCache.h"
408#include "TTreeCacheUnzip.h"
411#include "TVirtualIndex.h"
412#include "TVirtualPerfStats.h"
413#include "TVirtualPad.h"
414#include "TBranchSTL.h"
415#include "TSchemaRuleSet.h"
416#include "TFileMergeInfo.h"
417#include "ROOT/StringConv.hxx"
418#include "TVirtualMutex.h"
419#include "strlcpy.h"
420#include "snprintf.h"
421
422#include "TBranchIMTHelper.h"
423#include "TNotifyLink.h"
424
425#include <chrono>
426#include <cstddef>
427#include <iostream>
428#include <fstream>
429#include <sstream>
430#include <string>
431#include <cstdio>
432#include <climits>
433#include <algorithm>
434#include <set>
435
436#ifdef R__USE_IMT
438#include <thread>
439#endif
441constexpr Int_t kNEntriesResort = 100;
443
444Int_t TTree::fgBranchStyle = 1; // Use new TBranch style with TBranchElement.
445Long64_t TTree::fgMaxTreeSize = 100000000000LL;
446
448
449////////////////////////////////////////////////////////////////////////////////
450////////////////////////////////////////////////////////////////////////////////
451////////////////////////////////////////////////////////////////////////////////
453static char DataTypeToChar(EDataType datatype)
454{
455 // Return the leaflist 'char' for a given datatype.
456
457 switch(datatype) {
458 case kChar_t: return 'B';
459 case kUChar_t: return 'b';
460 case kBool_t: return 'O';
461 case kShort_t: return 'S';
462 case kUShort_t: return 's';
463 case kCounter:
464 case kInt_t: return 'I';
465 case kUInt_t: return 'i';
466 case kDouble_t: return 'D';
467 case kDouble32_t: return 'd';
468 case kFloat_t: return 'F';
469 case kFloat16_t: return 'f';
470 case kLong_t: return 'G';
471 case kULong_t: return 'g';
472 case kchar: return 0; // unsupported
473 case kLong64_t: return 'L';
474 case kULong64_t: return 'l';
475
476 case kCharStar: return 'C';
477 case kBits: return 0; //unsupported
478
479 case kOther_t:
480 case kNoType_t:
481 default:
482 return 0;
483 }
484 return 0;
485}
486
487////////////////////////////////////////////////////////////////////////////////
488/// \class TTree::TFriendLock
489/// Helper class to prevent infinite recursion in the usage of TTree Friends.
490
491////////////////////////////////////////////////////////////////////////////////
492/// Record in tree that it has been used while recursively looks through the friends.
495: fTree(tree)
496{
497 // We could also add some code to acquire an actual
498 // lock to prevent multi-thread issues
499 fMethodBit = methodbit;
500 if (fTree) {
503 } else {
504 fPrevious = false;
505 }
506}
507
508////////////////////////////////////////////////////////////////////////////////
509/// Copy constructor.
512 fTree(tfl.fTree),
513 fMethodBit(tfl.fMethodBit),
514 fPrevious(tfl.fPrevious)
515{
516}
517
518////////////////////////////////////////////////////////////////////////////////
519/// Assignment operator.
522{
523 if(this!=&tfl) {
524 fTree=tfl.fTree;
525 fMethodBit=tfl.fMethodBit;
526 fPrevious=tfl.fPrevious;
527 }
528 return *this;
529}
530
531////////////////////////////////////////////////////////////////////////////////
532/// Restore the state of tree the same as before we set the lock.
535{
536 if (fTree) {
537 if (!fPrevious) {
538 fTree->fFriendLockStatus &= ~(fMethodBit & kBitMask);
539 }
540 }
541}
542
543////////////////////////////////////////////////////////////////////////////////
544/// \class TTree::TClusterIterator
545/// Helper class to iterate over cluster of baskets.
546
547////////////////////////////////////////////////////////////////////////////////
548/// Regular constructor.
549/// TTree is not set as const, since we might modify if it is a TChain.
551TTree::TClusterIterator::TClusterIterator(TTree *tree, Long64_t firstEntry) : fTree(tree), fClusterRange(0), fStartEntry(0), fNextEntry(0), fEstimatedSize(-1)
552{
553 if (fTree->fNClusterRange) {
554 // Find the correct cluster range.
555 //
556 // Since fClusterRangeEnd contains the inclusive upper end of the range, we need to search for the
557 // range that was containing the previous entry and add 1 (because BinarySearch consider the values
558 // to be the inclusive start of the bucket).
560
561 Long64_t entryInRange;
562 Long64_t pedestal;
563 if (fClusterRange == 0) {
564 pedestal = 0;
565 entryInRange = firstEntry;
566 } else {
567 pedestal = fTree->fClusterRangeEnd[fClusterRange-1] + 1;
568 entryInRange = firstEntry - pedestal;
569 }
570 Long64_t autoflush;
572 autoflush = fTree->fAutoFlush;
573 } else {
574 autoflush = fTree->fClusterSize[fClusterRange];
575 }
576 if (autoflush <= 0) {
577 autoflush = GetEstimatedClusterSize();
578 }
579 fStartEntry = pedestal + entryInRange - entryInRange%autoflush;
580 } else if ( fTree->GetAutoFlush() <= 0 ) {
581 // Case of old files before November 9 2009 *or* small tree where AutoFlush was never set.
582 fStartEntry = firstEntry;
583 } else {
584 fStartEntry = firstEntry - firstEntry%fTree->GetAutoFlush();
585 }
586 fNextEntry = fStartEntry; // Position correctly for the first call to Next()
587}
588
589////////////////////////////////////////////////////////////////////////////////
590/// Estimate the cluster size.
591///
592/// In almost all cases, this quickly returns the size of the auto-flush
593/// in the TTree.
594///
595/// However, in the case where the cluster size was not fixed (old files and
596/// case where autoflush was explicitly set to zero), we need estimate
597/// a cluster size in relation to the size of the cache.
598///
599/// After this value is calculated once for the TClusterIterator, it is
600/// cached and reused in future calls.
603{
604 auto autoFlush = fTree->GetAutoFlush();
605 if (autoFlush > 0) return autoFlush;
606 if (fEstimatedSize > 0) return fEstimatedSize;
607
608 Long64_t zipBytes = fTree->GetZipBytes();
609 if (zipBytes == 0) {
610 fEstimatedSize = fTree->GetEntries() - 1;
611 if (fEstimatedSize <= 0)
612 fEstimatedSize = 1;
613 } else {
614 Long64_t clusterEstimate = 1;
615 Long64_t cacheSize = fTree->GetCacheSize();
616 if (cacheSize == 0) {
617 // Humm ... let's double check on the file.
618 TFile *file = fTree->GetCurrentFile();
619 if (file) {
620 TFileCacheRead *cache = fTree->GetReadCache(file);
621 if (cache) {
622 cacheSize = cache->GetBufferSize();
623 }
624 }
625 }
626 // If neither file nor tree has a cache, use the current default.
627 if (cacheSize <= 0) {
628 cacheSize = 30000000;
629 }
630 clusterEstimate = fTree->GetEntries() * cacheSize / zipBytes;
631 // If there are no entries, then just default to 1.
632 fEstimatedSize = clusterEstimate ? clusterEstimate : 1;
633 }
634 return fEstimatedSize;
635}
636
637////////////////////////////////////////////////////////////////////////////////
638/// Move on to the next cluster and return the starting entry
639/// of this next cluster
642{
643 fStartEntry = fNextEntry;
644 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
645 if (fClusterRange == fTree->fNClusterRange) {
646 // We are looking at a range which size
647 // is defined by AutoFlush itself and goes to the GetEntries.
648 fNextEntry += GetEstimatedClusterSize();
649 } else {
650 if (fStartEntry > fTree->fClusterRangeEnd[fClusterRange]) {
651 ++fClusterRange;
652 }
653 if (fClusterRange == fTree->fNClusterRange) {
654 // We are looking at the last range which size
655 // is defined by AutoFlush itself and goes to the GetEntries.
656 fNextEntry += GetEstimatedClusterSize();
657 } else {
658 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
659 if (clusterSize == 0) {
660 clusterSize = GetEstimatedClusterSize();
661 }
662 fNextEntry += clusterSize;
663 if (fNextEntry > fTree->fClusterRangeEnd[fClusterRange]) {
664 // The last cluster of the range was a partial cluster,
665 // so the next cluster starts at the beginning of the
666 // next range.
667 fNextEntry = fTree->fClusterRangeEnd[fClusterRange] + 1;
668 }
669 }
670 }
671 } else {
672 // Case of old files before November 9 2009
673 fNextEntry = fStartEntry + GetEstimatedClusterSize();
674 }
675 if (fNextEntry > fTree->GetEntries()) {
676 fNextEntry = fTree->GetEntries();
677 }
678 return fStartEntry;
679}
680
681////////////////////////////////////////////////////////////////////////////////
682/// Move on to the previous cluster and return the starting entry
683/// of this previous cluster
686{
687 fNextEntry = fStartEntry;
688 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
689 if (fClusterRange == 0 || fTree->fNClusterRange == 0) {
690 // We are looking at a range which size
691 // is defined by AutoFlush itself.
692 fStartEntry -= GetEstimatedClusterSize();
693 } else {
694 if (fNextEntry <= fTree->fClusterRangeEnd[fClusterRange]) {
695 --fClusterRange;
696 }
697 if (fClusterRange == 0) {
698 // We are looking at the first range.
699 fStartEntry = 0;
700 } else {
701 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
702 if (clusterSize == 0) {
703 clusterSize = GetEstimatedClusterSize();
704 }
705 fStartEntry -= clusterSize;
706 }
707 }
708 } else {
709 // Case of old files before November 9 2009 or trees that never auto-flushed.
710 fStartEntry = fNextEntry - GetEstimatedClusterSize();
711 }
712 if (fStartEntry < 0) {
713 fStartEntry = 0;
714 }
715 return fStartEntry;
716}
717
718////////////////////////////////////////////////////////////////////////////////
719////////////////////////////////////////////////////////////////////////////////
720////////////////////////////////////////////////////////////////////////////////
721
722////////////////////////////////////////////////////////////////////////////////
723/// Default constructor and I/O constructor.
724///
725/// Note: We do *not* insert ourself into the current directory.
726///
729: TNamed()
730, TAttLine()
731, TAttFill()
732, TAttMarker()
733, fEntries(0)
734, fTotBytes(0)
735, fZipBytes(0)
736, fSavedBytes(0)
737, fFlushedBytes(0)
738, fWeight(1)
740, fScanField(25)
741, fUpdate(0)
745, fMaxEntries(0)
746, fMaxEntryLoop(0)
748, fAutoSave( -300000000)
749, fAutoFlush(-30000000)
750, fEstimate(1000000)
751, fClusterRangeEnd(nullptr)
752, fClusterSize(nullptr)
753, fCacheSize(0)
754, fChainOffset(0)
755, fReadEntry(-1)
756, fTotalBuffers(0)
757, fPacketSize(100)
758, fNfill(0)
759, fDebug(0)
760, fDebugMin(0)
761, fDebugMax(9999999)
762, fMakeClass(0)
763, fFileNumber(0)
764, fNotify(nullptr)
765, fDirectory(nullptr)
766, fBranches()
767, fLeaves()
768, fAliases(nullptr)
769, fEventList(nullptr)
770, fEntryList(nullptr)
771, fIndexValues()
772, fIndex()
773, fTreeIndex(nullptr)
774, fFriends(nullptr)
775, fExternalFriends(nullptr)
776, fPerfStats(nullptr)
777, fUserInfo(nullptr)
778, fPlayer(nullptr)
779, fClones(nullptr)
780, fBranchRef(nullptr)
782, fTransientBuffer(nullptr)
783, fCacheDoAutoInit(true)
785, fCacheUserSet(false)
786, fIMTEnabled(ROOT::IsImplicitMTEnabled())
788{
789 fMaxEntries = 1000000000;
790 fMaxEntries *= 1000;
791
792 fMaxEntryLoop = 1000000000;
793 fMaxEntryLoop *= 1000;
794
795 fBranches.SetOwner(true);
796}
797
798////////////////////////////////////////////////////////////////////////////////
799/// Normal tree constructor.
800///
801/// The tree is created in the current directory.
802/// Use the various functions Branch below to add branches to this tree.
803///
804/// If the first character of title is a "/", the function assumes a folder name.
805/// In this case, it creates automatically branches following the folder hierarchy.
806/// splitlevel may be used in this case to control the split level.
808TTree::TTree(const char* name, const char* title, Int_t splitlevel /* = 99 */,
809 TDirectory* dir /* = gDirectory*/)
810: TNamed(name, title)
811, TAttLine()
812, TAttFill()
813, TAttMarker()
814, fEntries(0)
815, fTotBytes(0)
816, fZipBytes(0)
817, fSavedBytes(0)
818, fFlushedBytes(0)
819, fWeight(1)
820, fTimerInterval(0)
821, fScanField(25)
822, fUpdate(0)
823, fDefaultEntryOffsetLen(1000)
824, fNClusterRange(0)
825, fMaxClusterRange(0)
826, fMaxEntries(0)
827, fMaxEntryLoop(0)
828, fMaxVirtualSize(0)
829, fAutoSave( -300000000)
830, fAutoFlush(-30000000)
831, fEstimate(1000000)
832, fClusterRangeEnd(nullptr)
833, fClusterSize(nullptr)
834, fCacheSize(0)
835, fChainOffset(0)
836, fReadEntry(-1)
837, fTotalBuffers(0)
838, fPacketSize(100)
839, fNfill(0)
840, fDebug(0)
841, fDebugMin(0)
842, fDebugMax(9999999)
843, fMakeClass(0)
844, fFileNumber(0)
845, fNotify(nullptr)
846, fDirectory(dir)
847, fBranches()
848, fLeaves()
849, fAliases(nullptr)
850, fEventList(nullptr)
851, fEntryList(nullptr)
852, fIndexValues()
853, fIndex()
854, fTreeIndex(nullptr)
855, fFriends(nullptr)
856, fExternalFriends(nullptr)
857, fPerfStats(nullptr)
858, fUserInfo(nullptr)
859, fPlayer(nullptr)
860, fClones(nullptr)
861, fBranchRef(nullptr)
862, fFriendLockStatus(0)
863, fTransientBuffer(nullptr)
864, fCacheDoAutoInit(true)
865, fCacheDoClusterPrefetch(false)
866, fCacheUserSet(false)
867, fIMTEnabled(ROOT::IsImplicitMTEnabled())
868, fNEntriesSinceSorting(0)
869{
870 // TAttLine state.
874
875 // TAttFill state.
878
879 // TAttMarkerState.
883
884 fMaxEntries = 1000000000;
885 fMaxEntries *= 1000;
886
887 fMaxEntryLoop = 1000000000;
888 fMaxEntryLoop *= 1000;
889
890 // Insert ourself into the current directory.
891 // FIXME: This is very annoying behaviour, we should
892 // be able to choose to not do this like we
893 // can with a histogram.
894 if (fDirectory) fDirectory->Append(this);
895
896 fBranches.SetOwner(true);
897
898 // If title starts with "/" and is a valid folder name, a superbranch
899 // is created.
900 // FIXME: Why?
901 if (strlen(title) > 2) {
902 if (title[0] == '/') {
903 Branch(title+1,32000,splitlevel);
904 }
905 }
906}
907
908////////////////////////////////////////////////////////////////////////////////
909/// Destructor.
912{
913 if (auto link = dynamic_cast<TNotifyLinkBase*>(fNotify)) {
914 link->Clear();
915 }
916 if (fAllocationCount && (gDebug > 0)) {
917 Info("TTree::~TTree", "For tree %s, allocation count is %u.", GetName(), fAllocationCount.load());
918#ifdef R__TRACK_BASKET_ALLOC_TIME
919 Info("TTree::~TTree", "For tree %s, allocation time is %lluus.", GetName(), fAllocationTime.load());
920#endif
921 }
922
923 if (fDirectory) {
924 // We are in a directory, which may possibly be a file.
925 if (fDirectory->GetList()) {
926 // Remove us from the directory listing.
927 fDirectory->Remove(this);
928 }
929 //delete the file cache if it points to this Tree
930 TFile *file = fDirectory->GetFile();
931 MoveReadCache(file,nullptr);
932 }
933
934 // Remove the TTree from any list (linked to to the list of Cleanups) to avoid the unnecessary call to
935 // this RecursiveRemove while we delete our content.
937 ResetBit(kMustCleanup); // Don't redo it.
938
939 // We don't own the leaves in fLeaves, the branches do.
940 fLeaves.Clear();
941 // I'm ready to destroy any objects allocated by
942 // SetAddress() by my branches. If I have clones,
943 // tell them to zero their pointers to this shared
944 // memory.
945 if (fClones && fClones->GetEntries()) {
946 // I have clones.
947 // I am about to delete the objects created by
948 // SetAddress() which we are sharing, so tell
949 // the clones to release their pointers to them.
950 for (TObjLink* lnk = fClones->FirstLink(); lnk; lnk = lnk->Next()) {
951 TTree* clone = (TTree*) lnk->GetObject();
952 // clone->ResetBranchAddresses();
953
954 // Reset only the branch we have set the address of.
955 CopyAddresses(clone,true);
956 }
957 }
958 // Get rid of our branches, note that this will also release
959 // any memory allocated by TBranchElement::SetAddress().
961
962 // The TBranch destructor is using fDirectory to detect whether it
963 // owns the TFile that contains its data (See TBranch::~TBranch)
964 fDirectory = nullptr;
965
966 // FIXME: We must consider what to do with the reset of these if we are a clone.
967 delete fPlayer;
968 fPlayer = nullptr;
969 if (fExternalFriends) {
970 using namespace ROOT::Detail;
972 fetree->Reset();
973 fExternalFriends->Clear("nodelete");
975 }
976 if (fFriends) {
977 fFriends->Delete();
978 delete fFriends;
979 fFriends = nullptr;
980 }
981 if (fAliases) {
982 fAliases->Delete();
983 delete fAliases;
984 fAliases = nullptr;
985 }
986 if (fUserInfo) {
987 fUserInfo->Delete();
988 delete fUserInfo;
989 fUserInfo = nullptr;
990 }
991 if (fClones) {
992 // Clone trees should no longer be removed from fClones when they are deleted.
993 {
995 gROOT->GetListOfCleanups()->Remove(fClones);
996 }
997 // Note: fClones does not own its content.
998 delete fClones;
999 fClones = nullptr;
1000 }
1001 if (fEntryList) {
1002 if (fEntryList->TestBit(kCanDelete) && fEntryList->GetDirectory()==nullptr) {
1003 // Delete the entry list if it is marked to be deleted and it is not also
1004 // owned by a directory. (Otherwise we would need to make sure that a
1005 // TDirectoryFile that has a TTree in it does a 'slow' TList::Delete.
1006 delete fEntryList;
1007 fEntryList=nullptr;
1008 }
1009 }
1010 delete fTreeIndex;
1011 fTreeIndex = nullptr;
1012 delete fBranchRef;
1013 fBranchRef = nullptr;
1014 delete [] fClusterRangeEnd;
1015 fClusterRangeEnd = nullptr;
1016 delete [] fClusterSize;
1017 fClusterSize = nullptr;
1018
1019 if (fTransientBuffer) {
1020 delete fTransientBuffer;
1021 fTransientBuffer = nullptr;
1022 }
1023}
1024
1025////////////////////////////////////////////////////////////////////////////////
1026/// Returns the transient buffer currently used by this TTree for reading/writing baskets.
1029{
1030 if (fTransientBuffer) {
1031 if (fTransientBuffer->BufferSize() < size) {
1033 }
1034 return fTransientBuffer;
1035 }
1037 return fTransientBuffer;
1038}
1039
1040////////////////////////////////////////////////////////////////////////////////
1041/// Add branch with name bname to the Tree cache.
1042/// If bname="*" all branches are added to the cache.
1043/// if subbranches is true all the branches of the subbranches are
1044/// also put to the cache.
1045///
1046/// Returns:
1047/// - 0 branch added or already included
1048/// - -1 on error
1050Int_t TTree::AddBranchToCache(const char*bname, bool subbranches)
1051{
1052 if (!GetTree()) {
1053 if (LoadTree(0)<0) {
1054 Error("AddBranchToCache","Could not load a tree");
1055 return -1;
1056 }
1057 }
1058 if (GetTree()) {
1059 if (GetTree() != this) {
1060 return GetTree()->AddBranchToCache(bname, subbranches);
1061 }
1062 } else {
1063 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1064 return -1;
1065 }
1066
1067 TFile *f = GetCurrentFile();
1068 if (!f) {
1069 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1070 return -1;
1071 }
1072 TTreeCache *tc = GetReadCache(f,true);
1073 if (!tc) {
1074 Error("AddBranchToCache", "No cache is available, branch not added");
1075 return -1;
1076 }
1077 return tc->AddBranch(bname,subbranches);
1078}
1079
1080////////////////////////////////////////////////////////////////////////////////
1081/// Add branch b to the Tree cache.
1082/// if subbranches is true all the branches of the subbranches are
1083/// also put to the cache.
1084///
1085/// Returns:
1086/// - 0 branch added or already included
1087/// - -1 on error
1089Int_t TTree::AddBranchToCache(TBranch *b, bool subbranches)
1090{
1091 if (!GetTree()) {
1092 if (LoadTree(0)<0) {
1093 Error("AddBranchToCache","Could not load a tree");
1094 return -1;
1095 }
1096 }
1097 if (GetTree()) {
1098 if (GetTree() != this) {
1099 Int_t res = GetTree()->AddBranchToCache(b, subbranches);
1100 if (res<0) {
1101 Error("AddBranchToCache", "Error adding branch");
1102 }
1103 return res;
1104 }
1105 } else {
1106 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1107 return -1;
1108 }
1109
1110 TFile *f = GetCurrentFile();
1111 if (!f) {
1112 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1113 return -1;
1114 }
1115 TTreeCache *tc = GetReadCache(f,true);
1116 if (!tc) {
1117 Error("AddBranchToCache", "No cache is available, branch not added");
1118 return -1;
1119 }
1120 return tc->AddBranch(b,subbranches);
1121}
1122
1123////////////////////////////////////////////////////////////////////////////////
1124/// Remove the branch with name 'bname' from the Tree cache.
1125/// If bname="*" all branches are removed from the cache.
1126/// if subbranches is true all the branches of the subbranches are
1127/// also removed from the cache.
1128///
1129/// Returns:
1130/// - 0 branch dropped or not in cache
1131/// - -1 on error
1133Int_t TTree::DropBranchFromCache(const char*bname, bool subbranches)
1134{
1135 if (!GetTree()) {
1136 if (LoadTree(0)<0) {
1137 Error("DropBranchFromCache","Could not load a tree");
1138 return -1;
1139 }
1140 }
1141 if (GetTree()) {
1142 if (GetTree() != this) {
1143 return GetTree()->DropBranchFromCache(bname, subbranches);
1144 }
1145 } else {
1146 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1147 return -1;
1148 }
1149
1150 TFile *f = GetCurrentFile();
1151 if (!f) {
1152 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1153 return -1;
1154 }
1155 TTreeCache *tc = GetReadCache(f,true);
1156 if (!tc) {
1157 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1158 return -1;
1159 }
1160 return tc->DropBranch(bname,subbranches);
1161}
1162
1163////////////////////////////////////////////////////////////////////////////////
1164/// Remove the branch b from the Tree cache.
1165/// if subbranches is true all the branches of the subbranches are
1166/// also removed from the cache.
1167///
1168/// Returns:
1169/// - 0 branch dropped or not in cache
1170/// - -1 on error
1172Int_t TTree::DropBranchFromCache(TBranch *b, bool subbranches)
1173{
1174 if (!GetTree()) {
1175 if (LoadTree(0)<0) {
1176 Error("DropBranchFromCache","Could not load a tree");
1177 return -1;
1178 }
1179 }
1180 if (GetTree()) {
1181 if (GetTree() != this) {
1182 Int_t res = GetTree()->DropBranchFromCache(b, subbranches);
1183 if (res<0) {
1184 Error("DropBranchFromCache", "Error dropping branch");
1185 }
1186 return res;
1187 }
1188 } else {
1189 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1190 return -1;
1191 }
1192
1193 TFile *f = GetCurrentFile();
1194 if (!f) {
1195 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1196 return -1;
1197 }
1198 TTreeCache *tc = GetReadCache(f,true);
1199 if (!tc) {
1200 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1201 return -1;
1202 }
1203 return tc->DropBranch(b,subbranches);
1204}
1205
1206////////////////////////////////////////////////////////////////////////////////
1207/// Add a cloned tree to our list of trees to be notified whenever we change
1208/// our branch addresses or when we are deleted.
1210void TTree::AddClone(TTree* clone)
1211{
1212 if (!fClones) {
1213 fClones = new TList();
1214 fClones->SetOwner(false);
1215 // So that the clones are automatically removed from the list when
1216 // they are deleted.
1217 {
1219 gROOT->GetListOfCleanups()->Add(fClones);
1220 }
1221 }
1222 if (!fClones->FindObject(clone)) {
1223 fClones->Add(clone);
1224 }
1225}
1226
1227// Check whether mainTree and friendTree can be friends w.r.t. the kEntriesReshuffled bit.
1228// In particular, if any has the bit set, then friendTree must have a TTreeIndex and the
1229// branches used for indexing must be present in mainTree.
1230// Return true if the trees can be friends, false otherwise.
1231bool CheckReshuffling(TTree &mainTree, TTree &friendTree)
1232{
1233 const auto isMainReshuffled = mainTree.TestBit(TTree::kEntriesReshuffled);
1234 const auto isFriendReshuffled = friendTree.TestBit(TTree::kEntriesReshuffled);
1235 const auto friendHasValidIndex = [&] {
1236 auto idx = friendTree.GetTreeIndex();
1237 return idx ? idx->IsValidFor(&mainTree) : false;
1238 }();
1239
1240 if ((isMainReshuffled || isFriendReshuffled) && !friendHasValidIndex) {
1241 const auto reshuffledTreeName = isMainReshuffled ? mainTree.GetName() : friendTree.GetName();
1242 const auto msg =
1243 "Tree '%s' has the kEntriesReshuffled bit set and cannot have friends nor can be added as a friend unless the "
1244 "main tree has a TTreeIndex on the friend tree '%s'. You can also unset the bit manually if you know what you "
1245 "are doing; note that you risk associating wrong TTree entries of the friend with those of the main TTree!";
1246 Error("AddFriend", msg, reshuffledTreeName, friendTree.GetName());
1247 return false;
1248 }
1249 return true;
1250}
1251
1252////////////////////////////////////////////////////////////////////////////////
1253/// Add a TFriendElement to the list of friends.
1254///
1255/// This function:
1256/// - opens a file if filename is specified
1257/// - reads a Tree with name treename from the file (current directory)
1258/// - adds the Tree to the list of friends
1259/// see other AddFriend functions
1260///
1261/// A TFriendElement TF describes a TTree object TF in a file.
1262/// When a TFriendElement TF is added to the list of friends of an
1263/// existing TTree T, any variable from TF can be referenced in a query
1264/// to T.
1265///
1266/// A tree keeps a list of friends. In the context of a tree (or a chain),
1267/// friendship means unrestricted access to the friends data. In this way
1268/// it is much like adding another branch to the tree without taking the risk
1269/// of damaging it. To add a friend to the list, you can use the TTree::AddFriend
1270/// method. The tree in the diagram below has two friends (friend_tree1 and
1271/// friend_tree2) and now has access to the variables a,b,c,i,j,k,l and m.
1272///
1273/// \image html ttree_friend1.png
1274///
1275/// The AddFriend method has two parameters, the first is the tree name and the
1276/// second is the name of the ROOT file where the friend tree is saved.
1277/// AddFriend automatically opens the friend file. If no file name is given,
1278/// the tree called ft1 is assumed to be in the same file as the original tree.
1279///
1280/// tree.AddFriend("ft1","friendfile1.root");
1281/// If the friend tree has the same name as the original tree, you can give it
1282/// an alias in the context of the friendship:
1283///
1284/// tree.AddFriend("tree1 = tree","friendfile1.root");
1285/// Once the tree has friends, we can use TTree::Draw as if the friend's
1286/// variables were in the original tree. To specify which tree to use in
1287/// the Draw method, use the syntax:
1288/// ~~~ {.cpp}
1289/// <treeName>.<branchname>.<varname>
1290/// ~~~
1291/// If the variablename is enough to uniquely identify the variable, you can
1292/// leave out the tree and/or branch name.
1293/// For example, these commands generate a 3-d scatter plot of variable "var"
1294/// in the TTree tree versus variable v1 in TTree ft1 versus variable v2 in
1295/// TTree ft2.
1296/// ~~~ {.cpp}
1297/// tree.AddFriend("ft1","friendfile1.root");
1298/// tree.AddFriend("ft2","friendfile2.root");
1299/// tree.Draw("var:ft1.v1:ft2.v2");
1300/// ~~~
1301/// \image html ttree_friend2.png
1302///
1303/// The picture illustrates the access of the tree and its friends with a
1304/// Draw command.
1305/// When AddFriend is called, the ROOT file is automatically opened and the
1306/// friend tree (ft1) is read into memory. The new friend (ft1) is added to
1307/// the list of friends of tree.
1308/// The number of entries in the friend must be equal or greater to the number
1309/// of entries of the original tree. If the friend tree has fewer entries a
1310/// warning is given and the missing entries are not included in the histogram.
1311/// To retrieve the list of friends from a tree use TTree::GetListOfFriends.
1312/// When the tree is written to file (TTree::Write), the friends list is saved
1313/// with it. And when the tree is retrieved, the trees on the friends list are
1314/// also retrieved and the friendship restored.
1315/// When a tree is deleted, the elements of the friend list are also deleted.
1316/// It is possible to declare a friend tree that has the same internal
1317/// structure (same branches and leaves) as the original tree, and compare the
1318/// same values by specifying the tree.
1319/// ~~~ {.cpp}
1320/// tree.Draw("var:ft1.var:ft2.var")
1321/// ~~~
1323TFriendElement *TTree::AddFriend(const char *treename, const char *filename)
1324{
1325 if (!fFriends) {
1326 fFriends = new TList();
1327 }
1328 TFriendElement *fe = new TFriendElement(this, treename, filename);
1329
1330 TTree *t = fe->GetTree();
1331 bool canAddFriend = true;
1332 if (t) {
1333 canAddFriend = CheckReshuffling(*this, *t);
1334 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1335 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent Tree: %lld", treename,
1337 }
1338 } else {
1339 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, filename);
1340 canAddFriend = false;
1341 }
1342
1343 if (canAddFriend)
1344 fFriends->Add(fe);
1345 return fe;
1346}
1347
1348////////////////////////////////////////////////////////////////////////////////
1349/// Add a TFriendElement to the list of friends.
1350///
1351/// The TFile is managed by the user (e.g. the user must delete the file).
1352/// For complete description see AddFriend(const char *, const char *).
1353/// This function:
1354/// - reads a Tree with name treename from the file
1355/// - adds the Tree to the list of friends
1357TFriendElement *TTree::AddFriend(const char *treename, TFile *file)
1358{
1359 if (!fFriends) {
1360 fFriends = new TList();
1361 }
1362 TFriendElement *fe = new TFriendElement(this, treename, file);
1363 R__ASSERT(fe);
1364 TTree *t = fe->GetTree();
1365 bool canAddFriend = true;
1366 if (t) {
1367 canAddFriend = CheckReshuffling(*this, *t);
1368 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1369 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent tree: %lld", treename,
1370 file->GetName(), t->GetEntries(), fEntries);
1371 }
1372 } else {
1373 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, file->GetName());
1374 canAddFriend = false;
1375 }
1376
1377 if (canAddFriend)
1378 fFriends->Add(fe);
1379 return fe;
1380}
1381
1382////////////////////////////////////////////////////////////////////////////////
1383/// Add a TFriendElement to the list of friends.
1384///
1385/// The TTree is managed by the user (e.g., the user must delete the file).
1386/// For a complete description see AddFriend(const char *, const char *).
1388TFriendElement *TTree::AddFriend(TTree *tree, const char *alias, bool warn)
1389{
1390 if (!tree) {
1391 return nullptr;
1392 }
1393 if (!fFriends) {
1394 fFriends = new TList();
1395 }
1396 TFriendElement *fe = new TFriendElement(this, tree, alias);
1397 R__ASSERT(fe); // this assert is for historical reasons. Don't remove it unless you understand all the consequences.
1398 TTree *t = fe->GetTree();
1399 if (warn && (t->GetEntries() < fEntries)) {
1400 Warning("AddFriend", "FriendElement '%s' in file '%s' has less entries %lld than its parent tree: %lld",
1401 tree->GetName(), fe->GetFile() ? fe->GetFile()->GetName() : "(memory resident)", t->GetEntries(),
1402 fEntries);
1403 }
1404 if (CheckReshuffling(*this, *t))
1405 fFriends->Add(fe);
1406 else
1407 tree->RemoveExternalFriend(fe);
1408 return fe;
1409}
1410
1411////////////////////////////////////////////////////////////////////////////////
1412/// AutoSave tree header every fAutoSave bytes.
1413///
1414/// When large Trees are produced, it is safe to activate the AutoSave
1415/// procedure. Some branches may have buffers holding many entries.
1416/// If fAutoSave is negative, AutoSave is automatically called by
1417/// TTree::Fill when the number of bytes generated since the previous
1418/// AutoSave is greater than -fAutoSave bytes.
1419/// If fAutoSave is positive, AutoSave is automatically called by
1420/// TTree::Fill every N entries.
1421/// This function may also be invoked by the user.
1422/// Each AutoSave generates a new key on the file.
1423/// Once the key with the tree header has been written, the previous cycle
1424/// (if any) is deleted.
1425///
1426/// Note that calling TTree::AutoSave too frequently (or similarly calling
1427/// TTree::SetAutoSave with a small value) is an expensive operation.
1428/// You should make tests for your own application to find a compromise
1429/// between speed and the quantity of information you may loose in case of
1430/// a job crash.
1431///
1432/// In case your program crashes before closing the file holding this tree,
1433/// the file will be automatically recovered when you will connect the file
1434/// in UPDATE mode.
1435/// The Tree will be recovered at the status corresponding to the last AutoSave.
1436///
1437/// if option contains "SaveSelf", gDirectory->SaveSelf() is called.
1438/// This allows another process to analyze the Tree while the Tree is being filled.
1439///
1440/// if option contains "FlushBaskets", TTree::FlushBaskets is called and all
1441/// the current basket are closed-out and written to disk individually.
1442///
1443/// By default the previous header is deleted after having written the new header.
1444/// if option contains "Overwrite", the previous Tree header is deleted
1445/// before written the new header. This option is slightly faster, but
1446/// the default option is safer in case of a problem (disk quota exceeded)
1447/// when writing the new header.
1448///
1449/// The function returns the number of bytes written to the file.
1450/// if the number of bytes is null, an error has occurred while writing
1451/// the header to the file.
1452///
1453/// ## How to write a Tree in one process and view it from another process
1454///
1455/// The following two scripts illustrate how to do this.
1456/// The script treew.C is executed by process1, treer.C by process2
1457///
1458/// script treew.C:
1459/// ~~~ {.cpp}
1460/// void treew() {
1461/// TFile f("test.root","recreate");
1462/// TNtuple *ntuple = new TNtuple("ntuple","Demo","px:py:pz:random:i");
1463/// Float_t px, py, pz;
1464/// for ( Int_t i=0; i<10000000; i++) {
1465/// gRandom->Rannor(px,py);
1466/// pz = px*px + py*py;
1467/// Float_t random = gRandom->Rndm(1);
1468/// ntuple->Fill(px,py,pz,random,i);
1469/// if (i%1000 == 1) ntuple->AutoSave("SaveSelf");
1470/// }
1471/// }
1472/// ~~~
1473/// script treer.C:
1474/// ~~~ {.cpp}
1475/// void treer() {
1476/// TFile f("test.root");
1477/// TTree *ntuple = (TTree*)f.Get("ntuple");
1478/// TCanvas c1;
1479/// Int_t first = 0;
1480/// while(1) {
1481/// if (first == 0) ntuple->Draw("px>>hpx", "","",10000000,first);
1482/// else ntuple->Draw("px>>+hpx","","",10000000,first);
1483/// first = (Int_t)ntuple->GetEntries();
1484/// c1.Update();
1485/// gSystem->Sleep(1000); //sleep 1 second
1486/// ntuple->Refresh();
1487/// }
1488/// }
1489/// ~~~
1492{
1493 if (!fDirectory || fDirectory == gROOT || !fDirectory->IsWritable()) return 0;
1494 if (gDebug > 0) {
1495 Info("AutoSave", "Tree:%s after %lld bytes written\n",GetName(),GetTotBytes());
1496 }
1497 TString opt = option;
1498 opt.ToLower();
1499
1500 if (opt.Contains("flushbaskets")) {
1501 if (gDebug > 0) Info("AutoSave", "calling FlushBaskets \n");
1503 }
1504
1506
1508 Long64_t nbytes;
1509 if (opt.Contains("overwrite")) {
1510 nbytes = fDirectory->WriteTObject(this,"","overwrite");
1511 } else {
1512 nbytes = fDirectory->WriteTObject(this); //nbytes will be 0 if Write failed (disk space exceeded)
1513 if (nbytes && key && strcmp(ClassName(), key->GetClassName()) == 0) {
1514 key->Delete();
1515 delete key;
1516 }
1517 }
1518 // save StreamerInfo
1519 TFile *file = fDirectory->GetFile();
1520 if (file) file->WriteStreamerInfo();
1521
1522 if (opt.Contains("saveself")) {
1524 //the following line is required in case GetUserInfo contains a user class
1525 //for which the StreamerInfo must be written. One could probably be a bit faster (Rene)
1526 if (file) file->WriteHeader();
1527 }
1528
1529 return nbytes;
1530}
1531
1532namespace {
1533 // This error message is repeated several times in the code. We write it once.
1534 const char* writeStlWithoutProxyMsg = "The class requested (%s) for the branch \"%s\""
1535 " is an instance of an stl collection and does not have a compiled CollectionProxy."
1536 " Please generate the dictionary for this collection (%s) to avoid to write corrupted data.";
1537}
1538
1539////////////////////////////////////////////////////////////////////////////////
1540/// Same as TTree::Branch() with added check that addobj matches className.
1541///
1542/// \see TTree::Branch() for other details.
1543///
1545TBranch* TTree::BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel)
1546{
1547 TClass* claim = TClass::GetClass(classname);
1548 if (!ptrClass) {
1549 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1550 Error("Branch", writeStlWithoutProxyMsg,
1551 claim->GetName(), branchname, claim->GetName());
1552 return nullptr;
1553 }
1554 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1555 }
1556 TClass* actualClass = nullptr;
1557 void** addr = (void**) addobj;
1558 if (addr) {
1559 actualClass = ptrClass->GetActualClass(*addr);
1560 }
1561 if (ptrClass && claim) {
1562 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1563 // Note we currently do not warn in case of splicing or over-expectation).
1564 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1565 // The type is the same according to the C++ type_info, we must be in the case of
1566 // a template of Double32_t. This is actually a correct case.
1567 } else {
1568 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the pointer passed (%s)",
1569 claim->GetName(), branchname, ptrClass->GetName());
1570 }
1571 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1572 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1573 // The type is the same according to the C++ type_info, we must be in the case of
1574 // a template of Double32_t. This is actually a correct case.
1575 } else {
1576 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1577 actualClass->GetName(), branchname, claim->GetName());
1578 }
1579 }
1580 }
1581 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1582 Error("Branch", writeStlWithoutProxyMsg,
1583 claim->GetName(), branchname, claim->GetName());
1584 return nullptr;
1585 }
1586 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1587}
1588
1589////////////////////////////////////////////////////////////////////////////////
1590/// Same as TTree::Branch but automatic detection of the class name.
1591/// \see TTree::Branch for other details.
1593TBranch* TTree::BranchImp(const char* branchname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel)
1594{
1595 if (!ptrClass) {
1596 Error("Branch", "The pointer specified for %s is not of a class known to ROOT", branchname);
1597 return nullptr;
1598 }
1599 TClass* actualClass = nullptr;
1600 void** addr = (void**) addobj;
1601 if (addr && *addr) {
1602 actualClass = ptrClass->GetActualClass(*addr);
1603 if (!actualClass) {
1604 Warning("Branch", "The actual TClass corresponding to the object provided for the definition of the branch \"%s\" is missing.\n\tThe object will be truncated down to its %s part",
1605 branchname, ptrClass->GetName());
1606 actualClass = ptrClass;
1607 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1608 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s", actualClass->GetName(), branchname, ptrClass->GetName());
1609 return nullptr;
1610 }
1611 } else {
1612 actualClass = ptrClass;
1613 }
1614 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1615 Error("Branch", writeStlWithoutProxyMsg,
1616 actualClass->GetName(), branchname, actualClass->GetName());
1617 return nullptr;
1618 }
1619 return Branch(branchname, actualClass->GetName(), (void*) addobj, bufsize, splitlevel);
1620}
1621
1622////////////////////////////////////////////////////////////////////////////////
1623/// Same as TTree::Branch but automatic detection of the class name.
1624/// \see TTree::Branch for other details.
1626TBranch* TTree::BranchImpRef(const char* branchname, const char *classname, TClass* ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
1627{
1628 TClass* claim = TClass::GetClass(classname);
1629 if (!ptrClass) {
1630 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1631 Error("Branch", writeStlWithoutProxyMsg,
1632 claim->GetName(), branchname, claim->GetName());
1633 return nullptr;
1634 } else if (claim == nullptr) {
1635 Error("Branch", "The pointer specified for %s is not of a class known to ROOT and %s is not a known class", branchname, classname);
1636 return nullptr;
1637 }
1638 ptrClass = claim;
1639 }
1640 TClass* actualClass = nullptr;
1641 if (!addobj) {
1642 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1643 return nullptr;
1644 }
1645 actualClass = ptrClass->GetActualClass(addobj);
1646 if (ptrClass && claim) {
1647 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1648 // Note we currently do not warn in case of splicing or over-expectation).
1649 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1650 // The type is the same according to the C++ type_info, we must be in the case of
1651 // a template of Double32_t. This is actually a correct case.
1652 } else {
1653 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the object passed (%s)",
1654 claim->GetName(), branchname, ptrClass->GetName());
1655 }
1656 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1657 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1658 // The type is the same according to the C++ type_info, we must be in the case of
1659 // a template of Double32_t. This is actually a correct case.
1660 } else {
1661 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1662 actualClass->GetName(), branchname, claim->GetName());
1663 }
1664 }
1665 }
1666 if (!actualClass) {
1667 Warning("Branch", "The actual TClass corresponding to the object provided for the definition of the branch \"%s\" is missing.\n\tThe object will be truncated down to its %s part",
1668 branchname, ptrClass->GetName());
1669 actualClass = ptrClass;
1670 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1671 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s", actualClass->GetName(), branchname, ptrClass->GetName());
1672 return nullptr;
1673 }
1674 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1675 Error("Branch", writeStlWithoutProxyMsg,
1676 actualClass->GetName(), branchname, actualClass->GetName());
1677 return nullptr;
1678 }
1679 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1680}
1681
1682////////////////////////////////////////////////////////////////////////////////
1683/// Same as TTree::Branch but automatic detection of the class name.
1684/// \see TTree::Branch for other details.
1686TBranch* TTree::BranchImpRef(const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Int_t bufsize, Int_t splitlevel)
1687{
1688 if (!ptrClass) {
1689 if (datatype == kOther_t || datatype == kNoType_t) {
1690 Error("Branch", "The pointer specified for %s is not of a class or type known to ROOT", branchname);
1691 } else {
1692 TString varname; varname.Form("%s/%c",branchname,DataTypeToChar(datatype));
1693 return Branch(branchname,addobj,varname.Data(),bufsize);
1694 }
1695 return nullptr;
1696 }
1697 TClass* actualClass = nullptr;
1698 if (!addobj) {
1699 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1700 return nullptr;
1701 }
1702 actualClass = ptrClass->GetActualClass(addobj);
1703 if (!actualClass) {
1704 Warning("Branch", "The actual TClass corresponding to the object provided for the definition of the branch \"%s\" is missing.\n\tThe object will be truncated down to its %s part",
1705 branchname, ptrClass->GetName());
1706 actualClass = ptrClass;
1707 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1708 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s", actualClass->GetName(), branchname, ptrClass->GetName());
1709 return nullptr;
1710 }
1711 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1712 Error("Branch", writeStlWithoutProxyMsg,
1713 actualClass->GetName(), branchname, actualClass->GetName());
1714 return nullptr;
1715 }
1716 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1717}
1718
1719////////////////////////////////////////////////////////////////////////////////
1720// Wrapper to turn Branch call with an std::array into the relevant leaf list
1721// call
1722TBranch *TTree::BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Int_t bufsize,
1723 Int_t /* splitlevel */)
1724{
1725 if (datatype == kOther_t || datatype == kNoType_t) {
1726 Error("Branch",
1727 "The inner type of the std::array passed specified for %s is not of a class or type known to ROOT",
1728 branchname);
1729 } else {
1730 TString varname;
1731 varname.Form("%s[%d]/%c", branchname, (int)N, DataTypeToChar(datatype));
1732 return Branch(branchname, addobj, varname.Data(), bufsize);
1733 }
1734 return nullptr;
1735}
1736
1737////////////////////////////////////////////////////////////////////////////////
1738/// Deprecated function. Use next function instead.
1740Int_t TTree::Branch(TList* li, Int_t bufsize /* = 32000 */ , Int_t splitlevel /* = 99 */)
1741{
1742 return Branch((TCollection*) li, bufsize, splitlevel);
1743}
1744
1745////////////////////////////////////////////////////////////////////////////////
1746/// Create one branch for each element in the collection.
1747///
1748/// Each entry in the collection becomes a top level branch if the
1749/// corresponding class is not a collection. If it is a collection, the entry
1750/// in the collection becomes in turn top level branches, etc.
1751/// The splitlevel is decreased by 1 every time a new collection is found.
1752/// For example if list is a TObjArray*
1753/// - if splitlevel = 1, one top level branch is created for each element
1754/// of the TObjArray.
1755/// - if splitlevel = 2, one top level branch is created for each array element.
1756/// if, in turn, one of the array elements is a TCollection, one top level
1757/// branch will be created for each element of this collection.
1758///
1759/// In case a collection element is a TClonesArray, the special Tree constructor
1760/// for TClonesArray is called.
1761/// The collection itself cannot be a TClonesArray.
1762///
1763/// The function returns the total number of branches created.
1764///
1765/// If name is given, all branch names will be prefixed with name_.
1766///
1767/// IMPORTANT NOTE1: This function should not be called with splitlevel < 1.
1768///
1769/// IMPORTANT NOTE2: The branches created by this function will have names
1770/// corresponding to the collection or object names. It is important
1771/// to give names to collections to avoid misleading branch names or
1772/// identical branch names. By default collections have a name equal to
1773/// the corresponding class name, e.g. the default name for a TList is "TList".
1774///
1775/// And in general, in case two or more master branches contain subbranches
1776/// with identical names, one must add a "." (dot) character at the end
1777/// of the master branch name. This will force the name of the subbranches
1778/// to be of the form `master.subbranch` instead of simply `subbranch`.
1779/// This situation happens when the top level object
1780/// has two or more members referencing the same class.
1781/// For example, if a Tree has two branches B1 and B2 corresponding
1782/// to objects of the same class MyClass, one can do:
1783/// ~~~ {.cpp}
1784/// tree.Branch("B1.","MyClass",&b1,8000,1);
1785/// tree.Branch("B2.","MyClass",&b2,8000,1);
1786/// ~~~
1787/// if MyClass has 3 members a,b,c, the two instructions above will generate
1788/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
1789///
1790/// Example:
1791/// ~~~ {.cpp}
1792/// {
1793/// TTree T("T","test list");
1794/// TList *list = new TList();
1795///
1796/// TObjArray *a1 = new TObjArray();
1797/// a1->SetName("a1");
1798/// list->Add(a1);
1799/// TH1F *ha1a = new TH1F("ha1a","ha1",100,0,1);
1800/// TH1F *ha1b = new TH1F("ha1b","ha1",100,0,1);
1801/// a1->Add(ha1a);
1802/// a1->Add(ha1b);
1803/// TObjArray *b1 = new TObjArray();
1804/// b1->SetName("b1");
1805/// list->Add(b1);
1806/// TH1F *hb1a = new TH1F("hb1a","hb1",100,0,1);
1807/// TH1F *hb1b = new TH1F("hb1b","hb1",100,0,1);
1808/// b1->Add(hb1a);
1809/// b1->Add(hb1b);
1810///
1811/// TObjArray *a2 = new TObjArray();
1812/// a2->SetName("a2");
1813/// list->Add(a2);
1814/// TH1S *ha2a = new TH1S("ha2a","ha2",100,0,1);
1815/// TH1S *ha2b = new TH1S("ha2b","ha2",100,0,1);
1816/// a2->Add(ha2a);
1817/// a2->Add(ha2b);
1818///
1819/// T.Branch(list,16000,2);
1820/// T.Print();
1821/// }
1822/// ~~~
1824Int_t TTree::Branch(TCollection* li, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */, const char* name /* = "" */)
1825{
1826
1827 if (!li) {
1828 return 0;
1829 }
1830 TObject* obj = nullptr;
1831 Int_t nbranches = GetListOfBranches()->GetEntries();
1832 if (li->InheritsFrom(TClonesArray::Class())) {
1833 Error("Branch", "Cannot call this constructor for a TClonesArray");
1834 return 0;
1835 }
1836 Int_t nch = strlen(name);
1837 TString branchname;
1838 TIter next(li);
1839 while ((obj = next())) {
1840 if ((splitlevel > 1) && obj->InheritsFrom(TCollection::Class()) && !obj->InheritsFrom(TClonesArray::Class())) {
1841 TCollection* col = (TCollection*) obj;
1842 if (nch) {
1843 branchname.Form("%s_%s_", name, col->GetName());
1844 } else {
1845 branchname.Form("%s_", col->GetName());
1846 }
1847 Branch(col, bufsize, splitlevel - 1, branchname);
1848 } else {
1849 if (nch && (name[nch-1] == '_')) {
1850 branchname.Form("%s%s", name, obj->GetName());
1851 } else {
1852 if (nch) {
1853 branchname.Form("%s_%s", name, obj->GetName());
1854 } else {
1855 branchname.Form("%s", obj->GetName());
1856 }
1857 }
1858 if (splitlevel > 99) {
1859 branchname += ".";
1860 }
1861 Bronch(branchname, obj->ClassName(), li->GetObjectRef(obj), bufsize, splitlevel - 1);
1862 }
1863 }
1864 return GetListOfBranches()->GetEntries() - nbranches;
1865}
1866
1867////////////////////////////////////////////////////////////////////////////////
1868/// Create one branch for each element in the folder.
1869/// Returns the total number of branches created.
1871Int_t TTree::Branch(const char* foldername, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
1872{
1873 TObject* ob = gROOT->FindObjectAny(foldername);
1874 if (!ob) {
1875 return 0;
1876 }
1877 if (ob->IsA() != TFolder::Class()) {
1878 return 0;
1879 }
1880 Int_t nbranches = GetListOfBranches()->GetEntries();
1881 TFolder* folder = (TFolder*) ob;
1882 TIter next(folder->GetListOfFolders());
1883 TObject* obj = nullptr;
1884 char* curname = new char[1000];
1885 char occur[20];
1886 while ((obj = next())) {
1887 snprintf(curname,1000, "%s/%s", foldername, obj->GetName());
1888 if (obj->IsA() == TFolder::Class()) {
1889 Branch(curname, bufsize, splitlevel - 1);
1890 } else {
1891 void* add = (void*) folder->GetListOfFolders()->GetObjectRef(obj);
1892 for (Int_t i = 0; i < 1000; ++i) {
1893 if (curname[i] == 0) {
1894 break;
1895 }
1896 if (curname[i] == '/') {
1897 curname[i] = '.';
1898 }
1899 }
1900 Int_t noccur = folder->Occurence(obj);
1901 if (noccur > 0) {
1902 snprintf(occur,20, "_%d", noccur);
1903 strlcat(curname, occur,1000);
1904 }
1905 TBranchElement* br = (TBranchElement*) Bronch(curname, obj->ClassName(), add, bufsize, splitlevel - 1);
1906 if (br) br->SetBranchFolder();
1907 }
1908 }
1909 delete[] curname;
1910 return GetListOfBranches()->GetEntries() - nbranches;
1911}
1912
1913////////////////////////////////////////////////////////////////////////////////
1914/// Create a new TTree Branch.
1915///
1916/// This Branch constructor is provided to support non-objects in
1917/// a Tree. The variables described in leaflist may be simple
1918/// variables or structures. // See the two following
1919/// constructors for writing objects in a Tree.
1920///
1921/// By default the branch buffers are stored in the same file as the Tree.
1922/// use TBranch::SetFile to specify a different file
1923///
1924/// * address is the address of the first item of a structure.
1925/// * leaflist is the concatenation of all the variable names and types
1926/// separated by a colon character :
1927/// The variable name and the variable type are separated by a slash (/).
1928/// The variable type may be 0,1 or 2 characters. If no type is given,
1929/// the type of the variable is assumed to be the same as the previous
1930/// variable. If the first variable does not have a type, it is assumed
1931/// of type F by default. The list of currently supported types is given below:
1932/// - `C` : a character string terminated by the 0 character
1933/// - `B` : an 8 bit signed integer (`Char_t`); Treated as a character when in an array.
1934/// - `b` : an 8 bit unsigned integer (`UChar_t`)
1935/// - `S` : a 16 bit signed integer (`Short_t`)
1936/// - `s` : a 16 bit unsigned integer (`UShort_t`)
1937/// - `I` : a 32 bit signed integer (`Int_t`)
1938/// - `i` : a 32 bit unsigned integer (`UInt_t`)
1939/// - `F` : a 32 bit floating point (`Float_t`)
1940/// - `f` : a 24 bit floating point with truncated mantissa (`Float16_t`)
1941/// - `D` : a 64 bit floating point (`Double_t`)
1942/// - `d` : a 24 bit truncated floating point (`Double32_t`)
1943/// - `L` : a 64 bit signed integer (`Long64_t`)
1944/// - `l` : a 64 bit unsigned integer (`ULong64_t`)
1945/// - `G` : a long signed integer, stored as 64 bit (`Long_t`)
1946/// - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
1947/// - `O` : [the letter `o`, not a zero] a boolean (`bool`)
1948///
1949/// Arrays of values are supported with the following syntax:
1950/// - If leaf name has the form var[nelem], where nelem is alphanumeric, then
1951/// if nelem is a leaf name, it is used as the variable size of the array,
1952/// otherwise return 0.
1953/// The leaf referred to by nelem **MUST** be an int (/I),
1954/// - If leaf name has the form var[nelem], where nelem is a non-negative integer, then
1955/// it is used as the fixed size of the array.
1956/// - If leaf name has the form of a multi-dimensional array (e.g. var[nelem][nelem2])
1957/// where nelem and nelem2 are non-negative integer) then
1958/// it is used as a 2 dimensional array of fixed size.
1959/// - In case of the truncated floating point types (Float16_t and Double32_t) you can
1960/// furthermore specify the range in the style [xmin,xmax] or [xmin,xmax,nbits] after
1961/// the type character. See `TStreamerElement::GetRange()` for further information.
1962///
1963/// Any of other form is not supported.
1964///
1965/// Note that the TTree will assume that all the item are contiguous in memory.
1966/// On some platform, this is not always true of the member of a struct or a class,
1967/// due to padding and alignment. Sorting your data member in order of decreasing
1968/// sizeof usually leads to their being contiguous in memory.
1969///
1970/// * bufsize is the buffer size in bytes for this branch
1971/// The default value is 32000 bytes and should be ok for most cases.
1972/// You can specify a larger value (e.g. 256000) if your Tree is not split
1973/// and each entry is large (Megabytes)
1974/// A small value for bufsize is optimum if you intend to access
1975/// the entries in the Tree randomly and your Tree is in split mode.
1977TBranch* TTree::Branch(const char* name, void* address, const char* leaflist, Int_t bufsize /* = 32000 */)
1978{
1979 TBranch* branch = new TBranch(this, name, address, leaflist, bufsize);
1980 if (branch->IsZombie()) {
1981 delete branch;
1982 branch = nullptr;
1983 return nullptr;
1984 }
1985 fBranches.Add(branch);
1986 return branch;
1987}
1988
1989////////////////////////////////////////////////////////////////////////////////
1990/// Create a new branch with the object of class classname at address addobj.
1991///
1992/// WARNING:
1993///
1994/// Starting with Root version 3.01, the Branch function uses the new style
1995/// branches (TBranchElement). To get the old behaviour, you can:
1996/// - call BranchOld or
1997/// - call TTree::SetBranchStyle(0)
1998///
1999/// Note that with the new style, classname does not need to derive from TObject.
2000/// It must derived from TObject if the branch style has been set to 0 (old)
2001///
2002/// Note: See the comments in TBranchElement::SetAddress() for a more
2003/// detailed discussion of the meaning of the addobj parameter in
2004/// the case of new-style branches.
2005///
2006/// Use splitlevel < 0 instead of splitlevel=0 when the class
2007/// has a custom Streamer
2008///
2009/// Note: if the split level is set to the default (99), TTree::Branch will
2010/// not issue a warning if the class can not be split.
2012TBranch* TTree::Branch(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2013{
2014 if (fgBranchStyle == 1) {
2015 return Bronch(name, classname, addobj, bufsize, splitlevel);
2016 } else {
2017 if (splitlevel < 0) {
2018 splitlevel = 0;
2019 }
2020 return BranchOld(name, classname, addobj, bufsize, splitlevel);
2021 }
2022}
2023
2024////////////////////////////////////////////////////////////////////////////////
2025/// Create a new TTree BranchObject.
2026///
2027/// Build a TBranchObject for an object of class classname.
2028/// addobj is the address of a pointer to an object of class classname.
2029/// IMPORTANT: classname must derive from TObject.
2030/// The class dictionary must be available (ClassDef in class header).
2031///
2032/// This option requires access to the library where the corresponding class
2033/// is defined. Accessing one single data member in the object implies
2034/// reading the full object.
2035/// See the next Branch constructor for a more efficient storage
2036/// in case the entry consists of arrays of identical objects.
2037///
2038/// By default the branch buffers are stored in the same file as the Tree.
2039/// use TBranch::SetFile to specify a different file
2040///
2041/// IMPORTANT NOTE about branch names:
2042///
2043/// And in general, in case two or more master branches contain subbranches
2044/// with identical names, one must add a "." (dot) character at the end
2045/// of the master branch name. This will force the name of the subbranches
2046/// to be of the form `master.subbranch` instead of simply `subbranch`.
2047/// This situation happens when the top level object
2048/// has two or more members referencing the same class.
2049/// For example, if a Tree has two branches B1 and B2 corresponding
2050/// to objects of the same class MyClass, one can do:
2051/// ~~~ {.cpp}
2052/// tree.Branch("B1.","MyClass",&b1,8000,1);
2053/// tree.Branch("B2.","MyClass",&b2,8000,1);
2054/// ~~~
2055/// if MyClass has 3 members a,b,c, the two instructions above will generate
2056/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2057///
2058/// bufsize is the buffer size in bytes for this branch
2059/// The default value is 32000 bytes and should be ok for most cases.
2060/// You can specify a larger value (e.g. 256000) if your Tree is not split
2061/// and each entry is large (Megabytes)
2062/// A small value for bufsize is optimum if you intend to access
2063/// the entries in the Tree randomly and your Tree is in split mode.
2065TBranch* TTree::BranchOld(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 1 */)
2066{
2067 TClass* cl = TClass::GetClass(classname);
2068 if (!cl) {
2069 Error("BranchOld", "Cannot find class: '%s'", classname);
2070 return nullptr;
2071 }
2072 if (!cl->IsTObject()) {
2073 if (fgBranchStyle == 0) {
2074 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2075 "\tfgBranchStyle is set to zero requesting by default to use BranchOld.\n"
2076 "\tIf this is intentional use Bronch instead of Branch or BranchOld.", classname);
2077 } else {
2078 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2079 "\tYou can not use BranchOld to store objects of this type.",classname);
2080 }
2081 return nullptr;
2082 }
2083 TBranch* branch = new TBranchObject(this, name, classname, addobj, bufsize, splitlevel);
2084 fBranches.Add(branch);
2085 if (!splitlevel) {
2086 return branch;
2087 }
2088 // We are going to fully split the class now.
2089 TObjArray* blist = branch->GetListOfBranches();
2090 const char* rdname = nullptr;
2091 const char* dname = nullptr;
2092 TString branchname;
2093 char** apointer = (char**) addobj;
2094 TObject* obj = (TObject*) *apointer;
2095 bool delobj = false;
2096 if (!obj) {
2097 obj = (TObject*) cl->New();
2098 delobj = true;
2099 }
2100 // Build the StreamerInfo if first time for the class.
2101 BuildStreamerInfo(cl, obj);
2102 // Loop on all public data members of the class and its base classes.
2103 Int_t lenName = strlen(name);
2104 Int_t isDot = 0;
2105 if (name[lenName-1] == '.') {
2106 isDot = 1;
2107 }
2108 TBranch* branch1 = nullptr;
2109 TRealData* rd = nullptr;
2110 TRealData* rdi = nullptr;
2111 TIter nexti(cl->GetListOfRealData());
2112 TIter next(cl->GetListOfRealData());
2113 // Note: This loop results in a full split because the
2114 // real data list includes all data members of
2115 // data members.
2116 while ((rd = (TRealData*) next())) {
2117 if (rd->TestBit(TRealData::kTransient)) continue;
2118
2119 // Loop over all data members creating branches for each one.
2120 TDataMember* dm = rd->GetDataMember();
2121 if (!dm->IsPersistent()) {
2122 // Do not process members with an "!" as the first character in the comment field.
2123 continue;
2124 }
2125 if (rd->IsObject()) {
2126 // We skip data members of class type.
2127 // But we do build their real data, their
2128 // streamer info, and write their streamer
2129 // info to the current directory's file.
2130 // Oh yes, and we also do this for all of
2131 // their base classes.
2133 if (clm) {
2134 BuildStreamerInfo(clm, (char*) obj + rd->GetThisOffset());
2135 }
2136 continue;
2137 }
2138 rdname = rd->GetName();
2139 dname = dm->GetName();
2140 if (cl->CanIgnoreTObjectStreamer()) {
2141 // Skip the TObject base class data members.
2142 // FIXME: This prevents a user from ever
2143 // using these names themself!
2144 if (!strcmp(dname, "fBits")) {
2145 continue;
2146 }
2147 if (!strcmp(dname, "fUniqueID")) {
2148 continue;
2149 }
2150 }
2151 TDataType* dtype = dm->GetDataType();
2152 Int_t code = 0;
2153 if (dtype) {
2154 code = dm->GetDataType()->GetType();
2155 }
2156 // Encode branch name. Use real data member name
2157 branchname = rdname;
2158 if (isDot) {
2159 if (dm->IsaPointer()) {
2160 // FIXME: This is wrong! The asterisk is not usually in the front!
2161 branchname.Form("%s%s", name, &rdname[1]);
2162 } else {
2163 branchname.Form("%s%s", name, &rdname[0]);
2164 }
2165 }
2166 // FIXME: Change this to a string stream.
2167 TString leaflist;
2168 Int_t offset = rd->GetThisOffset();
2169 char* pointer = ((char*) obj) + offset;
2170 if (dm->IsaPointer()) {
2171 // We have a pointer to an object or a pointer to an array of basic types.
2172 TClass* clobj = nullptr;
2173 if (!dm->IsBasic()) {
2174 clobj = TClass::GetClass(dm->GetTypeName());
2175 }
2176 if (clobj && clobj->InheritsFrom(TClonesArray::Class())) {
2177 // We have a pointer to a clones array.
2178 char* cpointer = (char*) pointer;
2179 char** ppointer = (char**) cpointer;
2180 TClonesArray* li = (TClonesArray*) *ppointer;
2181 if (splitlevel != 2) {
2182 if (isDot) {
2183 branch1 = new TBranchClones(branch,branchname, pointer, bufsize);
2184 } else {
2185 // FIXME: This is wrong! The asterisk is not usually in the front!
2186 branch1 = new TBranchClones(branch,&branchname.Data()[1], pointer, bufsize);
2187 }
2188 blist->Add(branch1);
2189 } else {
2190 if (isDot) {
2191 branch1 = new TBranchObject(branch, branchname, li->ClassName(), pointer, bufsize);
2192 } else {
2193 // FIXME: This is wrong! The asterisk is not usually in the front!
2194 branch1 = new TBranchObject(branch, &branchname.Data()[1], li->ClassName(), pointer, bufsize);
2195 }
2196 blist->Add(branch1);
2197 }
2198 } else if (clobj) {
2199 // We have a pointer to an object.
2200 //
2201 // It must be a TObject object.
2202 if (!clobj->IsTObject()) {
2203 continue;
2204 }
2205 branch1 = new TBranchObject(branch, dname, clobj->GetName(), pointer, bufsize, 0);
2206 if (isDot) {
2207 branch1->SetName(branchname);
2208 } else {
2209 // FIXME: This is wrong! The asterisk is not usually in the front!
2210 // Do not use the first character (*).
2211 branch1->SetName(&branchname.Data()[1]);
2212 }
2213 blist->Add(branch1);
2214 } else {
2215 // We have a pointer to an array of basic types.
2216 //
2217 // Check the comments in the text of the code for an index specification.
2218 const char* index = dm->GetArrayIndex();
2219 if (index[0]) {
2220 // We are a pointer to a varying length array of basic types.
2221 //check that index is a valid data member name
2222 //if member is part of an object (e.g. fA and index=fN)
2223 //index must be changed from fN to fA.fN
2224 TString aindex (rd->GetName());
2225 Ssiz_t rdot = aindex.Last('.');
2226 if (rdot>=0) {
2227 aindex.Remove(rdot+1);
2228 aindex.Append(index);
2229 }
2230 nexti.Reset();
2231 while ((rdi = (TRealData*) nexti())) {
2232 if (rdi->TestBit(TRealData::kTransient)) continue;
2233
2234 if (!strcmp(rdi->GetName(), index)) {
2235 break;
2236 }
2237 if (!strcmp(rdi->GetName(), aindex)) {
2238 index = rdi->GetName();
2239 break;
2240 }
2241 }
2242
2243 char vcode = DataTypeToChar((EDataType)code);
2244 // Note that we differentiate between strings and
2245 // char array by the fact that there is NO specified
2246 // size for a string (see next if (code == 1)
2247
2248 if (vcode) {
2249 leaflist.Form("%s[%s]/%c", &rdname[0], index, vcode);
2250 } else {
2251 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2252 leaflist = "";
2253 }
2254 } else {
2255 // We are possibly a character string.
2256 if (code == 1) {
2257 // We are a character string.
2258 leaflist.Form("%s/%s", dname, "C");
2259 } else {
2260 // Invalid array specification.
2261 // FIXME: We need an error message here.
2262 continue;
2263 }
2264 }
2265 // There are '*' in both the branchname and leaflist, remove them.
2266 TString bname( branchname );
2267 bname.ReplaceAll("*","");
2268 leaflist.ReplaceAll("*","");
2269 // Add the branch to the tree and indicate that the address
2270 // is that of a pointer to be dereferenced before using.
2271 branch1 = new TBranch(branch, bname, *((void**) pointer), leaflist, bufsize);
2272 TLeaf* leaf = (TLeaf*) branch1->GetListOfLeaves()->At(0);
2274 leaf->SetAddress((void**) pointer);
2275 blist->Add(branch1);
2276 }
2277 } else if (dm->IsBasic()) {
2278 // We have a basic type.
2279
2280 char vcode = DataTypeToChar((EDataType)code);
2281 if (vcode) {
2282 leaflist.Form("%s/%c", rdname, vcode);
2283 } else {
2284 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2285 leaflist = "";
2286 }
2287 branch1 = new TBranch(branch, branchname, pointer, leaflist, bufsize);
2288 branch1->SetTitle(rdname);
2289 blist->Add(branch1);
2290 } else {
2291 // We have a class type.
2292 // Note: This cannot happen due to the rd->IsObject() test above.
2293 // FIXME: Put an error message here just in case.
2294 }
2295 if (branch1) {
2296 branch1->SetOffset(offset);
2297 } else {
2298 Warning("BranchOld", "Cannot process member: '%s'", rdname);
2299 }
2300 }
2301 if (delobj) {
2302 delete obj;
2303 obj = nullptr;
2304 }
2305 return branch;
2306}
2307
2308////////////////////////////////////////////////////////////////////////////////
2309/// Build the optional branch supporting the TRefTable.
2310/// This branch will keep all the information to find the branches
2311/// containing referenced objects.
2312///
2313/// At each Tree::Fill, the branch numbers containing the
2314/// referenced objects are saved to the TBranchRef basket.
2315/// When the Tree header is saved (via TTree::Write), the branch
2316/// is saved keeping the information with the pointers to the branches
2317/// having referenced objects.
2320{
2321 if (!fBranchRef) {
2322 fBranchRef = new TBranchRef(this);
2323 }
2324 return fBranchRef;
2325}
2326
2327////////////////////////////////////////////////////////////////////////////////
2328/// Create a new TTree BranchElement.
2329///
2330/// ## WARNING about this new function
2331///
2332/// This function is designed to replace the internal
2333/// implementation of the old TTree::Branch (whose implementation
2334/// has been moved to BranchOld).
2335///
2336/// NOTE: The 'Bronch' method supports only one possible calls
2337/// signature (where the object type has to be specified
2338/// explicitly and the address must be the address of a pointer).
2339/// For more flexibility use 'Branch'. Use Bronch only in (rare)
2340/// cases (likely to be legacy cases) where both the new and old
2341/// implementation of Branch needs to be used at the same time.
2342///
2343/// This function is far more powerful than the old Branch
2344/// function. It supports the full C++, including STL and has
2345/// the same behaviour in split or non-split mode. classname does
2346/// not have to derive from TObject. The function is based on
2347/// the new TStreamerInfo.
2348///
2349/// Build a TBranchElement for an object of class classname.
2350///
2351/// addr is the address of a pointer to an object of class
2352/// classname. The class dictionary must be available (ClassDef
2353/// in class header).
2354///
2355/// Note: See the comments in TBranchElement::SetAddress() for a more
2356/// detailed discussion of the meaning of the addr parameter.
2357///
2358/// This option requires access to the library where the
2359/// corresponding class is defined. Accessing one single data
2360/// member in the object implies reading the full object.
2361///
2362/// By default the branch buffers are stored in the same file as the Tree.
2363/// use TBranch::SetFile to specify a different file
2364///
2365/// IMPORTANT NOTE about branch names:
2366///
2367/// And in general, in case two or more master branches contain subbranches
2368/// with identical names, one must add a "." (dot) character at the end
2369/// of the master branch name. This will force the name of the subbranches
2370/// to be of the form `master.subbranch` instead of simply `subbranch`.
2371/// This situation happens when the top level object
2372/// has two or more members referencing the same class.
2373/// For example, if a Tree has two branches B1 and B2 corresponding
2374/// to objects of the same class MyClass, one can do:
2375/// ~~~ {.cpp}
2376/// tree.Branch("B1.","MyClass",&b1,8000,1);
2377/// tree.Branch("B2.","MyClass",&b2,8000,1);
2378/// ~~~
2379/// if MyClass has 3 members a,b,c, the two instructions above will generate
2380/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2381///
2382/// bufsize is the buffer size in bytes for this branch
2383/// The default value is 32000 bytes and should be ok for most cases.
2384/// You can specify a larger value (e.g. 256000) if your Tree is not split
2385/// and each entry is large (Megabytes)
2386/// A small value for bufsize is optimum if you intend to access
2387/// the entries in the Tree randomly and your Tree is in split mode.
2388///
2389/// Use splitlevel < 0 instead of splitlevel=0 when the class
2390/// has a custom Streamer
2391///
2392/// Note: if the split level is set to the default (99), TTree::Branch will
2393/// not issue a warning if the class can not be split.
2395TBranch* TTree::Bronch(const char* name, const char* classname, void* addr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2396{
2397 return BronchExec(name, classname, addr, true, bufsize, splitlevel);
2398}
2399
2400////////////////////////////////////////////////////////////////////////////////
2401/// Helper function implementing TTree::Bronch and TTree::Branch(const char *name, T &obj);
2403TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, bool isptrptr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2404{
2405 TClass* cl = TClass::GetClass(classname);
2406 if (!cl) {
2407 Error("Bronch", "Cannot find class:%s", classname);
2408 return nullptr;
2409 }
2410
2411 //if splitlevel <= 0 and class has a custom Streamer, we must create
2412 //a TBranchObject. We cannot assume that TClass::ReadBuffer is consistent
2413 //with the custom Streamer. The penalty is that one cannot process
2414 //this Tree without the class library containing the class.
2415
2416 char* objptr = nullptr;
2417 if (!isptrptr) {
2418 objptr = (char*)addr;
2419 } else if (addr) {
2420 objptr = *((char**) addr);
2421 }
2422
2423 if (cl == TClonesArray::Class()) {
2424 TClonesArray* clones = (TClonesArray*) objptr;
2425 if (!clones) {
2426 Error("Bronch", "Pointer to TClonesArray is null");
2427 return nullptr;
2428 }
2429 if (!clones->GetClass()) {
2430 Error("Bronch", "TClonesArray with no class defined in branch: %s", name);
2431 return nullptr;
2432 }
2433 if (!clones->GetClass()->HasDataMemberInfo()) {
2434 Error("Bronch", "TClonesArray with no dictionary defined in branch: %s", name);
2435 return nullptr;
2436 }
2437 bool hasCustomStreamer = clones->GetClass()->HasCustomStreamerMember();
2438 if (splitlevel > 0) {
2439 if (hasCustomStreamer)
2440 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", clones->GetClass()->GetName());
2441 } else {
2442 if (hasCustomStreamer) clones->BypassStreamer(false);
2443 TBranchObject *branch = new TBranchObject(this,name,classname,addr,bufsize,0,/*compress=*/ -1,isptrptr);
2444 fBranches.Add(branch);
2445 return branch;
2446 }
2447 }
2448
2449 if (cl->GetCollectionProxy()) {
2451 //if (!collProxy) {
2452 // Error("Bronch", "%s is missing its CollectionProxy (for branch %s)", classname, name);
2453 //}
2454 TClass* inklass = collProxy->GetValueClass();
2455 if (!inklass && (collProxy->GetType() == 0)) {
2456 Error("Bronch", "%s with no class defined in branch: %s", classname, name);
2457 return nullptr;
2458 }
2459 if ((splitlevel > 0) && inklass && (inklass->GetCollectionProxy() == nullptr)) {
2461 if ((stl != ROOT::kSTLmap) && (stl != ROOT::kSTLmultimap)) {
2462 if (!inklass->HasDataMemberInfo()) {
2463 Error("Bronch", "Container with no dictionary defined in branch: %s", name);
2464 return nullptr;
2465 }
2466 if (inklass->HasCustomStreamerMember()) {
2467 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", inklass->GetName());
2468 }
2469 }
2470 }
2471 //-------------------------------------------------------------------------
2472 // If the splitting switch is enabled, the split level is big enough and
2473 // the collection contains pointers we can split it
2474 //////////////////////////////////////////////////////////////////////////
2475
2476 TBranch *branch;
2477 if( splitlevel > kSplitCollectionOfPointers && collProxy->HasPointers() )
2478 branch = new TBranchSTL( this, name, collProxy, bufsize, splitlevel );
2479 else
2480 branch = new TBranchElement(this, name, collProxy, bufsize, splitlevel);
2481 fBranches.Add(branch);
2482 if (isptrptr) {
2483 branch->SetAddress(addr);
2484 } else {
2485 branch->SetObject(addr);
2486 }
2487 return branch;
2488 }
2489
2490 bool hasCustomStreamer = false;
2491 if (!cl->HasDataMemberInfo() && !cl->GetCollectionProxy()) {
2492 Error("Bronch", "Cannot find dictionary for class: %s", classname);
2493 return nullptr;
2494 }
2495
2496 if (!cl->GetCollectionProxy() && cl->HasCustomStreamerMember()) {
2497 // Not an STL container and the linkdef file had a "-" after the class name.
2498 hasCustomStreamer = true;
2499 }
2500
2501 if (splitlevel < 0 || ((splitlevel == 0) && hasCustomStreamer && cl->IsTObject())) {
2502 TBranchObject* branch = new TBranchObject(this, name, classname, addr, bufsize, 0, /*compress=*/ ROOT::RCompressionSetting::EAlgorithm::kInherit, isptrptr);
2503 fBranches.Add(branch);
2504 return branch;
2505 }
2506
2507 if (cl == TClonesArray::Class()) {
2508 // Special case of TClonesArray.
2509 // No dummy object is created.
2510 // The streamer info is not rebuilt unoptimized.
2511 // No dummy top-level branch is created.
2512 // No splitting is attempted.
2513 TBranchElement* branch = new TBranchElement(this, name, (TClonesArray*) objptr, bufsize, splitlevel%kSplitCollectionOfPointers);
2514 fBranches.Add(branch);
2515 if (isptrptr) {
2516 branch->SetAddress(addr);
2517 } else {
2518 branch->SetObject(addr);
2519 }
2520 return branch;
2521 }
2522
2523 //
2524 // If we are not given an object to use as an i/o buffer
2525 // then create a temporary one which we will delete just
2526 // before returning.
2527 //
2528
2529 bool delobj = false;
2530
2531 if (!objptr) {
2532 objptr = (char*) cl->New();
2533 delobj = true;
2534 }
2535
2536 //
2537 // Avoid splitting unsplittable classes.
2538 //
2539
2540 if ((splitlevel > 0) && !cl->CanSplit()) {
2541 if (splitlevel != 99) {
2542 Warning("Bronch", "%s cannot be split, resetting splitlevel to 0", cl->GetName());
2543 }
2544 splitlevel = 0;
2545 }
2546
2547 //
2548 // Make sure the streamer info is built and fetch it.
2549 //
2550 // If we are splitting, then make sure the streamer info
2551 // is built unoptimized (data members are not combined).
2552 //
2553
2554 TStreamerInfo* sinfo = BuildStreamerInfo(cl, objptr, splitlevel==0);
2555 if (!sinfo) {
2556 Error("Bronch", "Cannot build the StreamerInfo for class: %s", cl->GetName());
2557 return nullptr;
2558 }
2559
2560 //
2561 // Create a dummy top level branch object.
2562 //
2563
2564 Int_t id = -1;
2565 if (splitlevel > 0) {
2566 id = -2;
2567 }
2568 TBranchElement* branch = new TBranchElement(this, name, sinfo, id, objptr, bufsize, splitlevel);
2569 fBranches.Add(branch);
2570
2571 //
2572 // Do splitting, if requested.
2573 //
2574
2575 if (splitlevel%kSplitCollectionOfPointers > 0) {
2576 branch->Unroll(name, cl, sinfo, objptr, bufsize, splitlevel);
2577 }
2578
2579 //
2580 // Setup our offsets into the user's i/o buffer.
2581 //
2582
2583 if (isptrptr) {
2584 branch->SetAddress(addr);
2585 } else {
2586 branch->SetObject(addr);
2587 }
2588
2589 if (delobj) {
2590 cl->Destructor(objptr);
2591 objptr = nullptr;
2592 }
2593
2594 return branch;
2595}
2596
2597////////////////////////////////////////////////////////////////////////////////
2598/// Browse content of the TTree.
2601{
2603 if (fUserInfo) {
2604 if (strcmp("TList",fUserInfo->GetName())==0) {
2605 fUserInfo->SetName("UserInfo");
2606 b->Add(fUserInfo);
2607 fUserInfo->SetName("TList");
2608 } else {
2609 b->Add(fUserInfo);
2610 }
2611 }
2612}
2613
2614////////////////////////////////////////////////////////////////////////////////
2615/// Build a Tree Index (default is TTreeIndex).
2616/// See a description of the parameters and functionality in
2617/// TTreeIndex::TTreeIndex().
2618///
2619/// The return value is the number of entries in the Index (< 0 indicates failure).
2620///
2621/// A TTreeIndex object pointed by fTreeIndex is created.
2622/// This object will be automatically deleted by the TTree destructor.
2623/// If an index is already existing, this is replaced by the new one without being
2624/// deleted. This behaviour prevents the deletion of a previously external index
2625/// assigned to the TTree via the TTree::SetTreeIndex() method.
2626/// \see also comments in TTree::SetTreeIndex().
2628Int_t TTree::BuildIndex(const char* majorname, const char* minorname /* = "0" */)
2629{
2630 fTreeIndex = GetPlayer()->BuildIndex(this, majorname, minorname);
2631 if (fTreeIndex->IsZombie()) {
2632 delete fTreeIndex;
2633 fTreeIndex = nullptr;
2634 return 0;
2635 }
2636 return fTreeIndex->GetN();
2637}
2638
2639////////////////////////////////////////////////////////////////////////////////
2640/// Build StreamerInfo for class cl.
2641/// pointer is an optional argument that may contain a pointer to an object of cl.
2643TStreamerInfo* TTree::BuildStreamerInfo(TClass* cl, void* pointer /* = 0 */, bool canOptimize /* = true */ )
2644{
2645 if (!cl) {
2646 return nullptr;
2647 }
2648 cl->BuildRealData(pointer);
2650
2651 // Create StreamerInfo for all base classes.
2652 TBaseClass* base = nullptr;
2653 TIter nextb(cl->GetListOfBases());
2654 while((base = (TBaseClass*) nextb())) {
2655 if (base->IsSTLContainer()) {
2656 continue;
2657 }
2658 TClass* clm = TClass::GetClass(base->GetName());
2659 BuildStreamerInfo(clm, pointer, canOptimize);
2660 }
2661 if (sinfo && fDirectory) {
2663 }
2664 return sinfo;
2665}
2666
2667////////////////////////////////////////////////////////////////////////////////
2668/// Enable the TTreeCache unless explicitly disabled for this TTree by
2669/// a prior call to `SetCacheSize(0)`.
2670/// If the environment variable `ROOT_TTREECACHE_SIZE` or the rootrc config
2671/// `TTreeCache.Size` has been set to zero, this call will over-ride them with
2672/// a value of 1.0 (i.e. use a cache size to hold 1 cluster)
2673///
2674/// Return true if there is a cache attached to the `TTree` (either pre-exisiting
2675/// or created as part of this call)
2676bool TTree::EnableCache()
2677{
2678 TFile* file = GetCurrentFile();
2679 if (!file)
2680 return false;
2681 // Check for an existing cache
2682 TTreeCache* pf = GetReadCache(file);
2683 if (pf)
2684 return true;
2685 if (fCacheUserSet && fCacheSize == 0)
2686 return false;
2687 return (0 == SetCacheSizeAux(true, -1));
2688}
2689
2690////////////////////////////////////////////////////////////////////////////////
2691/// Called by TTree::Fill() when file has reached its maximum fgMaxTreeSize.
2692/// Create a new file. If the original file is named "myfile.root",
2693/// subsequent files are named "myfile_1.root", "myfile_2.root", etc.
2694///
2695/// Returns a pointer to the new file.
2696///
2697/// Currently, the automatic change of file is restricted
2698/// to the case where the tree is in the top level directory.
2699/// The file should not contain sub-directories.
2700///
2701/// Before switching to a new file, the tree header is written
2702/// to the current file, then the current file is closed.
2703///
2704/// To process the multiple files created by ChangeFile, one must use
2705/// a TChain.
2706///
2707/// The new file name has a suffix "_N" where N is equal to fFileNumber+1.
2708/// By default a Root session starts with fFileNumber=0. One can set
2709/// fFileNumber to a different value via TTree::SetFileNumber.
2710/// In case a file named "_N" already exists, the function will try
2711/// a file named "__N", then "___N", etc.
2712///
2713/// fgMaxTreeSize can be set via the static function TTree::SetMaxTreeSize.
2714/// The default value of fgMaxTreeSize is 100 Gigabytes.
2715///
2716/// If the current file contains other objects like TH1 and TTree,
2717/// these objects are automatically moved to the new file.
2718///
2719/// \warning Be careful when writing the final Tree header to the file!
2720/// Don't do:
2721/// ~~~ {.cpp}
2722/// TFile *file = new TFile("myfile.root","recreate");
2723/// TTree *T = new TTree("T","title");
2724/// T->Fill(); // Loop
2725/// file->Write();
2726/// file->Close();
2727/// ~~~
2728/// \warning but do the following:
2729/// ~~~ {.cpp}
2730/// TFile *file = new TFile("myfile.root","recreate");
2731/// TTree *T = new TTree("T","title");
2732/// T->Fill(); // Loop
2733/// file = T->GetCurrentFile(); // To get the pointer to the current file
2734/// file->Write();
2735/// file->Close();
2736/// ~~~
2737///
2738/// \note This method is never called if the input file is a `TMemFile` or derivate.
2741{
2742 file->cd();
2743 Write();
2744 Reset();
2745 constexpr auto kBufSize = 2000;
2746 char* fname = new char[kBufSize];
2747 ++fFileNumber;
2748 char uscore[10];
2749 for (Int_t i = 0; i < 10; ++i) {
2750 uscore[i] = 0;
2751 }
2752 Int_t nus = 0;
2753 // Try to find a suitable file name that does not already exist.
2754 while (nus < 10) {
2755 uscore[nus] = '_';
2756 fname[0] = 0;
2757 strlcpy(fname, file->GetName(), kBufSize);
2758
2759 if (fFileNumber > 1) {
2760 char* cunder = strrchr(fname, '_');
2761 if (cunder) {
2762 snprintf(cunder, kBufSize - Int_t(cunder - fname), "%s%d", uscore, fFileNumber);
2763 const char* cdot = strrchr(file->GetName(), '.');
2764 if (cdot) {
2765 strlcat(fname, cdot, kBufSize);
2766 }
2767 } else {
2768 char fcount[21];
2769 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2770 strlcat(fname, fcount, kBufSize);
2771 }
2772 } else {
2773 char* cdot = strrchr(fname, '.');
2774 if (cdot) {
2775 snprintf(cdot, kBufSize - Int_t(fname-cdot), "%s%d", uscore, fFileNumber);
2776 strlcat(fname, strrchr(file->GetName(), '.'), kBufSize);
2777 } else {
2778 char fcount[21];
2779 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2780 strlcat(fname, fcount, kBufSize);
2781 }
2782 }
2783 if (gSystem->AccessPathName(fname)) {
2784 break;
2785 }
2786 ++nus;
2787 Warning("ChangeFile", "file %s already exist, trying with %d underscores", fname, nus+1);
2788 }
2789 Int_t compress = file->GetCompressionSettings();
2790 TFile* newfile = TFile::Open(fname, "recreate", "chain files", compress);
2791 if (newfile == nullptr) {
2792 Error("Fill","Failed to open new file %s, continuing as a memory tree.",fname);
2793 } else {
2794 Printf("Fill: Switching to new file: %s", fname);
2795 }
2796 // The current directory may contain histograms and trees.
2797 // These objects must be moved to the new file.
2798 TBranch* branch = nullptr;
2799 TObject* obj = nullptr;
2800 while ((obj = file->GetList()->First())) {
2801 file->Remove(obj);
2802 // Histogram: just change the directory.
2803 if (obj->InheritsFrom("TH1")) {
2804 gROOT->ProcessLine(TString::Format("((%s*)0x%zx)->SetDirectory((TDirectory*)0x%zx);", obj->ClassName(), (size_t) obj, (size_t) newfile));
2805 continue;
2806 }
2807 // Tree: must save all trees in the old file, reset them.
2808 if (obj->InheritsFrom(TTree::Class())) {
2809 TTree* t = (TTree*) obj;
2810 if (t != this) {
2811 t->AutoSave();
2812 t->Reset();
2814 }
2815 t->SetDirectory(newfile);
2816 TIter nextb(t->GetListOfBranches());
2817 while ((branch = (TBranch*)nextb())) {
2818 branch->SetFile(newfile);
2819 }
2820 if (t->GetBranchRef()) {
2821 t->GetBranchRef()->SetFile(newfile);
2822 }
2823 continue;
2824 }
2825 // Not a TH1 or a TTree, move object to new file.
2826 if (newfile) newfile->Append(obj);
2827 file->Remove(obj);
2828 }
2829 file->TObject::Delete();
2830 file = nullptr;
2831 delete[] fname;
2832 fname = nullptr;
2833 return newfile;
2834}
2835
2836////////////////////////////////////////////////////////////////////////////////
2837/// Check whether or not the address described by the last 3 parameters
2838/// matches the content of the branch. If a Data Model Evolution conversion
2839/// is involved, reset the fInfo of the branch.
2840/// The return values are:
2841//
2842/// - kMissingBranch (-5) : Missing branch
2843/// - kInternalError (-4) : Internal error (could not find the type corresponding to a data type number)
2844/// - kMissingCompiledCollectionProxy (-3) : Missing compiled collection proxy for a compiled collection
2845/// - kMismatch (-2) : Non-Class Pointer type given does not match the type expected by the branch
2846/// - kClassMismatch (-1) : Class Pointer type given does not match the type expected by the branch
2847/// - kMatch (0) : perfect match
2848/// - kMatchConversion (1) : match with (I/O) conversion
2849/// - kMatchConversionCollection (2) : match with (I/O) conversion of the content of a collection
2850/// - kMakeClass (3) : MakeClass mode so we can not check.
2851/// - kVoidPtr (4) : void* passed so no check was made.
2852/// - kNoCheck (5) : Underlying TBranch not yet available so no check was made.
2853/// In addition this can be multiplexed with the two bits:
2854/// - kNeedEnableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to be in Decomposed Object (aka MakeClass) mode.
2855/// - kNeedDisableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to not be in Decomposed Object (aka MakeClass) mode.
2856/// This bits can be masked out by using kDecomposedObjMask
2858Int_t TTree::CheckBranchAddressType(TBranch* branch, TClass* ptrClass, EDataType datatype, bool isptr)
2859{
2860 if (GetMakeClass()) {
2861 // If we are in MakeClass mode so we do not really use classes.
2862 return kMakeClass;
2863 }
2864
2865 // Let's determine what we need!
2866 TClass* expectedClass = nullptr;
2867 EDataType expectedType = kOther_t;
2868 if (0 != branch->GetExpectedType(expectedClass,expectedType) ) {
2869 // Something went wrong, the warning message has already been issued.
2870 return kInternalError;
2871 }
2872 bool isBranchElement = branch->InheritsFrom( TBranchElement::Class() );
2873 if (expectedClass && datatype == kOther_t && ptrClass == nullptr) {
2874 if (isBranchElement) {
2875 TBranchElement* bEl = (TBranchElement*)branch;
2876 bEl->SetTargetClass( expectedClass->GetName() );
2877 }
2878 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
2879 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2880 "The class expected (%s) refers to an stl collection and do not have a compiled CollectionProxy. "
2881 "Please generate the dictionary for this class (%s)",
2882 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2884 }
2885 if (!expectedClass->IsLoaded()) {
2886 // The originally expected class does not have a dictionary, it is then plausible that the pointer being passed is the right type
2887 // (we really don't know). So let's express that.
2888 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2889 "The class expected (%s) does not have a dictionary and needs to be emulated for I/O purposes but is being passed a compiled object."
2890 "Please generate the dictionary for this class (%s)",
2891 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2892 } else {
2893 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2894 "This is probably due to a missing dictionary, the original data class for this branch is %s.", branch->GetName(), expectedClass->GetName());
2895 }
2896 return kClassMismatch;
2897 }
2898 if (expectedClass && ptrClass && (branch->GetMother() == branch)) {
2899 // Top Level branch
2900 if (!isptr) {
2901 Error("SetBranchAddress", "The address for \"%s\" should be the address of a pointer!", branch->GetName());
2902 }
2903 }
2904 if (expectedType == kFloat16_t) {
2905 expectedType = kFloat_t;
2906 }
2907 if (expectedType == kDouble32_t) {
2908 expectedType = kDouble_t;
2909 }
2910 if (datatype == kFloat16_t) {
2911 datatype = kFloat_t;
2912 }
2913 if (datatype == kDouble32_t) {
2914 datatype = kDouble_t;
2915 }
2916
2917 /////////////////////////////////////////////////////////////////////////////
2918 // Deal with the class renaming
2919 /////////////////////////////////////////////////////////////////////////////
2920
2921 if( expectedClass && ptrClass &&
2922 expectedClass != ptrClass &&
2923 isBranchElement &&
2924 ptrClass->GetSchemaRules() &&
2925 ptrClass->GetSchemaRules()->HasRuleWithSourceClass( expectedClass->GetName() ) ) {
2926 TBranchElement* bEl = (TBranchElement*)branch;
2927
2928 if ( ptrClass->GetCollectionProxy() && expectedClass->GetCollectionProxy() ) {
2929 if (gDebug > 7)
2930 Info("SetBranchAddress", "Matching STL collection (at least according to the SchemaRuleSet when "
2931 "reading a %s into a %s",expectedClass->GetName(),ptrClass->GetName());
2932
2933 bEl->SetTargetClass( ptrClass->GetName() );
2934 return kMatchConversion;
2935
2936 } else if ( !ptrClass->GetConversionStreamerInfo( expectedClass, bEl->GetClassVersion() ) &&
2937 !ptrClass->FindConversionStreamerInfo( expectedClass, bEl->GetCheckSum() ) ) {
2938 Error("SetBranchAddress", "The pointer type given \"%s\" does not correspond to the type needed \"%s\" by the branch: %s", ptrClass->GetName(), bEl->GetClassName(), branch->GetName());
2939
2940 bEl->SetTargetClass( expectedClass->GetName() );
2941 return kClassMismatch;
2942 }
2943 else {
2944
2945 bEl->SetTargetClass( ptrClass->GetName() );
2946 return kMatchConversion;
2947 }
2948
2949 } else if (expectedClass && ptrClass && !expectedClass->InheritsFrom(ptrClass)) {
2950
2951 if (expectedClass->GetCollectionProxy() && ptrClass->GetCollectionProxy() &&
2952 isBranchElement &&
2953 expectedClass->GetCollectionProxy()->GetValueClass() &&
2954 ptrClass->GetCollectionProxy()->GetValueClass() )
2955 {
2956 // In case of collection, we know how to convert them, if we know how to convert their content.
2957 // NOTE: we need to extend this to std::pair ...
2958
2959 TClass *onfileValueClass = expectedClass->GetCollectionProxy()->GetValueClass();
2960 TClass *inmemValueClass = ptrClass->GetCollectionProxy()->GetValueClass();
2961
2962 if (inmemValueClass->GetSchemaRules() &&
2963 inmemValueClass->GetSchemaRules()->HasRuleWithSourceClass(onfileValueClass->GetName() ) )
2964 {
2965 TBranchElement* bEl = (TBranchElement*)branch;
2966 bEl->SetTargetClass( ptrClass->GetName() );
2968 }
2969 }
2970
2971 Error("SetBranchAddress", "The pointer type given (%s) does not correspond to the class needed (%s) by the branch: %s", ptrClass->GetName(), expectedClass->GetName(), branch->GetName());
2972 if (isBranchElement) {
2973 TBranchElement* bEl = (TBranchElement*)branch;
2974 bEl->SetTargetClass( expectedClass->GetName() );
2975 }
2976 return kClassMismatch;
2977
2978 } else if ((expectedType != kOther_t) && (datatype != kOther_t) && (expectedType != kNoType_t) && (datatype != kNoType_t) && (expectedType != datatype)) {
2979 if (datatype != kChar_t) {
2980 // For backward compatibility we assume that (char*) was just a cast and/or a generic address
2981 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" (%d) by the branch: %s",
2982 TDataType::GetTypeName(datatype), datatype, TDataType::GetTypeName(expectedType), expectedType, branch->GetName());
2983 return kMismatch;
2984 }
2985 } else if ((expectedClass && (datatype != kOther_t && datatype != kNoType_t && datatype != kInt_t)) ||
2986 (ptrClass && (expectedType != kOther_t && expectedType != kNoType_t && datatype != kInt_t)) ) {
2987 // Sometime a null pointer can look an int, avoid complaining in that case.
2988 if (expectedClass) {
2989 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" by the branch: %s",
2990 TDataType::GetTypeName(datatype), datatype, expectedClass->GetName(), branch->GetName());
2991 if (isBranchElement) {
2992 TBranchElement* bEl = (TBranchElement*)branch;
2993 bEl->SetTargetClass( expectedClass->GetName() );
2994 }
2995 } else {
2996 // In this case, it is okay if the first data member is of the right type (to support the case where we are being passed
2997 // a struct).
2998 bool found = false;
2999 if (ptrClass->IsLoaded()) {
3000 TIter next(ptrClass->GetListOfRealData());
3001 TRealData *rdm;
3002 while ((rdm = (TRealData*)next())) {
3003 if (rdm->GetThisOffset() == 0) {
3004 TDataType *dmtype = rdm->GetDataMember()->GetDataType();
3005 if (dmtype) {
3006 EDataType etype = (EDataType)dmtype->GetType();
3007 if (etype == expectedType) {
3008 found = true;
3009 }
3010 }
3011 break;
3012 }
3013 }
3014 } else {
3015 TIter next(ptrClass->GetListOfDataMembers());
3016 TDataMember *dm;
3017 while ((dm = (TDataMember*)next())) {
3018 if (dm->GetOffset() == 0) {
3019 TDataType *dmtype = dm->GetDataType();
3020 if (dmtype) {
3021 EDataType etype = (EDataType)dmtype->GetType();
3022 if (etype == expectedType) {
3023 found = true;
3024 }
3025 }
3026 break;
3027 }
3028 }
3029 }
3030 if (found) {
3031 // let's check the size.
3032 TLeaf *last = (TLeaf*)branch->GetListOfLeaves()->Last();
3033 long len = last->GetOffset() + last->GetLenType() * last->GetLen();
3034 if (len <= ptrClass->Size()) {
3035 return kMatch;
3036 }
3037 }
3038 Error("SetBranchAddress", "The pointer type given \"%s\" does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3039 ptrClass->GetName(), TDataType::GetTypeName(expectedType), expectedType, branch->GetName());
3040 }
3041 return kMismatch;
3042 }
3043 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
3044 Error("SetBranchAddress", writeStlWithoutProxyMsg,
3045 expectedClass->GetName(), branch->GetName(), expectedClass->GetName());
3046 if (isBranchElement) {
3047 TBranchElement* bEl = (TBranchElement*)branch;
3048 bEl->SetTargetClass( expectedClass->GetName() );
3049 }
3051 }
3052 if (isBranchElement) {
3053 if (expectedClass) {
3054 TBranchElement* bEl = (TBranchElement*)branch;
3055 bEl->SetTargetClass( expectedClass->GetName() );
3056 } else if (expectedType != kNoType_t && expectedType != kOther_t) {
3058 }
3059 }
3060 return kMatch;
3061}
3062
3063////////////////////////////////////////////////////////////////////////////////
3064/// Create a clone of this tree and copy nentries.
3065///
3066/// By default copy all entries.
3067/// The compression level of the cloned tree is set to the destination
3068/// file's compression level.
3069///
3070/// NOTE: Only active branches are copied. See TTree::SetBranchStatus for more
3071/// information and usage regarding the (de)activation of branches. More
3072/// examples are provided in the tutorials listed below.
3073///
3074/// NOTE: If the TTree is a TChain, the structure of the first TTree
3075/// is used for the copy.
3076///
3077/// IMPORTANT: The cloned tree stays connected with this tree until
3078/// this tree is deleted. In particular, any changes in
3079/// branch addresses in this tree are forwarded to the
3080/// clone trees, unless a branch in a clone tree has had
3081/// its address changed, in which case that change stays in
3082/// effect. When this tree is deleted, all the addresses of
3083/// the cloned tree are reset to their default values.
3084///
3085/// If 'option' contains the word 'fast' and nentries is -1, the
3086/// cloning will be done without unzipping or unstreaming the baskets
3087/// (i.e., a direct copy of the raw bytes on disk).
3088///
3089/// When 'fast' is specified, 'option' can also contain a sorting
3090/// order for the baskets in the output file.
3091///
3092/// There are currently 3 supported sorting order:
3093///
3094/// - SortBasketsByOffset (the default)
3095/// - SortBasketsByBranch
3096/// - SortBasketsByEntry
3097///
3098/// When using SortBasketsByOffset the baskets are written in the
3099/// output file in the same order as in the original file (i.e. the
3100/// baskets are sorted by their offset in the original file; Usually
3101/// this also means that the baskets are sorted by the index/number of
3102/// the _last_ entry they contain)
3103///
3104/// When using SortBasketsByBranch all the baskets of each individual
3105/// branches are stored contiguously. This tends to optimize reading
3106/// speed when reading a small number (1->5) of branches, since all
3107/// their baskets will be clustered together instead of being spread
3108/// across the file. However it might decrease the performance when
3109/// reading more branches (or the full entry).
3110///
3111/// When using SortBasketsByEntry the baskets with the lowest starting
3112/// entry are written first. (i.e. the baskets are sorted by the
3113/// index/number of the first entry they contain). This means that on
3114/// the file the baskets will be in the order in which they will be
3115/// needed when reading the whole tree sequentially.
3116///
3117/// For examples of CloneTree, see tutorials:
3118///
3119/// - copytree.C:
3120/// A macro to copy a subset of a TTree to a new TTree.
3121/// The input file has been generated by the program in
3122/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3123///
3124/// - copytree2.C:
3125/// A macro to copy a subset of a TTree to a new TTree.
3126/// One branch of the new Tree is written to a separate file.
3127/// The input file has been generated by the program in
3128/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3130TTree* TTree::CloneTree(Long64_t nentries /* = -1 */, Option_t* option /* = "" */)
3131{
3132 // Options
3133 bool fastClone = false;
3134
3135 TString opt = option;
3136 opt.ToLower();
3137 if (opt.Contains("fast")) {
3138 fastClone = true;
3139 }
3140
3141 // If we are a chain, switch to the first tree.
3142 if ((fEntries > 0) && (LoadTree(0) < 0)) {
3143 // FIXME: We need an error message here.
3144 return nullptr;
3145 }
3146
3147 // Note: For a tree we get the this pointer, for
3148 // a chain we get the chain's current tree.
3149 TTree* thistree = GetTree();
3150
3151 // We will use this to override the IO features on the cloned branches.
3152 ROOT::TIOFeatures features = this->GetIOFeatures();
3153 ;
3154
3155 // Note: For a chain, the returned clone will be
3156 // a clone of the chain's first tree.
3157 TTree* newtree = (TTree*) thistree->Clone();
3158 if (!newtree) {
3159 return nullptr;
3160 }
3161
3162 // The clone should not delete any objects allocated by SetAddress().
3163 TObjArray* branches = newtree->GetListOfBranches();
3164 Int_t nb = branches->GetEntriesFast();
3165 for (Int_t i = 0; i < nb; ++i) {
3166 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3168 ((TBranchElement*) br)->ResetDeleteObject();
3169 }
3170 }
3171
3172 // Add the new tree to the list of clones so that
3173 // we can later inform it of changes to branch addresses.
3174 thistree->AddClone(newtree);
3175 if (thistree != this) {
3176 // In case this object is a TChain, add the clone
3177 // also to the TChain's list of clones.
3178 AddClone(newtree);
3179 }
3180
3181 newtree->Reset();
3182
3183 TDirectory* ndir = newtree->GetDirectory();
3184 TFile* nfile = nullptr;
3185 if (ndir) {
3186 nfile = ndir->GetFile();
3187 }
3188 Int_t newcomp = -1;
3189 if (nfile) {
3190 newcomp = nfile->GetCompressionSettings();
3191 }
3192
3193 //
3194 // Delete non-active branches from the clone.
3195 //
3196 // Note: If we are a chain, this does nothing
3197 // since chains have no leaves.
3198 TObjArray* leaves = newtree->GetListOfLeaves();
3199 Int_t nleaves = leaves->GetEntriesFast();
3200 for (Int_t lndx = 0; lndx < nleaves; ++lndx) {
3201 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(lndx);
3202 if (!leaf) {
3203 continue;
3204 }
3205 TBranch* branch = leaf->GetBranch();
3206 if (branch && (newcomp > -1)) {
3207 branch->SetCompressionSettings(newcomp);
3208 }
3209 if (branch) branch->SetIOFeatures(features);
3210 if (!branch || !branch->TestBit(kDoNotProcess)) {
3211 continue;
3212 }
3213 // size might change at each iteration of the loop over the leaves.
3214 nb = branches->GetEntriesFast();
3215 for (Long64_t i = 0; i < nb; ++i) {
3216 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3217 if (br == branch) {
3218 branches->RemoveAt(i);
3219 delete br;
3220 br = nullptr;
3221 branches->Compress();
3222 break;
3223 }
3224 TObjArray* lb = br->GetListOfBranches();
3225 Int_t nb1 = lb->GetEntriesFast();
3226 for (Int_t j = 0; j < nb1; ++j) {
3227 TBranch* b1 = (TBranch*) lb->UncheckedAt(j);
3228 if (!b1) {
3229 continue;
3230 }
3231 if (b1 == branch) {
3232 lb->RemoveAt(j);
3233 delete b1;
3234 b1 = nullptr;
3235 lb->Compress();
3236 break;
3237 }
3238 TObjArray* lb1 = b1->GetListOfBranches();
3239 Int_t nb2 = lb1->GetEntriesFast();
3240 for (Int_t k = 0; k < nb2; ++k) {
3241 TBranch* b2 = (TBranch*) lb1->UncheckedAt(k);
3242 if (!b2) {
3243 continue;
3244 }
3245 if (b2 == branch) {
3246 lb1->RemoveAt(k);
3247 delete b2;
3248 b2 = nullptr;
3249 lb1->Compress();
3250 break;
3251 }
3252 }
3253 }
3254 }
3255 }
3256 leaves->Compress();
3257
3258 // Copy MakeClass status.
3259 newtree->SetMakeClass(fMakeClass);
3260
3261 // Copy branch addresses.
3262 CopyAddresses(newtree);
3263
3264 //
3265 // Copy entries if requested.
3266 //
3267
3268 if (nentries != 0) {
3269 if (fastClone && (nentries < 0)) {
3270 if ( newtree->CopyEntries( this, -1, option, false ) < 0 ) {
3271 // There was a problem!
3272 Error("CloneTTree", "TTree has not been cloned\n");
3273 delete newtree;
3274 newtree = nullptr;
3275 return nullptr;
3276 }
3277 } else {
3278 newtree->CopyEntries( this, nentries, option, false );
3279 }
3280 }
3281
3282 return newtree;
3283}
3284
3285////////////////////////////////////////////////////////////////////////////////
3286/// Set branch addresses of passed tree equal to ours.
3287/// If undo is true, reset the branch addresses instead of copying them.
3288/// This ensures 'separation' of a cloned tree from its original.
3290void TTree::CopyAddresses(TTree* tree, bool undo)
3291{
3292 // Copy branch addresses starting from branches.
3293 TObjArray* branches = GetListOfBranches();
3294 Int_t nbranches = branches->GetEntriesFast();
3295 for (Int_t i = 0; i < nbranches; ++i) {
3296 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
3297 if (branch->TestBit(kDoNotProcess)) {
3298 continue;
3299 }
3300 if (undo) {
3301 TBranch* br = tree->GetBranch(branch->GetName());
3302 tree->ResetBranchAddress(br);
3303 } else {
3304 char* addr = branch->GetAddress();
3305 if (!addr) {
3306 if (branch->IsA() == TBranch::Class()) {
3307 // If the branch was created using a leaflist, the branch itself may not have
3308 // an address but the leaf might already.
3309 TLeaf *firstleaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
3310 if (!firstleaf || firstleaf->GetValuePointer()) {
3311 // Either there is no leaf (and thus no point in copying the address)
3312 // or the leaf has an address but we can not copy it via the branche
3313 // this will be copied via the next loop (over the leaf).
3314 continue;
3315 }
3316 }
3317 // Note: This may cause an object to be allocated.
3318 branch->SetAddress(nullptr);
3319 addr = branch->GetAddress();
3320 }
3321 TBranch* br = tree->GetBranch(branch->GetFullName());
3322 if (br) {
3323 if (br->GetMakeClass() != branch->GetMakeClass())
3324 br->SetMakeClass(branch->GetMakeClass());
3325 br->SetAddress(addr);
3326 // The copy does not own any object allocated by SetAddress().
3328 ((TBranchElement*) br)->ResetDeleteObject();
3329 }
3330 } else {
3331 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3332 }
3333 }
3334 }
3335
3336 // Copy branch addresses starting from leaves.
3337 TObjArray* tleaves = tree->GetListOfLeaves();
3338 Int_t ntleaves = tleaves->GetEntriesFast();
3339 std::set<TLeaf*> updatedLeafCount;
3340 for (Int_t i = 0; i < ntleaves; ++i) {
3341 TLeaf* tleaf = (TLeaf*) tleaves->UncheckedAt(i);
3342 TBranch* tbranch = tleaf->GetBranch();
3343 TBranch* branch = GetBranch(tbranch->GetName());
3344 if (!branch) {
3345 continue;
3346 }
3347 TLeaf* leaf = branch->GetLeaf(tleaf->GetName());
3348 if (!leaf) {
3349 continue;
3350 }
3351 if (branch->TestBit(kDoNotProcess)) {
3352 continue;
3353 }
3354 if (undo) {
3355 // Now we know whether the address has been transfered
3356 tree->ResetBranchAddress(tbranch);
3357 } else {
3358 TBranchElement *mother = dynamic_cast<TBranchElement*>(leaf->GetBranch()->GetMother());
3359 bool needAddressReset = false;
3360 if (leaf->GetLeafCount() && (leaf->TestBit(TLeaf::kNewValue) || !leaf->GetValuePointer() || (mother && mother->IsObjectOwner())) && tleaf->GetLeafCount())
3361 {
3362 // If it is an array and it was allocated by the leaf itself,
3363 // let's make sure it is large enough for the incoming data.
3364 if (leaf->GetLeafCount()->GetMaximum() < tleaf->GetLeafCount()->GetMaximum()) {
3365 leaf->GetLeafCount()->IncludeRange( tleaf->GetLeafCount() );
3366 updatedLeafCount.insert(leaf->GetLeafCount());
3367 needAddressReset = true;
3368 } else {
3369 needAddressReset = (updatedLeafCount.find(leaf->GetLeafCount()) != updatedLeafCount.end());
3370 }
3371 }
3372 if (needAddressReset && leaf->GetValuePointer()) {
3373 if (leaf->IsA() == TLeafElement::Class() && mother)
3374 mother->ResetAddress();
3375 else
3376 leaf->SetAddress(nullptr);
3377 }
3378 if (!branch->GetAddress() && !leaf->GetValuePointer()) {
3379 // We should attempts to set the address of the branch.
3380 // something like:
3381 //(TBranchElement*)branch->GetMother()->SetAddress(0)
3382 //plus a few more subtleties (see TBranchElement::GetEntry).
3383 //but for now we go the simplest route:
3384 //
3385 // Note: This may result in the allocation of an object.
3386 branch->SetupAddresses();
3387 }
3388 if (branch->GetAddress()) {
3389 tree->SetBranchAddress(branch->GetName(), (void*) branch->GetAddress());
3390 TBranch* br = tree->GetBranch(branch->GetName());
3391 if (br) {
3392 if (br->IsA() != branch->IsA()) {
3393 Error(
3394 "CopyAddresses",
3395 "Branch kind mismatch between input tree '%s' and output tree '%s' for branch '%s': '%s' vs '%s'",
3396 tree->GetName(), br->GetTree()->GetName(), br->GetName(), branch->IsA()->GetName(),
3397 br->IsA()->GetName());
3398 }
3399 // The copy does not own any object allocated by SetAddress().
3400 // FIXME: We do too much here, br may not be a top-level branch.
3402 ((TBranchElement*) br)->ResetDeleteObject();
3403 }
3404 } else {
3405 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3406 }
3407 } else {
3408 tleaf->SetAddress(leaf->GetValuePointer());
3409 }
3410 }
3411 }
3412
3413 if (undo &&
3414 ( tree->IsA()->InheritsFrom("TNtuple") || tree->IsA()->InheritsFrom("TNtupleD") )
3415 ) {
3416 tree->ResetBranchAddresses();
3417 }
3418}
3419
3420namespace {
3421
3422 enum EOnIndexError { kDrop, kKeep, kBuild };
3423
3424 bool R__HandleIndex(EOnIndexError onIndexError, TTree *newtree, TTree *oldtree)
3425 {
3426 // Return true if we should continue to handle indices, false otherwise.
3427
3428 bool withIndex = true;
3429
3430 if ( newtree->GetTreeIndex() ) {
3431 if ( oldtree->GetTree()->GetTreeIndex() == nullptr ) {
3432 switch (onIndexError) {
3433 case kDrop:
3434 delete newtree->GetTreeIndex();
3435 newtree->SetTreeIndex(nullptr);
3436 withIndex = false;
3437 break;
3438 case kKeep:
3439 // Nothing to do really.
3440 break;
3441 case kBuild:
3442 // Build the index then copy it
3443 if (oldtree->GetTree()->BuildIndex(newtree->GetTreeIndex()->GetMajorName(), newtree->GetTreeIndex()->GetMinorName())) {
3444 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3445 // Clean up
3446 delete oldtree->GetTree()->GetTreeIndex();
3447 oldtree->GetTree()->SetTreeIndex(nullptr);
3448 }
3449 break;
3450 }
3451 } else {
3452 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3453 }
3454 } else if ( oldtree->GetTree()->GetTreeIndex() != nullptr ) {
3455 // We discover the first index in the middle of the chain.
3456 switch (onIndexError) {
3457 case kDrop:
3458 // Nothing to do really.
3459 break;
3460 case kKeep: {
3462 index->SetTree(newtree);
3463 newtree->SetTreeIndex(index);
3464 break;
3465 }
3466 case kBuild:
3467 if (newtree->GetEntries() == 0) {
3468 // Start an index.
3470 index->SetTree(newtree);
3471 newtree->SetTreeIndex(index);
3472 } else {
3473 // Build the index so far.
3474 if (newtree->BuildIndex(oldtree->GetTree()->GetTreeIndex()->GetMajorName(), oldtree->GetTree()->GetTreeIndex()->GetMinorName())) {
3475 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3476 }
3477 }
3478 break;
3479 }
3480 } else if ( onIndexError == kDrop ) {
3481 // There is no index on this or on tree->GetTree(), we know we have to ignore any further
3482 // index
3483 withIndex = false;
3484 }
3485 return withIndex;
3486 }
3487}
3488
3489////////////////////////////////////////////////////////////////////////////////
3490/// Copy nentries from given tree to this tree.
3491/// This routines assumes that the branches that intended to be copied are
3492/// already connected. The typical case is that this tree was created using
3493/// tree->CloneTree(0).
3494///
3495/// By default copy all entries.
3496///
3497/// Returns number of bytes copied to this tree.
3498///
3499/// If 'option' contains the word 'fast' and nentries is -1, the cloning will be
3500/// done without unzipping or unstreaming the baskets (i.e., a direct copy of the
3501/// raw bytes on disk).
3502///
3503/// When 'fast' is specified, 'option' can also contains a sorting order for the
3504/// baskets in the output file.
3505///
3506/// There are currently 3 supported sorting order:
3507///
3508/// - SortBasketsByOffset (the default)
3509/// - SortBasketsByBranch
3510/// - SortBasketsByEntry
3511///
3512/// See TTree::CloneTree for a detailed explanation of the semantics of these 3 options.
3513///
3514/// If the tree or any of the underlying tree of the chain has an index, that index and any
3515/// index in the subsequent underlying TTree objects will be merged.
3516///
3517/// There are currently three 'options' to control this merging:
3518/// - NoIndex : all the TTreeIndex object are dropped.
3519/// - DropIndexOnError : if any of the underlying TTree object do no have a TTreeIndex,
3520/// they are all dropped.
3521/// - AsIsIndexOnError [default]: In case of missing TTreeIndex, the resulting TTree index has gaps.
3522/// - BuildIndexOnError : If any of the underlying TTree objects do not have a TTreeIndex,
3523/// all TTreeIndex are 'ignored' and the missing piece are rebuilt.
3525Long64_t TTree::CopyEntries(TTree* tree, Long64_t nentries /* = -1 */, Option_t* option /* = "" */, bool needCopyAddresses /* = false */)
3526{
3527 if (!tree) {
3528 return 0;
3529 }
3530 // Options
3531 TString opt = option;
3532 opt.ToLower();
3533 bool fastClone = opt.Contains("fast");
3534 bool withIndex = !opt.Contains("noindex");
3535 EOnIndexError onIndexError;
3536 if (opt.Contains("asisindex")) {
3537 onIndexError = kKeep;
3538 } else if (opt.Contains("buildindex")) {
3539 onIndexError = kBuild;
3540 } else if (opt.Contains("dropindex")) {
3541 onIndexError = kDrop;
3542 } else {
3543 onIndexError = kBuild;
3544 }
3545 Ssiz_t cacheSizeLoc = opt.Index("cachesize=");
3546 Long64_t cacheSize = -1;
3547 if (cacheSizeLoc != TString::kNPOS) {
3548 // If the parse faile, cacheSize stays at -1.
3549 Ssiz_t cacheSizeEnd = opt.Index(" ",cacheSizeLoc+10) - (cacheSizeLoc+10);
3550 TSubString cacheSizeStr( opt(cacheSizeLoc+10,cacheSizeEnd) );
3551 auto parseResult = ROOT::FromHumanReadableSize(cacheSizeStr,cacheSize);
3552 if (parseResult == ROOT::EFromHumanReadableSize::kParseFail) {
3553 Warning("CopyEntries","The cachesize option can not be parsed: %s. The default size will be used.",cacheSizeStr.String().Data());
3554 } else if (parseResult == ROOT::EFromHumanReadableSize::kOverflow) {
3555 double m;
3556 const char *munit = nullptr;
3557 ROOT::ToHumanReadableSize(std::numeric_limits<decltype(cacheSize)>::max(),false,&m,&munit);
3558
3559 Warning("CopyEntries","The cachesize option is too large: %s (%g%s max). The default size will be used.",cacheSizeStr.String().Data(),m,munit);
3560 }
3561 }
3562 if (gDebug > 0 && cacheSize != -1) Info("CopyEntries","Using Cache size: %lld\n",cacheSize);
3563
3564 Long64_t nbytes = 0;
3565 Long64_t treeEntries = tree->GetEntriesFast();
3566 if (nentries < 0) {
3567 nentries = treeEntries;
3568 } else if (nentries > treeEntries) {
3569 nentries = treeEntries;
3570 }
3571
3572 if (fastClone && (nentries < 0 || nentries == tree->GetEntriesFast())) {
3573 // Quickly copy the basket without decompression and streaming.
3574 Long64_t totbytes = GetTotBytes();
3575 for (Long64_t i = 0; i < nentries; i += tree->GetTree()->GetEntries()) {
3576 if (tree->LoadTree(i) < 0) {
3577 break;
3578 }
3579 if ( withIndex ) {
3580 withIndex = R__HandleIndex( onIndexError, this, tree );
3581 }
3582 if (this->GetDirectory()) {
3583 TFile* file2 = this->GetDirectory()->GetFile();
3584 if (file2 && (file2->GetEND() > TTree::GetMaxTreeSize())) {
3585 if (this->GetDirectory() == (TDirectory*) file2) {
3586 this->ChangeFile(file2);
3587 }
3588 }
3589 }
3590 TTreeCloner cloner(tree->GetTree(), this, option, TTreeCloner::kNoWarnings);
3591 if (cloner.IsValid()) {
3592 this->SetEntries(this->GetEntries() + tree->GetTree()->GetEntries());
3593 if (cacheSize != -1) cloner.SetCacheSize(cacheSize);
3594 cloner.Exec();
3595 } else {
3596 if (i == 0) {
3597 Warning("CopyEntries","%s",cloner.GetWarning());
3598 // If the first cloning does not work, something is really wrong
3599 // (since apriori the source and target are exactly the same structure!)
3600 return -1;
3601 } else {
3602 if (cloner.NeedConversion()) {
3603 TTree *localtree = tree->GetTree();
3604 Long64_t tentries = localtree->GetEntries();
3605 if (needCopyAddresses) {
3606 // Copy MakeClass status.
3607 tree->SetMakeClass(fMakeClass);
3608 // Copy branch addresses.
3609 CopyAddresses(tree);
3610 }
3611 for (Long64_t ii = 0; ii < tentries; ii++) {
3612 if (localtree->GetEntry(ii) <= 0) {
3613 break;
3614 }
3615 this->Fill();
3616 }
3617 if (needCopyAddresses)
3618 tree->ResetBranchAddresses();
3619 if (this->GetTreeIndex()) {
3620 this->GetTreeIndex()->Append(tree->GetTree()->GetTreeIndex(), true);
3621 }
3622 } else {
3623 Warning("CopyEntries","%s",cloner.GetWarning());
3624 if (tree->GetDirectory() && tree->GetDirectory()->GetFile()) {
3625 Warning("CopyEntries", "Skipped file %s\n", tree->GetDirectory()->GetFile()->GetName());
3626 } else {
3627 Warning("CopyEntries", "Skipped file number %d\n", tree->GetTreeNumber());
3628 }
3629 }
3630 }
3631 }
3632
3633 }
3634 if (this->GetTreeIndex()) {
3635 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3636 }
3637 nbytes = GetTotBytes() - totbytes;
3638 } else {
3639 if (nentries < 0) {
3640 nentries = treeEntries;
3641 } else if (nentries > treeEntries) {
3642 nentries = treeEntries;
3643 }
3644 if (needCopyAddresses) {
3645 // Copy MakeClass status.
3646 tree->SetMakeClass(fMakeClass);
3647 // Copy branch addresses.
3648 CopyAddresses(tree);
3649 }
3650 Int_t treenumber = -1;
3651 for (Long64_t i = 0; i < nentries; i++) {
3652 if (tree->LoadTree(i) < 0) {
3653 break;
3654 }
3655 if (treenumber != tree->GetTreeNumber()) {
3656 if ( withIndex ) {
3657 withIndex = R__HandleIndex( onIndexError, this, tree );
3658 }
3659 treenumber = tree->GetTreeNumber();
3660 }
3661 if (tree->GetEntry(i) <= 0) {
3662 break;
3663 }
3664 nbytes += this->Fill();
3665 }
3666 if (needCopyAddresses)
3667 tree->ResetBranchAddresses();
3668 if (this->GetTreeIndex()) {
3669 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3670 }
3671 }
3672 return nbytes;
3673}
3674
3675////////////////////////////////////////////////////////////////////////////////
3676/// Copy a tree with selection.
3677///
3678/// ### Important:
3679///
3680/// The returned copied tree stays connected with the original tree
3681/// until the original tree is deleted. In particular, any changes
3682/// to the branch addresses in the original tree are also made to
3683/// the copied tree. Any changes made to the branch addresses of the
3684/// copied tree are overridden anytime the original tree changes its
3685/// branch addresses. When the original tree is deleted, all the
3686/// branch addresses of the copied tree are set to zero.
3687///
3688/// For examples of CopyTree, see the tutorials:
3689///
3690/// - copytree.C:
3691/// Example macro to copy a subset of a tree to a new tree.
3692/// The input file was generated by running the program in
3693/// $ROOTSYS/test/Event in this way:
3694/// ~~~ {.cpp}
3695/// ./Event 1000 1 1 1
3696/// ~~~
3697/// - copytree2.C
3698/// Example macro to copy a subset of a tree to a new tree.
3699/// One branch of the new tree is written to a separate file.
3700/// The input file was generated by running the program in
3701/// $ROOTSYS/test/Event in this way:
3702/// ~~~ {.cpp}
3703/// ./Event 1000 1 1 1
3704/// ~~~
3705/// - copytree3.C
3706/// Example macro to copy a subset of a tree to a new tree.
3707/// Only selected entries are copied to the new tree.
3708/// NOTE that only the active branches are copied.
3710TTree* TTree::CopyTree(const char* selection, Option_t* option /* = 0 */, Long64_t nentries /* = TTree::kMaxEntries */, Long64_t firstentry /* = 0 */)
3711{
3712 GetPlayer();
3713 if (fPlayer) {
3714 return fPlayer->CopyTree(selection, option, nentries, firstentry);
3715 }
3716 return nullptr;
3717}
3718
3719////////////////////////////////////////////////////////////////////////////////
3720/// Create a basket for this tree and given branch.
3723{
3724 if (!branch) {
3725 return nullptr;
3726 }
3727 return new TBasket(branch->GetName(), GetName(), branch);
3728}
3729
3730////////////////////////////////////////////////////////////////////////////////
3731/// Delete this tree from memory or/and disk.
3732///
3733/// - if option == "all" delete Tree object from memory AND from disk
3734/// all baskets on disk are deleted. All keys with same name
3735/// are deleted.
3736/// - if option =="" only Tree object in memory is deleted.
3738void TTree::Delete(Option_t* option /* = "" */)
3739{
3740 TFile *file = GetCurrentFile();
3741
3742 // delete all baskets and header from file
3743 if (file && option && !strcmp(option,"all")) {
3744 if (!file->IsWritable()) {
3745 Error("Delete","File : %s is not writable, cannot delete Tree:%s", file->GetName(),GetName());
3746 return;
3747 }
3748
3749 //find key and import Tree header in memory
3750 TKey *key = fDirectory->GetKey(GetName());
3751 if (!key) return;
3752
3753 TDirectory *dirsav = gDirectory;
3754 file->cd();
3755
3756 //get list of leaves and loop on all the branches baskets
3757 TIter next(GetListOfLeaves());
3758 TLeaf *leaf;
3759 char header[16];
3760 Int_t ntot = 0;
3761 Int_t nbask = 0;
3762 Int_t nbytes,objlen,keylen;
3763 while ((leaf = (TLeaf*)next())) {
3764 TBranch *branch = leaf->GetBranch();
3765 Int_t nbaskets = branch->GetMaxBaskets();
3766 for (Int_t i=0;i<nbaskets;i++) {
3767 Long64_t pos = branch->GetBasketSeek(i);
3768 if (!pos) continue;
3769 TFile *branchFile = branch->GetFile();
3770 if (!branchFile) continue;
3771 branchFile->GetRecordHeader(header,pos,16,nbytes,objlen,keylen);
3772 if (nbytes <= 0) continue;
3773 branchFile->MakeFree(pos,pos+nbytes-1);
3774 ntot += nbytes;
3775 nbask++;
3776 }
3777 }
3778
3779 // delete Tree header key and all keys with the same name
3780 // A Tree may have been saved many times. Previous cycles are invalid.
3781 while (key) {
3782 ntot += key->GetNbytes();
3783 key->Delete();
3784 delete key;
3785 key = fDirectory->GetKey(GetName());
3786 }
3787 if (dirsav) dirsav->cd();
3788 if (gDebug) Info("TTree::Delete", "Deleting Tree: %s: %d baskets deleted. Total space freed = %d bytes\n",GetName(),nbask,ntot);
3789 }
3790
3791 if (fDirectory) {
3792 fDirectory->Remove(this);
3793 //delete the file cache if it points to this Tree
3794 MoveReadCache(file,nullptr);
3795 fDirectory = nullptr;
3797 }
3798
3799 // Delete object from CINT symbol table so it can not be used anymore.
3800 gCling->DeleteGlobal(this);
3801
3802 // Warning: We have intentional invalidated this object while inside a member function!
3803 delete this;
3804}
3805
3806 ///////////////////////////////////////////////////////////////////////////////
3807 /// Called by TKey and TObject::Clone to automatically add us to a directory
3808 /// when we are read from a file.
3811{
3812 if (fDirectory == dir) return;
3813 if (fDirectory) {
3814 fDirectory->Remove(this);
3815 // Delete or move the file cache if it points to this Tree
3816 TFile *file = fDirectory->GetFile();
3817 MoveReadCache(file,dir);
3818 }
3819 fDirectory = dir;
3820 TBranch* b = nullptr;
3821 TIter next(GetListOfBranches());
3822 while((b = (TBranch*) next())) {
3823 b->UpdateFile();
3824 }
3825 if (fBranchRef) {
3827 }
3828 if (fDirectory) fDirectory->Append(this);
3829}
3830
3831////////////////////////////////////////////////////////////////////////////////
3832/// Draw expression varexp for specified entries.
3833///
3834/// \return -1 in case of error or number of selected events in case of success.
3835///
3836/// This function accepts TCut objects as arguments.
3837/// Useful to use the string operator +
3838///
3839/// Example:
3840///
3841/// ~~~ {.cpp}
3842/// ntuple.Draw("x",cut1+cut2+cut3);
3843/// ~~~
3844
3846Long64_t TTree::Draw(const char* varexp, const TCut& selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
3847{
3848 return TTree::Draw(varexp, selection.GetTitle(), option, nentries, firstentry);
3849}
3850
3851/////////////////////////////////////////////////////////////////////////////////////////
3852/// \brief Draw expression varexp for entries and objects that pass a (optional) selection.
3853///
3854/// \return -1 in case of error or number of selected events in case of success.
3855///
3856/// \param [in] varexp
3857/// \parblock
3858/// A string that takes one of these general forms:
3859/// - "e1" produces a 1-d histogram (TH1F) of expression "e1"
3860/// - "e1:e2" produces an unbinned 2-d scatter-plot (TGraph) of "e1"
3861/// on the y-axis versus "e2" on the x-axis
3862/// - "e1:e2:e3" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3863/// vs "e2" vs "e3" on the z-, y-, x-axis, respectively
3864/// - "e1:e2:e3:e4" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3865/// vs "e2" vs "e3" and "e4" mapped on the current color palette.
3866/// (to create histograms in the 2, 3, and 4 dimensional case,
3867/// see section "Saving the result of Draw to an histogram")
3868/// - "e1:e2:e3:e4:e5" with option "GL5D" produces a 5D plot using OpenGL. `gStyle->SetCanvasPreferGL(true)` is needed.
3869/// - Any number of variables no fewer than two can be used with the options "CANDLE" and "PARA"
3870/// - An arbitrary number of variables can be used with the option "GOFF"
3871///
3872/// Examples:
3873/// - "x": the simplest case, it draws a 1-Dim histogram of column x
3874/// - "sqrt(x)", "x*y/z": draw histogram with the values of the specified numerical expression across TTree events
3875/// - "y:sqrt(x)": 2-Dim histogram of y versus sqrt(x)
3876/// - "px:py:pz:2.5*E": produces a 3-d scatter-plot of px vs py ps pz
3877/// and the color number of each marker will be 2.5*E.
3878/// If the color number is negative it is set to 0.
3879/// If the color number is greater than the current number of colors
3880/// it is set to the highest color number. The default number of
3881/// colors is 50. See TStyle::SetPalette for setting a new color palette.
3882///
3883/// The expressions can use all the operations and built-in functions
3884/// supported by TFormula (see TFormula::Analyze()), including free
3885/// functions taking numerical arguments (e.g. TMath::Bessel()).
3886/// In addition, you can call member functions taking numerical
3887/// arguments. For example, these are two valid expressions:
3888/// ~~~ {.cpp}
3889/// TMath::BreitWigner(fPx,3,2)
3890/// event.GetHistogram()->GetXaxis()->GetXmax()
3891/// ~~~
3892/// \endparblock
3893/// \param [in] selection
3894/// \parblock
3895/// A string containing a selection expression.
3896/// In a selection all usual C++ mathematical and logical operators are allowed.
3897/// The value corresponding to the selection expression is used as a weight
3898/// to fill the histogram (a weight of 0 is equivalent to not filling the histogram).\n
3899/// \n
3900/// Examples:
3901/// - "x<y && sqrt(z)>3.2": returns a weight = 0 or 1
3902/// - "(x+y)*(sqrt(z)>3.2)": returns a weight = x+y if sqrt(z)>3.2, 0 otherwise\n
3903/// \n
3904/// If the selection expression returns an array, it is iterated over in sync with the
3905/// array returned by the varexp argument (as described below in "Drawing expressions using arrays and array
3906/// elements"). For example, if, for a given event, varexp evaluates to
3907/// `{1., 2., 3.}` and selection evaluates to `{0, 1, 0}`, the resulting histogram is filled with the value 2. For example, for each event here we perform a simple object selection:
3908/// ~~~{.cpp}
3909/// // Muon_pt is an array: fill a histogram with the array elements > 100 in each event
3910/// tree->Draw('Muon_pt', 'Muon_pt > 100')
3911/// ~~~
3912/// \endparblock
3913/// \param [in] option
3914/// \parblock
3915/// The drawing option.
3916/// - When an histogram is produced it can be any histogram drawing option
3917/// listed in THistPainter.
3918/// - when no option is specified:
3919/// - the default histogram drawing option is used
3920/// if the expression is of the form "e1".
3921/// - if the expression is of the form "e1:e2"or "e1:e2:e3" a cloud of
3922/// unbinned 2D or 3D points is drawn respectively.
3923/// - if the expression has four fields "e1:e2:e3:e4" a cloud of unbinned 3D
3924/// points is produced with e1 vs e2 vs e3, and e4 is mapped on the current color
3925/// palette.
3926/// - If option COL is specified when varexp has three fields:
3927/// ~~~ {.cpp}
3928/// tree.Draw("e1:e2:e3","","col");
3929/// ~~~
3930/// a 2D scatter is produced with e1 vs e2, and e3 is mapped on the current
3931/// color palette. The colors for e3 are evaluated once in linear scale before
3932/// painting. Therefore changing the pad to log scale along Z as no effect
3933/// on the colors.
3934/// - if expression has more than four fields the option "PARA"or "CANDLE"
3935/// can be used.
3936/// - If option contains the string "goff", no graphics is generated.
3937/// \endparblock
3938/// \param [in] nentries The number of entries to process (default is all)
3939/// \param [in] firstentry The first entry to process (default is 0)
3940///
3941/// ### Drawing expressions using arrays and array elements
3942///
3943/// Let assumes, a leaf fMatrix, on the branch fEvent, which is a 3 by 3 array,
3944/// or a TClonesArray.
3945/// In a TTree::Draw expression you can now access fMatrix using the following
3946/// syntaxes:
3947///
3948/// | String passed | What is used for each entry of the tree
3949/// |-----------------|--------------------------------------------------------|
3950/// | `fMatrix` | the 9 elements of fMatrix |
3951/// | `fMatrix[][]` | the 9 elements of fMatrix |
3952/// | `fMatrix[2][2]` | only the elements fMatrix[2][2] |
3953/// | `fMatrix[1]` | the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2] |
3954/// | `fMatrix[1][]` | the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2] |
3955/// | `fMatrix[][0]` | the 3 elements fMatrix[0][0], fMatrix[1][0] and fMatrix[2][0] |
3956///
3957/// "fEvent.fMatrix...." same as "fMatrix..." (unless there is more than one leaf named fMatrix!).
3958///
3959/// In summary, if a specific index is not specified for a dimension, TTree::Draw
3960/// will loop through all the indices along this dimension. Leaving off the
3961/// last (right most) dimension of specifying then with the two characters '[]'
3962/// is equivalent. For variable size arrays (and TClonesArray) the range
3963/// of the first dimension is recalculated for each entry of the tree.
3964/// You can also specify the index as an expression of any other variables from the
3965/// tree.
3966///
3967/// TTree::Draw also now properly handling operations involving 2 or more arrays.
3968///
3969/// Let assume a second matrix fResults[5][2], here are a sample of some
3970/// of the possible combinations, the number of elements they produce and
3971/// the loop used:
3972///
3973/// | expression | element(s) | Loop |
3974/// |----------------------------------|------------|--------------------------|
3975/// | `fMatrix[2][1] - fResults[5][2]` | one | no loop |
3976/// | `fMatrix[2][] - fResults[5][2]` | three | on 2nd dim fMatrix |
3977/// | `fMatrix[2][] - fResults[5][]` | two | on both 2nd dimensions |
3978/// | `fMatrix[][2] - fResults[][1]` | three | on both 1st dimensions |
3979/// | `fMatrix[][2] - fResults[][]` | six | on both 1st and 2nd dimensions of fResults |
3980/// | `fMatrix[][2] - fResults[3][]` | two | on 1st dim of fMatrix and 2nd of fResults (at the same time) |
3981/// | `fMatrix[][] - fResults[][]` | six | on 1st dim then on 2nd dim |
3982/// | `fMatrix[][fResult[][]]` | 30 | on 1st dim of fMatrix then on both dimensions of fResults. The value if fResults[j][k] is used as the second index of fMatrix.|
3983///
3984///
3985/// In summary, TTree::Draw loops through all unspecified dimensions. To
3986/// figure out the range of each loop, we match each unspecified dimension
3987/// from left to right (ignoring ALL dimensions for which an index has been
3988/// specified), in the equivalent loop matched dimensions use the same index
3989/// and are restricted to the smallest range (of only the matched dimensions).
3990/// When involving variable arrays, the range can of course be different
3991/// for each entry of the tree.
3992///
3993/// So the loop equivalent to "fMatrix[][2] - fResults[3][]" is:
3994/// ~~~ {.cpp}
3995/// for (Int_t i0; i < min(3,2); i++) {
3996/// use the value of (fMatrix[i0][2] - fMatrix[3][i0])
3997/// }
3998/// ~~~
3999/// So the loop equivalent to "fMatrix[][2] - fResults[][]" is:
4000/// ~~~ {.cpp}
4001/// for (Int_t i0; i < min(3,5); i++) {
4002/// for (Int_t i1; i1 < 2; i1++) {
4003/// use the value of (fMatrix[i0][2] - fMatrix[i0][i1])
4004/// }
4005/// }
4006/// ~~~
4007/// So the loop equivalent to "fMatrix[][] - fResults[][]" is:
4008/// ~~~ {.cpp}
4009/// for (Int_t i0; i < min(3,5); i++) {
4010/// for (Int_t i1; i1 < min(3,2); i1++) {
4011/// use the value of (fMatrix[i0][i1] - fMatrix[i0][i1])
4012/// }
4013/// }
4014/// ~~~
4015/// So the loop equivalent to "fMatrix[][fResults[][]]" is:
4016/// ~~~ {.cpp}
4017/// for (Int_t i0; i0 < 3; i0++) {
4018/// for (Int_t j2; j2 < 5; j2++) {
4019/// for (Int_t j3; j3 < 2; j3++) {
4020/// i1 = fResults[j2][j3];
4021/// use the value of fMatrix[i0][i1]
4022/// }
4023/// }
4024/// ~~~
4025/// ### Retrieving the result of Draw
4026///
4027/// By default a temporary histogram called `htemp` is created. It will be:
4028///
4029/// - A TH1F* in case of a mono-dimensional distribution: `Draw("e1")`,
4030/// - A TH2F* in case of a bi-dimensional distribution: `Draw("e1:e2")`,
4031/// - A TH3F* in case of a three-dimensional distribution: `Draw("e1:e2:e3")`.
4032///
4033/// In the one dimensional case the `htemp` is filled and drawn whatever the drawing
4034/// option is.
4035///
4036/// In the two and three dimensional cases, with the default drawing option (`""`),
4037/// a cloud of points is drawn and the histogram `htemp` is not filled. For all the other
4038/// drawing options `htemp` will be filled.
4039///
4040/// In all cases `htemp` can be retrieved by calling:
4041///
4042/// ~~~ {.cpp}
4043/// auto htemp = (TH1F*)gPad->GetPrimitive("htemp"); // 1D
4044/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp"); // 2D
4045/// auto htemp = (TH3F*)gPad->GetPrimitive("htemp"); // 3D
4046/// ~~~
4047///
4048/// In the two dimensional case (`Draw("e1;e2")`), with the default drawing option, the
4049/// data is filled into a TGraph named `Graph`. This TGraph can be retrieved by
4050/// calling
4051///
4052/// ~~~ {.cpp}
4053/// auto graph = (TGraph*)gPad->GetPrimitive("Graph");
4054/// ~~~
4055///
4056/// For the three and four dimensional cases, with the default drawing option, an unnamed
4057/// TPolyMarker3D is produced, and therefore cannot be retrieved.
4058///
4059/// In all cases `htemp` can be used to access the axes. For instance in the 2D case:
4060///
4061/// ~~~ {.cpp}
4062/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp");
4063/// auto xaxis = htemp->GetXaxis();
4064/// ~~~
4065///
4066/// When the option `"A"` is used (with TGraph painting option) to draw a 2D
4067/// distribution:
4068/// ~~~ {.cpp}
4069/// tree.Draw("e1:e2","","A*");
4070/// ~~~
4071/// a scatter plot is produced (with stars in that case) but the axis creation is
4072/// delegated to TGraph and `htemp` is not created.
4073///
4074/// ### Saving the result of Draw to a histogram
4075///
4076/// If `varexp` contains `>>hnew` (following the variable(s) name(s)),
4077/// the new histogram called `hnew` is created and it is kept in the current
4078/// directory (and also the current pad). This works for all dimensions.
4079///
4080/// Example:
4081/// ~~~ {.cpp}
4082/// tree.Draw("sqrt(x)>>hsqrt","y>0")
4083/// ~~~
4084/// will draw `sqrt(x)` and save the histogram as "hsqrt" in the current
4085/// directory. To retrieve it do:
4086/// ~~~ {.cpp}
4087/// TH1F *hsqrt = (TH1F*)gDirectory->Get("hsqrt");
4088/// ~~~
4089/// The binning information is taken from the environment variables
4090/// ~~~ {.cpp}
4091/// Hist.Binning.?D.?
4092/// ~~~
4093/// In addition, the name of the histogram can be followed by up to 9
4094/// numbers between '(' and ')', where the numbers describe the
4095/// following:
4096///
4097/// - 1 - bins in x-direction
4098/// - 2 - lower limit in x-direction
4099/// - 3 - upper limit in x-direction
4100/// - 4-6 same for y-direction
4101/// - 7-9 same for z-direction
4102///
4103/// When a new binning is used the new value will become the default.
4104/// Values can be skipped.
4105///
4106/// Example:
4107/// ~~~ {.cpp}
4108/// tree.Draw("sqrt(x)>>hsqrt(500,10,20)")
4109/// // plot sqrt(x) between 10 and 20 using 500 bins
4110/// tree.Draw("sqrt(x):sin(y)>>hsqrt(100,10,60,50,.1,.5)")
4111/// // plot sqrt(x) against sin(y)
4112/// // 100 bins in x-direction; lower limit on x-axis is 10; upper limit is 60
4113/// // 50 bins in y-direction; lower limit on y-axis is .1; upper limit is .5
4114/// ~~~
4115/// By default, the specified histogram is reset.
4116/// To continue to append data to an existing histogram, use "+" in front
4117/// of the histogram name.
4118///
4119/// A '+' in front of the histogram name is ignored, when the name is followed by
4120/// binning information as described in the previous paragraph.
4121/// ~~~ {.cpp}
4122/// tree.Draw("sqrt(x)>>+hsqrt","y>0")
4123/// ~~~
4124/// will not reset `hsqrt`, but will continue filling. This works for 1-D, 2-D
4125/// and 3-D histograms.
4126///
4127/// ### Accessing collection objects
4128///
4129/// TTree::Draw default's handling of collections is to assume that any
4130/// request on a collection pertain to it content. For example, if fTracks
4131/// is a collection of Track objects, the following:
4132/// ~~~ {.cpp}
4133/// tree->Draw("event.fTracks.fPx");
4134/// ~~~
4135/// will plot the value of fPx for each Track objects inside the collection.
4136/// Also
4137/// ~~~ {.cpp}
4138/// tree->Draw("event.fTracks.size()");
4139/// ~~~
4140/// would plot the result of the member function Track::size() for each
4141/// Track object inside the collection.
4142/// To access information about the collection itself, TTree::Draw support
4143/// the '@' notation. If a variable which points to a collection is prefixed
4144/// or postfixed with '@', the next part of the expression will pertain to
4145/// the collection object. For example:
4146/// ~~~ {.cpp}
4147/// tree->Draw("event.@fTracks.size()");
4148/// ~~~
4149/// will plot the size of the collection referred to by `fTracks` (i.e the number
4150/// of Track objects).
4151///
4152/// ### Drawing 'objects'
4153///
4154/// When a class has a member function named AsDouble or AsString, requesting
4155/// to directly draw the object will imply a call to one of the 2 functions.
4156/// If both AsDouble and AsString are present, AsDouble will be used.
4157/// AsString can return either a char*, a std::string or a TString.s
4158/// For example, the following
4159/// ~~~ {.cpp}
4160/// tree->Draw("event.myTTimeStamp");
4161/// ~~~
4162/// will draw the same histogram as
4163/// ~~~ {.cpp}
4164/// tree->Draw("event.myTTimeStamp.AsDouble()");
4165/// ~~~
4166/// In addition, when the object is a type TString or std::string, TTree::Draw
4167/// will call respectively `TString::Data` and `std::string::c_str()`
4168///
4169/// If the object is a TBits, the histogram will contain the index of the bit
4170/// that are turned on.
4171///
4172/// ### Retrieving information about the tree itself.
4173///
4174/// You can refer to the tree (or chain) containing the data by using the
4175/// string 'This'.
4176/// You can then could any TTree methods. For example:
4177/// ~~~ {.cpp}
4178/// tree->Draw("This->GetReadEntry()");
4179/// ~~~
4180/// will display the local entry numbers be read.
4181/// ~~~ {.cpp}
4182/// tree->Draw("This->GetUserInfo()->At(0)->GetName()");
4183/// ~~~
4184/// will display the name of the first 'user info' object.
4185///
4186/// ### Special functions and variables
4187///
4188/// `Entry$`: A TTree::Draw formula can use the special variable `Entry$`
4189/// to access the entry number being read. For example to draw every
4190/// other entry use:
4191/// ~~~ {.cpp}
4192/// tree.Draw("myvar","Entry$%2==0");
4193/// ~~~
4194/// - `Entry$` : return the current entry number (`== TTree::GetReadEntry()`)
4195/// - `LocalEntry$` : return the current entry number in the current tree of a
4196/// chain (`== GetTree()->GetReadEntry()`)
4197/// - `Entries$` : return the total number of entries (== TTree::GetEntries())
4198/// - `LocalEntries$` : return the total number of entries in the current tree
4199/// of a chain (== GetTree()->TTree::GetEntries())
4200/// - `Length$` : return the total number of element of this formula for this
4201/// entry (`==TTreeFormula::GetNdata()`)
4202/// - `Iteration$` : return the current iteration over this formula for this
4203/// entry (i.e. varies from 0 to `Length$`).
4204/// - `Length$(formula )` : return the total number of element of the formula
4205/// given as a parameter.
4206/// - `Sum$(formula )` : return the sum of the value of the elements of the
4207/// formula given as a parameter. For example the mean for all the elements in
4208/// one entry can be calculated with: `Sum$(formula )/Length$(formula )`
4209/// - `Min$(formula )` : return the minimum (within one TTree entry) of the value of the
4210/// elements of the formula given as a parameter.
4211/// - `Max$(formula )` : return the maximum (within one TTree entry) of the value of the
4212/// elements of the formula given as a parameter.
4213/// - `MinIf$(formula,condition)`
4214/// - `MaxIf$(formula,condition)` : return the minimum (maximum) (within one TTree entry)
4215/// of the value of the elements of the formula given as a parameter
4216/// if they match the condition. If no element matches the condition,
4217/// the result is zero. To avoid the resulting peak at zero, use the
4218/// pattern:
4219/// ~~~ {.cpp}
4220/// tree->Draw("MinIf$(formula,condition)","condition");
4221/// ~~~
4222/// which will avoid calculation `MinIf$` for the entries that have no match
4223/// for the condition.
4224/// - `Alt$(primary,alternate)` : return the value of "primary" if it is available
4225/// for the current iteration otherwise return the value of "alternate".
4226/// For example, with arr1[3] and arr2[2]
4227/// ~~~ {.cpp}
4228/// tree->Draw("arr1+Alt$(arr2,0)");
4229/// ~~~
4230/// will draw arr1[0]+arr2[0] ; arr1[1]+arr2[1] and arr1[2]+0
4231/// Or with a variable size array arr3
4232/// ~~~ {.cpp}
4233/// tree->Draw("Alt$(arr3[0],0)+Alt$(arr3[1],0)+Alt$(arr3[2],0)");
4234/// ~~~
4235/// will draw the sum arr3 for the index 0 to min(2,actual_size_of_arr3-1)
4236/// As a comparison
4237/// ~~~ {.cpp}
4238/// tree->Draw("arr3[0]+arr3[1]+arr3[2]");
4239/// ~~~
4240/// will draw the sum arr3 for the index 0 to 2 only if the
4241/// actual_size_of_arr3 is greater or equal to 3.
4242/// Note that the array in 'primary' is flattened/linearized thus using
4243/// `Alt$` with multi-dimensional arrays of different dimensions in unlikely
4244/// to yield the expected results. To visualize a bit more what elements
4245/// would be matched by TTree::Draw, TTree::Scan can be used:
4246/// ~~~ {.cpp}
4247/// tree->Scan("arr1:Alt$(arr2,0)");
4248/// ~~~
4249/// will print on one line the value of arr1 and (arr2,0) that will be
4250/// matched by
4251/// ~~~ {.cpp}
4252/// tree->Draw("arr1-Alt$(arr2,0)");
4253/// ~~~
4254/// The ternary operator is not directly supported in TTree::Draw however, to plot the
4255/// equivalent of `var2<20 ? -99 : var1`, you can use:
4256/// ~~~ {.cpp}
4257/// tree->Draw("(var2<20)*99+(var2>=20)*var1","");
4258/// ~~~
4259///
4260/// ### Drawing a user function accessing the TTree data directly
4261///
4262/// If the formula contains a file name, TTree::MakeProxy will be used
4263/// to load and execute this file. In particular it will draw the
4264/// result of a function with the same name as the file. The function
4265/// will be executed in a context where the name of the branches can
4266/// be used as a C++ variable.
4267///
4268/// For example draw px using the file hsimple.root (generated by the
4269/// hsimple.C tutorial), we need a file named hsimple.cxx:
4270/// ~~~ {.cpp}
4271/// double hsimple() {
4272/// return px;
4273/// }
4274/// ~~~
4275/// MakeProxy can then be used indirectly via the TTree::Draw interface
4276/// as follow:
4277/// ~~~ {.cpp}
4278/// new TFile("hsimple.root")
4279/// ntuple->Draw("hsimple.cxx");
4280/// ~~~
4281/// A more complete example is available in the tutorials directory:
4282/// `h1analysisProxy.cxx`, `h1analysProxy.h` and `h1analysisProxyCut.C`
4283/// which reimplement the selector found in `h1analysis.C`
4284///
4285/// The main features of this facility are:
4286///
4287/// * on-demand loading of branches
4288/// * ability to use the 'branchname' as if it was a data member
4289/// * protection against array out-of-bound
4290/// * ability to use the branch data as object (when the user code is available)
4291///
4292/// See TTree::MakeProxy for more details.
4293///
4294/// ### Making a Profile histogram
4295///
4296/// In case of a 2-Dim expression, one can generate a TProfile histogram
4297/// instead of a TH2F histogram by specifying option=prof or option=profs
4298/// or option=profi or option=profg ; the trailing letter select the way
4299/// the bin error are computed, See TProfile2D::SetErrorOption for
4300/// details on the differences.
4301/// The option=prof is automatically selected in case of y:x>>pf
4302/// where pf is an existing TProfile histogram.
4303///
4304/// ### Making a 2D Profile histogram
4305///
4306/// In case of a 3-Dim expression, one can generate a TProfile2D histogram
4307/// instead of a TH3F histogram by specifying option=prof or option=profs.
4308/// or option=profi or option=profg ; the trailing letter select the way
4309/// the bin error are computed, See TProfile2D::SetErrorOption for
4310/// details on the differences.
4311/// The option=prof is automatically selected in case of z:y:x>>pf
4312/// where pf is an existing TProfile2D histogram.
4313///
4314/// ### Making a 5D plot using GL
4315///
4316/// If option GL5D is specified together with 5 variables, a 5D plot is drawn
4317/// using OpenGL. See $ROOTSYS/tutorials/io/tree/tree502_staff.C as example.
4318///
4319/// ### Making a parallel coordinates plot
4320///
4321/// In case of a 2-Dim or more expression with the option=para, one can generate
4322/// a parallel coordinates plot. With that option, the number of dimensions is
4323/// arbitrary. Giving more than 4 variables without the option=para or
4324/// option=candle or option=goff will produce an error.
4325///
4326/// ### Making a candle sticks chart
4327///
4328/// In case of a 2-Dim or more expression with the option=candle, one can generate
4329/// a candle sticks chart. With that option, the number of dimensions is
4330/// arbitrary. Giving more than 4 variables without the option=para or
4331/// option=candle or option=goff will produce an error.
4332///
4333/// ### Normalizing the output histogram to 1
4334///
4335/// When option contains "norm" the output histogram is normalized to 1.
4336///
4337/// ### Saving the result of Draw to a TEventList, a TEntryList or a TEntryListArray
4338///
4339/// TTree::Draw can be used to fill a TEventList object (list of entry numbers)
4340/// instead of histogramming one variable.
4341/// If varexp0 has the form >>elist , a TEventList object named "elist"
4342/// is created in the current directory. elist will contain the list
4343/// of entry numbers satisfying the current selection.
4344/// If option "entrylist" is used, a TEntryList object is created
4345/// If the selection contains arrays, vectors or any container class and option
4346/// "entrylistarray" is used, a TEntryListArray object is created
4347/// containing also the subentries satisfying the selection, i.e. the indices of
4348/// the branches which hold containers classes.
4349/// Example:
4350/// ~~~ {.cpp}
4351/// tree.Draw(">>yplus","y>0")
4352/// ~~~
4353/// will create a TEventList object named "yplus" in the current directory.
4354/// In an interactive session, one can type (after TTree::Draw)
4355/// ~~~ {.cpp}
4356/// yplus.Print("all")
4357/// ~~~
4358/// to print the list of entry numbers in the list.
4359/// ~~~ {.cpp}
4360/// tree.Draw(">>yplus", "y>0", "entrylist")
4361/// ~~~
4362/// will create a TEntryList object names "yplus" in the current directory
4363/// ~~~ {.cpp}
4364/// tree.Draw(">>yplus", "y>0", "entrylistarray")
4365/// ~~~
4366/// will create a TEntryListArray object names "yplus" in the current directory
4367///
4368/// By default, the specified entry list is reset.
4369/// To continue to append data to an existing list, use "+" in front
4370/// of the list name;
4371/// ~~~ {.cpp}
4372/// tree.Draw(">>+yplus","y>0")
4373/// ~~~
4374/// will not reset yplus, but will enter the selected entries at the end
4375/// of the existing list.
4376///
4377/// ### Using a TEventList, TEntryList or TEntryListArray as Input
4378///
4379/// Once a TEventList or a TEntryList object has been generated, it can be used as input
4380/// for TTree::Draw. Use TTree::SetEventList or TTree::SetEntryList to set the
4381/// current event list
4382///
4383/// Example 1:
4384/// ~~~ {.cpp}
4385/// TEventList *elist = (TEventList*)gDirectory->Get("yplus");
4386/// tree->SetEventList(elist);
4387/// tree->Draw("py");
4388/// ~~~
4389/// Example 2:
4390/// ~~~ {.cpp}
4391/// TEntryList *elist = (TEntryList*)gDirectory->Get("yplus");
4392/// tree->SetEntryList(elist);
4393/// tree->Draw("py");
4394/// ~~~
4395/// If a TEventList object is used as input, a new TEntryList object is created
4396/// inside the SetEventList function. In case of a TChain, all tree headers are loaded
4397/// for this transformation. This new object is owned by the chain and is deleted
4398/// with it, unless the user extracts it by calling GetEntryList() function.
4399/// See also comments to SetEventList() function of TTree and TChain.
4400///
4401/// If arrays are used in the selection criteria and TEntryListArray is not used,
4402/// all the entries that have at least one element of the array that satisfy the selection
4403/// are entered in the list.
4404///
4405/// Example:
4406/// ~~~ {.cpp}
4407/// tree.Draw(">>pyplus","fTracks.fPy>0");
4408/// tree->SetEventList(pyplus);
4409/// tree->Draw("fTracks.fPy");
4410/// ~~~
4411/// will draw the fPy of ALL tracks in event with at least one track with
4412/// a positive fPy.
4413///
4414/// To select only the elements that did match the original selection
4415/// use TEventList::SetReapplyCut or TEntryList::SetReapplyCut.
4416///
4417/// Example:
4418/// ~~~ {.cpp}
4419/// tree.Draw(">>pyplus","fTracks.fPy>0");
4420/// pyplus->SetReapplyCut(true);
4421/// tree->SetEventList(pyplus);
4422/// tree->Draw("fTracks.fPy");
4423/// ~~~
4424/// will draw the fPy of only the tracks that have a positive fPy.
4425///
4426/// To draw only the elements that match a selection in case of arrays,
4427/// you can also use TEntryListArray (faster in case of a more general selection).
4428///
4429/// Example:
4430/// ~~~ {.cpp}
4431/// tree.Draw(">>pyplus","fTracks.fPy>0", "entrylistarray");
4432/// tree->SetEntryList(pyplus);
4433/// tree->Draw("fTracks.fPy");
4434/// ~~~
4435/// will draw the fPy of only the tracks that have a positive fPy,
4436/// but without redoing the selection.
4437///
4438/// Note: Use tree->SetEventList(0) if you do not want use the list as input.
4439///
4440/// ### How to obtain more info from TTree::Draw
4441///
4442/// Once TTree::Draw has been called, it is possible to access useful
4443/// information still stored in the TTree object via the following functions:
4444///
4445/// - GetSelectedRows() // return the number of values accepted by the selection expression. In case where no selection was specified, returns the number of values processed.
4446/// - GetV1() // returns a pointer to the double array of V1
4447/// - GetV2() // returns a pointer to the double array of V2
4448/// - GetV3() // returns a pointer to the double array of V3
4449/// - GetV4() // returns a pointer to the double array of V4
4450/// - GetW() // returns a pointer to the double array of Weights where weight equal the result of the selection expression.
4451///
4452/// where V1,V2,V3 correspond to the expressions in
4453/// ~~~ {.cpp}
4454/// TTree::Draw("V1:V2:V3:V4",selection);
4455/// ~~~
4456/// If the expression has more than 4 component use GetVal(index)
4457///
4458/// Example:
4459/// ~~~ {.cpp}
4460/// Root > ntuple->Draw("py:px","pz>4");
4461/// Root > TGraph *gr = new TGraph(ntuple->GetSelectedRows(),
4462/// ntuple->GetV2(), ntuple->GetV1());
4463/// Root > gr->Draw("ap"); //draw graph in current pad
4464/// ~~~
4465///
4466/// A more complete complete tutorial (treegetval.C) shows how to use the
4467/// GetVal() method.
4468///
4469/// creates a TGraph object with a number of points corresponding to the
4470/// number of entries selected by the expression "pz>4", the x points of the graph
4471/// being the px values of the Tree and the y points the py values.
4472///
4473/// Important note: By default TTree::Draw creates the arrays obtained
4474/// with GetW, GetV1, GetV2, GetV3, GetV4, GetVal with a length corresponding
4475/// to the parameter fEstimate. The content will be the last `GetSelectedRows() % GetEstimate()`
4476/// values calculated.
4477/// By default fEstimate=1000000 and can be modified
4478/// via TTree::SetEstimate. To keep in memory all the results (in case
4479/// where there is only one result per entry), use
4480/// ~~~ {.cpp}
4481/// tree->SetEstimate(tree->GetEntries()+1); // same as tree->SetEstimate(-1);
4482/// ~~~
4483/// You must call SetEstimate if the expected number of selected rows
4484/// you need to look at is greater than 1000000.
4485///
4486/// You can use the option "goff" to turn off the graphics output
4487/// of TTree::Draw in the above example.
4488///
4489/// ### Automatic interface to TTree::Draw via the TTreeViewer
4490///
4491/// A complete graphical interface to this function is implemented
4492/// in the class TTreeViewer.
4493/// To start the TTreeViewer, three possibilities:
4494/// - select TTree context menu item "StartViewer"
4495/// - type the command "TTreeViewer TV(treeName)"
4496/// - execute statement "tree->StartViewer();"
4498Long64_t TTree::Draw(const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
4499{
4500 GetPlayer();
4501 if (fPlayer)
4502 return fPlayer->DrawSelect(varexp,selection,option,nentries,firstentry);
4503 return -1;
4504}
4505
4506////////////////////////////////////////////////////////////////////////////////
4507/// Remove some baskets from memory.
4509void TTree::DropBaskets()
4510{
4511 TBranch* branch = nullptr;
4513 for (Int_t i = 0; i < nb; ++i) {
4514 branch = (TBranch*) fBranches.UncheckedAt(i);
4515 branch->DropBaskets("all");
4516 }
4517}
4518
4519////////////////////////////////////////////////////////////////////////////////
4520/// Drop branch buffers to accommodate nbytes below MaxVirtualsize.
4523{
4524 // Be careful not to remove current read/write buffers.
4525 Int_t nleaves = fLeaves.GetEntriesFast();
4526 for (Int_t i = 0; i < nleaves; ++i) {
4527 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
4528 TBranch* branch = (TBranch*) leaf->GetBranch();
4529 Int_t nbaskets = branch->GetListOfBaskets()->GetEntries();
4530 for (Int_t j = 0; j < nbaskets - 1; ++j) {
4531 if ((j == branch->GetReadBasket()) || (j == branch->GetWriteBasket())) {
4532 continue;
4533 }
4534 TBasket* basket = (TBasket*)branch->GetListOfBaskets()->UncheckedAt(j);
4535 if (basket) {
4536 basket->DropBuffers();
4538 return;
4539 }
4540 }
4541 }
4542 }
4543}
4544
4545////////////////////////////////////////////////////////////////////////////////
4546/// Fill all branches.
4547///
4548/// This function loops on all the branches of this tree. For
4549/// each branch, it copies to the branch buffer (basket) the current
4550/// values of the leaves data types. If a leaf is a simple data type,
4551/// a simple conversion to a machine independent format has to be done.
4552///
4553/// This machine independent version of the data is copied into a
4554/// basket (each branch has its own basket). When a basket is full
4555/// (32k worth of data by default), it is then optionally compressed
4556/// and written to disk (this operation is also called committing or
4557/// 'flushing' the basket). The committed baskets are then
4558/// immediately removed from memory.
4559///
4560/// The function returns the number of bytes committed to the
4561/// individual branches.
4562///
4563/// If a write error occurs, the number of bytes returned is -1.
4564///
4565/// If no data are written, because, e.g., the branch is disabled,
4566/// the number of bytes returned is 0.
4567///
4568/// __The baskets are flushed and the Tree header saved at regular intervals__
4569///
4570/// At regular intervals, when the amount of data written so far is
4571/// greater than fAutoFlush (see SetAutoFlush) all the baskets are flushed to disk.
4572/// This makes future reading faster as it guarantees that baskets belonging to nearby
4573/// entries will be on the same disk region.
4574/// When the first call to flush the baskets happen, we also take this opportunity
4575/// to optimize the baskets buffers.
4576/// We also check if the amount of data written is greater than fAutoSave (see SetAutoSave).
4577/// In this case we also write the Tree header. This makes the Tree recoverable up to this point
4578/// in case the program writing the Tree crashes.
4579/// The decisions to FlushBaskets and Auto Save can be made based either on the number
4580/// of bytes written (fAutoFlush and fAutoSave negative) or on the number of entries
4581/// written (fAutoFlush and fAutoSave positive).
4582/// Note that the user can decide to call FlushBaskets and AutoSave in her event loop
4583/// base on the number of events written instead of the number of bytes written.
4584///
4585/// \note Calling `TTree::FlushBaskets` too often increases the IO time.
4586///
4587/// \note Calling `TTree::AutoSave` too often increases the IO time and also the
4588/// file size.
4589///
4590/// \note This method calls `TTree::ChangeFile` when the tree reaches a size
4591/// greater than `TTree::fgMaxTreeSize`. This doesn't happen if the tree is
4592/// attached to a `TMemFile` or derivate.
4595{
4596 Int_t nbytes = 0;
4597 Int_t nwrite = 0;
4598 Int_t nerror = 0;
4599 Int_t nbranches = fBranches.GetEntriesFast();
4600
4601 // Case of one single super branch. Automatically update
4602 // all the branch addresses if a new object was created.
4603 if (nbranches == 1)
4604 ((TBranch *)fBranches.UncheckedAt(0))->UpdateAddress();
4605
4606 if (fBranchRef)
4607 fBranchRef->Clear();
4608
4609#ifdef R__USE_IMT
4610 const auto useIMT = ROOT::IsImplicitMTEnabled() && fIMTEnabled;
4612 if (useIMT) {
4613 fIMTFlush = true;
4614 fIMTZipBytes.store(0);
4615 fIMTTotBytes.store(0);
4616 }
4617#endif
4618
4619 for (Int_t i = 0; i < nbranches; ++i) {
4620 // Loop over all branches, filling and accumulating bytes written and error counts.
4621 TBranch *branch = (TBranch *)fBranches.UncheckedAt(i);
4622
4623 if (branch->TestBit(kDoNotProcess))
4624 continue;
4625
4626#ifndef R__USE_IMT
4627 nwrite = branch->FillImpl(nullptr);
4628#else
4629 nwrite = branch->FillImpl(useIMT ? &imtHelper : nullptr);
4630#endif
4631 if (nwrite < 0) {
4632 if (nerror < 2) {
4633 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld\n"
4634 " This error is symptomatic of a Tree created as a memory-resident Tree\n"
4635 " Instead of doing:\n"
4636 " TTree *T = new TTree(...)\n"
4637 " TFile *f = new TFile(...)\n"
4638 " you should do:\n"
4639 " TFile *f = new TFile(...)\n"
4640 " TTree *T = new TTree(...)\n\n",
4641 GetName(), branch->GetName(), nwrite, fEntries + 1);
4642 } else {
4643 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld", GetName(), branch->GetName(), nwrite,
4644 fEntries + 1);
4645 }
4646 ++nerror;
4647 } else {
4648 nbytes += nwrite;
4649 }
4650 }
4651
4652#ifdef R__USE_IMT
4653 if (fIMTFlush) {
4654 imtHelper.Wait();
4655 fIMTFlush = false;
4656 const_cast<TTree *>(this)->AddTotBytes(fIMTTotBytes);
4657 const_cast<TTree *>(this)->AddZipBytes(fIMTZipBytes);
4658 nbytes += imtHelper.GetNbytes();
4659 nerror += imtHelper.GetNerrors();
4660 }
4661#endif
4662
4663 if (fBranchRef)
4664 fBranchRef->Fill();
4665
4666 ++fEntries;
4667
4668 if (fEntries > fMaxEntries)
4669 KeepCircular();
4670
4671 if (gDebug > 0)
4672 Info("TTree::Fill", " - A: %d %lld %lld %lld %lld %lld %lld \n", nbytes, fEntries, fAutoFlush, fAutoSave,
4674
4675 bool autoFlush = false;
4676 bool autoSave = false;
4677
4678 if (fAutoFlush != 0 || fAutoSave != 0) {
4679 // Is it time to flush or autosave baskets?
4680 if (fFlushedBytes == 0) {
4681 // If fFlushedBytes == 0, it means we never flushed or saved, so
4682 // we need to check if it's time to do it and recompute the values
4683 // of fAutoFlush and fAutoSave in terms of the number of entries.
4684 // Decision can be based initially either on the number of bytes
4685 // or the number of entries written.
4686 Long64_t zipBytes = GetZipBytes();
4687
4688 if (fAutoFlush)
4689 autoFlush = fAutoFlush < 0 ? (zipBytes > -fAutoFlush) : fEntries % fAutoFlush == 0;
4690
4691 if (fAutoSave)
4692 autoSave = fAutoSave < 0 ? (zipBytes > -fAutoSave) : fEntries % fAutoSave == 0;
4693
4694 if (autoFlush || autoSave) {
4695 // First call FlushBasket to make sure that fTotBytes is up to date.
4697 autoFlush = false; // avoid auto flushing again later
4698
4699 // When we are in one-basket-per-cluster mode, there is no need to optimize basket:
4700 // they will automatically grow to the size needed for an event cluster (with the basket
4701 // shrinking preventing them from growing too much larger than the actually-used space).
4703 OptimizeBaskets(GetTotBytes(), 1, "");
4704 if (gDebug > 0)
4705 Info("TTree::Fill", "OptimizeBaskets called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n",
4707 }
4709 fAutoFlush = fEntries; // Use test on entries rather than bytes
4710
4711 // subsequently in run
4712 if (fAutoSave < 0) {
4713 // Set fAutoSave to the largest integer multiple of
4714 // fAutoFlush events such that fAutoSave*fFlushedBytes
4715 // < (minus the input value of fAutoSave)
4716 Long64_t totBytes = GetTotBytes();
4717 if (zipBytes != 0) {
4718 fAutoSave = TMath::Max(fAutoFlush, fEntries * ((-fAutoSave / zipBytes) / fEntries));
4719 } else if (totBytes != 0) {
4720 fAutoSave = TMath::Max(fAutoFlush, fEntries * ((-fAutoSave / totBytes) / fEntries));
4721 } else {
4723 TTree::Class()->WriteBuffer(b, (TTree *)this);
4724 Long64_t total = b.Length();
4726 }
4727 } else if (fAutoSave > 0) {
4729 }
4730
4731 if (fAutoSave != 0 && fEntries >= fAutoSave)
4732 autoSave = true;
4733
4734 if (gDebug > 0)
4735 Info("TTree::Fill", "First AutoFlush. fAutoFlush = %lld, fAutoSave = %lld\n", fAutoFlush, fAutoSave);
4736 }
4737 } else {
4738 // Check if we need to auto flush
4739 if (fAutoFlush) {
4740 if (fNClusterRange == 0)
4741 autoFlush = fEntries > 1 && fEntries % fAutoFlush == 0;
4742 else
4743 autoFlush = (fEntries - (fClusterRangeEnd[fNClusterRange - 1] + 1)) % fAutoFlush == 0;
4744 }
4745 // Check if we need to auto save
4746 if (fAutoSave)
4747 autoSave = fEntries % fAutoSave == 0;
4748 }
4749 }
4750
4751 if (autoFlush) {
4753 if (gDebug > 0)
4754 Info("TTree::Fill", "FlushBaskets() called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n", fEntries,
4757 }
4758
4759 if (autoSave) {
4760 AutoSave(); // does not call FlushBasketsImpl() again
4761 if (gDebug > 0)
4762 Info("TTree::Fill", "AutoSave called at entry %lld, fZipBytes=%lld, fSavedBytes=%lld\n", fEntries,
4764 }
4765
4766 // Check that output file is still below the maximum size.
4767 // If above, close the current file and continue on a new file.
4768 // Currently, the automatic change of file is restricted
4769 // to the case where the tree is in the top level directory.
4770 if (fDirectory)
4771 if (TFile *file = fDirectory->GetFile())
4772 if (static_cast<TDirectory *>(file) == fDirectory && (file->GetEND() > fgMaxTreeSize))
4773 // Changing file clashes with the design of TMemFile and derivates, see #6523.
4774 if (!(dynamic_cast<TMemFile *>(file)))
4775 ChangeFile(file);
4776
4777 return nerror == 0 ? nbytes : -1;
4778}
4779
4780////////////////////////////////////////////////////////////////////////////////
4781/// Search in the array for a branch matching the branch name,
4782/// with the branch possibly expressed as a 'full' path name (with dots).
4784static TBranch *R__FindBranchHelper(TObjArray *list, const char *branchname) {
4785 if (list==nullptr || branchname == nullptr || branchname[0] == '\0') return nullptr;
4786
4787 Int_t nbranches = list->GetEntries();
4788
4789 UInt_t brlen = strlen(branchname);
4790
4791 for(Int_t index = 0; index < nbranches; ++index) {
4792 TBranch *where = (TBranch*)list->UncheckedAt(index);
4793
4794 const char *name = where->GetName();
4795 UInt_t len = strlen(name);
4796 if (len && name[len-1]==']') {
4797 const char *dim = strchr(name,'[');
4798 if (dim) {
4799 len = dim - name;
4800 }
4801 }
4802 if (brlen == len && strncmp(branchname,name,len)==0) {
4803 return where;
4804 }
4805 TBranch *next = nullptr;
4806 if ((brlen >= len) && (branchname[len] == '.')
4807 && strncmp(name, branchname, len) == 0) {
4808 // The prefix subbranch name match the branch name.
4809
4810 next = where->FindBranch(branchname);
4811 if (!next) {
4812 next = where->FindBranch(branchname+len+1);
4813 }
4814 if (next) return next;
4815 }
4816 const char *dot = strchr((char*)branchname,'.');
4817 if (dot) {
4818 if (len==(size_t)(dot-branchname) &&
4819 strncmp(branchname,name,dot-branchname)==0 ) {
4820 return R__FindBranchHelper(where->GetListOfBranches(),dot+1);
4821 }
4822 }
4823 }
4824 return nullptr;
4825}
4826
4827////////////////////////////////////////////////////////////////////////////////
4828/// Return the branch that correspond to the path 'branchname', which can
4829/// include the name of the tree or the omitted name of the parent branches.
4830/// In case of ambiguity, returns the first match.
4832TBranch* TTree::FindBranch(const char* branchname)
4833{
4834 // We already have been visited while recursively looking
4835 // through the friends tree, let return
4837 return nullptr;
4838 }
4839
4840 if (!branchname)
4841 return nullptr;
4842
4843 TBranch* branch = nullptr;
4844 // If the first part of the name match the TTree name, look for the right part in the
4845 // list of branches.
4846 // This will allow the branchname to be preceded by
4847 // the name of this tree.
4848 if (strncmp(fName.Data(),branchname,fName.Length())==0 && branchname[fName.Length()]=='.') {
4849 branch = R__FindBranchHelper( GetListOfBranches(), branchname + fName.Length() + 1);
4850 if (branch) return branch;
4851 }
4852 // If we did not find it, let's try to find the full name in the list of branches.
4853 branch = R__FindBranchHelper(GetListOfBranches(), branchname);
4854 if (branch) return branch;
4855
4856 // If we still did not find, let's try to find it within each branch assuming it does not the branch name.
4857 TIter next(GetListOfBranches());
4858 while ((branch = (TBranch*) next())) {
4859 TBranch* nestedbranch = branch->FindBranch(branchname);
4860 if (nestedbranch) {
4861 return nestedbranch;
4862 }
4863 }
4864
4865 // Search in list of friends.
4866 if (!fFriends) {
4867 return nullptr;
4868 }
4869 TFriendLock lock(this, kFindBranch);
4870 TIter nextf(fFriends);
4871 TFriendElement* fe = nullptr;
4872 while ((fe = (TFriendElement*) nextf())) {
4873 TTree* t = fe->GetTree();
4874 if (!t) {
4875 continue;
4876 }
4877 // If the alias is present replace it with the real name.
4878 const char *subbranch = strstr(branchname, fe->GetName());
4879 if (subbranch != branchname) {
4880 subbranch = nullptr;
4881 }
4882 if (subbranch) {
4883 subbranch += strlen(fe->GetName());
4884 if (*subbranch != '.') {
4885 subbranch = nullptr;
4886 } else {
4887 ++subbranch;
4888 }
4889 }
4890 std::ostringstream name;
4891 if (subbranch) {
4892 name << t->GetName() << "." << subbranch;
4893 } else {
4894 name << branchname;
4895 }
4896 branch = t->FindBranch(name.str().c_str());
4897 if (branch) {
4898 return branch;
4899 }
4900 }
4901 return nullptr;
4902}
4903
4904////////////////////////////////////////////////////////////////////////////////
4905/// Find leaf..
4907TLeaf* TTree::FindLeaf(const char* searchname)
4908{
4909 if (!searchname)
4910 return nullptr;
4911
4912 // We already have been visited while recursively looking
4913 // through the friends tree, let's return.
4915 return nullptr;
4916 }
4917
4918 // This will allow the branchname to be preceded by
4919 // the name of this tree.
4920 const char* subsearchname = strstr(searchname, GetName());
4921 if (subsearchname != searchname) {
4922 subsearchname = nullptr;
4923 }
4924 if (subsearchname) {
4925 subsearchname += strlen(GetName());
4926 if (*subsearchname != '.') {
4927 subsearchname = nullptr;
4928 } else {
4929 ++subsearchname;
4930 if (subsearchname[0] == 0) {
4931 subsearchname = nullptr;
4932 }
4933 }
4934 }
4935
4936 TString leafname;
4937 TString leaftitle;
4938 TString longname;
4939 TString longtitle;
4940
4941 const bool searchnameHasDot = strchr(searchname, '.') != nullptr;
4942
4943 // For leaves we allow for one level up to be prefixed to the name.
4944 TIter next(GetListOfLeaves());
4945 TLeaf* leaf = nullptr;
4946 while ((leaf = (TLeaf*) next())) {
4947 leafname = leaf->GetName();
4948 Ssiz_t dim = leafname.First('[');
4949 if (dim >= 0) leafname.Remove(dim);
4950
4951 if (leafname == searchname) {
4952 return leaf;
4953 }
4954 if (subsearchname && leafname == subsearchname) {
4955 return leaf;
4956 }
4957 // The TLeafElement contains the branch name
4958 // in its name, let's use the title.
4959 leaftitle = leaf->GetTitle();
4960 dim = leaftitle.First('[');
4961 if (dim >= 0) leaftitle.Remove(dim);
4962
4963 if (leaftitle == searchname) {
4964 return leaf;
4965 }
4966 if (subsearchname && leaftitle == subsearchname) {
4967 return leaf;
4968 }
4969 if (!searchnameHasDot)
4970 continue;
4971 TBranch* branch = leaf->GetBranch();
4972 if (branch) {
4973 longname.Form("%s.%s",branch->GetName(),leafname.Data());
4974 dim = longname.First('[');
4975 if (dim>=0) longname.Remove(dim);
4976 if (longname == searchname) {
4977 return leaf;
4978 }
4979 if (subsearchname && longname == subsearchname) {
4980 return leaf;
4981 }
4982 longtitle.Form("%s.%s",branch->GetName(),leaftitle.Data());
4983 dim = longtitle.First('[');
4984 if (dim>=0) longtitle.Remove(dim);
4985 if (longtitle == searchname) {
4986 return leaf;
4987 }
4988 if (subsearchname && longtitle == subsearchname) {
4989 return leaf;
4990 }
4991 // The following is for the case where the branch is only
4992 // a sub-branch. Since we do not see it through
4993 // TTree::GetListOfBranches, we need to see it indirectly.
4994 // This is the less sturdy part of this search ... it may
4995 // need refining ...
4996 if (strstr(searchname, ".") && !strcmp(searchname, branch->GetName())) {
4997 return leaf;
4998 }
4999 if (subsearchname && strstr(subsearchname, ".") && !strcmp(subsearchname, branch->GetName())) {
5000 return leaf;
5001 }
5002 }
5003 }
5004 // Search in list of friends.
5005 if (!fFriends) {
5006 return nullptr;
5007 }
5008 TFriendLock lock(this, kFindLeaf);
5009 TIter nextf(fFriends);
5010 TFriendElement* fe = nullptr;
5011 while ((fe = (TFriendElement*) nextf())) {
5012 TTree* t = fe->GetTree();
5013 if (!t) {
5014 continue;
5015 }
5016 // If the alias is present replace it with the real name.
5017 subsearchname = strstr(searchname, fe->GetName());
5018 if (subsearchname != searchname) {
5019 subsearchname = nullptr;
5020 }
5021 if (subsearchname) {
5022 subsearchname += strlen(fe->GetName());
5023 if (*subsearchname != '.') {
5024 subsearchname = nullptr;
5025 } else {
5026 ++subsearchname;
5027 }
5028 }
5029 if (subsearchname) {
5030 leafname.Form("%s.%s",t->GetName(),subsearchname);
5031 } else {
5032 leafname = searchname;
5033 }
5034 leaf = t->FindLeaf(leafname);
5035 if (leaf) {
5036 return leaf;
5037 }
5038 }
5039 return nullptr;
5040}
5041
5042////////////////////////////////////////////////////////////////////////////////
5043/// Fit a projected item(s) from a tree.
5044///
5045/// funcname is a TF1 function.
5046///
5047/// See TTree::Draw() for explanations of the other parameters.
5048///
5049/// By default the temporary histogram created is called htemp.
5050/// If varexp contains >>hnew , the new histogram created is called hnew
5051/// and it is kept in the current directory.
5052///
5053/// The function returns the number of selected entries.
5054///
5055/// Example:
5056/// ~~~ {.cpp}
5057/// tree.Fit(pol4,"sqrt(x)>>hsqrt","y>0")
5058/// ~~~
5059/// will fit sqrt(x) and save the histogram as "hsqrt" in the current
5060/// directory.
5061///
5062/// See also TTree::UnbinnedFit
5063///
5064/// ## Return status
5065///
5066/// The function returns the status of the histogram fit (see TH1::Fit)
5067/// If no entries were selected, the function returns -1;
5068/// (i.e. fitResult is null if the fit is OK)
5070Int_t TTree::Fit(const char* funcname, const char* varexp, const char* selection, Option_t* option, Option_t* goption, Long64_t nentries, Long64_t firstentry)
5071{
5072 GetPlayer();
5073 if (fPlayer) {
5074 return fPlayer->Fit(funcname, varexp, selection, option, goption, nentries, firstentry);
5075 }
5076 return -1;
5077}
5078
5079namespace {
5080struct BoolRAIIToggle {
5081 bool &m_val;
5082
5083 BoolRAIIToggle(bool &val) : m_val(val) { m_val = true; }
5084 ~BoolRAIIToggle() { m_val = false; }
5085};
5086}
5087
5088////////////////////////////////////////////////////////////////////////////////
5089/// Write to disk all the basket that have not yet been individually written and
5090/// create an event cluster boundary (by default).
5091///
5092/// If the caller wishes to flush the baskets but not create an event cluster,
5093/// then set create_cluster to false.
5094///
5095/// If ROOT has IMT-mode enabled, this will launch multiple TBB tasks in parallel
5096/// via TThreadExecutor to do this operation; one per basket compression. If the
5097/// caller utilizes TBB also, care must be taken to prevent deadlocks.
5098///
5099/// For example, let's say the caller holds mutex A and calls FlushBaskets; while
5100/// TBB is waiting for the ROOT compression tasks to complete, it may decide to
5101/// run another one of the user's tasks in this thread. If the second user task
5102/// tries to acquire A, then a deadlock will occur. The example call sequence
5103/// looks like this:
5104///
5105/// - User acquires mutex A
5106/// - User calls FlushBaskets.
5107/// - ROOT launches N tasks and calls wait.
5108/// - TBB schedules another user task, T2.
5109/// - T2 tries to acquire mutex A.
5110///
5111/// At this point, the thread will deadlock: the code may function with IMT-mode
5112/// disabled if the user assumed the legacy code never would run their own TBB
5113/// tasks.
5114///
5115/// SO: users of TBB who want to enable IMT-mode should carefully review their
5116/// locking patterns and make sure they hold no coarse-grained application
5117/// locks when they invoke ROOT.
5118///
5119/// Return the number of bytes written or -1 in case of write error.
5120Int_t TTree::FlushBaskets(bool create_cluster) const
5121{
5122 Int_t retval = FlushBasketsImpl();
5123 if (retval == -1) return retval;
5124
5125 if (create_cluster) const_cast<TTree *>(this)->MarkEventCluster();
5126 return retval;
5127}
5128
5129////////////////////////////////////////////////////////////////////////////////
5130/// Internal implementation of the FlushBaskets algorithm.
5131/// Unlike the public interface, this does NOT create an explicit event cluster
5132/// boundary; it is up to the (internal) caller to determine whether that should
5133/// done.
5134///
5135/// Otherwise, the comments for FlushBaskets applies.
5138{
5139 if (!fDirectory) return 0;
5140 Int_t nbytes = 0;
5141 Int_t nerror = 0;
5142 TObjArray *lb = const_cast<TTree*>(this)->GetListOfBranches();
5143 Int_t nb = lb->GetEntriesFast();
5144
5145#ifdef R__USE_IMT
5146 const auto useIMT = ROOT::IsImplicitMTEnabled() && fIMTEnabled;
5147 if (useIMT) {
5148 // ROOT-9668: here we need to check if the size of fSortedBranches is different from the
5149 // size of the list of branches before triggering the initialisation of the fSortedBranches
5150 // container to cover two cases:
5151 // 1. This is the first time we flush. fSortedBranches is empty and we need to fill it.
5152 // 2. We flushed at least once already but a branch has been be added to the tree since then
5153 if (fSortedBranches.size() != unsigned(nb)) { const_cast<TTree*>(this)->InitializeBranchLists(false); }
5154
5155 BoolRAIIToggle sentry(fIMTFlush);
5156 fIMTZipBytes.store(0);
5157 fIMTTotBytes.store(0);
5158 std::atomic<Int_t> nerrpar(0);
5159 std::atomic<Int_t> nbpar(0);
5160 std::atomic<Int_t> pos(0);
5161
5162 auto mapFunction = [&]() {
5163 // The branch to process is obtained when the task starts to run.
5164 // This way, since branches are sorted, we make sure that branches
5165 // leading to big tasks are processed first. If we assigned the
5166 // branch at task creation time, the scheduler would not necessarily
5167 // respect our sorting.
5168 Int_t j = pos.fetch_add(1);
5169
5170 auto branch = fSortedBranches[j].second;
5171 if (R__unlikely(!branch)) { return; }
5172
5173 if (R__unlikely(gDebug > 0)) {
5174 std::stringstream ss;
5175 ss << std::this_thread::get_id();
5176 Info("FlushBaskets", "[IMT] Thread %s", ss.str().c_str());
5177 Info("FlushBaskets", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5178 }
5179
5180 Int_t nbtask = branch->FlushBaskets();
5181
5182 if (nbtask < 0) { nerrpar++; }
5183 else { nbpar += nbtask; }
5184 };
5185
5187 pool.Foreach(mapFunction, nb);
5188
5189 fIMTFlush = false;
5190 const_cast<TTree*>(this)->AddTotBytes(fIMTTotBytes);
5191 const_cast<TTree*>(this)->AddZipBytes(fIMTZipBytes);
5192
5193 return nerrpar ? -1 : nbpar.load();
5194 }
5195#endif
5196 for (Int_t j = 0; j < nb; j++) {
5197 TBranch* branch = (TBranch*) lb->UncheckedAt(j);
5198 if (branch) {
5199 Int_t nwrite = branch->FlushBaskets();
5200 if (nwrite<0) {
5201 ++nerror;
5202 } else {
5203 nbytes += nwrite;
5204 }
5205 }
5206 }
5207 if (nerror) {
5208 return -1;
5209 } else {
5210 return nbytes;
5211 }
5212}
5213
5214////////////////////////////////////////////////////////////////////////////////
5215/// Returns the expanded value of the alias. Search in the friends if any.
5217const char* TTree::GetAlias(const char* aliasName) const
5218{
5219 // We already have been visited while recursively looking
5220 // through the friends tree, let's return.
5222 return nullptr;
5223 }
5224 if (fAliases) {
5225 TObject* alias = fAliases->FindObject(aliasName);
5226 if (alias) {
5227 return alias->GetTitle();
5228 }
5229 }
5230 if (!fFriends) {
5231 return nullptr;
5232 }
5233 TFriendLock lock(const_cast<TTree*>(this), kGetAlias);
5234 TIter nextf(fFriends);
5235 TFriendElement* fe = nullptr;
5236 while ((fe = (TFriendElement*) nextf())) {
5237 TTree* t = fe->GetTree();
5238 if (t) {
5239 const char* alias = t->GetAlias(aliasName);
5240 if (alias) {
5241 return alias;
5242 }
5243 const char* subAliasName = strstr(aliasName, fe->GetName());
5244 if (subAliasName && (subAliasName[strlen(fe->GetName())] == '.')) {
5245 alias = t->GetAlias(aliasName + strlen(fe->GetName()) + 1);
5246 if (alias) {
5247 return alias;
5248 }
5249 }
5250 }
5251 }
5252 return nullptr;
5253}
5254
5255namespace {
5256/// Do a breadth first search through the implied hierarchy
5257/// of branches.
5258/// To avoid scanning through the list multiple time
5259/// we also remember the 'depth-first' match.
5260TBranch *R__GetBranch(const TObjArray &branches, const char *name)
5261{
5262 TBranch *result = nullptr;
5263 Int_t nb = branches.GetEntriesFast();
5264 for (Int_t i = 0; i < nb; i++) {
5265 TBranch* b = (TBranch*)branches.UncheckedAt(i);
5266 if (!b)
5267 continue;
5268 if (!strcmp(b->GetName(), name)) {
5269 return b;
5270 }
5271 if (!strcmp(b->GetFullName(), name)) {
5272 return b;
5273 }
5274 if (!result)
5275 result = R__GetBranch(*(b->GetListOfBranches()), name);
5276 }
5277 return result;
5278}
5279}
5280
5281////////////////////////////////////////////////////////////////////////////////
5282/// Return pointer to the branch with the given name in this tree or its friends.
5283/// The search is done breadth first.
5285TBranch* TTree::GetBranch(const char* name)
5286{
5287 // We already have been visited while recursively
5288 // looking through the friends tree, let's return.
5290 return nullptr;
5291 }
5292
5293 if (!name)
5294 return nullptr;
5295
5296 // Look for an exact match in the list of top level
5297 // branches.
5299 if (result)
5300 return result;
5301
5302 // Search using branches, breadth first.
5303 result = R__GetBranch(fBranches, name);
5304 if (result)
5305 return result;
5306
5307 // Search using leaves.
5308 TObjArray* leaves = GetListOfLeaves();
5309 Int_t nleaves = leaves->GetEntriesFast();
5310 for (Int_t i = 0; i < nleaves; i++) {
5311 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(i);
5312 TBranch* branch = leaf->GetBranch();
5313 if (!strcmp(branch->GetName(), name)) {
5314 return branch;
5315 }
5316 if (!strcmp(branch->GetFullName(), name)) {
5317 return branch;
5318 }
5319 }
5320
5321 if (!fFriends) {
5322 return nullptr;
5323 }
5324
5325 // Search in list of friends.
5326 TFriendLock lock(this, kGetBranch);
5327 TIter next(fFriends);
5328 TFriendElement* fe = nullptr;
5329 while ((fe = (TFriendElement*) next())) {
5330 TTree* t = fe->GetTree();
5331 if (t) {
5332 TBranch* branch = t->GetBranch(name);
5333 if (branch) {
5334 return branch;
5335 }
5336 }
5337 }
5338
5339 // Second pass in the list of friends when
5340 // the branch name is prefixed by the tree name.
5341 next.Reset();
5342 while ((fe = (TFriendElement*) next())) {
5343 TTree* t = fe->GetTree();
5344 if (!t) {
5345 continue;
5346 }
5347 const char* subname = strstr(name, fe->GetName());
5348 if (subname != name) {
5349 continue;
5350 }
5351 Int_t l = strlen(fe->GetName());
5352 subname += l;
5353 if (*subname != '.') {
5354 continue;
5355 }
5356 subname++;
5357 TBranch* branch = t->GetBranch(subname);
5358 if (branch) {
5359 return branch;
5360 }
5361 }
5362 return nullptr;
5363}
5364
5365////////////////////////////////////////////////////////////////////////////////
5366/// Return status of branch with name branchname.
5367///
5368/// - 0 if branch is not activated
5369/// - 1 if branch is activated
5371bool TTree::GetBranchStatus(const char* branchname) const
5372{
5373 TBranch* br = const_cast<TTree*>(this)->GetBranch(branchname);
5374 if (br) {
5375 return br->TestBit(kDoNotProcess) == 0;
5376 }
5377 return false;
5378}
5379
5380////////////////////////////////////////////////////////////////////////////////
5381/// Static function returning the current branch style.
5382///
5383/// - style = 0 old Branch
5384/// - style = 1 new Bronch
5387{
5388 return fgBranchStyle;
5389}
5390
5391////////////////////////////////////////////////////////////////////////////////
5392/// Used for automatic sizing of the cache.
5393///
5394/// Estimates a suitable size for the tree cache based on AutoFlush.
5395/// A cache sizing factor is taken from the configuration. If this yields zero
5396/// and withDefault is true the historical algorithm for default size is used.
5398Long64_t TTree::GetCacheAutoSize(bool withDefault /* = false */ )
5399{
5400 auto calculateCacheSize = [this](Double_t cacheFactor)
5401 {
5402 Long64_t cacheSize = 0;
5403 if (fAutoFlush < 0) {
5404 cacheSize = Long64_t(-cacheFactor * fAutoFlush);
5405 } else if (fAutoFlush == 0) {
5406 const auto medianClusterSize = GetMedianClusterSize();
5407 if (medianClusterSize > 0)
5408 cacheSize = Long64_t(cacheFactor * 1.5 * medianClusterSize * GetZipBytes() / (fEntries + 1));
5409 else
5410 cacheSize = Long64_t(cacheFactor * 1.5 * 30000000); // use the default value of fAutoFlush
5411 } else {
5412 cacheSize = Long64_t(cacheFactor * 1.5 * fAutoFlush * GetZipBytes() / (fEntries + 1));
5413 }
5414 if (cacheSize >= (INT_MAX / 4)) {
5415 cacheSize = INT_MAX / 4;
5416 }
5417 return cacheSize;
5418 };
5419
5420 const char *stcs;
5421 Double_t cacheFactor = 0.0;
5422 if (!(stcs = gSystem->Getenv("ROOT_TTREECACHE_SIZE")) || !*stcs) {
5423 cacheFactor = gEnv->GetValue("TTreeCache.Size", 1.0);
5424 } else {
5425 cacheFactor = TString(stcs).Atof();
5426 }
5427
5428 if (cacheFactor < 0.0) {
5429 // ignore negative factors
5430 cacheFactor = 0.0;
5431 }
5432
5433 Long64_t cacheSize = calculateCacheSize(cacheFactor);
5434
5435 if (cacheSize < 0) {
5436 cacheSize = 0;
5437 }
5438
5439 if (cacheSize == 0 && withDefault) {
5440 cacheSize = calculateCacheSize(1.0);
5441 }
5442
5443 return cacheSize;
5444}
5445
5446////////////////////////////////////////////////////////////////////////////////
5447/// Return an iterator over the cluster of baskets starting at firstentry.
5448///
5449/// This iterator is not yet supported for TChain object.
5450/// ~~~ {.cpp}
5451/// TTree::TClusterIterator clusterIter = tree->GetClusterIterator(entry);
5452/// Long64_t clusterStart;
5453/// while( (clusterStart = clusterIter()) < tree->GetEntries() ) {
5454/// printf("The cluster starts at %lld and ends at %lld (inclusive)\n",clusterStart,clusterIter.GetNextEntry()-1);
5455/// }
5456/// ~~~
5459{
5460 // create cache if wanted
5461 if (fCacheDoAutoInit)
5463
5464 return TClusterIterator(this,firstentry);
5465}
5466
5467////////////////////////////////////////////////////////////////////////////////
5468/// Return pointer to the current file.
5471{
5472 if (!fDirectory || fDirectory==gROOT) {
5473 return nullptr;
5474 }
5475 return fDirectory->GetFile();
5476}
5477
5478////////////////////////////////////////////////////////////////////////////////
5479/// Return the number of entries matching the selection.
5480/// Return -1 in case of errors.
5481///
5482/// If the selection uses any arrays or containers, we return the number
5483/// of entries where at least one element match the selection.
5484/// GetEntries is implemented using the selector class TSelectorEntries,
5485/// which can be used directly (see code in TTreePlayer::GetEntries) for
5486/// additional option.
5487/// If SetEventList was used on the TTree or TChain, only that subset
5488/// of entries will be considered.
5490Long64_t TTree::GetEntries(const char *selection)
5491{
5492 GetPlayer();
5493 if (fPlayer) {
5494 return fPlayer->GetEntries(selection);
5495 }
5496 return -1;
5497}
5498
5499////////////////////////////////////////////////////////////////////////////////
5500/// Return pointer to the 1st Leaf named name in any Branch of this Tree or
5501/// any branch in the list of friend trees.
5504{
5505 if (fEntries) return fEntries;
5506 if (!fFriends) return 0;
5508 if (!fr) return 0;
5509 TTree *t = fr->GetTree();
5510 if (t==nullptr) return 0;
5511 return t->GetEntriesFriend();
5512}
5513
5514////////////////////////////////////////////////////////////////////////////////
5515/// Read all branches of entry and return total number of bytes read.
5516///
5517/// - `getall = 0` : get only active branches
5518/// - `getall = 1` : get all branches
5519///
5520/// The function returns the number of bytes read from the input buffer.
5521/// If entry does not exist the function returns 0.
5522/// If an I/O error occurs, the function returns -1.
5523///
5524/// If the Tree has friends, also read the friends entry.
5525///
5526/// To activate/deactivate one or more branches, use TBranch::SetBranchStatus
5527/// For example, if you have a Tree with several hundred branches, and you
5528/// are interested only by branches named "a" and "b", do
5529/// ~~~ {.cpp}
5530/// mytree.SetBranchStatus("*",0); //disable all branches
5531/// mytree.SetBranchStatus("a",1);
5532/// mytree.SetBranchStatus("b",1);
5533/// ~~~
5534/// when calling mytree.GetEntry(i); only branches "a" and "b" will be read.
5535///
5536/// __WARNING!!__
5537/// If your Tree has been created in split mode with a parent branch "parent.",
5538/// ~~~ {.cpp}
5539/// mytree.SetBranchStatus("parent",1);
5540/// ~~~
5541/// will not activate the sub-branches of "parent". You should do:
5542/// ~~~ {.cpp}
5543/// mytree.SetBranchStatus("parent*",1);
5544/// ~~~
5545/// Without the trailing dot in the branch creation you have no choice but to
5546/// call SetBranchStatus explicitly for each of the sub branches.
5547///
5548/// An alternative is to call directly
5549/// ~~~ {.cpp}
5550/// brancha.GetEntry(i)
5551/// branchb.GetEntry(i);
5552/// ~~~
5553/// ## IMPORTANT NOTE
5554///
5555/// By default, GetEntry reuses the space allocated by the previous object
5556/// for each branch. You can force the previous object to be automatically
5557/// deleted if you call mybranch.SetAutoDelete(true) (default is false).
5558///
5559/// Example:
5560///
5561/// Consider the example in $ROOTSYS/test/Event.h
5562/// The top level branch in the tree T is declared with:
5563/// ~~~ {.cpp}
5564/// Event *event = 0; //event must be null or point to a valid object
5565/// //it must be initialized
5566/// T.SetBranchAddress("event",&event);
5567/// ~~~
5568/// When reading the Tree, one can choose one of these 3 options:
5569///
5570/// ## OPTION 1
5571///
5572/// ~~~ {.cpp}
5573/// for (Long64_t i=0;i<nentries;i++) {
5574/// T.GetEntry(i);
5575/// // the object event has been filled at this point
5576/// }
5577/// ~~~
5578/// The default (recommended). At the first entry an object of the class
5579/// Event will be created and pointed by event. At the following entries,
5580/// event will be overwritten by the new data. All internal members that are
5581/// TObject* are automatically deleted. It is important that these members
5582/// be in a valid state when GetEntry is called. Pointers must be correctly
5583/// initialized. However these internal members will not be deleted if the
5584/// characters "->" are specified as the first characters in the comment
5585/// field of the data member declaration.
5586///
5587/// If "->" is specified, the pointer member is read via pointer->Streamer(buf).
5588/// In this case, it is assumed that the pointer is never null (case of
5589/// pointer TClonesArray *fTracks in the Event example). If "->" is not
5590/// specified, the pointer member is read via buf >> pointer. In this case
5591/// the pointer may be null. Note that the option with "->" is faster to
5592/// read or write and it also consumes less space in the file.
5593///
5594/// ## OPTION 2
5595///
5596/// The option AutoDelete is set
5597/// ~~~ {.cpp}
5598/// TBranch *branch = T.GetBranch("event");
5599/// branch->SetAddress(&event);
5600/// branch->SetAutoDelete(true);
5601/// for (Long64_t i=0;i<nentries;i++) {
5602/// T.GetEntry(i);
5603/// // the object event has been filled at this point
5604/// }
5605/// ~~~
5606/// In this case, at each iteration, the object event is deleted by GetEntry
5607/// and a new instance of Event is created and filled.
5608///
5609/// ## OPTION 3
5610///
5611/// ~~~ {.cpp}
5612/// Same as option 1, but you delete yourself the event.
5613///
5614/// for (Long64_t i=0;i<nentries;i++) {
5615/// delete event;
5616/// event = 0; // EXTREMELY IMPORTANT
5617/// T.GetEntry(i);
5618/// // the object event has been filled at this point
5619/// }
5620/// ~~~
5621/// It is strongly recommended to use the default option 1. It has the
5622/// additional advantage that functions like TTree::Draw (internally calling
5623/// TTree::GetEntry) will be functional even when the classes in the file are
5624/// not available.
5625///
5626/// Note: See the comments in TBranchElement::SetAddress() for the
5627/// object ownership policy of the underlying (user) data.
5629Int_t TTree::GetEntry(Long64_t entry, Int_t getall)
5630{
5631 // We already have been visited while recursively looking
5632 // through the friends tree, let return
5633 if (kGetEntry & fFriendLockStatus) return 0;
5634
5635 if (entry < 0 || entry >= fEntries) return 0;
5636 Int_t i;
5637 Int_t nbytes = 0;
5638 fReadEntry = entry;
5639
5640 // create cache if wanted
5641 if (fCacheDoAutoInit)
5643
5644 Int_t nbranches = fBranches.GetEntriesUnsafe();
5645 Int_t nb=0;
5646
5647 auto seqprocessing = [&]() {
5648 TBranch *branch;
5649 for (i=0;i<nbranches;i++) {
5650 branch = (TBranch*)fBranches.UncheckedAt(i);
5651 nb = branch->GetEntry(entry, getall);
5652 if (nb < 0) break;
5653 nbytes += nb;
5654 }
5655 };
5656
5657#ifdef R__USE_IMT
5659 if (fSortedBranches.empty())
5661
5662 // Count branches are processed first and sequentially
5663 for (auto branch : fSeqBranches) {
5664 nb = branch->GetEntry(entry, getall);
5665 if (nb < 0) break;
5666 nbytes += nb;
5667 }
5668 if (nb < 0) return nb;
5669
5670 // Enable this IMT use case (activate its locks)
5672
5673 Int_t errnb = 0;
5674 std::atomic<Int_t> pos(0);
5675 std::atomic<Int_t> nbpar(0);
5676
5677 auto mapFunction = [&]() {
5678 // The branch to process is obtained when the task starts to run.
5679 // This way, since branches are sorted, we make sure that branches
5680 // leading to big tasks are processed first. If we assigned the
5681 // branch at task creation time, the scheduler would not necessarily
5682 // respect our sorting.
5683 Int_t j = pos.fetch_add(1);
5684
5685 Int_t nbtask = 0;
5686 auto branch = fSortedBranches[j].second;
5687
5688 if (gDebug > 0) {
5689 std::stringstream ss;
5690 ss << std::this_thread::get_id();
5691 Info("GetEntry", "[IMT] Thread %s", ss.str().c_str());
5692 Info("GetEntry", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5693 }
5694
5695 std::chrono::time_point<std::chrono::system_clock> start, end;
5696
5697 start = std::chrono::system_clock::now();
5698 nbtask = branch->GetEntry(entry, getall);
5699 end = std::chrono::system_clock::now();
5700
5701 Long64_t tasktime = (Long64_t)std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
5702 fSortedBranches[j].first += tasktime;
5703
5704 if (nbtask < 0) errnb = nbtask;
5705 else nbpar += nbtask;
5706 };
5707
5709 pool.Foreach(mapFunction, fSortedBranches.size());
5710
5711 if (errnb < 0) {
5712 nb = errnb;
5713 }
5714 else {
5715 // Save the number of bytes read by the tasks
5716 nbytes += nbpar;
5717
5718 // Re-sort branches if necessary
5722 }
5723 }
5724 }
5725 else {
5726 seqprocessing();
5727 }
5728#else
5729 seqprocessing();
5730#endif
5731 if (nb < 0) return nb;
5732
5733 // GetEntry in list of friends
5734 if (!fFriends) return nbytes;
5735 TFriendLock lock(this,kGetEntry);
5736 TIter nextf(fFriends);
5737 TFriendElement *fe;
5738 while ((fe = (TFriendElement*)nextf())) {
5739 TTree *t = fe->GetTree();
5740 if (t) {
5742 nb = t->GetEntry(t->GetReadEntry(),getall);
5743 } else {
5744 if ( t->LoadTreeFriend(entry,this) >= 0 ) {
5745 nb = t->GetEntry(t->GetReadEntry(),getall);
5746 } else nb = 0;
5747 }
5748 if (nb < 0) return nb;
5749 nbytes += nb;
5750 }
5751 }
5752 return nbytes;
5753}
5754
5755
5756////////////////////////////////////////////////////////////////////////////////
5757/// Divides the top-level branches into two vectors: (i) branches to be
5758/// processed sequentially and (ii) branches to be processed in parallel.
5759/// Even if IMT is on, some branches might need to be processed first and in a
5760/// sequential fashion: in the parallelization of GetEntry, those are the
5761/// branches that store the size of another branch for every entry
5762/// (e.g. the size of an array branch). If such branches were processed
5763/// in parallel with the rest, there could be two threads invoking
5764/// TBranch::GetEntry on one of them at the same time, since a branch that
5765/// depends on a size (or count) branch will also invoke GetEntry on the latter.
5766/// This method can be invoked several times during the event loop if the TTree
5767/// is being written, for example when adding new branches. In these cases, the
5768/// `checkLeafCount` parameter is false.
5769/// \param[in] checkLeafCount True if we need to check whether some branches are
5770/// count leaves.
5772void TTree::InitializeBranchLists(bool checkLeafCount)
5773{
5774 Int_t nbranches = fBranches.GetEntriesFast();
5775
5776 // The special branch fBranchRef needs to be processed sequentially:
5777 // we add it once only.
5778 if (fBranchRef && fBranchRef != fSeqBranches[0]) {
5779 fSeqBranches.push_back(fBranchRef);
5780 }
5781
5782 // The branches to be processed sequentially are those that are the leaf count of another branch
5783 if (checkLeafCount) {
5784 for (Int_t i = 0; i < nbranches; i++) {
5785 TBranch* branch = (TBranch*)fBranches.UncheckedAt(i);
5786 auto leafCount = ((TLeaf*)branch->GetListOfLeaves()->At(0))->GetLeafCount();
5787 if (leafCount) {
5788 auto countBranch = leafCount->GetBranch();
5789 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), countBranch) == fSeqBranches.end()) {
5790 fSeqBranches.push_back(countBranch);
5791 }
5792 }
5793 }
5794 }
5795
5796 // Any branch that is not a leaf count can be safely processed in parallel when reading
5797 // We need to reset the vector to make sure we do not re-add several times the same branch.
5798 if (!checkLeafCount) {
5799 fSortedBranches.clear();
5800 }
5801 for (Int_t i = 0; i < nbranches; i++) {
5802 Long64_t bbytes = 0;
5803 TBranch* branch = (TBranch*)fBranches.UncheckedAt(i);
5804 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), branch) == fSeqBranches.end()) {
5805 bbytes = branch->GetTotBytes("*");
5806 fSortedBranches.emplace_back(bbytes, branch);
5807 }
5808 }
5809
5810 // Initially sort parallel branches by size
5811 std::sort(fSortedBranches.begin(),
5812 fSortedBranches.end(),
5813 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5814 return a.first > b.first;
5815 });
5816
5817 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5818 fSortedBranches[i].first = 0LL;
5819 }
5820}
5821
5822////////////////////////////////////////////////////////////////////////////////
5823/// Sorts top-level branches by the last average task time recorded per branch.
5826{
5827 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5829 }
5830
5831 std::sort(fSortedBranches.begin(),
5832 fSortedBranches.end(),
5833 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5834 return a.first > b.first;
5835 });
5836
5837 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5838 fSortedBranches[i].first = 0LL;
5839 }
5840}
5841
5842////////////////////////////////////////////////////////////////////////////////
5843///Returns the entry list assigned to this tree
5846{
5847 return fEntryList;
5848}
5849
5850////////////////////////////////////////////////////////////////////////////////
5851/// Return entry number corresponding to entry.
5852///
5853/// if no TEntryList set returns entry
5854/// else returns the entry number corresponding to the list index=entry
5857{
5858 if (!fEntryList) {
5859 return entry;
5860 }
5861
5862 return fEntryList->GetEntry(entry);
5863}
5864
5865////////////////////////////////////////////////////////////////////////////////
5866/// Return entry number corresponding to major and minor number.
5867/// Note that this function returns only the entry number, not the data
5868/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
5869/// the BuildIndex function has created a table of Long64_t* of sorted values
5870/// corresponding to val = major<<31 + minor;
5871/// The function performs binary search in this sorted table.
5872/// If it finds a pair that matches val, it returns directly the
5873/// index in the table.
5874/// If an entry corresponding to major and minor is not found, the function
5875/// returns the index of the major,minor pair immediately lower than the
5876/// requested value, ie it will return -1 if the pair is lower than
5877/// the first entry in the index.
5878///
5879/// See also GetEntryNumberWithIndex
5882{
5883 if (!fTreeIndex) {
5884 return -1;
5885 }
5886 return fTreeIndex->GetEntryNumberWithBestIndex(major, minor);
5887}
5888
5889////////////////////////////////////////////////////////////////////////////////
5890/// Return entry number corresponding to major and minor number.
5891/// Note that this function returns only the entry number, not the data
5892/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
5893/// the BuildIndex function has created a table of Long64_t* of sorted values
5894/// corresponding to val = major<<31 + minor;
5895/// The function performs binary search in this sorted table.
5896/// If it finds a pair that matches val, it returns directly the
5897/// index in the table, otherwise it returns -1.
5898///
5899/// See also GetEntryNumberWithBestIndex
5902{
5903 if (!fTreeIndex) {
5904 return -1;
5905 }
5906 return fTreeIndex->GetEntryNumberWithIndex(major, minor);
5907}
5908
5909////////////////////////////////////////////////////////////////////////////////
5910/// Read entry corresponding to major and minor number.
5911///
5912/// The function returns the total number of bytes read.
5913/// If the Tree has friend trees, the corresponding entry with
5914/// the index values (major,minor) is read. Note that the master Tree
5915/// and its friend may have different entry serial numbers corresponding
5916/// to (major,minor).
5919{
5920 // We already have been visited while recursively looking
5921 // through the friends tree, let's return.
5923 return 0;
5924 }
5925 Long64_t serial = GetEntryNumberWithIndex(major, minor);
5926 if (serial < 0) {
5927 return -1;
5928 }
5929 // create cache if wanted
5930 if (fCacheDoAutoInit)
5932
5933 Int_t i;
5934 Int_t nbytes = 0;
5935 fReadEntry = serial;
5936 TBranch *branch;
5937 Int_t nbranches = fBranches.GetEntriesFast();
5938 Int_t nb;
5939 for (i = 0; i < nbranches; ++i) {
5940 branch = (TBranch*)fBranches.UncheckedAt(i);
5941 nb = branch->GetEntry(serial);
5942 if (nb < 0) return nb;
5943 nbytes += nb;
5944 }
5945 // GetEntry in list of friends
5946 if (!fFriends) return nbytes;
5948 TIter nextf(fFriends);
5949 TFriendElement* fe = nullptr;
5950 while ((fe = (TFriendElement*) nextf())) {
5951 TTree *t = fe->GetTree();
5952 if (t) {
5953 serial = t->GetEntryNumberWithIndex(major,minor);
5954 if (serial <0) return -nbytes;
5955 nb = t->GetEntry(serial);
5956 if (nb < 0) return nb;
5957 nbytes += nb;
5958 }
5959 }
5960 return nbytes;
5961}
5962
5963////////////////////////////////////////////////////////////////////////////////
5964/// Return a pointer to the TTree friend whose name or alias is `friendname`.
5966TTree* TTree::GetFriend(const char *friendname) const
5967{
5968
5969 // We already have been visited while recursively
5970 // looking through the friends tree, let's return.
5972 return nullptr;
5973 }
5974 if (!fFriends) {
5975 return nullptr;
5976 }
5977 TFriendLock lock(const_cast<TTree*>(this), kGetFriend);
5978 TIter nextf(fFriends);
5979 TFriendElement* fe = nullptr;
5980 while ((fe = (TFriendElement*) nextf())) {
5981 if (strcmp(friendname,fe->GetName())==0
5982 || strcmp(friendname,fe->GetTreeName())==0) {
5983 return fe->GetTree();
5984 }
5985 }
5986 // After looking at the first level,
5987 // let's see if it is a friend of friends.
5988 nextf.Reset();
5989 fe = nullptr;
5990 while ((fe = (TFriendElement*) nextf())) {
5991 TTree *res = fe->GetTree()->GetFriend(friendname);
5992 if (res) {
5993 return res;
5994 }
5995 }
5996 return nullptr;
5997}
5998
5999////////////////////////////////////////////////////////////////////////////////
6000/// If the 'tree' is a friend, this method returns its alias name.
6001///
6002/// This alias is an alternate name for the tree.
6003///
6004/// It can be used in conjunction with a branch or leaf name in a TTreeFormula,
6005/// to specify in which particular tree the branch or leaf can be found if
6006/// the friend trees have branches or leaves with the same name as the master
6007/// tree.
6008///
6009/// It can also be used in conjunction with an alias created using
6010/// TTree::SetAlias in a TTreeFormula, e.g.:
6011/// ~~~ {.cpp}
6012/// maintree->Draw("treealias.fPx - treealias.myAlias");
6013/// ~~~
6014/// where fPx is a branch of the friend tree aliased as 'treealias' and 'myAlias'
6015/// was created using TTree::SetAlias on the friend tree.
6016///
6017/// However, note that 'treealias.myAlias' will be expanded literally,
6018/// without remembering that it comes from the aliased friend and thus
6019/// the branch name might not be disambiguated properly, which means
6020/// that you may not be able to take advantage of this feature.
6021///
6023const char* TTree::GetFriendAlias(TTree* tree) const
6024{
6025 if ((tree == this) || (tree == GetTree())) {
6026 return nullptr;
6027 }
6028
6029 // We already have been visited while recursively
6030 // looking through the friends tree, let's return.
6032 return nullptr;
6033 }
6034 if (!fFriends) {
6035 return nullptr;
6036 }
6037 TFriendLock lock(const_cast<TTree*>(this), kGetFriendAlias);
6038 TIter nextf(fFriends);
6039 TFriendElement* fe = nullptr;
6040 while ((fe = (TFriendElement*) nextf())) {
6041 TTree* t = fe->GetTree();
6042 if (t == tree) {
6043 return fe->GetName();
6044 }
6045 // Case of a chain:
6046 if (t && t->GetTree() == tree) {
6047 return fe->GetName();
6048 }
6049 }
6050 // After looking at the first level,
6051 // let's see if it is a friend of friends.
6052 nextf.Reset();
6053 fe = nullptr;
6054 while ((fe = (TFriendElement*) nextf())) {
6055 const char* res = fe->GetTree()->GetFriendAlias(tree);
6056 if (res) {
6057 return res;
6058 }
6059 }
6060 return nullptr;
6061}
6062
6063////////////////////////////////////////////////////////////////////////////////
6064/// Returns the current set of IO settings
6066{
6067 return fIOFeatures;
6068}
6069
6070////////////////////////////////////////////////////////////////////////////////
6071/// Creates a new iterator that will go through all the leaves on the tree itself and its friend.
6074{
6075 return new TTreeFriendLeafIter(this, dir);
6076}
6077
6078////////////////////////////////////////////////////////////////////////////////
6079/// Return pointer to the 1st Leaf named name in any Branch of this
6080/// Tree or any branch in the list of friend trees.
6081///
6082/// The leaf name can contain the name of a friend tree with the
6083/// syntax: friend_dir_and_tree.full_leaf_name
6084/// the friend_dir_and_tree can be of the form:
6085/// ~~~ {.cpp}
6086/// TDirectoryName/TreeName
6087/// ~~~
6089TLeaf* TTree::GetLeafImpl(const char* branchname, const char *leafname)
6090{
6091 TLeaf *leaf = nullptr;
6092 if (branchname) {
6093 TBranch *branch = FindBranch(branchname);
6094 if (branch) {
6095 leaf = branch->GetLeaf(leafname);
6096 if (leaf) {
6097 return leaf;
6098 }
6099 }
6100 }
6101 TIter nextl(GetListOfLeaves());
6102 while ((leaf = (TLeaf*)nextl())) {
6103 if (strcmp(leaf->GetFullName(), leafname) != 0 && strcmp(leaf->GetName(), leafname) != 0)
6104 continue; // leafname does not match GetName() nor GetFullName(), this is not the right leaf
6105 if (branchname) {
6106 // check the branchname is also a match
6107 TBranch *br = leaf->GetBranch();
6108 // if a quick comparison with the branch full name is a match, we are done
6109 if (!strcmp(br->GetFullName(), branchname))
6110 return leaf;
6111 UInt_t nbch = strlen(branchname);
6112 const char* brname = br->GetName();
6113 TBranch *mother = br->GetMother();
6114 if (strncmp(brname,branchname,nbch)) {
6115 if (mother != br) {
6116 const char *mothername = mother->GetName();
6117 UInt_t motherlen = strlen(mothername);
6118 if (!strcmp(mothername, branchname)) {
6119 return leaf;
6120 } else if (nbch > motherlen && strncmp(mothername,branchname,motherlen)==0 && (mothername[motherlen-1]=='.' || branchname[motherlen]=='.')) {
6121 // The left part of the requested name match the name of the mother, let's see if the right part match the name of the branch.
6122 if (strncmp(brname,branchname+motherlen+1,nbch-motherlen-1)) {
6123 // No it does not
6124 continue;
6125 } // else we have match so we can proceed.
6126 } else {
6127 // no match
6128 continue;
6129 }
6130 } else {
6131 continue;
6132 }
6133 }
6134 // The start of the branch name is identical to the content
6135 // of 'aname' before the first '/'.
6136 // Let's make sure that it is not longer (we are trying
6137 // to avoid having jet2/value match the branch jet23
6138 if ((strlen(brname) > nbch) && (brname[nbch] != '.') && (brname[nbch] != '[')) {
6139 continue;
6140 }
6141 }
6142 return leaf;
6143 }
6144 if (!fFriends) return nullptr;
6145 TFriendLock lock(this,kGetLeaf);
6146 TIter next(fFriends);
6147 TFriendElement *fe;
6148 while ((fe = (TFriendElement*)next())) {
6149 TTree *t = fe->GetTree();
6150 if (t) {
6151 leaf = t->GetLeaf(branchname, leafname);
6152 if (leaf) return leaf;
6153 }
6154 }
6155
6156 //second pass in the list of friends when the leaf name
6157 //is prefixed by the tree name
6158 TString strippedArg;
6159 next.Reset();
6160 while ((fe = (TFriendElement*)next())) {
6161 TTree *t = fe->GetTree();
6162 if (!t) continue;
6163 const char *subname = strstr(leafname,fe->GetName());
6164 if (subname != leafname) continue;
6165 Int_t l = strlen(fe->GetName());
6166 subname += l;
6167 if (*subname != '.') continue;
6168 subname++;
6169 strippedArg += subname;
6170 leaf = t->GetLeaf(branchname,subname);
6171 if (leaf) return leaf;
6172 }
6173 return nullptr;
6174}
6175
6176////////////////////////////////////////////////////////////////////////////////
6177/// Return pointer to the 1st Leaf named name in any Branch of this
6178/// Tree or any branch in the list of friend trees.
6179///
6180/// The leaf name can contain the name of a friend tree with the
6181/// syntax: friend_dir_and_tree.full_leaf_name
6182/// the friend_dir_and_tree can be of the form:
6183///
6184/// TDirectoryName/TreeName
6186TLeaf* TTree::GetLeaf(const char* branchname, const char *leafname)
6187{
6188 if (leafname == nullptr) return nullptr;
6189
6190 // We already have been visited while recursively looking
6191 // through the friends tree, let return
6193 return nullptr;
6194 }
6195
6196 return GetLeafImpl(branchname,leafname);
6197}
6198
6199////////////////////////////////////////////////////////////////////////////////
6200/// Return pointer to first leaf named "name" in any branch of this
6201/// tree or its friend trees.
6202///
6203/// \param[in] name may be in the form 'branch/leaf'
6204///
6206TLeaf* TTree::GetLeaf(const char *name)
6207{
6208 // Return nullptr if name is invalid or if we have
6209 // already been visited while searching friend trees
6210 if (!name || (kGetLeaf & fFriendLockStatus))
6211 return nullptr;
6212
6213 std::string path(name);
6214 const auto sep = path.find_last_of('/');
6215 if (sep != std::string::npos)
6216 return GetLeafImpl(path.substr(0, sep).c_str(), name+sep+1);
6217
6218 return GetLeafImpl(nullptr, name);
6219}
6220
6221////////////////////////////////////////////////////////////////////////////////
6222/// Return maximum of column with name columname.
6223/// if the Tree has an associated TEventList or TEntryList, the maximum
6224/// is computed for the entries in this list.
6226Double_t TTree::GetMaximum(const char* columname)
6227{
6228 TLeaf* leaf = this->GetLeaf(columname);
6229 if (!leaf) {
6230 return 0;
6231 }
6232
6233 // create cache if wanted
6234 if (fCacheDoAutoInit)
6236
6237 TBranch* branch = leaf->GetBranch();
6238 Double_t cmax = -DBL_MAX;
6239 for (Long64_t i = 0; i < fEntries; ++i) {
6240 Long64_t entryNumber = this->GetEntryNumber(i);
6241 if (entryNumber < 0) break;
6242 branch->GetEntry(entryNumber);
6243 for (Int_t j = 0; j < leaf->GetLen(); ++j) {
6244 Double_t val = leaf->GetValue(j);
6245 if (val > cmax) {
6246 cmax = val;
6247 }
6248 }
6249 }
6250 return cmax;
6251}
6252
6253////////////////////////////////////////////////////////////////////////////////
6254/// Static function which returns the tree file size limit in bytes.
6257{
6258 return fgMaxTreeSize;
6259}
6260
6261////////////////////////////////////////////////////////////////////////////////
6262/// Return minimum of column with name columname.
6263/// if the Tree has an associated TEventList or TEntryList, the minimum
6264/// is computed for the entries in this list.
6266Double_t TTree::GetMinimum(const char* columname)
6267{
6268 TLeaf* leaf = this->GetLeaf(columname);
6269 if (!leaf) {
6270 return 0;
6271 }
6272
6273 // create cache if wanted
6274 if (fCacheDoAutoInit)
6276
6277 TBranch* branch = leaf->GetBranch();
6278 Double_t cmin = DBL_MAX;
6279 for (Long64_t i = 0; i < fEntries; ++i) {
6280 Long64_t entryNumber = this->GetEntryNumber(i);
6281 if (entryNumber < 0) break;
6282 branch->GetEntry(entryNumber);
6283 for (Int_t j = 0;j < leaf->GetLen(); ++j) {
6284 Double_t val = leaf->GetValue(j);
6285 if (val < cmin) {
6286 cmin = val;
6287 }
6288 }
6289 }
6290 return cmin;
6291}
6292
6293////////////////////////////////////////////////////////////////////////////////
6294/// Load the TTreePlayer (if not already done).
6297{
6298 if (fPlayer) {
6299 return fPlayer;
6300 }
6302 return fPlayer;
6303}
6304
6305////////////////////////////////////////////////////////////////////////////////
6306/// Find and return the TTreeCache registered with the file and which may
6307/// contain branches for us.
6310{
6311 TTreeCache *pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6312 if (pe && pe->GetTree() != GetTree())
6313 pe = nullptr;
6314 return pe;
6315}
6316
6317////////////////////////////////////////////////////////////////////////////////
6318/// Find and return the TTreeCache registered with the file and which may
6319/// contain branches for us. If create is true and there is no cache
6320/// a new cache is created with default size.
6322TTreeCache *TTree::GetReadCache(TFile *file, bool create)
6323{
6324 TTreeCache *pe = GetReadCache(file);
6325 if (create && !pe) {
6326 if (fCacheDoAutoInit)
6327 SetCacheSizeAux(true, -1);
6328 pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6329 if (pe && pe->GetTree() != GetTree()) pe = nullptr;
6330 }
6331 return pe;
6332}
6333
6334////////////////////////////////////////////////////////////////////////////////
6335/// Return a pointer to the list containing user objects associated to this tree.
6336///
6337/// The list is automatically created if it does not exist.
6338///
6339/// WARNING: By default the TTree destructor will delete all objects added
6340/// to this list. If you do not want these objects to be deleted,
6341/// call:
6342///
6343/// mytree->GetUserInfo()->Clear();
6344///
6345/// before deleting the tree.
6348{
6349 if (!fUserInfo) {
6350 fUserInfo = new TList();
6351 fUserInfo->SetName("UserInfo");
6352 }
6353 return fUserInfo;
6354}
6355
6356////////////////////////////////////////////////////////////////////////////////
6357/// Appends the cluster range information stored in 'fromtree' to this tree,
6358/// including the value of fAutoFlush.
6359///
6360/// This is used when doing a fast cloning (by TTreeCloner).
6361/// See also fAutoFlush and fAutoSave if needed.
6363void TTree::ImportClusterRanges(TTree *fromtree)
6364{
6365 Long64_t autoflush = fromtree->GetAutoFlush();
6366 if (fromtree->fNClusterRange == 0 && fromtree->fAutoFlush == fAutoFlush) {
6367 // nothing to do
6368 } else if (fNClusterRange || fromtree->fNClusterRange) {
6369 Int_t newsize = fNClusterRange + 1 + fromtree->fNClusterRange;
6370 if (newsize > fMaxClusterRange) {
6371 if (fMaxClusterRange) {
6373 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6375 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6376 fMaxClusterRange = newsize;
6377 } else {
6378 fMaxClusterRange = newsize;
6381 }
6382 }
6383 if (fEntries) {
6387 }
6388 for (Int_t i = 0 ; i < fromtree->fNClusterRange; ++i) {
6392 }
6393 fAutoFlush = autoflush;
6394 } else {
6395 SetAutoFlush( autoflush );
6396 }
6397 Long64_t autosave = GetAutoSave();
6398 if (autoflush > 0 && autosave > 0) {
6399 SetAutoSave( autoflush*(autosave/autoflush) );
6400 }
6401}
6402
6403////////////////////////////////////////////////////////////////////////////////
6404/// Keep a maximum of fMaxEntries in memory.
6407{
6409 Long64_t maxEntries = fMaxEntries - (fMaxEntries / 10);
6410 for (Int_t i = 0; i < nb; ++i) {
6411 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
6412 branch->KeepCircular(maxEntries);
6413 }
6414 if (fNClusterRange) {
6415 Long64_t entriesOffset = fEntries - maxEntries;
6416 Int_t oldsize = fNClusterRange;
6417 for(Int_t i = 0, j = 0; j < oldsize; ++j) {
6418 if (fClusterRangeEnd[j] > entriesOffset) {
6419 fClusterRangeEnd[i] = fClusterRangeEnd[j] - entriesOffset;
6420 ++i;
6421 } else {
6423 }
6424 }
6425 }
6426 fEntries = maxEntries;
6427 fReadEntry = -1;
6428}
6429
6430////////////////////////////////////////////////////////////////////////////////
6431/// Read in memory all baskets from all branches up to the limit of maxmemory bytes.
6432///
6433/// If maxmemory is non null and positive SetMaxVirtualSize is called
6434/// with this value. Default for maxmemory is 2000000000 (2 Gigabytes).
6435/// The function returns the total number of baskets read into memory
6436/// if negative an error occurred while loading the branches.
6437/// This method may be called to force branch baskets in memory
6438/// when random access to branch entries is required.
6439/// If random access to only a few branches is required, you should
6440/// call directly TBranch::LoadBaskets.
6443{
6444 if (maxmemory > 0) SetMaxVirtualSize(maxmemory);
6445
6446 TIter next(GetListOfLeaves());
6447 TLeaf *leaf;
6448 Int_t nimported = 0;
6449 while ((leaf=(TLeaf*)next())) {
6450 nimported += leaf->GetBranch()->LoadBaskets();//break;
6451 }
6452 return nimported;
6453}
6454
6455////////////////////////////////////////////////////////////////////////////////
6456/// Set current entry.
6457///
6458/// Returns -2 if entry does not exist (just as TChain::LoadTree()).
6459/// Returns -6 if an error occurs in the notification callback (just as TChain::LoadTree()).
6460///
6461/// Calls fNotify->Notify() (if fNotify is not null) when starting the processing of a new tree.
6462///
6463/// \note This function is overloaded in TChain.
6465{
6466 // We have already been visited while recursively looking
6467 // through the friend trees, let's return
6469 // We need to return a negative value to avoid a circular list of friends
6470 // to think that there is always an entry somewhere in the list.
6471 return -1;
6472 }
6473
6474 // create cache if wanted
6475 if (fCacheDoAutoInit && entry >=0)
6477
6478 if (fNotify) {
6479 if (fReadEntry < 0) {
6480 fNotify->Notify();
6481 }
6482 }
6483 fReadEntry = entry;
6484
6485 bool friendHasEntry = false;
6486 if (fFriends) {
6487 // Set current entry in friends as well.
6488 //
6489 // An alternative would move this code to each of the
6490 // functions calling LoadTree (and to overload a few more).
6491 bool needUpdate = false;
6492 {
6493 // This scope is need to insure the lock is released at the right time
6494 TIter nextf(fFriends);
6495 TFriendLock lock(this, kLoadTree);
6496 TFriendElement* fe = nullptr;
6497 while ((fe = (TFriendElement*) nextf())) {
6499 // This friend element was added by the chain that owns this
6500 // tree, the chain will deal with loading the correct entry.
6501 continue;
6502 }
6503 TTree* friendTree = fe->GetTree();
6504 if (friendTree) {
6505 if (friendTree->LoadTreeFriend(entry, this) >= 0) {
6506 friendHasEntry = true;
6507 }
6508 }
6509 if (fe->IsUpdated()) {
6510 needUpdate = true;
6511 fe->ResetUpdated();
6512 }
6513 } // for each friend
6514 }
6515 if (needUpdate) {
6516 //update list of leaves in all TTreeFormula of the TTreePlayer (if any)
6517 if (fPlayer) {
6519 }
6520 //Notify user if requested
6521 if (fNotify) {
6522 if(!fNotify->Notify()) return -6;
6523 }
6524 }
6525 }
6526
6527 if ((fReadEntry >= fEntries) && !friendHasEntry) {
6528 fReadEntry = -1;
6529 return -2;
6530 }
6531 return fReadEntry;
6532}
6533
6534////////////////////////////////////////////////////////////////////////////////
6535/// Load entry on behalf of our master tree, we may use an index.
6536///
6537/// Called by LoadTree() when the masterTree looks for the entry
6538/// number in a friend tree (us) corresponding to the passed entry
6539/// number in the masterTree.
6540///
6541/// If we have no index, our entry number and the masterTree entry
6542/// number are the same.
6543///
6544/// If we *do* have an index, we must find the (major, minor) value pair
6545/// in masterTree to locate our corresponding entry.
6546///
6548Long64_t TTree::LoadTreeFriend(Long64_t entry, TTree* masterTree)
6549{
6550 if (!fTreeIndex) {
6551 return LoadTree(entry);
6552 }
6553 return LoadTree(fTreeIndex->GetEntryNumberFriend(masterTree));
6554}
6555
6556////////////////////////////////////////////////////////////////////////////////
6557/// Generate a skeleton analysis class for this tree.
6558///
6559/// The following files are produced: classname.h and classname.C.
6560/// If classname is 0, classname will be called "nameoftree".
6561///
6562/// The generated code in classname.h includes the following:
6563///
6564/// - Identification of the original tree and the input file name.
6565/// - Definition of an analysis class (data members and member functions).
6566/// - The following member functions:
6567/// - constructor (by default opening the tree file),
6568/// - GetEntry(Long64_t entry),
6569/// - Init(TTree* tree) to initialize a new TTree,
6570/// - Show(Long64_t entry) to read and dump entry.
6571///
6572/// The generated code in classname.C includes only the main
6573/// analysis function Loop.
6574///
6575/// To use this function:
6576///
6577/// - Open your tree file (eg: TFile f("myfile.root");)
6578/// - T->MakeClass("MyClass");
6579///
6580/// where T is the name of the TTree in file myfile.root,
6581/// and MyClass.h, MyClass.C the name of the files created by this function.
6582/// In a ROOT session, you can do:
6583/// ~~~ {.cpp}
6584/// root > .L MyClass.C
6585/// root > MyClass* t = new MyClass;
6586/// root > t->GetEntry(12); // Fill data members of t with entry number 12.
6587/// root > t->Show(); // Show values of entry 12.
6588/// root > t->Show(16); // Read and show values of entry 16.
6589/// root > t->Loop(); // Loop on all entries.
6590/// ~~~
6591/// NOTE: Do not use the code generated for a single TTree which is part
6592/// of a TChain to process that entire TChain. The maximum dimensions
6593/// calculated for arrays on the basis of a single TTree from the TChain
6594/// might be (will be!) too small when processing all of the TTrees in
6595/// the TChain. You must use myChain.MakeClass() to generate the code,
6596/// not myTree.MakeClass(...).
6598Int_t TTree::MakeClass(const char* classname, Option_t* option)
6599{
6600 GetPlayer();
6601 if (!fPlayer) {
6602 return 0;
6603 }
6604 return fPlayer->MakeClass(classname, option);
6605}
6606
6607////////////////////////////////////////////////////////////////////////////////
6608/// Generate a skeleton function for this tree.
6609///
6610/// The function code is written on filename.
6611/// If filename is 0, filename will be called nameoftree.C
6612///
6613/// The generated code includes the following:
6614/// - Identification of the original Tree and Input file name,
6615/// - Opening the Tree file,
6616/// - Declaration of Tree variables,
6617/// - Setting of branches addresses,
6618/// - A skeleton for the entry loop.
6619///
6620/// To use this function:
6621///
6622/// - Open your Tree file (eg: TFile f("myfile.root");)
6623/// - T->MakeCode("MyAnalysis.C");
6624///
6625/// where T is the name of the TTree in file myfile.root
6626/// and MyAnalysis.C the name of the file created by this function.
6627///
6628/// NOTE: Since the implementation of this function, a new and better
6629/// function TTree::MakeClass() has been developed.
6631Int_t TTree::MakeCode(const char* filename)
6632{
6633 Warning("MakeCode", "MakeCode is obsolete. Use MakeClass or MakeSelector instead");
6634
6635 GetPlayer();
6636 if (!fPlayer) return 0;
6637 return fPlayer->MakeCode(filename);
6638}
6639
6640////////////////////////////////////////////////////////////////////////////////
6641/// Generate a skeleton analysis class for this Tree using TBranchProxy.
6642///
6643/// TBranchProxy is the base of a class hierarchy implementing an
6644/// indirect access to the content of the branches of a TTree.
6645///
6646/// "proxyClassname" is expected to be of the form:
6647/// ~~~ {.cpp}
6648/// [path/]fileprefix
6649/// ~~~
6650/// The skeleton will then be generated in the file:
6651/// ~~~ {.cpp}
6652/// fileprefix.h
6653/// ~~~
6654/// located in the current directory or in 'path/' if it is specified.
6655/// The class generated will be named 'fileprefix'
6656///
6657/// "macrofilename" and optionally "cutfilename" are expected to point
6658/// to source files which will be included by the generated skeleton.
6659/// Method of the same name as the file(minus the extension and path)
6660/// will be called by the generated skeleton's Process method as follow:
6661/// ~~~ {.cpp}
6662/// [if (cutfilename())] htemp->Fill(macrofilename());
6663/// ~~~
6664/// "option" can be used select some of the optional features during
6665/// the code generation. The possible options are:
6666///
6667/// - nohist : indicates that the generated ProcessFill should not fill the histogram.
6668///
6669/// 'maxUnrolling' controls how deep in the class hierarchy does the
6670/// system 'unroll' classes that are not split. Unrolling a class
6671/// allows direct access to its data members (this emulates the behavior
6672/// of TTreeFormula).
6673///
6674/// The main features of this skeleton are:
6675///
6676/// * on-demand loading of branches
6677/// * ability to use the 'branchname' as if it was a data member
6678/// * protection against array out-of-bounds errors
6679/// * ability to use the branch data as an object (when the user code is available)
6680///
6681/// For example with Event.root, if
6682/// ~~~ {.cpp}
6683/// Double_t somePx = fTracks.fPx[2];
6684/// ~~~
6685/// is executed by one of the method of the skeleton,
6686/// somePx will updated with the current value of fPx of the 3rd track.
6687///
6688/// Both macrofilename and the optional cutfilename are expected to be
6689/// the name of source files which contain at least a free standing
6690/// function with the signature:
6691/// ~~~ {.cpp}
6692/// x_t macrofilename(); // i.e function with the same name as the file
6693/// ~~~
6694/// and
6695/// ~~~ {.cpp}
6696/// y_t cutfilename(); // i.e function with the same name as the file
6697/// ~~~
6698/// x_t and y_t needs to be types that can convert respectively to a double
6699/// and a bool (because the skeleton uses:
6700///
6701/// if (cutfilename()) htemp->Fill(macrofilename());
6702///
6703/// These two functions are run in a context such that the branch names are
6704/// available as local variables of the correct (read-only) type.
6705///
6706/// Note that if you use the same 'variable' twice, it is more efficient
6707/// to 'cache' the value. For example:
6708/// ~~~ {.cpp}
6709/// Int_t n = fEventNumber; // Read fEventNumber
6710/// if (n<10 || n>10) { ... }
6711/// ~~~
6712/// is more efficient than
6713/// ~~~ {.cpp}
6714/// if (fEventNumber<10 || fEventNumber>10)
6715/// ~~~
6716/// Also, optionally, the generated selector will also call methods named
6717/// macrofilename_methodname in each of 6 main selector methods if the method
6718/// macrofilename_methodname exist (Where macrofilename is stripped of its
6719/// extension).
6720///
6721/// Concretely, with the script named h1analysisProxy.C,
6722///
6723/// - The method calls the method (if it exist)
6724/// - Begin -> void h1analysisProxy_Begin(TTree*);
6725/// - SlaveBegin -> void h1analysisProxy_SlaveBegin(TTree*);
6726/// - Notify -> bool h1analysisProxy_Notify();
6727/// - Process -> bool h1analysisProxy_Process(Long64_t);
6728/// - SlaveTerminate -> void h1analysisProxy_SlaveTerminate();
6729/// - Terminate -> void h1analysisProxy_Terminate();
6730///
6731/// If a file name macrofilename.h (or .hh, .hpp, .hxx, .hPP, .hXX) exist
6732/// it is included before the declaration of the proxy class. This can
6733/// be used in particular to insure that the include files needed by
6734/// the macro file are properly loaded.
6735///
6736/// The default histogram is accessible via the variable named 'htemp'.
6737///
6738/// If the library of the classes describing the data in the branch is
6739/// loaded, the skeleton will add the needed `include` statements and
6740/// give the ability to access the object stored in the branches.
6741///
6742/// To draw px using the file hsimple.root (generated by the
6743/// hsimple.C tutorial), we need a file named hsimple.cxx:
6744/// ~~~ {.cpp}
6745/// double hsimple() {
6746/// return px;
6747/// }
6748/// ~~~
6749/// MakeProxy can then be used indirectly via the TTree::Draw interface
6750/// as follow:
6751/// ~~~ {.cpp}
6752/// new TFile("hsimple.root")
6753/// ntuple->Draw("hsimple.cxx");
6754/// ~~~
6755/// A more complete example is available in the tutorials directory:
6756/// h1analysisProxy.cxx , h1analysProxy.h and h1analysisProxyCut.C
6757/// which reimplement the selector found in h1analysis.C
6759Int_t TTree::MakeProxy(const char* proxyClassname, const char* macrofilename, const char* cutfilename, const char* option, Int_t maxUnrolling)
6760{
6761 GetPlayer();
6762 if (!fPlayer) return 0;
6763 return fPlayer->MakeProxy(proxyClassname,macrofilename,cutfilename,option,maxUnrolling);
6764}
6765
6766////////////////////////////////////////////////////////////////////////////////
6767/// Generate skeleton selector class for this tree.
6768///
6769/// The following files are produced: selector.h and selector.C.
6770/// If selector is 0, the selector will be called "nameoftree".
6771/// The option can be used to specify the branches that will have a data member.
6772/// - If option is "=legacy", a pre-ROOT6 selector will be generated (data
6773/// members and branch pointers instead of TTreeReaders).
6774/// - If option is empty, readers will be generated for each leaf.
6775/// - If option is "@", readers will be generated for the topmost branches.
6776/// - Individual branches can also be picked by their name:
6777/// - "X" generates readers for leaves of X.
6778/// - "@X" generates a reader for X as a whole.
6779/// - "@X;Y" generates a reader for X as a whole and also readers for the
6780/// leaves of Y.
6781/// - For further examples see the figure below.
6782///
6783/// \image html ttree_makeselector_option_examples.png
6784///
6785/// The generated code in selector.h includes the following:
6786/// - Identification of the original Tree and Input file name
6787/// - Definition of selector class (data and functions)
6788/// - The following class functions:
6789/// - constructor and destructor
6790/// - void Begin(TTree *tree)
6791/// - void SlaveBegin(TTree *tree)
6792/// - void Init(TTree *tree)
6793/// - bool Notify()
6794/// - bool Process(Long64_t entry)
6795/// - void Terminate()
6796/// - void SlaveTerminate()
6797///
6798/// The class selector derives from TSelector.
6799/// The generated code in selector.C includes empty functions defined above.
6800///
6801/// To use this function:
6802///
6803/// - connect your Tree file (eg: `TFile f("myfile.root");`)
6804/// - `T->MakeSelector("myselect");`
6805///
6806/// where T is the name of the Tree in file myfile.root
6807/// and myselect.h, myselect.C the name of the files created by this function.
6808/// In a ROOT session, you can do:
6809/// ~~~ {.cpp}
6810/// root > T->Process("myselect.C")
6811/// ~~~
6813Int_t TTree::MakeSelector(const char* selector, Option_t* option)
6814{
6815 TString opt(option);
6816 if(opt.EqualTo("=legacy", TString::ECaseCompare::kIgnoreCase)) {
6817 return MakeClass(selector, "selector");
6818 } else {
6819 GetPlayer();
6820 if (!fPlayer) return 0;
6821 return fPlayer->MakeReader(selector, option);
6822 }
6823}
6824
6825////////////////////////////////////////////////////////////////////////////////
6826/// Check if adding nbytes to memory we are still below MaxVirtualsize.
6828bool TTree::MemoryFull(Int_t nbytes)
6829{
6830 if ((fTotalBuffers + nbytes) < fMaxVirtualSize) {
6831 return false;
6832 }
6833 return true;
6834}
6835
6836////////////////////////////////////////////////////////////////////////////////
6837/// Static function merging the trees in the TList into a new tree.
6838///
6839/// Trees in the list can be memory or disk-resident trees.
6840/// The new tree is created in the current directory (memory if gROOT).
6842TTree* TTree::MergeTrees(TList* li, Option_t* options)
6843{
6844 if (!li) return nullptr;
6845 TIter next(li);
6846 TTree *newtree = nullptr;
6847 TObject *obj;
6848
6849 while ((obj=next())) {
6850 if (!obj->InheritsFrom(TTree::Class())) continue;
6851 TTree *tree = (TTree*)obj;
6852 Long64_t nentries = tree->GetEntries();
6853 if (nentries == 0) continue;
6854 if (!newtree) {
6855 newtree = (TTree*)tree->CloneTree(-1, options);
6856 if (!newtree) continue;
6857
6858 // Once the cloning is done, separate the trees,
6859 // to avoid as many side-effects as possible
6860 // The list of clones is guaranteed to exist since we
6861 // just cloned the tree.
6862 tree->GetListOfClones()->Remove(newtree);
6863 tree->ResetBranchAddresses();
6864 newtree->ResetBranchAddresses();
6865 continue;
6866 }
6867
6868 newtree->CopyEntries(tree, -1, options, true);
6869 }
6870 if (newtree && newtree->GetTreeIndex()) {
6871 newtree->GetTreeIndex()->Append(nullptr,false); // Force the sorting
6872 }
6873 return newtree;
6874}
6875
6876////////////////////////////////////////////////////////////////////////////////
6877/// Merge the trees in the TList into this tree.
6878///
6879/// Returns the total number of entries in the merged tree.
6882{
6883 if (!li) return 0;
6884 Long64_t storeAutoSave = fAutoSave;
6885 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
6886 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
6887 // Also since this is part of a merging operation, the output file is not as precious as in
6888 // the general case since the input file should still be around.
6889 fAutoSave = 0;
6890 TIter next(li);
6891 TTree *tree;
6892 while ((tree = (TTree*)next())) {
6893 if (tree==this) continue;
6894 if (!tree->InheritsFrom(TTree::Class())) {
6895 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
6896 fAutoSave = storeAutoSave;
6897 return -1;
6898 }
6899
6900 Long64_t nentries = tree->GetEntries();
6901 if (nentries == 0) continue;
6902
6903 CopyEntries(tree, -1, options, true);
6904 }
6905 fAutoSave = storeAutoSave;
6906 return GetEntries();
6907}
6908
6909////////////////////////////////////////////////////////////////////////////////
6910/// Merge the trees in the TList into this tree.
6911/// If info->fIsFirst is true, first we clone this TTree info the directory
6912/// info->fOutputDirectory and then overlay the new TTree information onto
6913/// this TTree object (so that this TTree object is now the appropriate to
6914/// use for further merging).
6915///
6916/// Returns the total number of entries in the merged tree.
6919{
6920 const char *options = info ? info->fOptions.Data() : "";
6921 if (info && info->fIsFirst && info->fOutputDirectory && info->fOutputDirectory->GetFile() != GetCurrentFile()) {
6922 if (GetCurrentFile() == nullptr) {
6923 // In memory TTree, all we need to do is ... write it.
6926 fDirectory->WriteTObject(this);
6927 } else if (info->fOptions.Contains("fast")) {
6929 } else {
6931 TIOFeatures saved_features = fIOFeatures;
6932 TTree *newtree = CloneTree(-1, options);
6933 if (info->fIOFeatures)
6934 fIOFeatures = *(info->fIOFeatures);
6935 else
6936 fIOFeatures = saved_features;
6937 if (newtree) {
6938 newtree->Write();
6939 delete newtree;
6940 }
6941 // Make sure things are really written out to disk before attempting any reading.
6942 info->fOutputDirectory->GetFile()->Flush();
6943 info->fOutputDirectory->ReadTObject(this,this->GetName());
6944 }
6945 }
6946 if (!li) return 0;
6947 Long64_t storeAutoSave = fAutoSave;
6948 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
6949 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
6950 // Also since this is part of a merging operation, the output file is not as precious as in
6951 // the general case since the input file should still be around.
6952 fAutoSave = 0;
6953 TIter next(li);
6954 TTree *tree;
6955 while ((tree = (TTree*)next())) {
6956 if (tree==this) continue;
6957 if (!tree->InheritsFrom(TTree::Class())) {
6958 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
6959 fAutoSave = storeAutoSave;
6960 return -1;
6961 }
6962
6963 CopyEntries(tree, -1, options, true);
6964 }
6965 fAutoSave = storeAutoSave;
6966 return GetEntries();
6967}
6968
6969////////////////////////////////////////////////////////////////////////////////
6970/// Move a cache from a file to the current file in dir.
6971/// if src is null no operation is done, if dir is null or there is no
6972/// current file the cache is deleted.
6975{
6976 if (!src) return;
6977 TFile *dst = (dir && dir != gROOT) ? dir->GetFile() : nullptr;
6978 if (src == dst) return;
6979
6981 if (dst) {
6982 src->SetCacheRead(nullptr,this);
6983 dst->SetCacheRead(pf, this);
6984 } else {
6985 if (pf) {
6986 pf->WaitFinishPrefetch();
6987 }
6988 src->SetCacheRead(nullptr,this);
6989 delete pf;
6990 }
6991}
6992
6993////////////////////////////////////////////////////////////////////////////////
6994/// Copy the content to a new new file, update this TTree with the new
6995/// location information and attach this TTree to the new directory.
6996///
6997/// options: Indicates a basket sorting method, see TTreeCloner::TTreeCloner for
6998/// details
6999///
7000/// If new and old directory are in the same file, the data is untouched,
7001/// this "just" does a call to SetDirectory.
7002/// Equivalent to an "in place" cloning of the TTree.
7003bool TTree::InPlaceClone(TDirectory *newdirectory, const char *options)
7004{
7005 if (!newdirectory) {
7007 SetDirectory(nullptr);
7008 return true;
7009 }
7010 if (newdirectory->GetFile() == GetCurrentFile()) {
7011 SetDirectory(newdirectory);
7012 return true;
7013 }
7014 TTreeCloner cloner(this, newdirectory, options);
7015 if (cloner.IsValid())
7016 return cloner.Exec();
7017 else
7018 return false;
7019}
7020
7021////////////////////////////////////////////////////////////////////////////////
7022/// Function called when loading a new class library.
7024bool TTree::Notify()
7025{
7026 TIter next(GetListOfLeaves());
7027 TLeaf* leaf = nullptr;
7028 while ((leaf = (TLeaf*) next())) {
7029 leaf->Notify();
7030 leaf->GetBranch()->Notify();
7031 }
7032 return true;
7033}
7034
7035////////////////////////////////////////////////////////////////////////////////
7036/// This function may be called after having filled some entries in a Tree.
7037/// Using the information in the existing branch buffers, it will reassign
7038/// new branch buffer sizes to optimize time and memory.
7039///
7040/// The function computes the best values for branch buffer sizes such that
7041/// the total buffer sizes is less than maxMemory and nearby entries written
7042/// at the same time.
7043/// In case the branch compression factor for the data written so far is less
7044/// than compMin, the compression is disabled.
7045///
7046/// if option ="d" an analysis report is printed.
7048void TTree::OptimizeBaskets(ULong64_t maxMemory, Float_t minComp, Option_t *option)
7049{
7050 //Flush existing baskets if the file is writable
7051 if (this->GetDirectory()->IsWritable()) this->FlushBasketsImpl();
7052
7053 TString opt( option );
7054 opt.ToLower();
7055 bool pDebug = opt.Contains("d");
7056 TObjArray *leaves = this->GetListOfLeaves();
7057 Int_t nleaves = leaves->GetEntries();
7058 Double_t treeSize = (Double_t)this->GetTotBytes();
7059
7060 if (nleaves == 0 || treeSize == 0) {
7061 // We're being called too early, we really have nothing to do ...
7062 return;
7063 }
7064 Double_t aveSize = treeSize/nleaves;
7065 UInt_t bmin = 512;
7066 UInt_t bmax = 256000;
7067 Double_t memFactor = 1;
7068 Int_t i, oldMemsize,newMemsize,oldBaskets,newBaskets;
7069 i = oldMemsize = newMemsize = oldBaskets = newBaskets = 0;
7070
7071 //we make two passes
7072 //one pass to compute the relative branch buffer sizes
7073 //a second pass to compute the absolute values
7074 for (Int_t pass =0;pass<2;pass++) {
7075 oldMemsize = 0; //to count size of baskets in memory with old buffer size
7076 newMemsize = 0; //to count size of baskets in memory with new buffer size
7077 oldBaskets = 0; //to count number of baskets with old buffer size
7078 newBaskets = 0; //to count number of baskets with new buffer size
7079 for (i=0;i<nleaves;i++) {
7080 TLeaf *leaf = (TLeaf*)leaves->At(i);
7081 TBranch *branch = leaf->GetBranch();
7082 Double_t totBytes = (Double_t)branch->GetTotBytes();
7083 Double_t idealFactor = totBytes/aveSize;
7084 UInt_t sizeOfOneEntry;
7085 if (branch->GetEntries() == 0) {
7086 // There is no data, so let's make a guess ...
7087 sizeOfOneEntry = aveSize;
7088 } else {
7089 sizeOfOneEntry = 1+(UInt_t)(totBytes / (Double_t)branch->GetEntries());
7090 }
7091 Int_t oldBsize = branch->GetBasketSize();
7092 oldMemsize += oldBsize;
7093 oldBaskets += 1+Int_t(totBytes/oldBsize);
7094 Int_t nb = branch->GetListOfBranches()->GetEntries();
7095 if (nb > 0) {
7096 newBaskets += 1+Int_t(totBytes/oldBsize);
7097 continue;
7098 }
7099 Double_t bsize = oldBsize*idealFactor*memFactor; //bsize can be very large !
7100 if (bsize < 0) bsize = bmax;
7101 if (bsize > bmax) bsize = bmax;
7102 UInt_t newBsize = UInt_t(bsize);
7103 if (pass) { // only on the second pass so that it doesn't interfere with scaling
7104 // If there is an entry offset, it will be stored in the same buffer as the object data; hence,
7105 // we must bump up the size of the branch to account for this extra footprint.
7106 // If fAutoFlush is not set yet, let's assume that it is 'in the process of being set' to
7107 // the value of GetEntries().
7108 Long64_t clusterSize = (fAutoFlush > 0) ? fAutoFlush : branch->GetEntries();
7109 if (branch->GetEntryOffsetLen()) {
7110 newBsize = newBsize + (clusterSize * sizeof(Int_t) * 2);
7111 }
7112 // We used ATLAS fully-split xAOD for testing, which is a rather unbalanced TTree, 10K branches,
7113 // with 8K having baskets smaller than 512 bytes. To achieve good I/O performance ATLAS uses auto-flush 100,
7114 // resulting in the smallest baskets being ~300-400 bytes, so this change increases their memory by about 8k*150B =~ 1MB,
7115 // at the same time it significantly reduces the number of total baskets because it ensures that all 100 entries can be
7116 // stored in a single basket (the old optimization tended to make baskets too small). In a toy example with fixed sized
7117 // structures we found a factor of 2 fewer baskets needed in the new scheme.
7118 // rounds up, increases basket size to ensure all entries fit into single basket as intended
7119 newBsize = newBsize - newBsize%512 + 512;
7120 }
7121 if (newBsize < sizeOfOneEntry) newBsize = sizeOfOneEntry;
7122 if (newBsize < bmin) newBsize = bmin;
7123 if (newBsize > 10000000) newBsize = bmax;
7124 if (pass) {
7125 if (pDebug) Info("OptimizeBaskets", "Changing buffer size from %6d to %6d bytes for %s\n",oldBsize,newBsize,branch->GetName());
7126 branch->SetBasketSize(newBsize);
7127 }
7128 newMemsize += newBsize;
7129 // For this number to be somewhat accurate when newBsize is 'low'
7130 // we do not include any space for meta data in the requested size (newBsize) even-though SetBasketSize will
7131 // not let it be lower than 100+TBranch::fEntryOffsetLen.
7132 newBaskets += 1+Int_t(totBytes/newBsize);
7133 if (pass == 0) continue;
7134 //Reset the compression level in case the compression factor is small
7135 Double_t comp = 1;
7136 if (branch->GetZipBytes() > 0) comp = totBytes/Double_t(branch->GetZipBytes());
7137 if (comp > 1 && comp < minComp) {
7138 if (pDebug) Info("OptimizeBaskets", "Disabling compression for branch : %s\n",branch->GetName());
7140 }
7141 }
7142 // coverity[divide_by_zero] newMemsize can not be zero as there is at least one leaf
7143 memFactor = Double_t(maxMemory)/Double_t(newMemsize);
7144 if (memFactor > 100) memFactor = 100;
7145 Double_t bmin_new = bmin*memFactor;
7146 Double_t bmax_new = bmax*memFactor;
7147 static const UInt_t hardmax = 1*1024*1024*1024; // Really, really never give more than 1Gb to a single buffer.
7148
7149 // Really, really never go lower than 8 bytes (we use this number
7150 // so that the calculation of the number of basket is consistent
7151 // but in fact SetBasketSize will not let the size go below
7152 // TBranch::fEntryOffsetLen + (100 + strlen(branch->GetName())
7153 // (The 2nd part being a slight over estimate of the key length.
7154 static const UInt_t hardmin = 8;
7155 bmin = (bmin_new > hardmax) ? hardmax : ( bmin_new < hardmin ? hardmin : (UInt_t)bmin_new );
7156 bmax = (bmax_new > hardmax) ? bmin : (UInt_t)bmax_new;
7157 }
7158 if (pDebug) {
7159 Info("OptimizeBaskets", "oldMemsize = %d, newMemsize = %d\n",oldMemsize, newMemsize);
7160 Info("OptimizeBaskets", "oldBaskets = %d, newBaskets = %d\n",oldBaskets, newBaskets);
7161 }
7162}
7163
7164////////////////////////////////////////////////////////////////////////////////
7165/// Interface to the Principal Components Analysis class.
7166///
7167/// Create an instance of TPrincipal
7168///
7169/// Fill it with the selected variables
7170///
7171/// - if option "n" is specified, the TPrincipal object is filled with
7172/// normalized variables.
7173/// - If option "p" is specified, compute the principal components
7174/// - If option "p" and "d" print results of analysis
7175/// - If option "p" and "h" generate standard histograms
7176/// - If option "p" and "c" generate code of conversion functions
7177/// - return a pointer to the TPrincipal object. It is the user responsibility
7178/// - to delete this object.
7179/// - The option default value is "np"
7180///
7181/// see TTree::Draw for explanation of the other parameters.
7182///
7183/// The created object is named "principal" and a reference to it
7184/// is added to the list of specials Root objects.
7185/// you can retrieve a pointer to the created object via:
7186/// ~~~ {.cpp}
7187/// TPrincipal *principal =
7188/// (TPrincipal*)gROOT->GetListOfSpecials()->FindObject("principal");
7189/// ~~~
7191TPrincipal* TTree::Principal(const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
7192{
7193 GetPlayer();
7194 if (fPlayer) {
7195 return fPlayer->Principal(varexp, selection, option, nentries, firstentry);
7196 }
7197 return nullptr;
7198}
7199
7200////////////////////////////////////////////////////////////////////////////////
7201/// Print a summary of the tree contents.
7202///
7203/// - If option contains "all" friend trees are also printed.
7204/// - If option contains "toponly" only the top level branches are printed.
7205/// - If option contains "clusters" information about the cluster of baskets is printed.
7206///
7207/// Wildcarding can be used to print only a subset of the branches, e.g.,
7208/// `T.Print("Elec*")` will print all branches with name starting with "Elec".
7210void TTree::Print(Option_t* option) const
7211{
7212 // We already have been visited while recursively looking
7213 // through the friends tree, let's return.
7214 if (kPrint & fFriendLockStatus) {
7215 return;
7216 }
7217 Int_t s = 0;
7218 Int_t skey = 0;
7219 if (fDirectory) {
7220 TKey* key = fDirectory->GetKey(GetName());
7221 if (key) {
7222 skey = key->GetKeylen();
7223 s = key->GetNbytes();
7224 }
7225 }
7226 Long64_t total = skey;
7227 Long64_t zipBytes = GetZipBytes();
7228 if (zipBytes > 0) {
7229 total += GetTotBytes();
7230 }
7232 TTree::Class()->WriteBuffer(b, (TTree*) this);
7233 total += b.Length();
7234 Long64_t file = zipBytes + s;
7235 Float_t cx = 1;
7236 if (zipBytes) {
7237 cx = (GetTotBytes() + 0.00001) / zipBytes;
7238 }
7239 Printf("******************************************************************************");
7240 Printf("*Tree :%-10s: %-54s *", GetName(), GetTitle());
7241 Printf("*Entries : %8lld : Total = %15lld bytes File Size = %10lld *", fEntries, total, file);
7242 Printf("* : : Tree compression factor = %6.2f *", cx);
7243 Printf("******************************************************************************");
7244
7245 // Avoid many check of option validity
7246 if (!option)
7247 option = "";
7248
7249 if (strncmp(option,"clusters",std::char_traits<char>::length("clusters"))==0) {
7250 Printf("%-16s %-16s %-16s %8s %20s",
7251 "Cluster Range #", "Entry Start", "Last Entry", "Size", "Number of clusters");
7252 Int_t index= 0;
7253 Long64_t clusterRangeStart = 0;
7254 Long64_t totalClusters = 0;
7255 bool estimated = false;
7256 bool unknown = false;
7257 auto printer = [this, &totalClusters, &estimated, &unknown](Int_t ind, Long64_t start, Long64_t end, Long64_t recordedSize) {
7258 Long64_t nclusters = 0;
7259 if (recordedSize > 0) {
7260 nclusters = (1 + end - start) / recordedSize;
7261 Printf("%-16d %-16lld %-16lld %8lld %10lld",
7262 ind, start, end, recordedSize, nclusters);
7263 } else {
7264 // NOTE: const_cast ... DO NOT Merge for now
7265 TClusterIterator iter((TTree*)this, start);
7266 iter.Next();
7267 auto estimated_size = iter.GetNextEntry() - start;
7268 if (estimated_size > 0) {
7269 nclusters = (1 + end - start) / estimated_size;
7270 Printf("%-16d %-16lld %-16lld %8lld %10lld (estimated)",
7271 ind, start, end, recordedSize, nclusters);
7272 estimated = true;
7273 } else {
7274 Printf("%-16d %-16lld %-16lld %8lld (unknown)",
7275 ind, start, end, recordedSize);
7276 unknown = true;
7277 }
7278 }
7279 start = end + 1;
7280 totalClusters += nclusters;
7281 };
7282 if (fNClusterRange) {
7283 for( ; index < fNClusterRange; ++index) {
7284 printer(index, clusterRangeStart, fClusterRangeEnd[index], fClusterSize[index]);
7285 clusterRangeStart = fClusterRangeEnd[index] + 1;
7286 }
7287 }
7288 printer(index, clusterRangeStart, fEntries - 1, fAutoFlush);
7289 if (unknown) {
7290 Printf("Total number of clusters: (unknown)");
7291 } else {
7292 Printf("Total number of clusters: %lld %s", totalClusters, estimated ? "(estimated)" : "");
7293 }
7294 return;
7295 }
7296
7297 Int_t nl = const_cast<TTree*>(this)->GetListOfLeaves()->GetEntries();
7298 Int_t l;
7299 TBranch* br = nullptr;
7300 TLeaf* leaf = nullptr;
7301 if (strstr(option, "toponly")) {
7302 Long64_t *count = new Long64_t[nl];
7303 Int_t keep =0;
7304 for (l=0;l<nl;l++) {
7305 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7306 br = leaf->GetBranch();
7307 if (strchr(br->GetName(),'.')) {
7308 count[l] = -1;
7309 count[keep] += br->GetZipBytes();
7310 } else {
7311 keep = l;
7312 count[keep] = br->GetZipBytes();
7313 }
7314 }
7315 for (l=0;l<nl;l++) {
7316 if (count[l] < 0) continue;
7317 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7318 br = leaf->GetBranch();
7319 Printf("branch: %-20s %9lld",br->GetName(),count[l]);
7320 }
7321 delete [] count;
7322 } else {
7323 TString reg = "*";
7324 if (strlen(option) && strchr(option,'*')) reg = option;
7325 TRegexp re(reg,true);
7326 TIter next(const_cast<TTree*>(this)->GetListOfBranches());
7328 while ((br= (TBranch*)next())) {
7329 TString st = br->GetName();
7330 st.ReplaceAll("/","_");
7331 if (st.Index(re) == kNPOS) continue;
7332 br->Print(option);
7333 }
7334 }
7335
7336 //print TRefTable (if one)
7338
7339 //print friends if option "all"
7340 if (!fFriends || !strstr(option,"all")) return;
7341 TIter nextf(fFriends);
7342 TFriendLock lock(const_cast<TTree*>(this),kPrint);
7343 TFriendElement *fr;
7344 while ((fr = (TFriendElement*)nextf())) {
7345 TTree * t = fr->GetTree();
7346 if (t) t->Print(option);
7347 }
7348}
7349
7350////////////////////////////////////////////////////////////////////////////////
7351/// Print statistics about the TreeCache for this tree.
7352/// Like:
7353/// ~~~ {.cpp}
7354/// ******TreeCache statistics for file: cms2.root ******
7355/// Reading 73921562 bytes in 716 transactions
7356/// Average transaction = 103.242405 Kbytes
7357/// Number of blocks in current cache: 202, total size : 6001193
7358/// ~~~
7359/// if option = "a" the list of blocks in the cache is printed
7362{
7363 TFile *f = GetCurrentFile();
7364 if (!f) return;
7365 TTreeCache *tc = GetReadCache(f);
7366 if (tc) tc->Print(option);
7367}
7368
7369////////////////////////////////////////////////////////////////////////////////
7370/// Process this tree executing the TSelector code in the specified filename.
7371/// The return value is -1 in case of error and TSelector::GetStatus() in
7372/// in case of success.
7373///
7374/// The code in filename is loaded (interpreted or compiled, see below),
7375/// filename must contain a valid class implementation derived from TSelector,
7376/// where TSelector has the following member functions:
7377///
7378/// - `Begin()`: called every time a loop on the tree starts,
7379/// a convenient place to create your histograms.
7380/// - `SlaveBegin()`: called after Begin(), when on PROOF called only on the
7381/// slave servers.
7382/// - `Process()`: called for each event, in this function you decide what
7383/// to read and fill your histograms.
7384/// - `SlaveTerminate`: called at the end of the loop on the tree, when on PROOF
7385/// called only on the slave servers.
7386/// - `Terminate()`: called at the end of the loop on the tree,
7387/// a convenient place to draw/fit your histograms.
7388///
7389/// If filename is of the form file.C, the file will be interpreted.
7390///
7391/// If filename is of the form file.C++, the file file.C will be compiled
7392/// and dynamically loaded.
7393///
7394/// If filename is of the form file.C+, the file file.C will be compiled
7395/// and dynamically loaded. At next call, if file.C is older than file.o
7396/// and file.so, the file.C is not compiled, only file.so is loaded.
7397///
7398/// ## NOTE1
7399///
7400/// It may be more interesting to invoke directly the other Process function
7401/// accepting a TSelector* as argument.eg
7402/// ~~~ {.cpp}
7403/// MySelector *selector = (MySelector*)TSelector::GetSelector(filename);
7404/// selector->CallSomeFunction(..);
7405/// mytree.Process(selector,..);
7406/// ~~~
7407/// ## NOTE2
7408//
7409/// One should not call this function twice with the same selector file
7410/// in the same script. If this is required, proceed as indicated in NOTE1,
7411/// by getting a pointer to the corresponding TSelector,eg
7412///
7413/// ### Workaround 1
7414///
7415/// ~~~ {.cpp}
7416/// void stubs1() {
7417/// TSelector *selector = TSelector::GetSelector("h1test.C");
7418/// TFile *f1 = new TFile("stubs_nood_le1.root");
7419/// TTree *h1 = (TTree*)f1->Get("h1");
7420/// h1->Process(selector);
7421/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7422/// TTree *h2 = (TTree*)f2->Get("h1");
7423/// h2->Process(selector);
7424/// }
7425/// ~~~
7426/// or use ACLIC to compile the selector
7427///
7428/// ### Workaround 2
7429///
7430/// ~~~ {.cpp}
7431/// void stubs2() {
7432/// TFile *f1 = new TFile("stubs_nood_le1.root");
7433/// TTree *h1 = (TTree*)f1->Get("h1");
7434/// h1->Process("h1test.C+");
7435/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7436/// TTree *h2 = (TTree*)f2->Get("h1");
7437/// h2->Process("h1test.C+");
7438/// }
7439/// ~~~
7442{
7443 GetPlayer();
7444 if (fPlayer) {
7445 return fPlayer->Process(filename, option, nentries, firstentry);
7446 }
7447 return -1;
7448}
7449
7450////////////////////////////////////////////////////////////////////////////////
7451/// Process this tree executing the code in the specified selector.
7452/// The return value is -1 in case of error and TSelector::GetStatus() in
7453/// in case of success.
7454///
7455/// The TSelector class has the following member functions:
7456///
7457/// - `Begin()`: called every time a loop on the tree starts,
7458/// a convenient place to create your histograms.
7459/// - `SlaveBegin()`: called after Begin(), when on PROOF called only on the
7460/// slave servers.
7461/// - `Process()`: called for each event, in this function you decide what
7462/// to read and fill your histograms.
7463/// - `SlaveTerminate`: called at the end of the loop on the tree, when on PROOF
7464/// called only on the slave servers.
7465/// - `Terminate()`: called at the end of the loop on the tree,
7466/// a convenient place to draw/fit your histograms.
7467///
7468/// If the Tree (Chain) has an associated EventList, the loop is on the nentries
7469/// of the EventList, starting at firstentry, otherwise the loop is on the
7470/// specified Tree entries.
7473{
7474 GetPlayer();
7475 if (fPlayer) {
7476 return fPlayer->Process(selector, option, nentries, firstentry);
7477 }
7478 return -1;
7479}
7480
7481////////////////////////////////////////////////////////////////////////////////
7482/// Make a projection of a tree using selections.
7483///
7484/// Depending on the value of varexp (described in Draw) a 1-D, 2-D, etc.,
7485/// projection of the tree will be filled in histogram hname.
7486/// Note that the dimension of hname must match with the dimension of varexp.
7487///
7489Long64_t TTree::Project(const char* hname, const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
7490{
7491 TString var;
7492 var.Form("%s>>%s", varexp, hname);
7493 TString opt("goff");
7494 if (option) {
7495 opt.Form("%sgoff", option);
7496 }
7497 Long64_t nsel = Draw(var, selection, opt, nentries, firstentry);
7498 return nsel;
7499}
7500
7501////////////////////////////////////////////////////////////////////////////////
7502/// Loop over entries and return a TSQLResult object containing entries following selection.
7504TSQLResult* TTree::Query(const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
7505{
7506 GetPlayer();
7507 if (fPlayer) {
7508 return fPlayer->Query(varexp, selection, option, nentries, firstentry);
7509 }
7510 return nullptr;
7511}
7512
7513////////////////////////////////////////////////////////////////////////////////
7514/// Create or simply read branches from filename.
7515///
7516/// if branchDescriptor = "" (default), it is assumed that the Tree descriptor
7517/// is given in the first line of the file with a syntax like
7518/// ~~~ {.cpp}
7519/// A/D:Table[2]/F:Ntracks/I:astring/C
7520/// ~~~
7521/// otherwise branchDescriptor must be specified with the above syntax.
7522///
7523/// - If the type of the first variable is not specified, it is assumed to be "/F"
7524/// - If the type of any other variable is not specified, the type of the previous
7525/// variable is assumed. eg
7526/// - `x:y:z` (all variables are assumed of type "F")
7527/// - `x/D:y:z` (all variables are of type "D")
7528/// - `x:y/D:z` (x is type "F", y and z of type "D")
7529///
7530/// delimiter allows for the use of another delimiter besides whitespace.
7531/// This provides support for direct import of common data file formats
7532/// like csv. If delimiter != ' ' and branchDescriptor == "", then the
7533/// branch description is taken from the first line in the file, but
7534/// delimiter is used for the branch names tokenization rather than ':'.
7535/// Note however that if the values in the first line do not use the
7536/// /[type] syntax, all variables are assumed to be of type "F".
7537/// If the filename ends with extensions .csv or .CSV and a delimiter is
7538/// not specified (besides ' '), the delimiter is automatically set to ','.
7539///
7540/// Lines in the input file starting with "#" are ignored. Leading whitespace
7541/// for each column data is skipped. Empty lines are skipped.
7542///
7543/// A TBranch object is created for each variable in the expression.
7544/// The total number of rows read from the file is returned.
7545///
7546/// ## FILLING a TTree WITH MULTIPLE INPUT TEXT FILES
7547///
7548/// To fill a TTree with multiple input text files, proceed as indicated above
7549/// for the first input file and omit the second argument for subsequent calls
7550/// ~~~ {.cpp}
7551/// T.ReadFile("file1.dat","branch descriptor");
7552/// T.ReadFile("file2.dat");
7553/// ~~~
7555Long64_t TTree::ReadFile(const char* filename, const char* branchDescriptor, char delimiter)
7556{
7557 if (!filename || !*filename) {
7558 Error("ReadFile","File name not specified");
7559 return 0;
7560 }
7561
7562 std::ifstream in;
7563 in.open(filename);
7564 if (!in.good()) {
7565 Error("ReadFile","Cannot open file: %s",filename);
7566 return 0;
7567 }
7568 const char* ext = strrchr(filename, '.');
7569 if(ext && ((strcmp(ext, ".csv") == 0) || (strcmp(ext, ".CSV") == 0)) && delimiter == ' ') {
7570 delimiter = ',';
7571 }
7572 return ReadStream(in, branchDescriptor, delimiter);
7573}
7574
7575////////////////////////////////////////////////////////////////////////////////
7576/// Determine which newline this file is using.
7577/// Return '\\r' for Windows '\\r\\n' as that already terminates.
7579char TTree::GetNewlineValue(std::istream &inputStream)
7580{
7581 Long_t inPos = inputStream.tellg();
7582 char newline = '\n';
7583 while(true) {
7584 char c = 0;
7585 inputStream.get(c);
7586 if(!inputStream.good()) {
7587 Error("ReadStream","Error reading stream: no newline found.");
7588 return 0;
7589 }
7590 if(c == newline) break;
7591 if(c == '\r') {
7592 newline = '\r';
7593 break;
7594 }
7595 }
7596 inputStream.clear();
7597 inputStream.seekg(inPos);
7598 return newline;
7599}
7600
7601////////////////////////////////////////////////////////////////////////////////
7602/// Create or simply read branches from an input stream.
7603///
7604/// \see reference information for TTree::ReadFile
7606Long64_t TTree::ReadStream(std::istream& inputStream, const char *branchDescriptor, char delimiter)
7607{
7608 char newline = 0;
7609 std::stringstream ss;
7610 std::istream *inTemp;
7611 Long_t inPos = inputStream.tellg();
7612 if (!inputStream.good()) {
7613 Error("ReadStream","Error reading stream");
7614 return 0;
7615 }
7616 if (inPos == -1) {
7617 ss << std::cin.rdbuf();
7618 newline = GetNewlineValue(ss);
7619 inTemp = &ss;
7620 } else {
7621 newline = GetNewlineValue(inputStream);
7622 inTemp = &inputStream;
7623 }
7624 std::istream& in = *inTemp;
7625 Long64_t nlines = 0;
7626
7627 TBranch *branch = nullptr;
7628 Int_t nbranches = fBranches.GetEntries();
7629 if (nbranches == 0) {
7630 char *bdname = new char[4000];
7631 char *bd = new char[100000];
7632 Int_t nch = 0;
7633 if (branchDescriptor) nch = strlen(branchDescriptor);
7634 // branch Descriptor is null, read its definition from the first line in the file
7635 if (!nch) {
7636 do {
7637 in.getline(bd, 100000, newline);
7638 if (!in.good()) {
7639 delete [] bdname;
7640 delete [] bd;
7641 Error("ReadStream","Error reading stream");
7642 return 0;
7643 }
7644 char *cursor = bd;
7645 while( isspace(*cursor) && *cursor != '\n' && *cursor != '\0') {
7646 ++cursor;
7647 }
7648 if (*cursor != '#' && *cursor != '\n' && *cursor != '\0') {
7649 break;
7650 }
7651 } while (true);
7652 ++nlines;
7653 nch = strlen(bd);
7654 } else {
7655 strlcpy(bd,branchDescriptor,100000);
7656 }
7657
7658 //parse the branch descriptor and create a branch for each element
7659 //separated by ":"
7660 void *address = &bd[90000];
7661 char *bdcur = bd;
7662 TString desc="", olddesc="F";
7663 char bdelim = ':';
7664 if(delimiter != ' ') {
7665 bdelim = delimiter;
7666 if (strchr(bdcur,bdelim)==nullptr && strchr(bdcur,':') != nullptr) {
7667 // revert to the default
7668 bdelim = ':';
7669 }
7670 }
7671 while (bdcur) {
7672 char *colon = strchr(bdcur,bdelim);
7673 if (colon) *colon = 0;
7674 strlcpy(bdname,bdcur,4000);
7675 char *slash = strchr(bdname,'/');
7676 if (slash) {
7677 *slash = 0;
7678 desc = bdcur;
7679 olddesc = slash+1;
7680 } else {
7681 desc.Form("%s/%s",bdname,olddesc.Data());
7682 }
7683 char *bracket = strchr(bdname,'[');
7684 if (bracket) {
7685 *bracket = 0;
7686 }
7687 branch = new TBranch(this,bdname,address,desc.Data(),32000);
7688 if (branch->IsZombie()) {
7689 delete branch;
7690 Warning("ReadStream","Illegal branch definition: %s",bdcur);
7691 } else {
7692 fBranches.Add(branch);
7693 branch->SetAddress(nullptr);
7694 }
7695 if (!colon)break;
7696 bdcur = colon+1;
7697 }
7698 delete [] bdname;
7699 delete [] bd;
7700 }
7701
7702 nbranches = fBranches.GetEntries();
7703
7704 if (gDebug > 1) {
7705 Info("ReadStream", "Will use branches:");
7706 for (int i = 0 ; i < nbranches; ++i) {
7707 TBranch* br = (TBranch*) fBranches.At(i);
7708 Info("ReadStream", " %s: %s [%s]", br->GetName(),
7709 br->GetTitle(), br->GetListOfLeaves()->At(0)->IsA()->GetName());
7710 }
7711 if (gDebug > 3) {
7712 Info("ReadStream", "Dumping read tokens, format:");
7713 Info("ReadStream", "LLLLL:BBB:gfbe:GFBE:T");
7714 Info("ReadStream", " L: line number");
7715 Info("ReadStream", " B: branch number");
7716 Info("ReadStream", " gfbe: good / fail / bad / eof of token");
7717 Info("ReadStream", " GFBE: good / fail / bad / eof of file");
7718 Info("ReadStream", " T: Token being read");
7719 }
7720 }
7721
7722 //loop on all lines in the file
7723 Long64_t nGoodLines = 0;
7724 std::string line;
7725 const char sDelimBuf[2] = { delimiter, 0 };
7726 const char* sDelim = sDelimBuf;
7727 if (delimiter == ' ') {
7728 // ' ' really means whitespace
7729 sDelim = "[ \t]";
7730 }
7731 while(in.good()) {
7732 if (newline == '\r' && in.peek() == '\n') {
7733 // Windows, skip '\n':
7734 in.get();
7735 }
7736 std::getline(in, line, newline);
7737 ++nlines;
7738
7739 TString sLine(line);
7740 sLine = sLine.Strip(TString::kLeading); // skip leading whitespace
7741 if (sLine.IsNull()) {
7742 if (gDebug > 2) {
7743 Info("ReadStream", "Skipping empty line number %lld", nlines);
7744 }
7745 continue; // silently skip empty lines
7746 }
7747 if (sLine[0] == '#') {
7748 if (gDebug > 2) {
7749 Info("ReadStream", "Skipping comment line number %lld: '%s'",
7750 nlines, line.c_str());
7751 }
7752 continue;
7753 }
7754 if (gDebug > 2) {
7755 Info("ReadStream", "Parsing line number %lld: '%s'",
7756 nlines, line.c_str());
7757 }
7758
7759 // Loop on branches and read the branch values into their buffer
7760 branch = nullptr;
7761 TString tok; // one column's data
7762 TString leafData; // leaf data, possibly multiple tokens for e.g. /I[2]
7763 std::stringstream sToken; // string stream feeding leafData into leaves
7764 Ssiz_t pos = 0;
7765 Int_t iBranch = 0;
7766 bool goodLine = true; // whether the row can be filled into the tree
7767 Int_t remainingLeafLen = 0; // remaining columns for the current leaf
7768 while (goodLine && iBranch < nbranches
7769 && sLine.Tokenize(tok, pos, sDelim)) {
7770 tok = tok.Strip(TString::kLeading); // skip leading whitespace
7771 if (tok.IsNull() && delimiter == ' ') {
7772 // 1 2 should not be interpreted as 1,,,2 but 1, 2.
7773 // Thus continue until we have a non-empty token.
7774 continue;
7775 }
7776
7777 if (!remainingLeafLen) {
7778 // next branch!
7779 branch = (TBranch*)fBranches.At(iBranch);
7780 }
7781 TLeaf *leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
7782 if (!remainingLeafLen) {
7783 remainingLeafLen = leaf->GetLen();
7784 if (leaf->GetMaximum() > 0) {
7785 // This is a dynamic leaf length, i.e. most likely a TLeafC's
7786 // string size. This still translates into one token:
7787 remainingLeafLen = 1;
7788 }
7789
7790 leafData = tok;
7791 } else {
7792 // append token to laf data:
7793 leafData += " ";
7794 leafData += tok;
7795 }
7796 --remainingLeafLen;
7797 if (remainingLeafLen) {
7798 // need more columns for this branch:
7799 continue;
7800 }
7801 ++iBranch;
7802
7803 // initialize stringstream with token
7804 sToken.clear();
7805 sToken.seekp(0, std::ios_base::beg);
7806 sToken.str(leafData.Data());
7807 sToken.seekg(0, std::ios_base::beg);
7808 leaf->ReadValue(sToken, 0 /* 0 = "all" */);
7809 if (gDebug > 3) {
7810 Info("ReadStream", "%5lld:%3d:%d%d%d%d:%d%d%d%d:%s",
7811 nlines, iBranch,
7812 (int)sToken.good(), (int)sToken.fail(),
7813 (int)sToken.bad(), (int)sToken.eof(),
7814 (int)in.good(), (int)in.fail(),
7815 (int)in.bad(), (int)in.eof(),
7816 sToken.str().c_str());
7817 }
7818
7819 // Error handling
7820 if (sToken.bad()) {
7821 // How could that happen for a stringstream?
7822 Warning("ReadStream",
7823 "Buffer error while reading data for branch %s on line %lld",
7824 branch->GetName(), nlines);
7825 } else if (!sToken.eof()) {
7826 if (sToken.fail()) {
7827 Warning("ReadStream",
7828 "Couldn't read formatted data in \"%s\" for branch %s on line %lld; ignoring line",
7829 tok.Data(), branch->GetName(), nlines);
7830 goodLine = false;
7831 } else {
7832 std::string remainder;
7833 std::getline(sToken, remainder, newline);
7834 if (!remainder.empty()) {
7835 Warning("ReadStream",
7836 "Ignoring trailing \"%s\" while reading data for branch %s on line %lld",
7837 remainder.c_str(), branch->GetName(), nlines);
7838 }
7839 }
7840 }
7841 } // tokenizer loop
7842
7843 if (iBranch < nbranches) {
7844 Warning("ReadStream",
7845 "Read too few columns (%d < %d) in line %lld; ignoring line",
7846 iBranch, nbranches, nlines);
7847 goodLine = false;
7848 } else if (pos != kNPOS) {
7849 sLine = sLine.Strip(TString::kTrailing);
7850 if (pos < sLine.Length()) {
7851 Warning("ReadStream",
7852 "Ignoring trailing \"%s\" while reading line %lld",
7853 sLine.Data() + pos - 1 /* also print delimiter */,
7854 nlines);
7855 }
7856 }
7857
7858 //we are now ready to fill the tree
7859 if (goodLine) {
7860 Fill();
7861 ++nGoodLines;
7862 }
7863 }
7864
7865 return nGoodLines;
7866}
7867
7868////////////////////////////////////////////////////////////////////////////////
7869/// Make sure that obj (which is being deleted or will soon be) is no
7870/// longer referenced by this TTree.
7873{
7874 if (obj == fEventList) {
7875 fEventList = nullptr;
7876 }
7877 if (obj == fEntryList) {
7878 fEntryList = nullptr;
7879 }
7880 if (fUserInfo) {
7882 }
7883 if (fPlayer == obj) {
7884 fPlayer = nullptr;
7885 }
7886 if (fTreeIndex == obj) {
7887 fTreeIndex = nullptr;
7888 }
7889 if (fAliases == obj) {
7890 fAliases = nullptr;
7891 } else if (fAliases) {
7893 }
7894 if (fFriends == obj) {
7895 fFriends = nullptr;
7896 } else if (fFriends) {
7898 }
7899}
7900
7901////////////////////////////////////////////////////////////////////////////////
7902/// Refresh contents of this tree and its branches from the current status on disk.
7903///
7904/// One can call this function in case the tree file is being
7905/// updated by another process.
7907void TTree::Refresh()
7908{
7909 if (!fDirectory->GetFile()) {
7910 return;
7911 }
7913 fDirectory->Remove(this);
7914 TTree* tree; fDirectory->GetObject(GetName(),tree);
7915 if (!tree) {
7916 return;
7917 }
7918 //copy info from tree header into this Tree
7919 fEntries = 0;
7920 fNClusterRange = 0;
7921 ImportClusterRanges(tree);
7922
7923 fAutoSave = tree->fAutoSave;
7924 fEntries = tree->fEntries;
7925 fTotBytes = tree->GetTotBytes();
7926 fZipBytes = tree->GetZipBytes();
7927 fSavedBytes = tree->fSavedBytes;
7928 fTotalBuffers = tree->fTotalBuffers.load();
7929
7930 //loop on all branches and update them
7931 Int_t nleaves = fLeaves.GetEntriesFast();
7932 for (Int_t i = 0; i < nleaves; i++) {
7933 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
7934 TBranch* branch = (TBranch*) leaf->GetBranch();
7935 branch->Refresh(tree->GetBranch(branch->GetName()));
7936 }
7937 fDirectory->Remove(tree);
7938 fDirectory->Append(this);
7939 delete tree;
7940 tree = nullptr;
7941}
7942
7943////////////////////////////////////////////////////////////////////////////////
7944/// Record a TFriendElement that we need to warn when the chain switches to
7945/// a new file (typically this is because this chain is a friend of another
7946/// TChain)
7949{
7950 if (!fExternalFriends)
7951 fExternalFriends = new TList();
7952 fExternalFriends->Add(fe);
7953}
7954
7955
7956////////////////////////////////////////////////////////////////////////////////
7957/// Removes external friend
7960{
7962}
7963
7964
7965////////////////////////////////////////////////////////////////////////////////
7966/// Remove a friend from the list of friends.
7968void TTree::RemoveFriend(TTree* oldFriend)
7969{
7970 // We already have been visited while recursively looking
7971 // through the friends tree, let return
7973 return;
7974 }
7975 if (!fFriends) {
7976 return;
7977 }
7978 TFriendLock lock(this, kRemoveFriend);
7979 TIter nextf(fFriends);
7980 TFriendElement* fe = nullptr;
7981 while ((fe = (TFriendElement*) nextf())) {
7982 TTree* friend_t = fe->GetTree();
7983 if (friend_t == oldFriend) {
7984 fFriends->Remove(fe);
7985 delete fe;
7986 fe = nullptr;
7987 }
7988 }
7989}
7990
7991////////////////////////////////////////////////////////////////////////////////
7992/// Reset baskets, buffers and entries count in all branches and leaves.
7995{
7996 fNotify = nullptr;
7997 fEntries = 0;
7998 fNClusterRange = 0;
7999 fTotBytes = 0;
8000 fZipBytes = 0;
8001 fFlushedBytes = 0;
8002 fSavedBytes = 0;
8003 fTotalBuffers = 0;
8004 fChainOffset = 0;
8005 fReadEntry = -1;
8006
8007 delete fTreeIndex;
8008 fTreeIndex = nullptr;
8009
8011 for (Int_t i = 0; i < nb; ++i) {
8012 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
8013 branch->Reset(option);
8014 }
8015
8016 if (fBranchRef) {
8017 fBranchRef->Reset();
8018 }
8019}
8020
8021////////////////////////////////////////////////////////////////////////////////
8022/// Resets the state of this TTree after a merge (keep the customization but
8023/// forget the data).
8026{
8027 fEntries = 0;
8028 fNClusterRange = 0;
8029 fTotBytes = 0;
8030 fZipBytes = 0;
8031 fSavedBytes = 0;
8032 fFlushedBytes = 0;
8033 fTotalBuffers = 0;
8034 fChainOffset = 0;
8035 fReadEntry = -1;
8036
8037 delete fTreeIndex;
8038 fTreeIndex = nullptr;
8039
8041 for (Int_t i = 0; i < nb; ++i) {
8042 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
8043 branch->ResetAfterMerge(info);
8044 }
8045
8046 if (fBranchRef) {
8048 }
8049}
8050
8051////////////////////////////////////////////////////////////////////////////////
8052/// Tell all of our branches to set their addresses to zero.
8053///
8054/// Note: If any of our branches own any objects, they are deleted.
8057{
8058 if (br && br->GetTree()) {
8059 br->ResetAddress();
8060 }
8061}
8062
8063////////////////////////////////////////////////////////////////////////////////
8064/// Tell all of our branches to drop their current objects and allocate new ones.
8067{
8068 TObjArray* branches = GetListOfBranches();
8069 Int_t nbranches = branches->GetEntriesFast();
8070 for (Int_t i = 0; i < nbranches; ++i) {
8071 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
8072 branch->ResetAddress();
8073 }
8074}
8075
8076////////////////////////////////////////////////////////////////////////////////
8077/// Loop over tree entries and print entries passing selection. Interactive
8078/// pagination break is on by default.
8079///
8080/// - If varexp is 0 (or "") then print only first 8 columns.
8081/// - If varexp = "*" print all columns.
8082///
8083/// Otherwise a columns selection can be made using "var1:var2:var3".
8084///
8085/// \param firstentry first entry to scan
8086/// \param nentries total number of entries to scan (starting from firstentry). Defaults to all entries.
8087/// \see TTree::SetScanField to control how many lines are printed between pagination breaks (Use 0 to disable pagination)
8088/// \see TTreePlayer::Scan for more information
8090Long64_t TTree::Scan(const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
8091{
8092 GetPlayer();
8093 if (fPlayer) {
8094 return fPlayer->Scan(varexp, selection, option, nentries, firstentry);
8095 }
8096 return -1;
8097}
8098
8099////////////////////////////////////////////////////////////////////////////////
8100/// Set a tree variable alias.
8101///
8102/// Set an alias for an expression/formula based on the tree 'variables'.
8103///
8104/// The content of 'aliasName' can be used in TTreeFormula (i.e. TTree::Draw,
8105/// TTree::Scan, TTreeViewer) and will be evaluated as the content of
8106/// 'aliasFormula'.
8107///
8108/// If the content of 'aliasFormula' only contains symbol names, periods and
8109/// array index specification (for example event.fTracks[3]), then
8110/// the content of 'aliasName' can be used as the start of symbol.
8111///
8112/// If the alias 'aliasName' already existed, it is replaced by the new
8113/// value.
8114///
8115/// When being used, the alias can be preceded by an eventual 'Friend Alias'
8116/// (see TTree::GetFriendAlias)
8117///
8118/// Return true if it was added properly.
8119///
8120/// For example:
8121/// ~~~ {.cpp}
8122/// tree->SetAlias("x1","(tdc1[1]-tdc1[0])/49");
8123/// tree->SetAlias("y1","(tdc1[3]-tdc1[2])/47");
8124/// tree->SetAlias("x2","(tdc2[1]-tdc2[0])/49");
8125/// tree->SetAlias("y2","(tdc2[3]-tdc2[2])/47");
8126/// tree->Draw("y2-y1:x2-x1");
8127///
8128/// tree->SetAlias("theGoodTrack","event.fTracks[3]");
8129/// tree->Draw("theGoodTrack.fPx"); // same as "event.fTracks[3].fPx"
8130/// ~~~
8132bool TTree::SetAlias(const char* aliasName, const char* aliasFormula)
8133{
8134 if (!aliasName || !aliasFormula) {
8135 return false;
8136 }
8137 if (!aliasName[0] || !aliasFormula[0]) {
8138 return false;
8139 }
8140 if (!fAliases) {
8141 fAliases = new TList;
8142 } else {
8143 TNamed* oldHolder = (TNamed*) fAliases->FindObject(aliasName);
8144 if (oldHolder) {
8145 oldHolder->SetTitle(aliasFormula);
8146 return true;
8147 }
8148 }
8149 TNamed* holder = new TNamed(aliasName, aliasFormula);
8150 fAliases->Add(holder);
8151 return true;
8152}
8153
8154////////////////////////////////////////////////////////////////////////////////
8155/// This function may be called at the start of a program to change
8156/// the default value for fAutoFlush.
8157///
8158/// ### CASE 1 : autof > 0
8159///
8160/// autof is the number of consecutive entries after which TTree::Fill will
8161/// flush all branch buffers to disk.
8162///
8163/// ### CASE 2 : autof < 0
8164///
8165/// When filling the Tree the branch buffers will be flushed to disk when
8166/// more than autof bytes have been written to the file. At the first FlushBaskets
8167/// TTree::Fill will replace fAutoFlush by the current value of fEntries.
8168///
8169/// Calling this function with autof<0 is interesting when it is hard to estimate
8170/// the size of one entry. This value is also independent of the Tree.
8171///
8172/// The Tree is initialized with fAutoFlush=-30000000, ie that, by default,
8173/// the first AutoFlush will be done when 30 MBytes of data are written to the file.
8174///
8175/// ### CASE 3 : autof = 0
8176///
8177/// The AutoFlush mechanism is disabled.
8178///
8179/// Flushing the buffers at regular intervals optimize the location of
8180/// consecutive entries on the disk by creating clusters of baskets.
8181///
8182/// A cluster of baskets is a set of baskets that contains all
8183/// the data for a (consecutive) set of entries and that is stored
8184/// consecutively on the disk. When reading all the branches, this
8185/// is the minimum set of baskets that the TTreeCache will read.
8187void TTree::SetAutoFlush(Long64_t autof /* = -30000000 */ )
8188{
8189 // Implementation note:
8190 //
8191 // A positive value of autoflush determines the size (in number of entries) of
8192 // a cluster of baskets.
8193 //
8194 // If the value of autoflush is changed over time (this happens in
8195 // particular when the TTree results from fast merging many trees),
8196 // we record the values of fAutoFlush in the data members:
8197 // fClusterRangeEnd and fClusterSize.
8198 // In the code we refer to a range of entries where the size of the
8199 // cluster of baskets is the same (i.e the value of AutoFlush was
8200 // constant) is called a ClusterRange.
8201 //
8202 // The 2 arrays (fClusterRangeEnd and fClusterSize) have fNClusterRange
8203 // active (used) values and have fMaxClusterRange allocated entries.
8204 //
8205 // fClusterRangeEnd contains the last entries number of a cluster range.
8206 // In particular this means that the 'next' cluster starts at fClusterRangeEnd[]+1
8207 // fClusterSize contains the size in number of entries of all the cluster
8208 // within the given range.
8209 // The last range (and the only one if fNClusterRange is zero) start at
8210 // fNClusterRange[fNClusterRange-1]+1 and ends at the end of the TTree. The
8211 // size of the cluster in this range is given by the value of fAutoFlush.
8212 //
8213 // For example printing the beginning and end of each the ranges can be done by:
8214 //
8215 // Printf("%-16s %-16s %-16s %5s",
8216 // "Cluster Range #", "Entry Start", "Last Entry", "Size");
8217 // Int_t index= 0;
8218 // Long64_t clusterRangeStart = 0;
8219 // if (fNClusterRange) {
8220 // for( ; index < fNClusterRange; ++index) {
8221 // Printf("%-16d %-16lld %-16lld %5lld",
8222 // index, clusterRangeStart, fClusterRangeEnd[index], fClusterSize[index]);
8223 // clusterRangeStart = fClusterRangeEnd[index] + 1;
8224 // }
8225 // }
8226 // Printf("%-16d %-16lld %-16lld %5lld",
8227 // index, prevEntry, fEntries - 1, fAutoFlush);
8228 //
8229
8230 // Note: We store the entry number corresponding to the end of the cluster
8231 // rather than its start in order to avoid using the array if the cluster
8232 // size never varies (If there is only one value of AutoFlush for the whole TTree).
8233
8234 if( fAutoFlush != autof) {
8235 if ((fAutoFlush > 0 || autof > 0) && fFlushedBytes) {
8236 // The mechanism was already enabled, let's record the previous
8237 // cluster if needed.
8239 }
8240 fAutoFlush = autof;
8241 }
8242}
8243
8244////////////////////////////////////////////////////////////////////////////////
8245/// Mark the previous event as being at the end of the event cluster.
8246///
8247/// So, if fEntries is set to 10 (and this is the first cluster) when MarkEventCluster
8248/// is called, then the first cluster has 9 events.
8250{
8251 if (!fEntries) return;
8252
8253 if ( (fNClusterRange+1) > fMaxClusterRange ) {
8254 if (fMaxClusterRange) {
8255 // Resize arrays to hold a larger event cluster.
8256 Int_t newsize = TMath::Max(10,Int_t(2*fMaxClusterRange));
8258 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8260 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8261 fMaxClusterRange = newsize;
8262 } else {
8263 // Cluster ranges have never been initialized; create them now.
8264 fMaxClusterRange = 2;
8267 }
8268 }
8270 // If we are auto-flushing, then the cluster size is the same as the current auto-flush setting.
8271 if (fAutoFlush > 0) {
8272 // Even if the user triggers MarkEventRange prior to fAutoFlush being present, the TClusterIterator
8273 // will appropriately go to the next event range.
8275 // Otherwise, assume there is one cluster per event range (e.g., user is manually controlling the flush).
8276 } else if (fNClusterRange == 0) {
8278 } else {
8280 }
8282}
8283
8284/// Estimate the median cluster size for the TTree.
8285/// This value provides e.g. a reasonable cache size default if other heuristics fail.
8286/// Clusters with size 0 and the very last cluster range, that might not have been committed to fClusterSize yet,
8287/// are ignored for the purposes of the calculation.
8289{
8290 std::vector<Long64_t> clusterSizesPerRange;
8291 clusterSizesPerRange.reserve(fNClusterRange);
8292
8293 // We ignore cluster sizes of 0 for the purposes of this function.
8294 // We also ignore the very last cluster range which might not have been committed to fClusterSize.
8295 std::copy_if(fClusterSize, fClusterSize + fNClusterRange, std::back_inserter(clusterSizesPerRange),
8296 [](Long64_t size) { return size != 0; });
8297
8298 std::vector<double> nClustersInRange; // we need to store doubles because of the signature of TMath::Median
8299 nClustersInRange.reserve(clusterSizesPerRange.size());
8300
8301 auto clusterRangeStart = 0ll;
8302 for (int i = 0; i < fNClusterRange; ++i) {
8303 const auto size = fClusterSize[i];
8304 R__ASSERT(size >= 0);
8305 if (fClusterSize[i] == 0)
8306 continue;
8307 const auto nClusters = (1 + fClusterRangeEnd[i] - clusterRangeStart) / fClusterSize[i];
8308 nClustersInRange.emplace_back(nClusters);
8309 clusterRangeStart = fClusterRangeEnd[i] + 1;
8310 }
8311
8312 R__ASSERT(nClustersInRange.size() == clusterSizesPerRange.size());
8313 const auto medianClusterSize =
8314 TMath::Median(nClustersInRange.size(), clusterSizesPerRange.data(), nClustersInRange.data());
8315 return medianClusterSize;
8316}
8317
8318////////////////////////////////////////////////////////////////////////////////
8319/// In case of a program crash, it will be possible to recover the data in the
8320/// tree up to the last AutoSave point.
8321/// This function may be called before filling a TTree to specify when the
8322/// branch buffers and TTree header are flushed to disk as part of
8323/// TTree::Fill().
8324/// The default is -300000000, ie the TTree will write data to disk once it
8325/// exceeds 300 MBytes.
8326/// CASE 1: If fAutoSave is positive the watermark is reached when a multiple of
8327/// fAutoSave entries have been filled.
8328/// CASE 2: If fAutoSave is negative the watermark is reached when -fAutoSave
8329/// bytes can be written to the file.
8330/// CASE 3: If fAutoSave is 0, AutoSave() will never be called automatically
8331/// as part of TTree::Fill().
8333void TTree::SetAutoSave(Long64_t autos)
8334{
8335 fAutoSave = autos;
8336}
8337
8338////////////////////////////////////////////////////////////////////////////////
8339/// Set a branch's basket size.
8340///
8341/// bname is the name of a branch.
8342///
8343/// - if bname="*", apply to all branches.
8344/// - if bname="xxx*", apply to all branches with name starting with xxx
8345///
8346/// see TRegexp for wildcarding options
8347/// buffsize = branc basket size
8349void TTree::SetBasketSize(const char* bname, Int_t buffsize)
8350{
8351 Int_t nleaves = fLeaves.GetEntriesFast();
8352 TRegexp re(bname, true);
8353 Int_t nb = 0;
8354 for (Int_t i = 0; i < nleaves; i++) {
8355 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
8356 TBranch* branch = (TBranch*) leaf->GetBranch();
8357 TString s = branch->GetName();
8358 if (strcmp(bname, branch->GetName()) && (s.Index(re) == kNPOS)) {
8359 continue;
8360 }
8361 nb++;
8362 branch->SetBasketSize(buffsize);
8363 }
8364 if (!nb) {
8365 Error("SetBasketSize", "unknown branch -> '%s'", bname);
8366 }
8367}
8368
8369////////////////////////////////////////////////////////////////////////////////
8370/// Change branch address, dealing with clone trees properly.
8371/// See TTree::CheckBranchAddressType for the semantic of the return value.
8372///
8373/// Note: See the comments in TBranchElement::SetAddress() for the
8374/// meaning of the addr parameter and the object ownership policy.
8376Int_t TTree::SetBranchAddress(const char* bname, void* addr, TBranch** ptr)
8377{
8378 TBranch* branch = GetBranch(bname);
8379 if (!branch) {
8380 if (ptr) *ptr = nullptr;
8381 Error("SetBranchAddress", "unknown branch -> %s", bname);
8382 return kMissingBranch;
8383 }
8384 return SetBranchAddressImp(branch,addr,ptr);
8385}
8386
8387////////////////////////////////////////////////////////////////////////////////
8388/// Verify the validity of the type of addr before calling SetBranchAddress.
8389/// See TTree::CheckBranchAddressType for the semantic of the return value.
8390///
8391/// Note: See the comments in TBranchElement::SetAddress() for the
8392/// meaning of the addr parameter and the object ownership policy.
8394Int_t TTree::SetBranchAddress(const char* bname, void* addr, TClass* ptrClass, EDataType datatype, bool isptr)
8395{
8396 return SetBranchAddress(bname, addr, nullptr, ptrClass, datatype, isptr);
8397}
8398
8399////////////////////////////////////////////////////////////////////////////////
8400/// Verify the validity of the type of addr before calling SetBranchAddress.
8401/// See TTree::CheckBranchAddressType for the semantic of the return value.
8402///
8403/// Note: See the comments in TBranchElement::SetAddress() for the
8404/// meaning of the addr parameter and the object ownership policy.
8406Int_t TTree::SetBranchAddress(const char* bname, void* addr, TBranch** ptr, TClass* ptrClass, EDataType datatype, bool isptr)
8407{
8408 TBranch* branch = GetBranch(bname);
8409 if (!branch) {
8410 if (ptr) *ptr = nullptr;
8411 Error("SetBranchAddress", "unknown branch -> %s", bname);
8412 return kMissingBranch;
8413 }
8414
8415 Int_t res = CheckBranchAddressType(branch, ptrClass, datatype, isptr);
8416
8417 // This will set the value of *ptr to branch.
8418 if (res >= 0) {
8419 // The check succeeded.
8420 if ((res & kNeedEnableDecomposedObj) && !branch->GetMakeClass())
8421 branch->SetMakeClass(true);
8422 SetBranchAddressImp(branch,addr,ptr);
8423 } else {
8424 if (ptr) *ptr = nullptr;
8425 }
8426 return res;
8427}
8428
8429////////////////////////////////////////////////////////////////////////////////
8430/// Change branch address, dealing with clone trees properly.
8431/// See TTree::CheckBranchAddressType for the semantic of the return value.
8432///
8433/// Note: See the comments in TBranchElement::SetAddress() for the
8434/// meaning of the addr parameter and the object ownership policy.
8436Int_t TTree::SetBranchAddressImp(TBranch *branch, void* addr, TBranch** ptr)
8437{
8438 if (ptr) {
8439 *ptr = branch;
8440 }
8441 if (fClones) {
8442 void* oldAddr = branch->GetAddress();
8443 TIter next(fClones);
8444 TTree* clone = nullptr;
8445 const char *bname = branch->GetName();
8446 while ((clone = (TTree*) next())) {
8447 TBranch* cloneBr = clone->GetBranch(bname);
8448 if (cloneBr && (cloneBr->GetAddress() == oldAddr)) {
8449 cloneBr->SetAddress(addr);
8450 }
8451 }
8452 }
8453 branch->SetAddress(addr);
8454 return kVoidPtr;
8455}
8456
8457////////////////////////////////////////////////////////////////////////////////
8458/// Set branch status to Process or DoNotProcess.
8459///
8460/// When reading a Tree, by default, all branches are read.
8461/// One can speed up considerably the analysis phase by activating
8462/// only the branches that hold variables involved in a query.
8463///
8464/// bname is the name of a branch.
8465///
8466/// - if bname="*", apply to all branches.
8467/// - if bname="xxx*", apply to all branches with name starting with xxx
8468///
8469/// see TRegexp for wildcarding options
8470///
8471/// - status = 1 branch will be processed
8472/// - = 0 branch will not be processed
8473///
8474/// Example:
8475///
8476/// Assume a tree T with sub-branches a,b,c,d,e,f,g,etc..
8477/// when doing T.GetEntry(i) all branches are read for entry i.
8478/// to read only the branches c and e, one can do
8479/// ~~~ {.cpp}
8480/// T.SetBranchStatus("*",0); //disable all branches
8481/// T.SetBranchStatus("c",1);
8482/// T.setBranchStatus("e",1);
8483/// T.GetEntry(i);
8484/// ~~~
8485/// bname is interpreted as a wild-carded TRegexp (see TRegexp::MakeWildcard).
8486/// Thus, "a*b" or "a.*b" matches branches starting with "a" and ending with
8487/// "b", but not any other branch with an "a" followed at some point by a
8488/// "b". For this second behavior, use "*a*b*". Note that TRegExp does not
8489/// support '|', and so you cannot select, e.g. track and shower branches
8490/// with "track|shower".
8491///
8492/// __WARNING! WARNING! WARNING!__
8493///
8494/// SetBranchStatus is matching the branch based on match of the branch
8495/// 'name' and not on the branch hierarchy! In order to be able to
8496/// selectively enable a top level object that is 'split' you need to make
8497/// sure the name of the top level branch is prefixed to the sub-branches'
8498/// name (by adding a dot ('.') at the end of the Branch creation and use the
8499/// corresponding bname.
8500///
8501/// I.e If your Tree has been created in split mode with a parent branch "parent."
8502/// (note the trailing dot).
8503/// ~~~ {.cpp}
8504/// T.SetBranchStatus("parent",1);
8505/// ~~~
8506/// will not activate the sub-branches of "parent". You should do:
8507/// ~~~ {.cpp}
8508/// T.SetBranchStatus("parent*",1);
8509/// ~~~
8510/// Without the trailing dot in the branch creation you have no choice but to
8511/// call SetBranchStatus explicitly for each of the sub branches.
8512///
8513/// An alternative to this function is to read directly and only
8514/// the interesting branches. Example:
8515/// ~~~ {.cpp}
8516/// TBranch *brc = T.GetBranch("c");
8517/// TBranch *bre = T.GetBranch("e");
8518/// brc->GetEntry(i);
8519/// bre->GetEntry(i);
8520/// ~~~
8521/// If found is not 0, the number of branch(es) found matching the regular
8522/// expression is returned in *found AND the error message 'unknown branch'
8523/// is suppressed.
8525void TTree::SetBranchStatus(const char* bname, bool status, UInt_t* found)
8526{
8527 // We already have been visited while recursively looking
8528 // through the friends tree, let return
8530 return;
8531 }
8532
8533 if (!bname || !*bname) {
8534 Error("SetBranchStatus", "Input regexp is an empty string: no match against branch names will be attempted.");
8535 return;
8536 }
8537
8538 TBranch *branch, *bcount, *bson;
8539 TLeaf *leaf, *leafcount;
8540
8541 Int_t i,j;
8542 Int_t nleaves = fLeaves.GetEntriesFast();
8543 TRegexp re(bname,true);
8544 Int_t nb = 0;
8545
8546 // first pass, loop on all branches
8547 // for leafcount branches activate/deactivate in function of status
8548 for (i=0;i<nleaves;i++) {
8549 leaf = (TLeaf*)fLeaves.UncheckedAt(i);
8550 branch = (TBranch*)leaf->GetBranch();
8551 TString s = branch->GetName();
8552 if (strcmp(bname,"*")) { //Regexp gives wrong result for [] in name
8553 TString longname;
8554 longname.Form("%s.%s",GetName(),branch->GetName());
8555 if (strcmp(bname,branch->GetName())
8556 && longname != bname
8557 && s.Index(re) == kNPOS) continue;
8558 }
8559 nb++;
8560 if (status) branch->ResetBit(kDoNotProcess);
8561 else branch->SetBit(kDoNotProcess);
8562 leafcount = leaf->GetLeafCount();
8563 if (leafcount) {
8564 bcount = leafcount->GetBranch();
8565 if (status) bcount->ResetBit(kDoNotProcess);
8566 else bcount->SetBit(kDoNotProcess);
8567 }
8568 }
8569 if (nb==0 && !strchr(bname,'*')) {
8570 branch = GetBranch(bname);
8571 if (branch) {
8572 if (status) branch->ResetBit(kDoNotProcess);
8573 else branch->SetBit(kDoNotProcess);
8574 ++nb;
8575 }
8576 }
8577
8578 //search in list of friends
8579 UInt_t foundInFriend = 0;
8580 if (fFriends) {
8581 TFriendLock lock(this,kSetBranchStatus);
8582 TIter nextf(fFriends);
8583 TFriendElement *fe;
8584 TString name;
8585 while ((fe = (TFriendElement*)nextf())) {
8586 TTree *t = fe->GetTree();
8587 if (!t) continue;
8588
8589 // If the alias is present replace it with the real name.
8590 const char *subbranch = strstr(bname,fe->GetName());
8591 if (subbranch!=bname) subbranch = nullptr;
8592 if (subbranch) {
8593 subbranch += strlen(fe->GetName());
8594 if ( *subbranch != '.' ) subbranch = nullptr;
8595 else subbranch ++;
8596 }
8597 if (subbranch) {
8598 name.Form("%s.%s",t->GetName(),subbranch);
8599 } else {
8600 name = bname;
8601 }
8602 t->SetBranchStatus(name,status, &foundInFriend);
8603 }
8604 }
8605 if (!nb && !foundInFriend) {
8606 if (!found) {
8607 if (status) {
8608 if (strchr(bname,'*') != nullptr)
8609 Error("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
8610 else
8611 Error("SetBranchStatus", "unknown branch -> %s", bname);
8612 } else {
8613 if (strchr(bname,'*') != nullptr)
8614 Warning("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
8615 else
8616 Warning("SetBranchStatus", "unknown branch -> %s", bname);
8617 }
8618 }
8619 return;
8620 }
8621 if (found) *found = nb + foundInFriend;
8622
8623 // second pass, loop again on all branches
8624 // activate leafcount branches for active branches only
8625 for (i = 0; i < nleaves; i++) {
8626 leaf = (TLeaf*)fLeaves.UncheckedAt(i);
8627 branch = (TBranch*)leaf->GetBranch();
8628 if (!branch->TestBit(kDoNotProcess)) {
8629 leafcount = leaf->GetLeafCount();
8630 if (leafcount) {
8631 bcount = leafcount->GetBranch();
8632 bcount->ResetBit(kDoNotProcess);
8633 }
8634 } else {
8635 //Int_t nbranches = branch->GetListOfBranches()->GetEntriesFast();
8636 Int_t nbranches = branch->GetListOfBranches()->GetEntries();
8637 for (j=0;j<nbranches;j++) {
8638 bson = (TBranch*)branch->GetListOfBranches()->UncheckedAt(j);
8639 if (!bson) continue;
8640 if (!bson->TestBit(kDoNotProcess)) {
8641 if (bson->GetNleaves() <= 0) continue;
8642 branch->ResetBit(kDoNotProcess);
8643 break;
8644 }
8645 }
8646 }
8647 }
8648}
8649
8650////////////////////////////////////////////////////////////////////////////////
8651/// Set the current branch style. (static function)
8652///
8653/// - style = 0 old Branch
8654/// - style = 1 new Bronch
8657{
8659}
8660
8661////////////////////////////////////////////////////////////////////////////////
8662/// Set maximum size of the file cache .
8663//
8664/// - if cachesize = 0 the existing cache (if any) is deleted.
8665/// - if cachesize = -1 (default) it is set to the AutoFlush value when writing
8666/// the Tree (default is 30 MBytes).
8667///
8668/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
8669///
8670/// Returns:
8671/// - 0 size set, cache was created if possible
8672/// - -1 on error
8675{
8676 // remember that the user has requested an explicit cache setup
8677 fCacheUserSet = true;
8678
8679 return SetCacheSizeAux(false, cacheSize);
8680}
8681
8682////////////////////////////////////////////////////////////////////////////////
8683/// Set the size of the file cache and create it if possible.
8684///
8685/// If autocache is true:
8686/// this may be an autocreated cache, possibly enlarging an existing
8687/// autocreated cache. The size is calculated. The value passed in cacheSize:
8688/// - cacheSize = 0 make cache if default cache creation is enabled
8689/// - cacheSize = -1 make a default sized cache in any case
8690///
8691/// If autocache is false:
8692/// this is a user requested cache. cacheSize is used to size the cache.
8693/// This cache should never be automatically adjusted.
8694///
8695/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
8696///
8697/// Returns:
8698/// - 0 size set, or existing autosized cache almost large enough.
8699/// (cache was created if possible)
8700/// - -1 on error
8702Int_t TTree::SetCacheSizeAux(bool autocache /* = true */, Long64_t cacheSize /* = 0 */ )
8703{
8704 if (autocache) {
8705 // used as a once only control for automatic cache setup
8706 fCacheDoAutoInit = false;
8707 }
8708
8709 if (!autocache) {
8710 // negative size means the user requests the default
8711 if (cacheSize < 0) {
8712 cacheSize = GetCacheAutoSize(true);
8713 }
8714 } else {
8715 if (cacheSize == 0) {
8716 cacheSize = GetCacheAutoSize();
8717 } else if (cacheSize < 0) {
8718 cacheSize = GetCacheAutoSize(true);
8719 }
8720 }
8721
8722 TFile* file = GetCurrentFile();
8723 if (!file || GetTree() != this) {
8724 // if there's no file or we are not a plain tree (e.g. if we're a TChain)
8725 // do not create a cache, only record the size if one was given
8726 if (!autocache) {
8727 fCacheSize = cacheSize;
8728 }
8729 if (GetTree() != this) {
8730 return 0;
8731 }
8732 if (!autocache && cacheSize>0) {
8733 Warning("SetCacheSizeAux", "A TTreeCache could not be created because the TTree has no file");
8734 }
8735 return 0;
8736 }
8737
8738 // Check for an existing cache
8739 TTreeCache* pf = GetReadCache(file);
8740 if (pf) {
8741 if (autocache) {
8742 // reset our cache status tracking in case existing cache was added
8743 // by the user without using one of the TTree methods
8744 fCacheSize = pf->GetBufferSize();
8746
8747 if (fCacheUserSet) {
8748 // existing cache was created by the user, don't change it
8749 return 0;
8750 }
8751 } else {
8752 // update the cache to ensure it records the user has explicitly
8753 // requested it
8754 pf->SetAutoCreated(false);
8755 }
8756
8757 // if we're using an automatically calculated size and the existing
8758 // cache is already almost large enough don't resize
8759 if (autocache && Long64_t(0.80*cacheSize) < fCacheSize) {
8760 // already large enough
8761 return 0;
8762 }
8763
8764 if (cacheSize == fCacheSize) {
8765 return 0;
8766 }
8767
8768 if (cacheSize == 0) {
8769 // delete existing cache
8770 pf->WaitFinishPrefetch();
8771 file->SetCacheRead(nullptr,this);
8772 delete pf;
8773 pf = nullptr;
8774 } else {
8775 // resize
8776 Int_t res = pf->SetBufferSize(cacheSize);
8777 if (res < 0) {
8778 return -1;
8779 }
8780 cacheSize = pf->GetBufferSize(); // update after potential clamp
8781 }
8782 } else {
8783 // no existing cache
8784 if (autocache) {
8785 if (fCacheUserSet) {
8786 // value was already set manually.
8787 if (fCacheSize == 0) return 0;
8788 // Expected a cache should exist; perhaps the user moved it
8789 // Do nothing more here.
8790 if (cacheSize) {
8791 Error("SetCacheSizeAux", "Not setting up an automatically sized TTreeCache because of missing cache previously set");
8792 }
8793 return -1;
8794 }
8795 }
8796 }
8797
8798 fCacheSize = cacheSize;
8799 if (cacheSize == 0 || pf) {
8800 return 0;
8801 }
8802
8803#ifdef R__USE_IMT
8805 pf = new TTreeCacheUnzip(this, cacheSize);
8806 else
8807#endif
8808 pf = new TTreeCache(this, cacheSize);
8809
8810 pf->SetAutoCreated(autocache);
8811
8812 return 0;
8813}
8814
8815////////////////////////////////////////////////////////////////////////////////
8816///interface to TTreeCache to set the cache entry range
8817///
8818/// Returns:
8819/// - 0 entry range set
8820/// - -1 on error
8823{
8824 if (!GetTree()) {
8825 if (LoadTree(0)<0) {
8826 Error("SetCacheEntryRange","Could not load a tree");
8827 return -1;
8828 }
8829 }
8830 if (GetTree()) {
8831 if (GetTree() != this) {
8832 return GetTree()->SetCacheEntryRange(first, last);
8833 }
8834 } else {
8835 Error("SetCacheEntryRange", "No tree is available. Could not set cache entry range");
8836 return -1;
8837 }
8838
8839 TFile *f = GetCurrentFile();
8840 if (!f) {
8841 Error("SetCacheEntryRange", "No file is available. Could not set cache entry range");
8842 return -1;
8843 }
8844 TTreeCache *tc = GetReadCache(f,true);
8845 if (!tc) {
8846 Error("SetCacheEntryRange", "No cache is available. Could not set entry range");
8847 return -1;
8848 }
8849 tc->SetEntryRange(first,last);
8850 return 0;
8851}
8852
8853////////////////////////////////////////////////////////////////////////////////
8854/// Interface to TTreeCache to set the number of entries for the learning phase
8857{
8859}
8860
8861////////////////////////////////////////////////////////////////////////////////
8862/// Enable/Disable circularity for this tree.
8863///
8864/// if maxEntries > 0 a maximum of maxEntries is kept in one buffer/basket
8865/// per branch in memory.
8866/// Note that when this function is called (maxEntries>0) the Tree
8867/// must be empty or having only one basket per branch.
8868/// if maxEntries <= 0 the tree circularity is disabled.
8869///
8870/// #### NOTE 1:
8871/// Circular Trees are interesting in online real time environments
8872/// to store the results of the last maxEntries events.
8873/// #### NOTE 2:
8874/// Calling SetCircular with maxEntries <= 0 is necessary before
8875/// merging circular Trees that have been saved on files.
8876/// #### NOTE 3:
8877/// SetCircular with maxEntries <= 0 is automatically called
8878/// by TChain::Merge
8879/// #### NOTE 4:
8880/// A circular Tree can still be saved in a file. When read back,
8881/// it is still a circular Tree and can be filled again.
8883void TTree::SetCircular(Long64_t maxEntries)
8884{
8885 if (maxEntries <= 0) {
8886 // Disable circularity.
8887 fMaxEntries = 1000000000;
8888 fMaxEntries *= 1000;
8890 //in case the Tree was originally created in gROOT, the branch
8891 //compression level was set to -1. If the Tree is now associated to
8892 //a file, reset the compression level to the file compression level
8893 if (fDirectory) {
8894 TFile* bfile = fDirectory->GetFile();
8896 if (bfile) {
8897 compress = bfile->GetCompressionSettings();
8898 }
8900 for (Int_t i = 0; i < nb; i++) {
8901 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
8902 branch->SetCompressionSettings(compress);
8903 }
8904 }
8905 } else {
8906 // Enable circularity.
8907 fMaxEntries = maxEntries;
8909 }
8910}
8911
8912////////////////////////////////////////////////////////////////////////////////
8913/// Set the debug level and the debug range.
8914///
8915/// For entries in the debug range, the functions TBranchElement::Fill
8916/// and TBranchElement::GetEntry will print the number of bytes filled
8917/// or read for each branch.
8919void TTree::SetDebug(Int_t level, Long64_t min, Long64_t max)
8920{
8921 fDebug = level;
8922 fDebugMin = min;
8923 fDebugMax = max;
8924}
8925
8926////////////////////////////////////////////////////////////////////////////////
8927/// Update the default value for the branch's fEntryOffsetLen.
8928/// If updateExisting is true, also update all the existing branches.
8929/// If newdefault is less than 10, the new default value will be 10.
8931void TTree::SetDefaultEntryOffsetLen(Int_t newdefault, bool updateExisting)
8932{
8933 if (newdefault < 10) {
8934 newdefault = 10;
8935 }
8936 fDefaultEntryOffsetLen = newdefault;
8937 if (updateExisting) {
8938 TIter next( GetListOfBranches() );
8939 TBranch *b;
8940 while ( ( b = (TBranch*)next() ) ) {
8941 b->SetEntryOffsetLen( newdefault, true );
8942 }
8943 if (fBranchRef) {
8944 fBranchRef->SetEntryOffsetLen( newdefault, true );
8945 }
8946 }
8947}
8948
8949////////////////////////////////////////////////////////////////////////////////
8950/// Change the tree's directory.
8951///
8952/// Remove reference to this tree from current directory and
8953/// add reference to new directory dir. The dir parameter can
8954/// be 0 in which case the tree does not belong to any directory.
8955///
8958{
8959 if (fDirectory == dir) {
8960 return;
8961 }
8962 if (fDirectory) {
8963 fDirectory->Remove(this);
8964
8965 // Delete or move the file cache if it points to this Tree
8966 TFile *file = fDirectory->GetFile();
8967 MoveReadCache(file,dir);
8968 }
8969 fDirectory = dir;
8970 if (fDirectory) {
8971 fDirectory->Append(this);
8972 }
8973 TFile* file = nullptr;
8974 if (fDirectory) {
8975 file = fDirectory->GetFile();
8976 }
8977 if (fBranchRef) {
8978 fBranchRef->SetFile(file);
8979 }
8980 TBranch* b = nullptr;
8981 TIter next(GetListOfBranches());
8982 while((b = (TBranch*) next())) {
8983 b->SetFile(file);
8984 }
8985}
8986
8987////////////////////////////////////////////////////////////////////////////////
8988/// Change number of entries in the tree.
8989///
8990/// If n >= 0, set number of entries in the tree = n.
8991///
8992/// If n < 0, set number of entries in the tree to match the
8993/// number of entries in each branch. (default for n is -1)
8994///
8995/// This function should be called only when one fills each branch
8996/// independently via TBranch::Fill without calling TTree::Fill.
8997/// Calling TTree::SetEntries() make sense only if the number of entries
8998/// in each branch is identical, a warning is issued otherwise.
8999/// The function returns the number of entries.
9000///
9003{
9004 // case 1 : force number of entries to n
9005 if (n >= 0) {
9006 fEntries = n;
9007 return n;
9008 }
9009
9010 // case 2; compute the number of entries from the number of entries in the branches
9011 TBranch* b(nullptr), *bMin(nullptr), *bMax(nullptr);
9012 Long64_t nMin = kMaxEntries;
9013 Long64_t nMax = 0;
9014 TIter next(GetListOfBranches());
9015 while((b = (TBranch*) next())){
9016 Long64_t n2 = b->GetEntries();
9017 if (!bMin || n2 < nMin) {
9018 nMin = n2;
9019 bMin = b;
9020 }
9021 if (!bMax || n2 > nMax) {
9022 nMax = n2;
9023 bMax = b;
9024 }
9025 }
9026 if (bMin && nMin != nMax) {
9027 Warning("SetEntries", "Tree branches have different numbers of entries, eg %s has %lld entries while %s has %lld entries.",
9028 bMin->GetName(), nMin, bMax->GetName(), nMax);
9029 }
9030 fEntries = nMax;
9031 return fEntries;
9032}
9033
9034////////////////////////////////////////////////////////////////////////////////
9035/// Set an EntryList
9037void TTree::SetEntryList(TEntryList *enlist, Option_t * /*opt*/)
9038{
9039 if (fEntryList) {
9040 //check if the previous entry list is owned by the tree
9042 delete fEntryList;
9043 }
9044 }
9045 fEventList = nullptr;
9046 if (!enlist) {
9047 fEntryList = nullptr;
9048 return;
9049 }
9050 fEntryList = enlist;
9051 fEntryList->SetTree(this);
9052
9053}
9054
9055////////////////////////////////////////////////////////////////////////////////
9056/// This function transfroms the given TEventList into a TEntryList
9057/// The new TEntryList is owned by the TTree and gets deleted when the tree
9058/// is deleted. This TEntryList can be returned by GetEntryList() function.
9060void TTree::SetEventList(TEventList *evlist)
9061{
9062 fEventList = evlist;
9063 if (fEntryList){
9065 TEntryList *tmp = fEntryList;
9066 fEntryList = nullptr; // Avoid problem with RecursiveRemove.
9067 delete tmp;
9068 } else {
9069 fEntryList = nullptr;
9070 }
9071 }
9072
9073 if (!evlist) {
9074 fEntryList = nullptr;
9075 fEventList = nullptr;
9076 return;
9077 }
9078
9079 fEventList = evlist;
9080 char enlistname[100];
9081 snprintf(enlistname,100, "%s_%s", evlist->GetName(), "entrylist");
9082 fEntryList = new TEntryList(enlistname, evlist->GetTitle());
9083 fEntryList->SetDirectory(nullptr); // We own this.
9084 Int_t nsel = evlist->GetN();
9085 fEntryList->SetTree(this);
9086 Long64_t entry;
9087 for (Int_t i=0; i<nsel; i++){
9088 entry = evlist->GetEntry(i);
9089 fEntryList->Enter(entry);
9090 }
9093}
9094
9095////////////////////////////////////////////////////////////////////////////////
9096/// Set number of entries to estimate variable limits.
9097/// If n is -1, the estimate is set to be the current maximum
9098/// for the tree (i.e. GetEntries() + 1)
9099/// If n is less than -1, the behavior is undefined.
9101void TTree::SetEstimate(Long64_t n /* = 1000000 */)
9102{
9103 if (n == 0) {
9104 n = 10000;
9105 } else if (n < 0) {
9106 n = fEntries - n;
9107 }
9108 fEstimate = n;
9109 GetPlayer();
9110 if (fPlayer) {
9112 }
9113}
9114
9115////////////////////////////////////////////////////////////////////////////////
9116/// Provide the end-user with the ability to enable/disable various experimental
9117/// IO features for this TTree.
9118///
9119/// Returns all the newly-set IO settings.
9122{
9123 // Purposely ignore all unsupported bits; TIOFeatures implementation already warned the user about the
9124 // error of their ways; this is just a safety check.
9125 UChar_t featuresRequested = features.GetFeatures() & static_cast<UChar_t>(TBasket::EIOBits::kSupported);
9126
9127 UChar_t curFeatures = fIOFeatures.GetFeatures();
9128 UChar_t newFeatures = ~curFeatures & featuresRequested;
9129 curFeatures |= newFeatures;
9130 fIOFeatures.Set(curFeatures);
9131
9132 ROOT::TIOFeatures newSettings(newFeatures);
9133 return newSettings;
9134}
9135
9136////////////////////////////////////////////////////////////////////////////////
9137/// Set fFileNumber to number.
9138/// fFileNumber is used by TTree::Fill to set the file name
9139/// for a new file to be created when the current file exceeds fgTreeMaxSize.
9140/// (see TTree::ChangeFile)
9141/// if fFileNumber=10, the new file name will have a suffix "_11",
9142/// ie, fFileNumber is incremented before setting the file name
9144void TTree::SetFileNumber(Int_t number)
9145{
9146 if (fFileNumber < 0) {
9147 Warning("SetFileNumber", "file number must be positive. Set to 0");
9148 fFileNumber = 0;
9149 return;
9150 }
9151 fFileNumber = number;
9152}
9153
9154////////////////////////////////////////////////////////////////////////////////
9155/// Set all the branches in this TTree to be in decomposed object mode
9156/// (also known as MakeClass mode).
9157///
9158/// For MakeClass mode 0, the TTree expects the address where the data is stored
9159/// to be set by either the user or the TTree to the address of a full object
9160/// through the top level branch.
9161/// For MakeClass mode 1, this address is expected to point to a numerical type
9162/// or C-style array (variable or not) of numerical type, representing the
9163/// primitive data members.
9164/// The function's primary purpose is to allow the user to access the data
9165/// directly with numerical type variable rather than having to have the original
9166/// set of classes (or a reproduction thereof).
9168void TTree::SetMakeClass(Int_t make)
9169{
9170 fMakeClass = make;
9171
9173 for (Int_t i = 0; i < nb; ++i) {
9174 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
9175 branch->SetMakeClass(make);
9176 }
9177}
9178
9179////////////////////////////////////////////////////////////////////////////////
9180/// Set the maximum size in bytes of a Tree file (static function).
9181/// The default size is 100000000000LL, ie 100 Gigabytes.
9182///
9183/// In TTree::Fill, when the file has a size > fgMaxTreeSize,
9184/// the function closes the current file and starts writing into
9185/// a new file with a name of the style "file_1.root" if the original
9186/// requested file name was "file.root".
9188void TTree::SetMaxTreeSize(Long64_t maxsize)
9189{
9190 fgMaxTreeSize = maxsize;
9191}
9192
9193////////////////////////////////////////////////////////////////////////////////
9194/// Change the name of this tree.
9196void TTree::SetName(const char* name)
9197{
9198 if (gPad) {
9199 gPad->Modified();
9200 }
9201 // Trees are named objects in a THashList.
9202 // We must update hashlists if we change the name.
9203 TFile *file = nullptr;
9204 TTreeCache *pf = nullptr;
9205 if (fDirectory) {
9206 fDirectory->Remove(this);
9207 if ((file = GetCurrentFile())) {
9208 pf = GetReadCache(file);
9209 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9210 }
9211 }
9212 // This changes our hash value.
9213 fName = name;
9214 if (fDirectory) {
9215 fDirectory->Append(this);
9216 if (pf) {
9218 }
9219 }
9220}
9222void TTree::SetNotify(TObject *obj)
9223{
9224 if (obj && fNotify && dynamic_cast<TNotifyLinkBase *>(fNotify)) {
9225 auto *oldLink = static_cast<TNotifyLinkBase *>(fNotify);
9226 auto *newLink = dynamic_cast<TNotifyLinkBase *>(obj);
9227 if (!newLink) {
9228 Warning("TTree::SetNotify",
9229 "The tree or chain already has a fNotify registered and it is a TNotifyLink, while the new object is "
9230 "not a TNotifyLink. Setting fNotify to the new value will lead to an orphan linked list of "
9231 "TNotifyLinks and it is most likely not intended. If this is the intended goal, please call "
9232 "SetNotify(nullptr) first to silence this warning.");
9233 } else if (newLink->GetNext() != oldLink && oldLink->GetNext() != newLink) {
9234 // If newLink->GetNext() == oldLink then we are prepending the new head, as in TNotifyLink::PrependLink
9235 // If oldLink->GetNext() == newLink then we are removing the head of the list, as in TNotifyLink::RemoveLink
9236 // Otherwise newLink and oldLink are unrelated:
9237 Warning("TTree::SetNotify",
9238 "The tree or chain already has a TNotifyLink registered, and the new TNotifyLink `obj` does not link "
9239 "to it. Setting fNotify to the new value will lead to an orphan linked list of TNotifyLinks and it is "
9240 "most likely not intended. If this is the intended goal, please call SetNotify(nullptr) first to "
9241 "silence this warning.");
9242 }
9243 }
9244
9245 fNotify = obj;
9246}
9247
9248////////////////////////////////////////////////////////////////////////////////
9249/// Change the name and title of this tree.
9251void TTree::SetObject(const char* name, const char* title)
9252{
9253 if (gPad) {
9254 gPad->Modified();
9255 }
9256
9257 // Trees are named objects in a THashList.
9258 // We must update hashlists if we change the name
9259 TFile *file = nullptr;
9260 TTreeCache *pf = nullptr;
9261 if (fDirectory) {
9262 fDirectory->Remove(this);
9263 if ((file = GetCurrentFile())) {
9264 pf = GetReadCache(file);
9265 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9266 }
9267 }
9268 // This changes our hash value.
9269 fName = name;
9270 fTitle = title;
9271 if (fDirectory) {
9272 fDirectory->Append(this);
9273 if (pf) {
9275 }
9276 }
9277}
9278
9279////////////////////////////////////////////////////////////////////////////////
9280/// Enable or disable parallel unzipping of Tree buffers.
9282void TTree::SetParallelUnzip(bool opt, Float_t RelSize)
9283{
9284#ifdef R__USE_IMT
9285 if (GetTree() == nullptr) {
9287 if (!GetTree())
9288 return;
9289 }
9290 if (GetTree() != this) {
9291 GetTree()->SetParallelUnzip(opt, RelSize);
9292 return;
9293 }
9294 TFile* file = GetCurrentFile();
9295 if (!file)
9296 return;
9297
9298 TTreeCache* pf = GetReadCache(file);
9299 if (pf && !( opt ^ (nullptr != dynamic_cast<TTreeCacheUnzip*>(pf)))) {
9300 // done with opt and type are in agreement.
9301 return;
9302 }
9303 delete pf;
9304 auto cacheSize = GetCacheAutoSize(true);
9305 if (opt) {
9306 auto unzip = new TTreeCacheUnzip(this, cacheSize);
9307 unzip->SetUnzipBufferSize( Long64_t(cacheSize * RelSize) );
9308 } else {
9309 pf = new TTreeCache(this, cacheSize);
9310 }
9311#else
9312 (void)opt;
9313 (void)RelSize;
9314#endif
9315}
9316
9317////////////////////////////////////////////////////////////////////////////////
9318/// Set perf stats
9321{
9322 fPerfStats = perf;
9323}
9324
9325////////////////////////////////////////////////////////////////////////////////
9326/// The current TreeIndex is replaced by the new index.
9327/// Note that this function does not delete the previous index.
9328/// This gives the possibility to play with more than one index, e.g.,
9329/// ~~~ {.cpp}
9330/// TVirtualIndex* oldIndex = tree.GetTreeIndex();
9331/// tree.SetTreeIndex(newIndex);
9332/// tree.Draw();
9333/// tree.SetTreeIndex(oldIndex);
9334/// tree.Draw(); etc
9335/// ~~~
9338{
9339 if (fTreeIndex) {
9340 fTreeIndex->SetTree(nullptr);
9341 }
9342 fTreeIndex = index;
9343}
9344
9345////////////////////////////////////////////////////////////////////////////////
9346/// Set tree weight.
9347///
9348/// The weight is used by TTree::Draw to automatically weight each
9349/// selected entry in the resulting histogram.
9350///
9351/// For example the equivalent of:
9352/// ~~~ {.cpp}
9353/// T.Draw("x", "w")
9354/// ~~~
9355/// is:
9356/// ~~~ {.cpp}
9357/// T.SetWeight(w);
9358/// T.Draw("x");
9359/// ~~~
9360/// This function is redefined by TChain::SetWeight. In case of a
9361/// TChain, an option "global" may be specified to set the same weight
9362/// for all trees in the TChain instead of the default behaviour
9363/// using the weights of each tree in the chain (see TChain::SetWeight).
9366{
9367 fWeight = w;
9368}
9369
9370////////////////////////////////////////////////////////////////////////////////
9371/// Print values of all active leaves for entry.
9372///
9373/// - if entry==-1, print current entry (default)
9374/// - if a leaf is an array, a maximum of lenmax elements is printed.
9376void TTree::Show(Long64_t entry, Int_t lenmax)
9377{
9378 if (entry != -1) {
9379 Int_t ret = LoadTree(entry);
9380 if (ret == -2) {
9381 Error("Show()", "Cannot read entry %lld (entry does not exist)", entry);
9382 return;
9383 } else if (ret == -1) {
9384 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9385 return;
9386 }
9387 ret = GetEntry(entry);
9388 if (ret == -1) {
9389 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9390 return;
9391 } else if (ret == 0) {
9392 Error("Show()", "Cannot read entry %lld (no data read)", entry);
9393 return;
9394 }
9395 }
9396 printf("======> EVENT:%lld\n", fReadEntry);
9397 TObjArray* leaves = GetListOfLeaves();
9398 Int_t nleaves = leaves->GetEntriesFast();
9399 Int_t ltype;
9400 for (Int_t i = 0; i < nleaves; i++) {
9401 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(i);
9402 TBranch* branch = leaf->GetBranch();
9403 if (branch->TestBit(kDoNotProcess)) {
9404 continue;
9405 }
9406 Int_t len = leaf->GetLen();
9407 if (len <= 0) {
9408 continue;
9409 }
9410 len = TMath::Min(len, lenmax);
9411 if (leaf->IsA() == TLeafElement::Class()) {
9412 leaf->PrintValue(lenmax);
9413 continue;
9414 }
9415 if (branch->GetListOfBranches()->GetEntriesFast() > 0) {
9416 continue;
9417 }
9418 ltype = 10;
9419 if (leaf->IsA() == TLeafF::Class()) {
9420 ltype = 5;
9421 }
9422 if (leaf->IsA() == TLeafD::Class()) {
9423 ltype = 5;
9424 }
9425 if (leaf->IsA() == TLeafC::Class()) {
9426 len = 1;
9427 ltype = 5;
9428 };
9429 printf(" %-15s = ", leaf->GetName());
9430 for (Int_t l = 0; l < len; l++) {
9431 leaf->PrintValue(l);
9432 if (l == (len - 1)) {
9433 printf("\n");
9434 continue;
9435 }
9436 printf(", ");
9437 if ((l % ltype) == 0) {
9438 printf("\n ");
9439 }
9440 }
9441 }
9442}
9443
9444////////////////////////////////////////////////////////////////////////////////
9445/// Start the TTreeViewer on this tree.
9446///
9447/// - ww is the width of the canvas in pixels
9448/// - wh is the height of the canvas in pixels
9450void TTree::StartViewer()
9451{
9452 GetPlayer();
9453 if (fPlayer) {
9454 fPlayer->StartViewer(600, 400);
9455 }
9456}
9457
9458////////////////////////////////////////////////////////////////////////////////
9459/// Stop the cache learning phase
9460///
9461/// Returns:
9462/// - 0 learning phase stopped or not active
9463/// - -1 on error
9466{
9467 if (!GetTree()) {
9468 if (LoadTree(0)<0) {
9469 Error("StopCacheLearningPhase","Could not load a tree");
9470 return -1;
9471 }
9472 }
9473 if (GetTree()) {
9474 if (GetTree() != this) {
9475 return GetTree()->StopCacheLearningPhase();
9476 }
9477 } else {
9478 Error("StopCacheLearningPhase", "No tree is available. Could not stop cache learning phase");
9479 return -1;
9480 }
9481
9482 TFile *f = GetCurrentFile();
9483 if (!f) {
9484 Error("StopCacheLearningPhase", "No file is available. Could not stop cache learning phase");
9485 return -1;
9486 }
9487 TTreeCache *tc = GetReadCache(f,true);
9488 if (!tc) {
9489 Error("StopCacheLearningPhase", "No cache is available. Could not stop learning phase");
9490 return -1;
9491 }
9492 tc->StopLearningPhase();
9493 return 0;
9494}
9495
9496////////////////////////////////////////////////////////////////////////////////
9497/// Set the fTree member for all branches and sub branches.
9499static void TBranch__SetTree(TTree *tree, TObjArray &branches)
9500{
9501 Int_t nb = branches.GetEntriesFast();
9502 for (Int_t i = 0; i < nb; ++i) {
9503 TBranch* br = (TBranch*) branches.UncheckedAt(i);
9504 br->SetTree(tree);
9505
9506 Int_t writeBasket = br->GetWriteBasket();
9507 for (Int_t j = writeBasket; j >= 0; --j) {
9508 TBasket *bk = (TBasket*)br->GetListOfBaskets()->UncheckedAt(j);
9509 if (bk) {
9510 tree->IncrementTotalBuffers(bk->GetBufferSize());
9511 }
9512 }
9513
9515 }
9516}
9517
9518////////////////////////////////////////////////////////////////////////////////
9519/// Set the fTree member for all friend elements.
9521void TFriendElement__SetTree(TTree *tree, TList *frlist)
9522{
9523 if (frlist) {
9524 TObjLink *lnk = frlist->FirstLink();
9525 while (lnk) {
9526 TFriendElement *elem = (TFriendElement*)lnk->GetObject();
9527 elem->fParentTree = tree;
9528 lnk = lnk->Next();
9529 }
9530 }
9531}
9532
9533////////////////////////////////////////////////////////////////////////////////
9534/// Stream a class object.
9537{
9538 if (b.IsReading()) {
9539 UInt_t R__s, R__c;
9540 if (fDirectory) {
9541 fDirectory->Remove(this);
9542 //delete the file cache if it points to this Tree
9543 TFile *file = fDirectory->GetFile();
9544 MoveReadCache(file,nullptr);
9545 }
9546 fDirectory = nullptr;
9547 fCacheDoAutoInit = true;
9548 fCacheUserSet = false;
9549 Version_t R__v = b.ReadVersion(&R__s, &R__c);
9550 if (R__v > 4) {
9551 b.ReadClassBuffer(TTree::Class(), this, R__v, R__s, R__c);
9552
9553 fBranches.SetOwner(true); // True needed only for R__v < 19 and most R__v == 19
9554
9555 if (fBranchRef) fBranchRef->SetTree(this);
9558
9559 if (fTreeIndex) {
9560 fTreeIndex->SetTree(this);
9561 }
9562 if (fIndex.fN) {
9563 Warning("Streamer", "Old style index in this tree is deleted. Rebuild the index via TTree::BuildIndex");
9564 fIndex.Set(0);
9565 fIndexValues.Set(0);
9566 }
9567 if (fEstimate <= 10000) {
9568 fEstimate = 1000000;
9569 }
9570
9571 if (fNClusterRange) {
9572 // The I/O allocated just enough memory to hold the
9573 // current set of ranges.
9575 }
9576
9577 // Throughs calls to `GetCacheAutoSize` or `EnableCache` (for example
9578 // by TTreePlayer::Process, the cache size will be automatically
9579 // determined unless the user explicitly call `SetCacheSize`
9580 fCacheSize = 0;
9581 fCacheUserSet = false;
9582
9584 return;
9585 }
9586 //====process old versions before automatic schema evolution
9587 Stat_t djunk;
9588 Int_t ijunk;
9593 b >> fScanField;
9594 b >> ijunk; fMaxEntryLoop = (Long64_t)ijunk;
9595 b >> ijunk; fMaxVirtualSize = (Long64_t)ijunk;
9596 b >> djunk; fEntries = (Long64_t)djunk;
9597 b >> djunk; fTotBytes = (Long64_t)djunk;
9598 b >> djunk; fZipBytes = (Long64_t)djunk;
9599 b >> ijunk; fAutoSave = (Long64_t)ijunk;
9600 b >> ijunk; fEstimate = (Long64_t)ijunk;
9601 if (fEstimate <= 10000) fEstimate = 1000000;
9603 if (fBranchRef) fBranchRef->SetTree(this);
9607 if (R__v > 1) fIndexValues.Streamer(b);
9608 if (R__v > 2) fIndex.Streamer(b);
9609 if (R__v > 3) {
9610 TList OldInfoList;
9611 OldInfoList.Streamer(b);
9612 OldInfoList.Delete();
9613 }
9614 fNClusterRange = 0;
9617 b.CheckByteCount(R__s, R__c, TTree::IsA());
9618 //====end of old versions
9619 } else {
9620 if (fBranchRef) {
9621 fBranchRef->Clear();
9622 }
9624 if (table) TRefTable::SetRefTable(nullptr);
9625
9626 b.WriteClassBuffer(TTree::Class(), this);
9627
9628 if (table) TRefTable::SetRefTable(table);
9629 }
9630}
9631
9632////////////////////////////////////////////////////////////////////////////////
9633/// Unbinned fit of one or more variable(s) from a tree.
9634///
9635/// funcname is a TF1 function.
9636///
9637/// \see TTree::Draw for explanations of the other parameters.
9638///
9639/// Fit the variable varexp using the function funcname using the
9640/// selection cuts given by selection.
9641///
9642/// The list of fit options is given in parameter option.
9643///
9644/// - option = "Q" Quiet mode (minimum printing)
9645/// - option = "V" Verbose mode (default is between Q and V)
9646/// - option = "E" Perform better Errors estimation using Minos technique
9647/// - option = "M" More. Improve fit results
9648///
9649/// You can specify boundary limits for some or all parameters via
9650/// ~~~ {.cpp}
9651/// func->SetParLimits(p_number, parmin, parmax);
9652/// ~~~
9653/// if parmin>=parmax, the parameter is fixed
9654///
9655/// Note that you are not forced to fix the limits for all parameters.
9656/// For example, if you fit a function with 6 parameters, you can do:
9657/// ~~~ {.cpp}
9658/// func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
9659/// func->SetParLimits(4,-10,-4);
9660/// func->SetParLimits(5, 1,1);
9661/// ~~~
9662/// With this setup:
9663///
9664/// - Parameters 0->3 can vary freely
9665/// - Parameter 4 has boundaries [-10,-4] with initial value -8
9666/// - Parameter 5 is fixed to 100.
9667///
9668/// For the fit to be meaningful, the function must be self-normalized.
9669///
9670/// i.e. It must have the same integral regardless of the parameter
9671/// settings. Otherwise the fit will effectively just maximize the
9672/// area.
9673///
9674/// It is mandatory to have a normalization variable
9675/// which is fixed for the fit. e.g.
9676/// ~~~ {.cpp}
9677/// TF1* f1 = new TF1("f1", "gaus(0)/sqrt(2*3.14159)/[2]", 0, 5);
9678/// f1->SetParameters(1, 3.1, 0.01);
9679/// f1->SetParLimits(0, 1, 1); // fix the normalization parameter to 1
9680/// data->UnbinnedFit("f1", "jpsimass", "jpsipt>3.0");
9681/// ~~~
9682/// 1, 2 and 3 Dimensional fits are supported. See also TTree::Fit
9683///
9684/// Return status:
9685///
9686/// - The function return the status of the fit in the following form
9687/// fitResult = migradResult + 10*minosResult + 100*hesseResult + 1000*improveResult
9688/// - The fitResult is 0 is the fit is OK.
9689/// - The fitResult is negative in case of an error not connected with the fit.
9690/// - The number of entries used in the fit can be obtained via mytree.GetSelectedRows();
9691/// - If the number of selected entries is null the function returns -1
9693Int_t TTree::UnbinnedFit(const char* funcname, const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
9694{
9695 GetPlayer();
9696 if (fPlayer) {
9697 return fPlayer->UnbinnedFit(funcname, varexp, selection, option, nentries, firstentry);
9698 }
9699 return -1;
9700}
9701
9702////////////////////////////////////////////////////////////////////////////////
9703/// Replace current attributes by current style.
9706{
9707 if (gStyle->IsReading()) {
9716 } else {
9725 }
9726}
9727
9728////////////////////////////////////////////////////////////////////////////////
9729/// Write this object to the current directory. For more see TObject::Write
9730/// If option & kFlushBasket, call FlushBasket before writing the tree.
9732Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const
9733{
9736 return 0;
9737 return TObject::Write(name, option, bufsize);
9738}
9739
9740////////////////////////////////////////////////////////////////////////////////
9741/// Write this object to the current directory. For more see TObject::Write
9742/// If option & kFlushBasket, call FlushBasket before writing the tree.
9744Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize)
9745{
9746 return ((const TTree*)this)->Write(name, option, bufsize);
9747}
9748
9749////////////////////////////////////////////////////////////////////////////////
9750/// \class TTreeFriendLeafIter
9751///
9752/// Iterator on all the leaves in a TTree and its friend
9753
9755
9756////////////////////////////////////////////////////////////////////////////////
9757/// Create a new iterator. By default the iteration direction
9758/// is kIterForward. To go backward use kIterBackward.
9761: fTree(const_cast<TTree*>(tree))
9762, fLeafIter(nullptr)
9763, fTreeIter(nullptr)
9764, fDirection(dir)
9765{
9766}
9767
9768////////////////////////////////////////////////////////////////////////////////
9769/// Copy constructor. Does NOT copy the 'cursor' location!
9772: TIterator(iter)
9773, fTree(iter.fTree)
9774, fLeafIter(nullptr)
9775, fTreeIter(nullptr)
9776, fDirection(iter.fDirection)
9777{
9778}
9779
9780////////////////////////////////////////////////////////////////////////////////
9781/// Overridden assignment operator. Does NOT copy the 'cursor' location!
9784{
9785 if (this != &rhs && rhs.IsA() == TTreeFriendLeafIter::Class()) {
9786 const TTreeFriendLeafIter &rhs1 = (const TTreeFriendLeafIter &)rhs;
9787 fDirection = rhs1.fDirection;
9788 }
9789 return *this;
9790}
9791
9792////////////////////////////////////////////////////////////////////////////////
9793/// Overridden assignment operator. Does NOT copy the 'cursor' location!
9796{
9797 if (this != &rhs) {
9798 fDirection = rhs.fDirection;
9799 }
9800 return *this;
9801}
9802
9803////////////////////////////////////////////////////////////////////////////////
9804/// Go the next friend element
9807{
9808 if (!fTree) return nullptr;
9809
9810 TObject * next;
9811 TTree * nextTree;
9812
9813 if (!fLeafIter) {
9814 TObjArray *list = fTree->GetListOfLeaves();
9815 if (!list) return nullptr; // Can happen with an empty chain.
9817 if (!fLeafIter) return nullptr;
9818 }
9819
9820 next = fLeafIter->Next();
9821 if (!next) {
9822 if (!fTreeIter) {
9824 if (!list) return next;
9826 if (!fTreeIter) return nullptr;
9827 }
9828 TFriendElement * nextFriend = (TFriendElement*) fTreeIter->Next();
9829 ///nextTree = (TTree*)fTreeIter->Next();
9830 if (nextFriend) {
9831 nextTree = const_cast<TTree*>(nextFriend->GetTree());
9832 if (!nextTree) return Next();
9835 if (!fLeafIter) return nullptr;
9836 next = fLeafIter->Next();
9837 }
9838 }
9839 return next;
9840}
9841
9842////////////////////////////////////////////////////////////////////////////////
9843/// Returns the object option stored in the list.
9846{
9847 if (fLeafIter) return fLeafIter->GetOption();
9848 return "";
9849}
#define R__unlikely(expr)
Definition RConfig.hxx:594
#define SafeDelete(p)
Definition RConfig.hxx:533
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Definition RtypesCore.h:45
short Version_t
Definition RtypesCore.h:65
unsigned char UChar_t
Definition RtypesCore.h:38
long Long_t
Definition RtypesCore.h:54
unsigned int UInt_t
Definition RtypesCore.h:46
float Float_t
Definition RtypesCore.h:57
double Double_t
Definition RtypesCore.h:59
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:117
long long Long64_t
Definition RtypesCore.h:69
unsigned long long ULong64_t
Definition RtypesCore.h:70
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:382
const Int_t kDoNotProcess
Definition TBranch.h:56
EDataType
Definition TDataType.h:28
@ kNoType_t
Definition TDataType.h:33
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kchar
Definition TDataType.h:31
@ kLong_t
Definition TDataType.h:30
@ kDouble32_t
Definition TDataType.h:31
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kBits
Definition TDataType.h:34
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kCharStar
Definition TDataType.h:34
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kCounter
Definition TDataType.h:34
@ kUInt_t
Definition TDataType.h:30
@ kFloat16_t
Definition TDataType.h:33
@ kOther_t
Definition TDataType.h:32
#define gDirectory
Definition TDirectory.h:384
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
#define N
static unsigned int total
Option_t Option_t option
Option_t Option_t SetLineWidth
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t cursor
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t SetFillStyle
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t SetLineColor
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t SetFillColor
Option_t Option_t SetMarkerStyle
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void reg
Option_t Option_t style
char name[80]
Definition TGX11.cxx:110
int nentries
R__EXTERN TInterpreter * gCling
Int_t gDebug
Definition TROOT.cxx:597
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:406
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2503
R__EXTERN TStyle * gStyle
Definition TStyle.h:436
R__EXTERN TSystem * gSystem
Definition TSystem.h:561
constexpr Int_t kNEntriesResort
Definition TTree.cxx:440
static TBranch * R__FindBranchHelper(TObjArray *list, const char *branchname)
Search in the array for a branch matching the branch name, with the branch possibly expressed as a 'f...
Definition TTree.cxx:4783
static char DataTypeToChar(EDataType datatype)
Definition TTree.cxx:452
void TFriendElement__SetTree(TTree *tree, TList *frlist)
Set the fTree member for all friend elements.
Definition TTree.cxx:9520
bool CheckReshuffling(TTree &mainTree, TTree &friendTree)
Definition TTree.cxx:1230
static void TBranch__SetTree(TTree *tree, TObjArray &branches)
Set the fTree member for all branches and sub branches.
Definition TTree.cxx:9498
constexpr Float_t kNEntriesResortInv
Definition TTree.cxx:441
#define R__LOCKGUARD(mutex)
#define gPad
#define snprintf
Definition civetweb.c:1540
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is 'source'.
A helper class for managing IMT work during TTree:Fill operations.
TIOFeatures provides the end-user with the ability to change the IO behavior of data written via a TT...
UChar_t GetFeatures() const
bool Set(EIOFeatures bits)
Set a specific IO feature.
This class provides a simple interface to execute the same task multiple times in parallel threads,...
void Foreach(F func, unsigned nTimes, unsigned nChunks=0)
Execute a function without arguments several times in parallel, dividing the execution in nChunks.
void Streamer(TBuffer &) override
Stream a TArrayD object.
Definition TArrayD.cxx:149
void Set(Int_t n) override
Set size of this array to n doubles.
Definition TArrayD.cxx:106
void Set(Int_t n) override
Set size of this array to n ints.
Definition TArrayI.cxx:105
void Streamer(TBuffer &) override
Stream a TArrayI object.
Definition TArrayI.cxx:148
Int_t fN
Definition TArray.h:38
Fill Area Attributes class.
Definition TAttFill.h:19
virtual void Streamer(TBuffer &)
virtual Color_t GetFillColor() const
Return the fill area color.
Definition TAttFill.h:30
virtual Style_t GetFillStyle() const
Return the fill area style.
Definition TAttFill.h:31
Line Attributes class.
Definition TAttLine.h:18
virtual void Streamer(TBuffer &)
virtual Color_t GetLineColor() const
Return the line color.
Definition TAttLine.h:33
virtual void SetLineStyle(Style_t lstyle)
Set the line style.
Definition TAttLine.h:42
virtual Width_t GetLineWidth() const
Return the line width.
Definition TAttLine.h:35
virtual Style_t GetLineStyle() const
Return the line style.
Definition TAttLine.h:34
Marker Attributes class.
Definition TAttMarker.h:19
virtual Style_t GetMarkerStyle() const
Return the marker style.
Definition TAttMarker.h:32
virtual void SetMarkerColor(Color_t mcolor=1)
Set the marker color.
Definition TAttMarker.h:38
virtual Color_t GetMarkerColor() const
Return the marker color.
Definition TAttMarker.h:31
virtual Size_t GetMarkerSize() const
Return the marker size.
Definition TAttMarker.h:33
virtual void SetMarkerStyle(Style_t mstyle=1)
Set the marker style.
Definition TAttMarker.h:40
virtual void Streamer(TBuffer &)
virtual void SetMarkerSize(Size_t msize=1)
Set the marker size.
Definition TAttMarker.h:45
Each class (see TClass) has a linked list of its base class(es).
Definition TBaseClass.h:33
ROOT::ESTLType IsSTLContainer()
Return which type (if any) of STL container the data member is.
Manages buffers for branches of a Tree.
Definition TBasket.h:34
virtual Int_t DropBuffers()
Drop buffers of this basket if it is not the current basket.
Definition TBasket.cxx:173
Int_t GetBufferSize() const
Definition TBasket.h:122
A Branch for the case of an array of clone objects.
A Branch for the case of an object.
virtual bool IsObjectOwner() const
virtual void SetBranchFolder()
static TClass * Class()
Int_t GetClassVersion()
const char * GetClassName() const override
Return the name of the user class whose content is stored in this branch, if any.
void ResetAddress() override
Set branch address to zero and free all allocated memory.
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 SetAddress(void *addobj) override
Point this branch at an object.
virtual void SetTargetClass(const char *name)
Set the name of the class of the in-memory object into which the data will loaded.
void SetObject(void *objadd) override
Set object this branch is pointing to.
A Branch for the case of an object.
A branch containing and managing a TRefTable for TRef autoloading.
Definition TBranchRef.h:34
void Reset(Option_t *option="") override
void Print(Option_t *option="") const override
Print the TRefTable branch.
void Clear(Option_t *option="") override
Clear entries in the TRefTable.
void ResetAfterMerge(TFileMergeInfo *) override
Reset a Branch after a Merge operation (drop data but keep customizations) TRefTable is cleared.
A Branch handling STL collection of pointers (vectors, lists, queues, sets and multisets) while stori...
Definition TBranchSTL.h:22
A TTree is a list of TBranches.
Definition TBranch.h:93
virtual TLeaf * GetLeaf(const char *name) const
Return pointer to the 1st Leaf named name in thisBranch.
Definition TBranch.cxx:2055
virtual bool GetMakeClass() const
Return whether this branch is in a mode where the object are decomposed or not (Also known as MakeCla...
Definition TBranch.cxx:2117
virtual void SetupAddresses()
If the branch address is not set, we set all addresses starting with the top level parent branch.
Definition TBranch.cxx:3294
virtual void ResetAddress()
Reset the address of the branch.
Definition TBranch.cxx:2651
virtual Long64_t GetBasketSeek(Int_t basket) const
Return address of basket in the file.
Definition TBranch.cxx:1302
virtual char * GetAddress() const
Definition TBranch.h:212
void SetCompressionSettings(Int_t settings=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault)
Set compression settings.
Definition TBranch.cxx:2805
TTree * GetTree() const
Definition TBranch.h:252
static TClass * Class()
virtual TString GetFullName() const
Return the 'full' name of the branch.
Definition TBranch.cxx:2031
Int_t GetWriteBasket() const
Definition TBranch.h:238
virtual void DropBaskets(Option_t *option="")
Loop on all branch baskets.
Definition TBranch.cxx:757
TObjArray * GetListOfBranches()
Definition TBranch.h:246
virtual void SetTree(TTree *tree)
Definition TBranch.h:287
virtual Int_t GetEntry(Long64_t entry=0, Int_t getall=0)
Read all leaves of entry and return total number of bytes read.
Definition TBranch.cxx:1706
TClass * IsA() const override
Definition TBranch.h:295
void Print(Option_t *option="") const override
Print TBranch parameters.
Definition TBranch.cxx:2341
static void ResetCount()
Static function resetting fgCount.
Definition TBranch.cxx:2674
virtual void SetObject(void *objadd)
Set object this branch is pointing to.
Definition TBranch.cxx:2936
Int_t FlushBaskets()
Flush to disk all the baskets of this branch and any of subbranches.
Definition TBranch.cxx:1136
virtual void SetAddress(void *add)
Set address of this branch.
Definition TBranch.cxx:2682
Int_t GetNleaves() const
Definition TBranch.h:249
virtual void SetFile(TFile *file=nullptr)
Set file where this branch writes/reads its buffers.
Definition TBranch.cxx:2863
virtual void SetEntryOffsetLen(Int_t len, bool updateSubBranches=false)
Update the default value for the branch's fEntryOffsetLen if and only if it was already non zero (and...
Definition TBranch.cxx:2821
TObjArray * GetListOfBaskets()
Definition TBranch.h:245
Long64_t GetEntries() const
Definition TBranch.h:251
virtual void UpdateFile()
Refresh the value of fDirectory (i.e.
Definition TBranch.cxx:3304
Int_t GetReadBasket() const
Definition TBranch.h:236
Int_t GetMaxBaskets() const
Definition TBranch.h:248
virtual TFile * GetFile(Int_t mode=0)
Return pointer to the file where branch buffers reside, returns 0 in case branch buffers reside in th...
Definition TBranch.cxx:1853
virtual void KeepCircular(Long64_t maxEntries)
keep a maximum of fMaxEntries in memory
Definition TBranch.cxx:2283
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset a Branch.
Definition TBranch.cxx:2598
virtual TBranch * FindBranch(const char *name)
Find the immediate sub-branch with passed name.
Definition TBranch.cxx:1035
virtual Int_t LoadBaskets()
Baskets associated to this branch are forced to be in memory.
Definition TBranch.cxx:2309
void SetIOFeatures(TIOFeatures &features)
Definition TBranch.h:283
Long64_t GetTotBytes(Option_t *option="") const
Return total number of bytes in the branch (excluding current buffer) if option ="*" includes all sub...
Definition TBranch.cxx:2220
virtual void SetOffset(Int_t offset=0)
Definition TBranch.h:285
virtual Int_t GetExpectedType(TClass *&clptr, EDataType &type)
Fill expectedClass and expectedType with information on the data type of the object/values contained ...
Definition TBranch.cxx:1834
virtual Int_t GetBasketSize() const
Definition TBranch.h:217
Long64_t GetZipBytes(Option_t *option="") const
Return total number of zip bytes in the branch if option ="*" includes all sub-branches of this branc...
Definition TBranch.cxx:2238
virtual void SetBasketSize(Int_t buffsize)
Set the basket size The function makes sure that the basket size is greater than fEntryOffsetlen.
Definition TBranch.cxx:2729
virtual void Refresh(TBranch *b)
Refresh this branch using new information in b This function is called by TTree::Refresh.
Definition TBranch.cxx:2508
virtual bool SetMakeClass(bool decomposeObj=true)
Set the branch in a mode where the object are decomposed (Also known as MakeClass mode).
Definition TBranch.cxx:2927
TObjArray * GetListOfLeaves()
Definition TBranch.h:247
Int_t Fill()
Definition TBranch.h:205
virtual void Reset(Option_t *option="")
Reset a Branch.
Definition TBranch.cxx:2557
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition TBranch.cxx:2127
virtual Int_t FillImpl(ROOT::Internal::TBranchIMTHelper *)
Loop on all leaves of this branch to fill Basket buffer.
Definition TBranch.cxx:856
Int_t GetEntryOffsetLen() const
Definition TBranch.h:227
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
Buffer base class used for serializing objects.
Definition TBuffer.h:43
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition TBuffer.cxx:223
Int_t BufferSize() const
Definition TBuffer.h:98
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2388
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2955
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5059
Bool_t HasDataMemberInfo() const
Definition TClass.h:407
Bool_t HasCustomStreamerMember() const
The class has a Streamer method and it is implemented by the user or an older (not StreamerInfo based...
Definition TClass.h:509
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5481
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2100
const std::type_info * GetTypeInfo() const
Definition TClass.h:497
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3839
TList * GetListOfRealData() const
Definition TClass.h:454
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:393
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition TClass.cxx:2001
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3705
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:5993
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6019
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition TClass.cxx:4668
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4943
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2966
TVirtualStreamerInfo * GetConversionStreamerInfo(const char *onfile_classname, Int_t version) const
Return a Conversion StreamerInfo from the class 'classname' for version number 'version' to this clas...
Definition TClass.cxx:7167
TVirtualStreamerInfo * FindConversionStreamerInfo(const char *onfile_classname, UInt_t checksum) const
Return a Conversion StreamerInfo from the class 'classname' for the layout represented by 'checksum' ...
Definition TClass.cxx:7274
Version_t GetClassVersion() const
Definition TClass.h:421
TClass * GetActualClass(const void *object) const
Return a pointer to the real class of the object.
Definition TClass.cxx:2676
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:3037
Int_t WriteBuffer(TBuffer &b, void *pointer, const char *info="")
Function called by the Streamer functions to serialize object at p to buffer b.
Definition TClass.cxx:6860
An array of clone (identical) objects.
void BypassStreamer(Bool_t bypass=kTRUE)
When the kBypassStreamer bit is set, the automatically generated Streamer can call directly TClass::W...
TClass * GetClass() const
static TClass * Class()
Collection abstract base class.
Definition TCollection.h:65
virtual TObject ** GetObjectRef(const TObject *obj) const =0
virtual TIterator * MakeIterator(Bool_t dir=kIterForward) const =0
static TClass * Class()
void SetName(const char *name)
const char * GetName() const override
Return name of this collection.
virtual Int_t GetEntries() const
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
void Browse(TBrowser *b) override
Browse this collection (called by TBrowser).
A specialized string object used for TTree selections.
Definition TCut.h:25
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Bool_t IsPersistent() const
Definition TDataMember.h:91
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
Bool_t IsaPointer() const
Return true if data member is a pointer.
TDataType * GetDataType() const
Definition TDataMember.h:76
Longptr_t GetOffset() const
Get offset from "this".
const char * GetTypeName() const
Get the decayed type name of this data member, removing const and volatile qualifiers,...
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
const char * GetFullTypeName() const
Get the concrete type name of this data member, including const and volatile qualifiers.
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
Int_t GetType() const
Definition TDataType.h:68
TString GetTypeName()
Get basic type of typedef, e,g.: "class TDirectory*" -> "TDirectory".
Bool_t cd() override
Change current directory to "this" directory.
void Append(TObject *obj, Bool_t replace=kFALSE) override
Append object to this directory.
Bool_t IsWritable() const override
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
Describe directory structure in memory.
Definition TDirectory.h:45
virtual TList * GetList() const
Definition TDirectory.h:222
virtual void Append(TObject *obj, Bool_t replace=kFALSE)
Append object to this directory.
virtual Int_t WriteTObject(const TObject *obj, const char *name=nullptr, Option_t *="", Int_t=0)
Write an object with proper type checking.
virtual TFile * GetFile() const
Definition TDirectory.h:220
virtual Bool_t cd()
Change current directory to "this" directory.
virtual Int_t ReadKeys(Bool_t=kTRUE)
Definition TDirectory.h:248
virtual Bool_t IsWritable() const
Definition TDirectory.h:237
virtual TKey * GetKey(const char *, Short_t=9999) const
Definition TDirectory.h:221
virtual Int_t ReadTObject(TObject *, const char *)
Definition TDirectory.h:249
virtual void SaveSelf(Bool_t=kFALSE)
Definition TDirectory.h:255
virtual TList * GetListOfKeys() const
Definition TDirectory.h:223
void GetObject(const char *namecycle, T *&ptr)
Get an object with proper type checking.
Definition TDirectory.h:212
virtual TObject * Remove(TObject *)
Remove an object from the in-memory list.
Streamer around an arbitrary STL like container, which implements basic container functionality.
A List of entry numbers in a TTree or TChain.
Definition TEntryList.h:26
virtual bool Enter(Long64_t entry, TTree *tree=nullptr)
Add entry #entry to the list.
virtual void SetTree(const TTree *tree)
If a list for a tree with such name and filename exists, sets it as the current sublist If not,...
virtual TDirectory * GetDirectory() const
Definition TEntryList.h:77
virtual void SetReapplyCut(bool apply=false)
Definition TEntryList.h:108
virtual void SetDirectory(TDirectory *dir)
Add reference to directory dir. dir can be 0.
virtual Long64_t GetEntry(Long64_t index)
Return the number of the entry #index of this TEntryList in the TTree or TChain See also Next().
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:491
<div class="legacybox"><h2>Legacy Code</h2> TEventList is a legacy interface: there will be no bug fi...
Definition TEventList.h:31
virtual Long64_t GetEntry(Int_t index) const
Return value of entry at index in the list.
virtual bool GetReapplyCut() const
Definition TEventList.h:57
virtual Int_t GetN() const
Definition TEventList.h:56
A cache when reading files over the network.
virtual void WaitFinishPrefetch()
virtual Int_t GetBufferSize() const
TIOFeatures * fIOFeatures
TDirectory * fOutputDirectory
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:53
virtual void SetCacheRead(TFileCacheRead *cache, TObject *tree=nullptr, ECacheAction action=kDisconnect)
Set a pointer to the read cache.
Definition TFile.cxx:2362
Int_t GetCompressionSettings() const
Definition TFile.h:397
Int_t GetCompressionLevel() const
Definition TFile.h:391
virtual Long64_t GetEND() const
Definition TFile.h:231
virtual void WriteStreamerInfo()
Write the list of TStreamerInfo as a single object in this file The class Streamer description for al...
Definition TFile.cxx:3789
@ kDoNotDisconnect
Definition TFile.h:70
virtual void Flush()
Synchronize a file's in-memory and on-disk states.
Definition TFile.cxx:1138
virtual void MakeFree(Long64_t first, Long64_t last)
Mark unused bytes on the file.
Definition TFile.cxx:1481
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:4086
virtual void WriteHeader()
Write File Header.
Definition TFile.cxx:2612
Int_t GetRecordHeader(char *buf, Long64_t first, Int_t maxbytes, Int_t &nbytes, Int_t &objlen, Int_t &keylen)
Read the logical record header starting at a certain postion.
Definition TFile.cxx:1298
TFileCacheRead * GetCacheRead(const TObject *tree=nullptr) const
Return a pointer to the current read cache.
Definition TFile.cxx:1259
<div class="legacybox"><h2>Legacy Code</h2> TFolder is a legacy interface: there will be no bug fixes...
Definition TFolder.h:30
TCollection * GetListOfFolders() const
Definition TFolder.h:55
virtual Int_t Occurence(const TObject *obj) const
Return occurence number of object in the list of objects of this folder.
Definition TFolder.cxx:427
static TClass * Class()
A TFriendElement TF describes a TTree object TF in a file.
virtual const char * GetTreeName() const
Get the actual TTree name of the friend.
virtual TTree * GetTree()
Return pointer to friend TTree.
bool IsUpdated() const
virtual TFile * GetFile()
Return pointer to TFile containing this friend TTree.
TTree * fParentTree
! pointer to the parent TTree
virtual Int_t DeleteGlobal(void *obj)=0
void Reset()
Iterator abstract base class.
Definition TIterator.h:30
virtual TObject * Next()=0
virtual TClass * IsA() const
Definition TIterator.h:48
virtual Option_t * GetOption() const
Definition TIterator.h:40
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
void Delete(Option_t *option="") override
Delete an object from the file.
Definition TKey.cxx:538
Int_t GetKeylen() const
Definition TKey.h:84
Int_t GetNbytes() const
Definition TKey.h:86
virtual const char * GetClassName() const
Definition TKey.h:75
static TClass * Class()
static TClass * Class()
static TClass * Class()
static TClass * Class()
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
virtual Double_t GetValue(Int_t i=0) const
Definition TLeaf.h:183
virtual void * GetValuePointer() const
Definition TLeaf.h:138
virtual Int_t GetLenType() const
Definition TLeaf.h:133
virtual void ReadValue(std::istream &, Char_t=' ')
Definition TLeaf.h:156
virtual Int_t GetMaximum() const
Definition TLeaf.h:134
virtual Int_t GetLen() const
Return the number of effective elements of this leaf, for the current entry.
Definition TLeaf.cxx:404
virtual TLeaf * GetLeafCount() const
If this leaf stores a variable-sized array or a multi-dimensional array whose last dimension has vari...
Definition TLeaf.h:121
TClass * IsA() const override
Definition TLeaf.h:168
virtual bool IncludeRange(TLeaf *)
Definition TLeaf.h:146
virtual void SetAddress(void *add=nullptr)
Definition TLeaf.h:185
TBranch * GetBranch() const
Definition TLeaf.h:116
@ kNewValue
Set if we own the value buffer and so must delete it ourselves.
Definition TLeaf.h:96
@ kIndirectAddress
Data member is a pointer to an array of basic types.
Definition TLeaf.h:95
virtual TString GetFullName() const
Return the full name (including the parent's branch names) of the leaf.
Definition TLeaf.cxx:224
virtual Int_t GetOffset() const
Definition TLeaf.h:137
virtual void PrintValue(Int_t i=0) const
Definition TLeaf.h:184
A doubly linked list.
Definition TList.h:38
void Streamer(TBuffer &) override
Stream all objects in the collection to or from the I/O buffer.
Definition TList.cxx:1189
void Clear(Option_t *option="") override
Remove all objects from the list.
Definition TList.cxx:400
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:576
void RecursiveRemove(TObject *obj) override
Remove object from this collection and recursively remove the object from all other objects (and coll...
Definition TList.cxx:762
void Add(TObject *obj) override
Definition TList.h:81
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:820
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:657
virtual TObjLink * FirstLink() const
Definition TList.h:102
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:468
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:355
A TMemFile is like a normal TFile except that it reads and writes only from memory.
Definition TMemFile.h:19
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
Definition TNamed.cxx:74
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
void Streamer(TBuffer &) override
Stream an object of class TObject.
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
TString fTitle
Definition TNamed.h:33
TNamed()
Definition TNamed.h:36
TString fName
Definition TNamed.h:32
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:140
See TNotifyLink.
Definition TNotifyLink.h:47
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
Int_t GetEntriesUnsafe() const
Return the number of objects in array (i.e.
TObject * Last() const override
Return the object in the last filled slot. Returns 0 if no entries.
void Clear(Option_t *option="") override
Remove all objects from the array.
void Streamer(TBuffer &) override
Stream all objects in the array to or from the I/O buffer.
TIterator * MakeIterator(Bool_t dir=kIterForward) const override
Returns an array iterator.
virtual void Compress()
Remove empty slots from array.
Int_t GetEntries() const override
Return the number of objects in array (i.e.
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
TObject * At(Int_t idx) const override
Definition TObjArray.h:164
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
TObject * RemoveAt(Int_t idx) override
Remove object at index idx.
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
void Add(TObject *obj) override
Definition TObjArray.h:68
Mother of all ROOT objects.
Definition TObject.h:41
virtual Bool_t Notify()
This method must be overridden to handle object notification (the base implementation is no-op).
Definition TObject.cxx:611
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:456
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:199
@ kBitMask
Definition TObject.h:86
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:225
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:991
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition TObject.h:153
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition TObject.cxx:898
@ kOnlyPrepStep
Used to request that the class specific implementation of TObject::Write just prepare the objects to ...
Definition TObject.h:106
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:798
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:542
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1005
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1033
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:500
virtual TClass * IsA() const
Definition TObject.h:243
void ResetBit(UInt_t f)
Definition TObject.h:198
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:62
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:64
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:979
Principal Components Analysis (PCA)
Definition TPrincipal.h:21
The TRealData class manages the effective list of all data members for a given class.
Definition TRealData.h:30
const char * GetName() const override
Returns name of object.
Definition TRealData.h:52
TDataMember * GetDataMember() const
Definition TRealData.h:53
Bool_t IsObject() const
Definition TRealData.h:56
Long_t GetThisOffset() const
Definition TRealData.h:55
A TRefTable maintains the association between a referenced object and the parent object supporting th...
Definition TRefTable.h:35
static void SetRefTable(TRefTable *table)
Static function setting the current TRefTable.
static TRefTable * GetRefTable()
Static function returning the current TRefTable.
Regular expression class.
Definition TRegexp.h:31
A TSelector object is used by the TTree::Draw, TTree::Scan, TTree::Process to navigate in a TTree and...
Definition TSelector.h:31
static void * ReAlloc(void *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition TStorage.cxx:183
Describes a persistent version of a class.
void ForceWriteInfo(TFile *file, Bool_t force=kFALSE) override
Recursively mark streamer infos for writing to a file.
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
void ToLower()
Change string to lower-case.
Definition TString.cxx:1182
static constexpr Ssiz_t kNPOS
Definition TString.h:278
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1163
Double_t Atof() const
Return floating-point value contained in string.
Definition TString.cxx:2054
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition TString.cxx:538
const char * Data() const
Definition TString.h:376
Bool_t EqualTo(const char *cs, ECaseCompare cmp=kExact) const
Definition TString.h:645
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:704
@ kLeading
Definition TString.h:276
@ kTrailing
Definition TString.h:276
@ kIgnoreCase
Definition TString.h:277
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition TString.cxx:931
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2264
Bool_t IsNull() const
Definition TString.h:414
TString & Remove(Ssiz_t pos)
Definition TString.h:685
TString & Append(const char *cs)
Definition TString.h:572
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2378
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2356
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
void SetHistFillColor(Color_t color=1)
Definition TStyle.h:379
Color_t GetHistLineColor() const
Definition TStyle.h:233
Bool_t IsReading() const
Definition TStyle.h:296
void SetHistLineStyle(Style_t styl=0)
Definition TStyle.h:382
Style_t GetHistFillStyle() const
Definition TStyle.h:234
Color_t GetHistFillColor() const
Definition TStyle.h:232
void SetHistLineColor(Color_t color=1)
Definition TStyle.h:380
Style_t GetHistLineStyle() const
Definition TStyle.h:235
void SetHistFillStyle(Style_t styl=0)
Definition TStyle.h:381
Width_t GetHistLineWidth() const
Definition TStyle.h:236
void SetHistLineWidth(Width_t width=1)
Definition TStyle.h:383
A zero length substring is legal.
Definition TString.h:85
TString & String()
Definition TString.h:124
virtual const char * Getenv(const char *env)
Get environment variable.
Definition TSystem.cxx:1665
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition TSystem.cxx:1296
A TTreeCache which exploits parallelized decompression of its own content.
static bool IsParallelUnzip()
Static function that tells wether the multithreading unzipping is activated.
A cache to speed-up the reading of ROOT datasets.
Definition TTreeCache.h:32
bool IsAutoCreated() const
Definition TTreeCache.h:150
Int_t SetBufferSize(Long64_t buffersize) override
Change the underlying buffer size of the cache.
static void SetLearnEntries(Int_t n=10)
Static function to set the number of entries to be used in learning mode The default value for n is 1...
TTree * GetTree() const
Definition TTreeCache.h:149
virtual void SetEntryRange(Long64_t emin, Long64_t emax)
Set the minimum and maximum entry number to be processed this information helps to optimize the numbe...
virtual Int_t DropBranch(TBranch *b, bool subbranches=false)
Remove a branch to the list of branches to be stored in the cache this function is called by TBranch:...
void SetAutoCreated(bool val)
Definition TTreeCache.h:164
virtual void StopLearningPhase()
This is the counterpart of StartLearningPhase() and can be used to stop the learning phase.
void Print(Option_t *option="") const override
Print cache statistics.
Int_t AddBranch(TBranch *b, bool subgbranches=false) override
Add a branch to the list of branches to be stored in the cache this function is called by the user vi...
Class implementing or helping the various TTree cloning method.
Definition TTreeCloner.h:31
const char * GetWarning() const
bool Exec()
Execute the cloning.
bool NeedConversion()
bool IsValid()
void SetCacheSize(Long64_t size)
Set the cache size used by the matching TFile.
Iterator on all the leaves in a TTree and its friend.
Definition TTree.h:716
TTree * fTree
tree being iterated
Definition TTree.h:719
TIterator & operator=(const TIterator &rhs) override
Overridden assignment operator. Does NOT copy the 'cursor' location!
Definition TTree.cxx:9782
TObject * Next() override
Go the next friend element.
Definition TTree.cxx:9805
TIterator * fLeafIter
current leaf sub-iterator.
Definition TTree.h:720
Option_t * GetOption() const override
Returns the object option stored in the list.
Definition TTree.cxx:9844
TIterator * fTreeIter
current tree sub-iterator.
Definition TTree.h:721
bool fDirection
iteration direction
Definition TTree.h:722
static TClass * Class()
Helper class to iterate over cluster of baskets.
Definition TTree.h:270
Long64_t GetEstimatedClusterSize()
Estimate the cluster size.
Definition TTree.cxx:601
Long64_t Previous()
Move on to the previous cluster and return the starting entry of this previous cluster.
Definition TTree.cxx:684
Long64_t Next()
Move on to the next cluster and return the starting entry of this next cluster.
Definition TTree.cxx:640
Long64_t GetNextEntry()
Definition TTree.h:307
TClusterIterator(TTree *tree, Long64_t firstEntry)
Regular constructor.
Definition TTree.cxx:550
Helper class to prevent infinite recursion in the usage of TTree Friends.
Definition TTree.h:188
TFriendLock & operator=(const TFriendLock &)
Assignment operator.
Definition TTree.cxx:520
TFriendLock(const TFriendLock &)
Copy constructor.
Definition TTree.cxx:510
UInt_t fMethodBit
Definition TTree.h:192
TTree * fTree
Definition TTree.h:191
~TFriendLock()
Restore the state of tree the same as before we set the lock.
Definition TTree.cxx:533
A TTree represents a columnar dataset.
Definition TTree.h:79
virtual Int_t Fill()
Fill all branches.
Definition TTree.cxx:4593
virtual TFriendElement * AddFriend(const char *treename, const char *filename="")
Add a TFriendElement to the list of friends.
Definition TTree.cxx:1322
TBranchRef * fBranchRef
Branch supporting the TRefTable (if any)
Definition TTree.h:136
TStreamerInfo * BuildStreamerInfo(TClass *cl, void *pointer=nullptr, bool canOptimize=true)
Build StreamerInfo for class cl.
Definition TTree.cxx:2642
virtual TBranch * FindBranch(const char *name)
Return the branch that correspond to the path 'branchname', which can include the name of the tree or...
Definition TTree.cxx:4831
virtual void SetBranchStatus(const char *bname, bool status=true, UInt_t *found=nullptr)
Set branch status to Process or DoNotProcess.
Definition TTree.cxx:8524
bool EnableCache()
Enable the TTreeCache unless explicitly disabled for this TTree by a prior call to SetCacheSize(0).
Definition TTree.cxx:2675
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5284
static Int_t GetBranchStyle()
Static function returning the current branch style.
Definition TTree.cxx:5385
TList * fFriends
pointer to list of friend elements
Definition TTree.h:130
bool fIMTEnabled
! true if implicit multi-threading is enabled for this tree
Definition TTree.h:142
virtual bool GetBranchStatus(const char *branchname) const
Return status of branch with name branchname.
Definition TTree.cxx:5370
UInt_t fFriendLockStatus
! Record which method is locking the friend recursion
Definition TTree.h:137
virtual TLeaf * GetLeafImpl(const char *branchname, const char *leafname)
Return pointer to the 1st Leaf named name in any Branch of this Tree or any branch in the list of fri...
Definition TTree.cxx:6088
Long64_t fTotBytes
Total number of bytes in all branches before compression.
Definition TTree.h:86
virtual Int_t FlushBaskets(bool create_cluster=true) const
Write to disk all the basket that have not yet been individually written and create an event cluster ...
Definition TTree.cxx:5119
Int_t fMaxClusterRange
! Memory allocated for the cluster range.
Definition TTree.h:96
virtual void Show(Long64_t entry=-1, Int_t lenmax=20)
Print values of all active leaves for entry.
Definition TTree.cxx:9375
TEventList * fEventList
! Pointer to event selection list (if one)
Definition TTree.h:125
virtual Long64_t GetAutoSave() const
Definition TTree.h:448
virtual Int_t StopCacheLearningPhase()
Stop the cache learning phase.
Definition TTree.cxx:9464
virtual Int_t GetEntry(Long64_t entry, Int_t getall=0)
Read all branches of entry and return total number of bytes read.
Definition TTree.cxx:5628
std::vector< std::pair< Long64_t, TBranch * > > fSortedBranches
! Branches to be processed in parallel when IMT is on, sorted by average task time
Definition TTree.h:144
virtual void SetCircular(Long64_t maxEntries)
Enable/Disable circularity for this tree.
Definition TTree.cxx:8882
Long64_t fSavedBytes
Number of autosaved bytes.
Definition TTree.h:88
virtual Int_t AddBranchToCache(const char *bname, bool subbranches=false)
Add branch with name bname to the Tree cache.
Definition TTree.cxx:1049
Long64_t GetMedianClusterSize()
Estimate the median cluster size for the TTree.
Definition TTree.cxx:8287
virtual TClusterIterator GetClusterIterator(Long64_t firstentry)
Return an iterator over the cluster of baskets starting at firstentry.
Definition TTree.cxx:5457
virtual void ResetBranchAddress(TBranch *)
Tell all of our branches to set their addresses to zero.
Definition TTree.cxx:8055
bool fCacheUserSet
! true if the cache setting was explicitly given by user
Definition TTree.h:141
char GetNewlineValue(std::istream &inputStream)
Determine which newline this file is using.
Definition TTree.cxx:7578
TIOFeatures fIOFeatures
IO features to define for newly-written baskets and branches.
Definition TTree.h:114
virtual Long64_t GetEntryNumberWithIndex(Long64_t major, Long64_t minor=0) const
Return entry number corresponding to major and minor number.
Definition TTree.cxx:5900
Long64_t fDebugMin
! First entry number to debug
Definition TTree.h:112
virtual Long64_t SetEntries(Long64_t n=-1)
Change number of entries in the tree.
Definition TTree.cxx:9001
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:529
virtual TBranch * BranchOld(const char *name, const char *classname, void *addobj, Int_t bufsize=32000, Int_t splitlevel=1)
Create a new TTree BranchObject.
Definition TTree.cxx:2064
Long64_t GetCacheAutoSize(bool withDefault=false)
Used for automatic sizing of the cache.
Definition TTree.cxx:5397
virtual TBranch * BranchRef()
Build the optional branch supporting the TRefTable.
Definition TTree.cxx:2318
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5469
TList * fAliases
List of aliases for expressions based on the tree branches.
Definition TTree.h:124
virtual TTree * CopyTree(const char *selection, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Copy a tree with selection.
Definition TTree.cxx:3709
virtual Int_t DropBranchFromCache(const char *bname, bool subbranches=false)
Remove the branch with name 'bname' from the Tree cache.
Definition TTree.cxx:1132
virtual Int_t Fit(const char *funcname, const char *varexp, const char *selection="", Option_t *option="", Option_t *goption="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Fit a projected item(s) from a tree.
Definition TTree.cxx:5069
Long64_t * fClusterRangeEnd
[fNClusterRange] Last entry of a cluster range.
Definition TTree.h:103
void Streamer(TBuffer &) override
Stream a class object.
Definition TTree.cxx:9535
std::atomic< Long64_t > fIMTZipBytes
! Zip bytes for the IMT flush baskets.
Definition TTree.h:161
void RecursiveRemove(TObject *obj) override
Make sure that obj (which is being deleted or will soon be) is no longer referenced by this TTree.
Definition TTree.cxx:7871
TVirtualTreePlayer * GetPlayer()
Load the TTreePlayer (if not already done).
Definition TTree.cxx:6295
virtual Int_t MakeProxy(const char *classname, const char *macrofilename=nullptr, const char *cutfilename=nullptr, const char *option=nullptr, Int_t maxUnrolling=3)
Generate a skeleton analysis class for this Tree using TBranchProxy.
Definition TTree.cxx:6758
@ kSplitCollectionOfPointers
Definition TTree.h:266
virtual Long64_t ReadStream(std::istream &inputStream, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from an input stream.
Definition TTree.cxx:7605
virtual void SetDebug(Int_t level=1, Long64_t min=0, Long64_t max=9999999)
Set the debug level and the debug range.
Definition TTree.cxx:8918
Int_t fScanField
Number of runs before prompting in Scan.
Definition TTree.h:92
void Draw(Option_t *opt) override
Default Draw method for all objects.
Definition TTree.h:431
virtual TTree * GetFriend(const char *) const
Return a pointer to the TTree friend whose name or alias is friendname.
Definition TTree.cxx:5965
virtual void SetNotify(TObject *obj)
Sets the address of the object to be notified when the tree is loaded.
Definition TTree.cxx:9221
virtual Double_t GetMaximum(const char *columname)
Return maximum of column with name columname.
Definition TTree.cxx:6225
virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor=0) const
Return entry number corresponding to major and minor number.
Definition TTree.cxx:5880
static void SetMaxTreeSize(Long64_t maxsize=100000000000LL)
Set the maximum size in bytes of a Tree file (static function).
Definition TTree.cxx:9187
void Print(Option_t *option="") const override
Print a summary of the tree contents.
Definition TTree.cxx:7209
virtual Int_t UnbinnedFit(const char *funcname, const char *varexp, const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Unbinned fit of one or more variable(s) from a tree.
Definition TTree.cxx:9692
Int_t fNClusterRange
Number of Cluster range in addition to the one defined by 'AutoFlush'.
Definition TTree.h:95
virtual void PrintCacheStats(Option_t *option="") const
Print statistics about the TreeCache for this tree.
Definition TTree.cxx:7360
virtual Int_t BuildIndex(const char *majorname, const char *minorname="0")
Build a Tree Index (default is TTreeIndex).
Definition TTree.cxx:2627
TVirtualTreePlayer * fPlayer
! Pointer to current Tree player
Definition TTree.h:134
virtual TIterator * GetIteratorOnAllLeaves(bool dir=kIterForward)
Creates a new iterator that will go through all the leaves on the tree itself and its friend.
Definition TTree.cxx:6072
virtual void SetMakeClass(Int_t make)
Set all the branches in this TTree to be in decomposed object mode (also known as MakeClass mode).
Definition TTree.cxx:9167
virtual bool InPlaceClone(TDirectory *newdirectory, const char *options="")
Copy the content to a new new file, update this TTree with the new location information and attach th...
Definition TTree.cxx:7002
TObjArray fBranches
List of Branches.
Definition TTree.h:122
TDirectory * GetDirectory() const
Definition TTree.h:462
bool fCacheDoAutoInit
! true if cache auto creation or resize check is needed
Definition TTree.h:139
TTreeCache * GetReadCache(TFile *file) const
Find and return the TTreeCache registered with the file and which may contain branches for us.
Definition TTree.cxx:6308
Long64_t fEntries
Number of entries.
Definition TTree.h:84
virtual TFile * ChangeFile(TFile *file)
Called by TTree::Fill() when file has reached its maximum fgMaxTreeSize.
Definition TTree.cxx:2739
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5844
virtual void SetWeight(Double_t w=1, Option_t *option="")
Set tree weight.
Definition TTree.cxx:9364
void InitializeBranchLists(bool checkLeafCount)
Divides the top-level branches into two vectors: (i) branches to be processed sequentially and (ii) b...
Definition TTree.cxx:5771
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr=nullptr)
Change branch address, dealing with clone trees properly.
Definition TTree.cxx:8375
Long64_t * fClusterSize
[fNClusterRange] Number of entries in each cluster for a given range.
Definition TTree.h:104
Long64_t fFlushedBytes
Number of auto-flushed bytes.
Definition TTree.h:89
virtual void SetPerfStats(TVirtualPerfStats *perf)
Set perf stats.
Definition TTree.cxx:9319
std::atomic< Long64_t > fIMTTotBytes
! Total bytes for the IMT flush baskets
Definition TTree.h:160
virtual void SetCacheLearnEntries(Int_t n=10)
Interface to TTreeCache to set the number of entries for the learning phase.
Definition TTree.cxx:8855
TEntryList * fEntryList
! Pointer to event selection list (if one)
Definition TTree.h:126
virtual TVirtualIndex * GetTreeIndex() const
Definition TTree.h:558
TList * fExternalFriends
! List of TFriendsElement pointing to us and need to be notified of LoadTree. Content not owned.
Definition TTree.h:131
virtual Long64_t Merge(TCollection *list, Option_t *option="")
Merge the trees in the TList into this tree.
Definition TTree.cxx:6880
virtual void SetMaxVirtualSize(Long64_t size=0)
Definition TTree.h:665
virtual void DropBaskets()
Remove some baskets from memory.
Definition TTree.cxx:4508
virtual void SetAutoSave(Long64_t autos=-300000000)
In case of a program crash, it will be possible to recover the data in the tree up to the last AutoSa...
Definition TTree.cxx:8332
Long64_t fMaxEntryLoop
Maximum number of entries to process.
Definition TTree.h:98
virtual void SetParallelUnzip(bool opt=true, Float_t RelSize=-1)
Enable or disable parallel unzipping of Tree buffers.
Definition TTree.cxx:9281
virtual void SetDirectory(TDirectory *dir)
Change the tree's directory.
Definition TTree.cxx:8956
void SortBranchesByTime()
Sorts top-level branches by the last average task time recorded per branch.
Definition TTree.cxx:5824
void Delete(Option_t *option="") override
Delete this tree from memory or/and disk.
Definition TTree.cxx:3737
virtual TBranchRef * GetBranchRef() const
Definition TTree.h:450
virtual Long64_t Process(const char *filename, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Process this tree executing the TSelector code in the specified filename.
Definition TTree.cxx:7440
virtual TBranch * BranchImpRef(const char *branchname, const char *classname, TClass *ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
Same as TTree::Branch but automatic detection of the class name.
Definition TTree.cxx:1625
virtual void SetEventList(TEventList *list)
This function transfroms the given TEventList into a TEntryList The new TEntryList is owned by the TT...
Definition TTree.cxx:9059
void MoveReadCache(TFile *src, TDirectory *dir)
Move a cache from a file to the current file in dir.
Definition TTree.cxx:6973
Long64_t fAutoFlush
Auto-flush tree when fAutoFlush entries written or -fAutoFlush (compressed) bytes produced.
Definition TTree.h:101
Int_t fUpdate
Update frequency for EntryLoop.
Definition TTree.h:93
virtual void ResetAfterMerge(TFileMergeInfo *)
Resets the state of this TTree after a merge (keep the customization but forget the data).
Definition TTree.cxx:8024
virtual Long64_t GetEntries() const
Definition TTree.h:463
virtual void SetEstimate(Long64_t nentries=1000000)
Set number of entries to estimate variable limits.
Definition TTree.cxx:9100
Int_t fTimerInterval
Timer interval in milliseconds.
Definition TTree.h:91
Int_t fDebug
! Debug level
Definition TTree.h:111
Int_t SetCacheSizeAux(bool autocache=true, Long64_t cacheSize=0)
Set the size of the file cache and create it if possible.
Definition TTree.cxx:8701
virtual Long64_t AutoSave(Option_t *option="")
AutoSave tree header every fAutoSave bytes.
Definition TTree.cxx:1490
virtual Long64_t GetEntryNumber(Long64_t entry) const
Return entry number corresponding to entry.
Definition TTree.cxx:5855
virtual TTree * CloneTree(Long64_t nentries=-1, Option_t *option="")
Create a clone of this tree and copy nentries.
Definition TTree.cxx:3129
Int_t fFileNumber
! current file number (if file extensions)
Definition TTree.h:116
virtual TLeaf * GetLeaf(const char *branchname, const char *leafname)
Return pointer to the 1st Leaf named name in any Branch of this Tree or any branch in the list of fri...
Definition TTree.cxx:6185
virtual Long64_t GetZipBytes() const
Definition TTree.h:585
TObjArray fLeaves
Direct pointers to individual branch leaves.
Definition TTree.h:123
virtual void Reset(Option_t *option="")
Reset baskets, buffers and entries count in all branches and leaves.
Definition TTree.cxx:7993
virtual void KeepCircular()
Keep a maximum of fMaxEntries in memory.
Definition TTree.cxx:6405
virtual void SetDefaultEntryOffsetLen(Int_t newdefault, bool updateExisting=false)
Update the default value for the branch's fEntryOffsetLen.
Definition TTree.cxx:8930
virtual void DirectoryAutoAdd(TDirectory *)
Called by TKey and TObject::Clone to automatically add us to a directory when we are read from a file...
Definition TTree.cxx:3809
Long64_t fMaxVirtualSize
Maximum total size of buffers kept in memory.
Definition TTree.h:99
virtual Long64_t GetTotBytes() const
Definition TTree.h:556
virtual Int_t MakeSelector(const char *selector=nullptr, Option_t *option="")
Generate skeleton selector class for this tree.
Definition TTree.cxx:6812
virtual void SetObject(const char *name, const char *title)
Change the name and title of this tree.
Definition TTree.cxx:9250
TVirtualPerfStats * fPerfStats
! pointer to the current perf stats object
Definition TTree.h:132
Double_t fWeight
Tree weight (see TTree::SetWeight)
Definition TTree.h:90
std::vector< TBranch * > fSeqBranches
! Branches to be processed sequentially when IMT is on
Definition TTree.h:145
Long64_t fDebugMax
! Last entry number to debug
Definition TTree.h:113
Int_t fDefaultEntryOffsetLen
Initial Length of fEntryOffset table in the basket buffers.
Definition TTree.h:94
TTree()
Default constructor and I/O constructor.
Definition TTree.cxx:727
Long64_t fAutoSave
Autosave tree when fAutoSave entries written or -fAutoSave (compressed) bytes produced.
Definition TTree.h:100
TBranch * Branch(const char *name, T *obj, Int_t bufsize=32000, Int_t splitlevel=99)
Add a new branch, and infer the data type from the type of obj being passed.
Definition TTree.h:353
std::atomic< UInt_t > fAllocationCount
indicates basket should be resized to exact memory usage, but causes significant
Definition TTree.h:152
virtual Int_t GetEntryWithIndex(Int_t major, Int_t minor=0)
Read entry corresponding to major and minor number.
Definition TTree.cxx:5917
static TTree * MergeTrees(TList *list, Option_t *option="")
Static function merging the trees in the TList into a new tree.
Definition TTree.cxx:6841
bool MemoryFull(Int_t nbytes)
Check if adding nbytes to memory we are still below MaxVirtualsize.
Definition TTree.cxx:6827
virtual Long64_t GetReadEntry() const
Definition TTree.h:549
virtual TObjArray * GetListOfBranches()
Definition TTree.h:528
Long64_t fZipBytes
Total number of bytes in all branches after compression.
Definition TTree.h:87
virtual TTree * GetTree() const
Definition TTree.h:557
TBuffer * fTransientBuffer
! Pointer to the current transient buffer.
Definition TTree.h:138
virtual void SetEntryList(TEntryList *list, Option_t *opt="")
Set an EntryList.
Definition TTree.cxx:9036
bool Notify() override
Function called when loading a new class library.
Definition TTree.cxx:7023
virtual void AddZipBytes(Int_t zip)
Definition TTree.h:332
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6463
virtual Long64_t ReadFile(const char *filename, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from filename.
Definition TTree.cxx:7554
virtual const char * GetAlias(const char *aliasName) const
Returns the expanded value of the alias. Search in the friends if any.
Definition TTree.cxx:5216
ROOT::TIOFeatures SetIOFeatures(const ROOT::TIOFeatures &)
Provide the end-user with the ability to enable/disable various experimental IO features for this TTr...
Definition TTree.cxx:9120
virtual TBasket * CreateBasket(TBranch *)
Create a basket for this tree and given branch.
Definition TTree.cxx:3721
TList * fUserInfo
pointer to a list of user objects associated to this Tree
Definition TTree.h:133
virtual Double_t GetMinimum(const char *columname)
Return minimum of column with name columname.
Definition TTree.cxx:6265
virtual void RemoveFriend(TTree *)
Remove a friend from the list of friends.
Definition TTree.cxx:7967
virtual Long64_t GetEntriesFast() const
Return a number greater or equal to the total number of entries in the dataset.
Definition TTree.h:505
void Browse(TBrowser *) override
Browse content of the TTree.
Definition TTree.cxx:2599
virtual TList * GetUserInfo()
Return a pointer to the list containing user objects associated to this tree.
Definition TTree.cxx:6346
Long64_t fChainOffset
! Offset of 1st entry of this Tree in a TChain
Definition TTree.h:106
@ kOnlyFlushAtCluster
If set, the branch's buffers will grow until an event cluster boundary is hit, guaranteeing a basket ...
Definition TTree.h:256
@ kEntriesReshuffled
If set, signals that this TTree is the output of the processing of another TTree, and the entries are...
Definition TTree.h:261
@ kCircular
Definition TTree.h:252
virtual Long64_t GetEntriesFriend() const
Return pointer to the 1st Leaf named name in any Branch of this Tree or any branch in the list of fri...
Definition TTree.cxx:5502
virtual TSQLResult * Query(const char *varexp="", const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Loop over entries and return a TSQLResult object containing entries following selection.
Definition TTree.cxx:7503
virtual TBranch * Bronch(const char *name, const char *classname, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99)
Create a new TTree BranchElement.
Definition TTree.cxx:2394
virtual void SetBasketSize(const char *bname, Int_t buffsize=16000)
Set a branch's basket size.
Definition TTree.cxx:8348
static void SetBranchStyle(Int_t style=1)
Set the current branch style.
Definition TTree.cxx:8655
~TTree() override
Destructor.
Definition TTree.cxx:910
void ImportClusterRanges(TTree *fromtree)
Appends the cluster range information stored in 'fromtree' to this tree, including the value of fAuto...
Definition TTree.cxx:6362
TClass * IsA() const override
Definition TTree.h:705
Long64_t fEstimate
Number of entries to estimate histogram limits.
Definition TTree.h:102
Int_t FlushBasketsImpl() const
Internal implementation of the FlushBaskets algorithm.
Definition TTree.cxx:5136
virtual Long64_t LoadTreeFriend(Long64_t entry, TTree *T)
Load entry on behalf of our master tree, we may use an index.
Definition TTree.cxx:6547
Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) override
Write this object to the current directory.
Definition TTree.cxx:9743
TVirtualIndex * fTreeIndex
Pointer to the tree Index (if any)
Definition TTree.h:129
void UseCurrentStyle() override
Replace current attributes by current style.
Definition TTree.cxx:9704
TObject * fNotify
Object to be notified when loading a Tree.
Definition TTree.h:120
virtual TBranch * BranchImp(const char *branchname, const char *classname, TClass *ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
Same as TTree::Branch() with added check that addobj matches className.
Definition TTree.cxx:1544
Long64_t fCacheSize
! Maximum size of file buffers
Definition TTree.h:105
TList * fClones
! List of cloned trees which share our addresses
Definition TTree.h:135
std::atomic< Long64_t > fTotalBuffers
! Total number of bytes in branch buffers
Definition TTree.h:108
static TClass * Class()
@ kFindBranch
Definition TTree.h:212
@ kFindLeaf
Definition TTree.h:213
@ kGetEntryWithIndex
Definition TTree.h:217
@ kPrint
Definition TTree.h:222
@ kGetFriend
Definition TTree.h:218
@ kGetBranch
Definition TTree.h:215
@ kSetBranchStatus
Definition TTree.h:224
@ kLoadTree
Definition TTree.h:221
@ kGetEntry
Definition TTree.h:216
@ kGetLeaf
Definition TTree.h:220
@ kRemoveFriend
Definition TTree.h:223
@ kGetFriendAlias
Definition TTree.h:219
@ kGetAlias
Definition TTree.h:214
virtual void SetTreeIndex(TVirtualIndex *index)
The current TreeIndex is replaced by the new index.
Definition TTree.cxx:9336
virtual void OptimizeBaskets(ULong64_t maxMemory=10000000, Float_t minComp=1.1, Option_t *option="")
This function may be called after having filled some entries in a Tree.
Definition TTree.cxx:7047
virtual Long64_t Project(const char *hname, const char *varexp, const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Make a projection of a tree using selections.
Definition TTree.cxx:7488
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:8821
static Long64_t GetMaxTreeSize()
Static function which returns the tree file size limit in bytes.
Definition TTree.cxx:6255
bool fCacheDoClusterPrefetch
! true if cache is prefetching whole clusters
Definition TTree.h:140
Int_t SetBranchAddressImp(TBranch *branch, void *addr, TBranch **ptr)
Change branch address, dealing with clone trees properly.
Definition TTree.cxx:8435
virtual bool SetAlias(const char *aliasName, const char *aliasFormula)
Set a tree variable alias.
Definition TTree.cxx:8131
virtual void CopyAddresses(TTree *, bool undo=false)
Set branch addresses of passed tree equal to ours.
Definition TTree.cxx:3289
Long64_t fMaxEntries
Maximum number of entries in case of circular buffers.
Definition TTree.h:97
virtual void DropBuffers(Int_t nbytes)
Drop branch buffers to accommodate nbytes below MaxVirtualsize.
Definition TTree.cxx:4521
virtual TList * GetListOfFriends() const
Definition TTree.h:530
virtual void Refresh()
Refresh contents of this tree and its branches from the current status on disk.
Definition TTree.cxx:7906
virtual void SetAutoFlush(Long64_t autof=-30000000)
This function may be called at the start of a program to change the default value for fAutoFlush.
Definition TTree.cxx:8186
static Long64_t fgMaxTreeSize
Maximum size of a file containing a Tree.
Definition TTree.h:155
Long64_t fReadEntry
! Number of the entry being processed
Definition TTree.h:107
TArrayD fIndexValues
Sorted index values.
Definition TTree.h:127
void MarkEventCluster()
Mark the previous event as being at the end of the event cluster.
Definition TTree.cxx:8248
UInt_t fNEntriesSinceSorting
! Number of entries processed since the last re-sorting of branches
Definition TTree.h:143
virtual void SetFileNumber(Int_t number=0)
Set fFileNumber to number.
Definition TTree.cxx:9143
virtual TLeaf * FindLeaf(const char *name)
Find leaf..
Definition TTree.cxx:4906
virtual void StartViewer()
Start the TTreeViewer on this tree.
Definition TTree.cxx:9449
Int_t GetMakeClass() const
Definition TTree.h:535
virtual Int_t MakeCode(const char *filename=nullptr)
Generate a skeleton function for this tree.
Definition TTree.cxx:6630
bool fIMTFlush
! True if we are doing a multithreaded flush.
Definition TTree.h:159
TDirectory * fDirectory
! Pointer to directory holding this tree
Definition TTree.h:121
@ kNeedEnableDecomposedObj
Definition TTree.h:244
@ kClassMismatch
Definition TTree.h:237
@ kVoidPtr
Definition TTree.h:242
@ kMatchConversionCollection
Definition TTree.h:240
@ kMissingCompiledCollectionProxy
Definition TTree.h:235
@ kMismatch
Definition TTree.h:236
@ kMatchConversion
Definition TTree.h:239
@ kInternalError
Definition TTree.h:234
@ kMatch
Definition TTree.h:238
@ kMissingBranch
Definition TTree.h:233
@ kMakeClass
Definition TTree.h:241
static Int_t fgBranchStyle
Old/New branch style.
Definition TTree.h:154
virtual void ResetBranchAddresses()
Tell all of our branches to drop their current objects and allocate new ones.
Definition TTree.cxx:8065
Int_t fNfill
! Local for EntryLoop
Definition TTree.h:110
void SetName(const char *name) override
Change the name of this tree.
Definition TTree.cxx:9195
virtual void RegisterExternalFriend(TFriendElement *)
Record a TFriendElement that we need to warn when the chain switches to a new file (typically this is...
Definition TTree.cxx:7947
TArrayI fIndex
Index of sorted values.
Definition TTree.h:128
virtual Int_t SetCacheSize(Long64_t cachesize=-1)
Set maximum size of the file cache .
Definition TTree.cxx:8673
void AddClone(TTree *)
Add a cloned tree to our list of trees to be notified whenever we change our branch addresses or when...
Definition TTree.cxx:1209
virtual Int_t CheckBranchAddressType(TBranch *branch, TClass *ptrClass, EDataType datatype, bool ptr)
Check whether or not the address described by the last 3 parameters matches the content of the branch...
Definition TTree.cxx:2857
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TTree for reading/writing baskets.
Definition TTree.cxx:1027
ROOT::TIOFeatures GetIOFeatures() const
Returns the current set of IO settings.
Definition TTree.cxx:6064
virtual Int_t MakeClass(const char *classname=nullptr, Option_t *option="")
Generate a skeleton analysis class for this tree.
Definition TTree.cxx:6597
virtual const char * GetFriendAlias(TTree *) const
If the 'tree' is a friend, this method returns its alias name.
Definition TTree.cxx:6022
virtual void RemoveExternalFriend(TFriendElement *)
Removes external friend.
Definition TTree.cxx:7958
Int_t fPacketSize
! Number of entries in one packet for parallel root
Definition TTree.h:109
virtual TBranch * BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Int_t bufsize, Int_t splitlevel)
Definition TTree.cxx:1721
virtual Long64_t Scan(const char *varexp="", const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Loop over tree entries and print entries passing selection.
Definition TTree.cxx:8089
virtual TBranch * BronchExec(const char *name, const char *classname, void *addobj, bool isptrptr, Int_t bufsize, Int_t splitlevel)
Helper function implementing TTree::Bronch and TTree::Branch(const char *name, T &obj);.
Definition TTree.cxx:2402
virtual void AddTotBytes(Int_t tot)
Definition TTree.h:331
virtual Long64_t CopyEntries(TTree *tree, Long64_t nentries=-1, Option_t *option="", bool needCopyAddresses=false)
Copy nentries from given tree to this tree.
Definition TTree.cxx:3524
Int_t fMakeClass
! not zero when processing code generated by MakeClass
Definition TTree.h:115
virtual Int_t LoadBaskets(Long64_t maxmemory=2000000000)
Read in memory all baskets from all branches up to the limit of maxmemory bytes.
Definition TTree.cxx:6441
static constexpr Long64_t kMaxEntries
Definition TTree.h:229
TPrincipal * Principal(const char *varexp="", const char *selection="", Option_t *option="np", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Interface to the Principal Components Analysis class.
Definition TTree.cxx:7190
virtual Long64_t GetAutoFlush() const
Definition TTree.h:447
Defines a common interface to inspect/change the contents of an object that represents a collection.
virtual EDataType GetType() const =0
If the value type is a fundamental data type, return its type (see enumeration EDataType).
virtual TClass * GetValueClass() const =0
If the value type is a user-defined class, return a pointer to the TClass representing the value type...
virtual Bool_t HasPointers() const =0
Return true if the content is of type 'pointer to'.
Abstract interface for Tree Index.
virtual const char * GetMajorName() const =0
virtual Long64_t GetEntryNumberWithIndex(Long64_t major, Long64_t minor) const =0
virtual Long64_t GetEntryNumberFriend(const TTree *)=0
virtual void Append(const TVirtualIndex *, bool delaySort=false)=0
virtual const char * GetMinorName() const =0
virtual void SetTree(TTree *T)=0
virtual Long64_t GetN() const =0
virtual bool IsValidFor(const TTree *parent)=0
virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor) const =0
Provides the interface for the PROOF internal performance measurement and event tracing.
Abstract base class defining the interface for the plugins that implement Draw, Scan,...
virtual Long64_t Scan(const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)=0
virtual void UpdateFormulaLeaves()=0
virtual Long64_t DrawSelect(const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)=0
virtual Int_t MakeCode(const char *filename)=0
virtual Int_t UnbinnedFit(const char *formula, const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)=0
virtual Long64_t GetEntries(const char *)=0
virtual Int_t MakeProxy(const char *classname, const char *macrofilename=nullptr, const char *cutfilename=nullptr, const char *option=nullptr, Int_t maxUnrolling=3)=0
virtual TSQLResult * Query(const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)=0
virtual TPrincipal * Principal(const char *varexp="", const char *selection="", Option_t *option="np", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)=0
virtual void StartViewer(Int_t ww, Int_t wh)=0
virtual Int_t MakeReader(const char *classname, Option_t *option)=0
virtual TVirtualIndex * BuildIndex(const TTree *T, const char *majorname, const char *minorname)=0
virtual TTree * CopyTree(const char *selection, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)=0
virtual Long64_t Process(const char *filename, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)=0
virtual void SetEstimate(Long64_t n)=0
static TVirtualTreePlayer * TreePlayer(TTree *obj)
Static function returning a pointer to a Tree player.
virtual Int_t MakeClass(const char *classname, const char *option)=0
virtual Int_t Fit(const char *formula, const char *varexp, const char *selection, Option_t *option, Option_t *goption, Long64_t nentries, Long64_t firstentry)=0
TLine * line
const Int_t n
Definition legend1.C:16
Special implementation of ROOT::RRangeCast for TCollection, including a check that the cast target ty...
Definition TObject.h:387
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:570
ESTLType
Definition ESTLType.h:28
@ kSTLmap
Definition ESTLType.h:33
@ kSTLmultimap
Definition ESTLType.h:34
void CallRecursiveRemoveIfNeeded(TObject &obj)
call RecursiveRemove for obj if gROOT is valid and obj.TestBit(kMustCleanup) is true.
Definition TROOT.h:395
void ToHumanReadableSize(value_type bytes, Bool_t si, Double_t *coeff, const char **units)
Return the size expressed in 'human readable' format.
EFromHumanReadableSize FromHumanReadableSize(std::string_view str, T &value)
Convert strings like the following into byte counts 5MB, 5 MB, 5M, 3.7GB, 123b, 456kB,...
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:250
Double_t Median(Long64_t n, const T *a, const Double_t *w=nullptr, Long64_t *work=nullptr)
Same as RMS.
Definition TMath.h:1352
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:198
Long64_t BinarySearch(Long64_t n, const T *array, T value)
Binary search in an array of n values to locate value.
Definition TMathBase.h:347
TCanvas * slash()
Definition slash.C:1
@ kUseGlobal
Use the global compression algorithm.
Definition Compression.h:93
@ kInherit
Some objects use this value to denote that the compression algorithm should be inherited from the par...
Definition Compression.h:91
@ kUseCompiledDefault
Use the compile-time default setting.
Definition Compression.h:53
th1 Draw()
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4