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