Logo ROOT   master
Reference Guide
TLeaf.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-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TLeaf
13 \ingroup tree
14 
15 A TLeaf describes individual elements of a TBranch
16 See TBranch structure in TTree.
17 */
18 
19 #include "TLeaf.h"
20 #include "TBranch.h"
21 #include "TBuffer.h"
22 #include "TTree.h"
23 #include "TVirtualPad.h"
24 #include "TBrowser.h"
25 #include "TClass.h"
26 
27 #include <ctype.h>
28 
30 
31 ////////////////////////////////////////////////////////////////////////////////
32 
34  : TNamed()
35  , fNdata(0)
36  , fLen(0)
37  , fLenType(0)
38  , fOffset(0)
39  , fIsRange(kFALSE)
40  , fIsUnsigned(kFALSE)
41  , fLeafCount(0)
42  , fBranch(0)
43  , fLeafCountValues(0)
44 {
45 }
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 /// Create a Leaf.
49 ///
50 /// See the TTree and TBranch constructors for explanation of parameters.
51 
52 TLeaf::TLeaf(TBranch *parent, const char* name, const char *)
53  : TNamed(name, name)
54  , fNdata(0)
55  , fLen(0)
56  , fLenType(4)
57  , fOffset(0)
58  , fIsRange(kFALSE)
59  , fIsUnsigned(kFALSE)
60  , fLeafCount(0)
61  , fBranch(parent)
62  , fLeafCountValues(0)
63 {
65 
66  if (fLen == -1) {
67  MakeZombie();
68  return;
69  }
70 
71  const char *bracket = strchr(name, '[');
72  if (bracket) fName.ReplaceAll(bracket,"");
73 }
74 
75 ////////////////////////////////////////////////////////////////////////////////
76 /// Copy constructor.
77 
78 TLeaf::TLeaf(const TLeaf& lf) :
79  TNamed(lf),
80  fNdata(lf.fNdata),
81  fLen(lf.fLen),
82  fLenType(lf.fLenType),
83  fOffset(lf.fOffset),
84  fIsRange(lf.fIsRange),
85  fIsUnsigned(lf.fIsUnsigned),
86  fLeafCount(lf.fLeafCount),
87  fBranch(lf.fBranch),
88  fLeafCountValues(nullptr)
89 {
90 }
91 
92 ////////////////////////////////////////////////////////////////////////////////
93 /// Assignment operator.
94 
96 {
97  if(this!=&lf) {
99  fNdata=lf.fNdata;
100  fLen=lf.fLen;
101  fLenType=lf.fLenType;
102  fOffset=lf.fOffset;
103  fIsRange=lf.fIsRange;
106  fBranch=lf.fBranch;
107  if (fLeafCountValues) {
109  fLeafCountValues->fValues.resize(0);
110  }
111  }
112  return *this;
113 }
114 
115 ////////////////////////////////////////////////////////////////////////////////
116 /// Destructor.
117 
119 {
120  if (fBranch) {
121  TTree* tree = fBranch->GetTree();
122  fBranch = 0;
123  if (tree) {
124  TObjArray *lst = tree->GetListOfLeaves();
125  if (lst->GetLast()!=-1) lst->Remove(this);
126  }
127  }
128  fLeafCount = 0;
129  delete fLeafCountValues;
130 }
131 
132 ////////////////////////////////////////////////////////////////////////////////
133 /// Browse the content of this leaf.
134 
136 {
137  if (strchr(GetName(), '.')) {
138  fBranch->GetTree()->Draw(GetName(), "", b ? b->GetDrawOption() : "");
139  } else {
140  if ((fBranch->GetListOfLeaves()->GetEntries() > 1) ||
141  (strcmp(fBranch->GetName(), GetName()) != 0)) {
143  if (!name.EndsWith(".")) name += ".";
144  name += GetName();
145  fBranch->GetTree()->Draw(name, "", b ? b->GetDrawOption() : "");
146  } else {
147  fBranch->GetTree()->Draw(GetName(), "", b ? b->GetDrawOption() : "");
148  }
149  }
150  if (gPad) {
151  gPad->Update();
152  }
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Pack leaf elements in Basket output buffer.
157 
159 {
160 }
161 
162 ////////////////////////////////////////////////////////////////////////////////
163 /// If the class supports it, generate an offset array base.
164 ///
165 /// This class only returns `nullptr` on error.
167 {
168  // In order to avoid a virtual call, we assume ROOT developers will override
169  // the default GenerateOffsetArray for cases where this function does not apply.
170 
171  Int_t *retval = new Int_t[events];
172  if (R__unlikely(!retval || !fLeafCount)) {
173  delete [] retval;
174  return nullptr;
175  }
176 
177  Long64_t orig_entry = std::max(fBranch->GetReadEntry(), 0LL); // -1 indicates to start at the beginning
178  const std::vector<Int_t> *countValues = fLeafCount->GetLeafCountValues(orig_entry, events);
179 
180  if (!countValues || ((Int_t)countValues->size()) < events) {
181  Error("GenerateOffsetArrayBase", "The leaf %s could not retrieve enough entries from its branch count (%s), ask for %d and got %ld",
182  GetName(), fLeafCount->GetName(), events, (long)(countValues ? countValues->size() : -1));
183  delete [] retval;
184  return nullptr;
185  }
186 
187  Int_t header = GetOffsetHeaderSize();
188  Int_t len = 0;
189  for (Int_t idx = 0, offset = base; idx < events; idx++) {
190  retval[idx] = offset;
191  len = (*countValues)[idx];
192  offset += fLenType * len + header;
193  }
194 
195  return retval;
196 }
197 
198 ////////////////////////////////////////////////////////////////////////////////
199 /// Return a pointer to the counter of this leaf (if any) or store the number of elements that the leaf contains in
200 /// countval.
201 ///
202 /// - If leaf name has the form var[nelem], where nelem is alphanumeric, then
203 /// if nelem is a leaf name, return countval = 1 and the pointer to
204 /// the leaf named nelem, otherwise return 0.
205 /// - If leaf name has the form var[nelem], where nelem is a non-negative integer, then
206 /// return countval = nelem and a null pointer.
207 /// - If leaf name has the form of a multi-dimensional array (e.g. var[nelem][nelem2]
208 /// where nelem and nelem2 are non-negative integers) then
209 /// return countval = product of all dimension sizes and a null pointer.
210 /// - If leaf name has the form var[... (and does not match the previous 2
211 /// cases) return countval = -1 and null pointer;
212 /// - Otherwise return countval = 1 and a null pointer.
213 
215 {
216  countval = 1;
217  const char* name = GetTitle();
218  char* bleft = (char*) strchr(name, '[');
219  if (!bleft) {
220  return 0;
221  }
222  bleft++;
223  Int_t nch = strlen(bleft);
224  char* countname = new char[nch+1];
225  strcpy(countname, bleft);
226  char* bright = (char*) strchr(countname, ']');
227  if (!bright) {
228  delete[] countname;
229  countname = 0;
230  countval = -1;
231  return 0;
232  }
233  char *bleft2 = (char*) strchr(countname, '[');
234  *bright = 0;
235  nch = strlen(countname);
236 
237  // Now search a branch name with a leaf name = countname
238  if (fBranch == 0) {
239  Error("GetLeafCounter","TLeaf %s is not setup properly, fBranch is null.",GetName());
240  delete[] countname;
241  return 0;
242  }
243  if (fBranch->GetTree() == 0) {
244  Error("GetLeafCounter","For Leaf %s, the TBranch %s is not setup properly, fTree is null.",GetName(),fBranch->GetName());
245  delete[] countname;
246  return 0;
247  }
248  TTree* pTree = fBranch->GetTree();
249 
250  TLeaf* leaf = (TLeaf*) GetBranch()->GetListOfLeaves()->FindObject(countname);
251  if (leaf == 0) {
252  // Try outside the branch:
253  leaf = (TLeaf*) pTree->GetListOfLeaves()->FindObject(countname);
254  }
255  //if not found, make one more trial in case the leaf name has a "."
256  if (!leaf && strchr(GetName(), '.')) {
257  char* withdot = new char[strlen(GetName())+strlen(countname)+1];
258  strcpy(withdot, GetName());
259  char* lastdot = strrchr(withdot, '.');
260  strcpy(lastdot, countname);
261  leaf = (TLeaf*) pTree->GetListOfLeaves()->FindObject(countname);
262  delete[] withdot;
263  withdot = 0;
264  }
265  if (!leaf && strchr(countname,'.')) {
266  // Not yet found and the countname has a dot in it, let's try
267  // to find the leaf using its full name
268  leaf = pTree->FindLeaf(countname);
269  }
270  Int_t i = 0;
271  if (leaf) {
272  countval = 1;
273  leaf->SetRange();
274  if (bleft2) {
275  sscanf(bleft2, "[%d]", &i);
276  countval *= i;
277  }
278  bleft = bleft2;
279  while (bleft) {
280  bleft2++;
281  bleft = (char*) strchr(bleft2, '[');
282  if (!bleft) {
283  break;
284  }
285  sscanf(bleft, "[%d]", &i);
286  countval *= i;
287  bleft2 = bleft;
288  }
289  delete[] countname;
290  countname = 0;
291  return leaf;
292  }
293  // not found in a branch/leaf. Is it a numerical value?
294  for (i = 0; i < nch; i++) {
295  if (!isdigit(countname[i])) {
296  delete[] countname;
297  countname = 0;
298  countval = -1;
299  return 0;
300  }
301  }
302  sscanf(countname, "%d", &countval);
303  if (bleft2) {
304  sscanf(bleft2, "[%d]", &i);
305  countval *= i;
306  }
307  bleft = bleft2;
308  while (bleft) {
309  bleft2++;
310  bleft = (char*) strchr(bleft2, '[');
311  if (!bleft) {
312  break;
313  }
314  sscanf(bleft, "[%d]", &i);
315  countval *= i;
316  bleft2 = bleft;
317  }
318 
319  delete[] countname;
320  countname = 0;
321  return 0;
322 }
323 
324 ////////////////////////////////////////////////////////////////////////////////
325 /// If this branch is a branch count, return the set of collection size for
326 /// the entry range requested
327 /// start: first entry to read and return information about
328 /// len: number of entries to read.
330 {
331  if (len <= 0 || !IsRange())
332  return nullptr;
333 
334  if (fLeafCountValues) {
335  if (fLeafCountValues->fStartEntry == start && len < (Long64_t)fLeafCountValues->fValues.size())
336  {
337  return &fLeafCountValues->fValues;
338  }
339  if (start >= fLeafCountValues->fStartEntry &&
340  (start+len) <= (Long64_t)(fLeafCountValues->fStartEntry + fLeafCountValues->fValues.size()))
341  {
342  auto &values(fLeafCountValues->fValues);
343  values.erase(values.begin(), values.begin() + start-fLeafCountValues->fStartEntry);
344  return &values;
345  }
346  } else {
348  }
349 
350 
351  fLeafCountValues->fValues.clear();
352  fLeafCountValues->fValues.reserve(len);
353  fLeafCountValues->fStartEntry = start;
354 
355  auto branch = GetBranch();
356  Long64_t orig_leaf_entry = branch->GetReadEntry();
357  for (Long64_t idx = 0; idx < len; ++idx) {
358  branch->GetEntry(start + idx);
359  auto size = static_cast<Int_t>(GetValue());
360  fLeafCountValues->fValues.push_back( size );
361  }
362  branch->GetEntry(orig_leaf_entry);
363  return &(fLeafCountValues->fValues);
364 }
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 /// Return the number of effective elements of this leaf, for the current entry.
368 
370 {
371  if (fLeafCount) {
372  // -- We are a varying length array.
373  Int_t len = Int_t(fLeafCount->GetValue());
374  if (len > fLeafCount->GetMaximum()) {
375  Error("GetLen", "Leaf counter is greater than maximum! leaf: '%s' len: %d max: %d", GetName(), len, fLeafCount->GetMaximum());
376  len = fLeafCount->GetMaximum();
377  }
378  return len * fLen;
379  } else {
380  // -- We are a fixed size thing.
381  return fLen;
382  }
383 }
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 /// Helper routine for TLeafX::SetAddress.
387 ///
388 /// The return value is non-zero if we owned the old
389 /// value buffer and must delete it now. The size
390 /// of the value buffer is recalculated and stored,
391 /// and a decision is made whether or not we own the
392 /// new value buffer.
393 
394 Int_t TLeaf::ResetAddress(void* addr, Bool_t calledFromDestructor)
395 {
396  // The kNewValue bit records whether or not we own
397  // the current value buffer or not. If we own it,
398  // then we are responsible for deleting it.
399  Bool_t deleteValue = kFALSE;
400  if (TestBit(kNewValue)) {
401  deleteValue = kTRUE;
402  }
403  // If we are not being called from a destructor,
404  // recalculate the value buffer size and decide
405  // whether or not we own the new value buffer.
406  if (!calledFromDestructor) {
407  // -- Recalculate value buffer size and decide ownership of value.
408  if (fLeafCount) {
409  // -- Varying length array data member.
410  fNdata = (fLeafCount->GetMaximum() + 1) * fLen;
411  } else {
412  // -- Fixed size data member.
413  fNdata = fLen;
414  }
415  // If we were provided an address, then we do not own
416  // the value, otherwise we do and must delete it later,
417  // keep track of this with bit kNewValue.
418  if (addr) {
420  } else {
421  SetBit(kNewValue);
422  }
423  }
424  return deleteValue;
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 /// Set the leaf count of this leaf.
429 
431 {
432  if (IsZombie() && (fLen == -1) && leaf) {
433  // The constructor noted that it could not find the
434  // leafcount. Now that we did find it, let's remove
435  // the side-effects.
436  ResetBit(kZombie);
437  fLen = 1;
438  }
439  fLeafCount = leaf;
440 }
441 
442 ////////////////////////////////////////////////////////////////////////////////
443 /// Stream a class object.
444 
445 void TLeaf::Streamer(TBuffer &b)
446 {
447  if (b.IsReading()) {
448  UInt_t R__s, R__c;
449  Version_t R__v = b.ReadVersion(&R__s, &R__c);
450  if (R__v > 1) {
451  b.ReadClassBuffer(TLeaf::Class(), this, R__v, R__s, R__c);
452  } else {
453  // -- Process old versions before automatic schema evolution.
454  TNamed::Streamer(b);
455  b >> fLen;
456  b >> fLenType;
457  b >> fOffset;
458  b >> fIsRange;
459  b >> fIsUnsigned;
460  b >> fLeafCount;
461  b.CheckByteCount(R__s, R__c, TLeaf::IsA());
462  }
463  if (!fLen) {
464  fLen = 1;
465  }
466  // We do not own the value buffer right now.
468  SetAddress();
469  } else {
470  b.WriteClassBuffer(TLeaf::Class(), this);
471  }
472 }
473 
virtual ~TLeaf()
Destructor.
Definition: TLeaf.cxx:118
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:55
An array of TObjects.
Definition: TObjArray.h:37
long long Long64_t
Definition: RtypesCore.h:71
short Version_t
Definition: RtypesCore.h:63
virtual const Counts_t * GetLeafCountValues(Long64_t start, Long64_t len)
If this branch is a branch count, return the set of collection size for the entry range requested sta...
Definition: TLeaf.cxx:329
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:687
virtual TLeaf * GetLeafCounter(Int_t &countval) const
Return a pointer to the counter of this leaf (if any) or store the number of elements that the leaf c...
Definition: TLeaf.cxx:214
#define R__unlikely(expr)
Definition: RConfig.hxx:604
Buffer base class used for serializing objects.
Definition: TBuffer.h:42
Int_t * GenerateOffsetArrayBase(Int_t base, Int_t events) const
If the class supports it, generate an offset array base.
Definition: TLeaf.cxx:166
virtual TObject * Remove(TObject *obj)
Remove object from array.
Definition: TObjArray.cxx:719
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
Long64_t fStartEntry
! entry number of corresponding to element 0 of the vector.
Definition: TLeaf.h:66
Basic string class.
Definition: TString.h:131
virtual Int_t GetOffsetHeaderSize() const
Definition: TLeaf.h:59
int Int_t
Definition: RtypesCore.h:43
Int_t fLenType
Number of bytes for this data type.
Definition: TLeaf.h:71
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual void SetRange(Bool_t range=kTRUE)
Definition: TLeaf.h:161
std::vector< Int_t > Counts_t
Definition: TLeaf.h:63
void Class()
Definition: Class.C:29
virtual Double_t GetValue(Int_t i=0) const
Definition: TLeaf.h:179
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:415
Set if we own the value buffer and so must delete it ourselves.
Definition: TLeaf.h:94
virtual Bool_t IsRange() const
Definition: TLeaf.h:145
Counts_t fValues
Definition: TLeaf.h:65
Int_t fLen
Number of fixed length elements in the leaf&#39;s data.
Definition: TLeaf.h:70
virtual void SetAddress(void *add=0)
Definition: TLeaf.h:181
virtual void FillBasket(TBuffer &b)
Pack leaf elements in Basket output buffer.
Definition: TLeaf.cxx:158
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition: TObject.h:134
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:37
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:577
virtual Int_t GetLen() const
Return the number of effective elements of this leaf, for the current entry.
Definition: TLeaf.cxx:369
TNamed & operator=(const TNamed &rhs)
TNamed assignment operator.
Definition: TNamed.cxx:51
Int_t fNdata
! Number of elements in fAddress data buffer.
Definition: TLeaf.h:69
LeafCountValues * fLeafCountValues
! Cache of collection/array sizes
Definition: TLeaf.h:77
unsigned int UInt_t
Definition: RtypesCore.h:44
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:888
virtual TLeaf * FindLeaf(const char *name)
Find leaf..
Definition: TTree.cxx:4815
virtual void SetLeafCount(TLeaf *leaf)
Set the leaf count of this leaf.
Definition: TLeaf.cxx:430
TString fName
Definition: TNamed.h:32
const Bool_t kFALSE
Definition: RtypesCore.h:90
virtual Int_t GetMaximum() const
Definition: TLeaf.h:130
#define ClassImp(name)
Definition: Rtypes.h:361
virtual void Browse(TBrowser *b)
Browse the content of this leaf.
Definition: TLeaf.cxx:135
virtual void Draw(Option_t *opt)
Default Draw method for all objects.
Definition: TTree.h:423
Bool_t fIsUnsigned
(=kTRUE if unsigned, kFALSE otherwise)
Definition: TLeaf.h:74
TObjArray * GetListOfLeaves()
Definition: TBranch.h:238
Int_t fOffset
Offset in ClonesArray object (if one)
Definition: TLeaf.h:72
Bool_t fIsRange
(=kTRUE if leaf has a range, kFALSE otherwise). This is equivalent to being a &#39;leafcount&#39;. For a TLeafElement the range information is actually store in the TBranchElement.
Definition: TLeaf.h:73
object ctor failed
Definition: TObject.h:79
TBranch * fBranch
! Pointer to supporting branch (we do not own the branch)
Definition: TLeaf.h:76
Int_t ResetAddress(void *add, Bool_t destructor=kFALSE)
Helper routine for TLeafX::SetAddress.
Definition: TLeaf.cxx:394
void MakeZombie()
Definition: TObject.h:49
TLeaf * fLeafCount
Pointer to Leaf count if variable length (we do not own the counter)
Definition: TLeaf.h:75
Long64_t GetReadEntry() const
Definition: TBranch.h:228
TLeaf()
Definition: TLeaf.cxx:33
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
TTree * GetTree() const
Definition: TBranch.h:243
#define gPad
Definition: TVirtualPad.h:287
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:523
Definition: tree.py:1
A TTree represents a columnar dataset.
Definition: TTree.h:78
void ResetBit(UInt_t f)
Definition: TObject.h:171
TLeaf & operator=(const TLeaf &)
Assignment operator.
Definition: TLeaf.cxx:95
TBranch * GetBranch() const
Definition: TLeaf.h:113
A TTree is a list of TBranches.
Definition: TBranch.h:88
const Bool_t kTRUE
Definition: RtypesCore.h:89
char name[80]
Definition: TGX11.cxx:109
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
virtual TObjArray * GetListOfLeaves()
Definition: TTree.h:480