Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TBranchObject.cxx
Go to the documentation of this file.
1 // @(#)root/tree:$Id$
2 // Author: Rene Brun 11/02/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 TBranchObject
13 \ingroup tree
14 
15 A Branch for the case of an object.
16 */
17 
18 #include "TBranchObject.h"
19 
20 #include "TBasket.h"
21 #include "TBranchClones.h"
22 #include "TBrowser.h"
23 #include "TBuffer.h"
24 #include "TClass.h"
25 #include "TClonesArray.h"
26 #include "TDataMember.h"
27 #include "TDataType.h"
28 #include "TFile.h"
29 #include "TLeafObject.h"
30 #include "TRealData.h"
31 #include "TStreamerInfo.h"
32 #include "TTree.h"
33 #include "TVirtualPad.h"
34 
35 ClassImp(TBranchObject);
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 /// Default constructor for BranchObject.
39 
40 TBranchObject::TBranchObject()
41 : TBranch()
42 {
43  fNleaves = 1;
44  fOldObject = 0;
45 }
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 /// Create a BranchObject.
49 
50 TBranchObject::TBranchObject(TTree *tree, const char* name, const char* classname, void* addobj, Int_t basketsize, Int_t splitlevel, Int_t compress, Bool_t isptrptr /* = kTRUE */)
51 : TBranch()
52 {
53  Init(tree,0,name,classname,addobj,basketsize,splitlevel,compress,isptrptr);
54 }
55 
56 ////////////////////////////////////////////////////////////////////////////////
57 /// Create a BranchObject.
58 
59 TBranchObject::TBranchObject(TBranch *parent, const char* name, const char* classname, void* addobj, Int_t basketsize, Int_t splitlevel, Int_t compress, Bool_t isptrptr /* = kTRUE */)
60 : TBranch()
61 {
62  Init(0,parent,name,classname,addobj,basketsize,splitlevel,compress,isptrptr);
63 }
64 
65 ////////////////////////////////////////////////////////////////////////////////
66 /// Initialization routine (run from the constructor so do not make this function virtual)
67 
68 void TBranchObject::Init(TTree *tree, TBranch *parent, const char* name, const char* classname, void* addobj, Int_t basketsize, Int_t /*splitlevel*/, Int_t compress, Bool_t isptrptr)
69 {
70  if (tree==0 && parent!=0) tree = parent->GetTree();
71  fTree = tree;
72  fMother = parent ? parent->GetMother() : this;
73  fParent = parent;
74 
75  TClass* cl = TClass::GetClass(classname);
76 
77  if (!cl) {
78  Error("TBranchObject", "Cannot find class:%s", classname);
79  return;
80  }
81 
82  if (!isptrptr) {
83  fOldObject = (TObject*)addobj;
84  addobj = &fOldObject;
85  } else {
86  fOldObject = 0;
87  }
88 
89  char** apointer = (char**) addobj;
90  TObject* obj = (TObject*) (*apointer);
91 
92  Bool_t delobj = kFALSE;
93  if (!obj) {
94  obj = (TObject*) cl->New();
95  delobj = kTRUE;
96  }
97 
98  tree->BuildStreamerInfo(cl, obj);
99 
100  if (delobj) {
101  cl->Destructor(obj);
102  }
103 
104  SetName(name);
105  SetTitle(name);
106 
107  fCompress = compress;
108  if ((compress == -1) && tree->GetDirectory()) {
109  TFile* bfile = tree->GetDirectory()->GetFile();
110  if (bfile) {
111  fCompress = bfile->GetCompressionSettings();
112  }
113  }
114  if (basketsize < 100) {
115  basketsize = 100;
116  }
117  fBasketSize = basketsize;
118  fAddress = (char*) addobj;
119  fClassName = classname;
120  fBasketBytes = new Int_t[fMaxBaskets];
121  fBasketEntry = new Long64_t[fMaxBaskets];
122  fBasketSeek = new Long64_t[fMaxBaskets];
123 
124  for (Int_t i = 0; i < fMaxBaskets; ++i) {
125  fBasketBytes[i] = 0;
126  fBasketEntry[i] = 0;
127  fBasketSeek[i] = 0;
128  }
129 
130  TLeaf* leaf = new TLeafObject(this, name, classname);
131  leaf->SetAddress(addobj);
132  fNleaves = 1;
133  fLeaves.Add(leaf);
134  tree->GetListOfLeaves()->Add(leaf);
135 
136  // Set the bit kAutoDelete to specify that when reading
137  // in TLeafObject::ReadBasket, the object should be deleted
138  // before calling Streamer.
139  // It is foreseen to not set this bit in a future version.
140  if (isptrptr) SetAutoDelete(kTRUE);
141 
142  fDirectory = fTree->GetDirectory();
143  fFileName = "";
144 
145 }
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 /// Destructor for a BranchObject.
149 
150 TBranchObject::~TBranchObject()
151 {
152  fBranches.Delete();
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Browse the branch content.
157 
158 void TBranchObject::Browse(TBrowser* b)
159 {
160  Int_t nbranches = fBranches.GetEntriesFast();
161  if (nbranches > 1) {
162  fBranches.Browse(b);
163  }
164  if (GetBrowsables() && GetBrowsables()->GetSize()) {
165  GetBrowsables()->Browse(b);
166  }
167 }
168 
169 ////////////////////////////////////////////////////////////////////////////////
170 /// Loop on all leaves of this branch to fill Basket buffer.
171 
172 Int_t TBranchObject::FillImpl(ROOT::Internal::TBranchIMTHelper *imtHelper)
173 {
174  Int_t nbytes = 0;
175  Int_t nbranches = fBranches.GetEntriesFast();
176  if (nbranches) {
177  ++fEntries;
178  UpdateAddress();
179  for (Int_t i = 0; i < nbranches; ++i) {
180  TBranch* branch = (TBranch*) fBranches[i];
181  if (!branch->TestBit(kDoNotProcess)) {
182  Int_t bc = branch->FillImpl(imtHelper);
183  nbytes += bc;
184  }
185  }
186  } else {
187  if (!TestBit(kDoNotProcess)) {
188  Int_t bc = TBranch::FillImpl(imtHelper);
189  nbytes += bc;
190  }
191  }
192  return nbytes;
193 }
194 
195 ////////////////////////////////////////////////////////////////////////////////
196 /// Read all branches of a BranchObject and return total number of bytes.
197 ///
198 /// - If entry = 0 take current entry number + 1
199 /// - If entry < 0 reset entry number to 0
200 ///
201 /// The function returns the number of bytes read from the input buffer.
202 ///
203 /// - If entry does not exist the function returns 0.
204 /// - If an I/O error occurs, the function returns -1.
205 
206 Int_t TBranchObject::GetEntry(Long64_t entry, Int_t getall)
207 {
208  if (TestBit(kDoNotProcess) && !getall) {
209  return 0;
210  }
211  Int_t nbytes;
212  Int_t nbranches = fBranches.GetEntriesFast();
213 
214  if (nbranches) {
215  if (fAddress == 0) {
216  SetupAddresses();
217  }
218  nbytes = 0;
219  Int_t nb;
220  for (Int_t i = 0; i < nbranches; ++i) {
221  TBranch* branch = (TBranch*) fBranches[i];
222  if (branch) {
223  nb = branch->GetEntry(entry, getall);
224  if (nb < 0) {
225  return nb;
226  }
227  nbytes += nb;
228  }
229  }
230  } else {
231  nbytes = TBranch::GetEntry(entry, getall);
232  }
233  return nbytes;
234 }
235 
236 ////////////////////////////////////////////////////////////////////////////////
237 /// Fill expectedClass and expectedType with information on the data type of the
238 /// object/values contained in this branch (and thus the type of pointers
239 /// expected to be passed to Set[Branch]Address
240 /// return 0 in case of success and > 0 in case of failure.
241 
242 Int_t TBranchObject::GetExpectedType(TClass *&expectedClass,EDataType &expectedType)
243 {
244  expectedClass = 0;
245  expectedType = kOther_t;
246  TLeafObject* lobj = (TLeafObject*) GetListOfLeaves()->At(0);
247  if (!lobj) {
248  Error("GetExpectedType", "Did not find any leaves in %s",GetName());
249  return 1;
250  }
251  expectedClass = lobj->GetClass();
252  return 0;
253 }
254 
255 ////////////////////////////////////////////////////////////////////////////////
256 /// Return TRUE if more than one leaf or if fBrowsables, FALSE otherwise.
257 
258 Bool_t TBranchObject::IsFolder() const
259 {
260  Int_t nbranches = fBranches.GetEntriesFast();
261 
262  if (nbranches >= 1) {
263  return kTRUE;
264  }
265 
266  TList* browsables = const_cast<TBranchObject*>(this)->GetBrowsables();
267 
268  return browsables && browsables->GetSize();
269 }
270 
271 ////////////////////////////////////////////////////////////////////////////////
272 /// Print TBranch parameters.
273 
274 void TBranchObject::Print(Option_t* option) const
275 {
276  Int_t nbranches = fBranches.GetEntriesFast();
277  if (nbranches) {
278  Printf("*Branch :%-9s : %-54s *", GetName(), GetTitle());
279  Printf("*Entries : %8d : BranchObject (see below) *", Int_t(fEntries));
280  Printf("*............................................................................*");
281  for (Int_t i = 0; i < nbranches; ++i) {
282  TBranch* branch = (TBranch*) fBranches.At(i);
283  if (branch) {
284  branch->Print(option);
285  }
286  }
287  } else {
288  TBranch::Print(option);
289  }
290 }
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 /// Reset a branch.
294 ///
295 /// - Existing buffers are deleted.
296 /// - Entries, max and min are reset.
297 
298 void TBranchObject::Reset(Option_t* option)
299 {
300  TBranch::Reset(option);
301 
302  Int_t nbranches = fBranches.GetEntriesFast();
303  for (Int_t i = 0; i < nbranches; ++i) {
304  TBranch* branch = (TBranch*) fBranches[i];
305  branch->Reset(option);
306  }
307 }
308 
309 ////////////////////////////////////////////////////////////////////////////////
310 /// Reset a Branch after a Merge operation (drop data but keep customizations)
311 void TBranchObject::ResetAfterMerge(TFileMergeInfo *info)
312 {
313  TBranch::ResetAfterMerge(info);
314 
315  Int_t nbranches = fBranches.GetEntriesFast();
316  for (Int_t i = 0; i < nbranches; ++i) {
317  TBranch* branch = (TBranch*) fBranches[i];
318  branch->ResetAfterMerge(info);
319  }
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Set address of this branch.
324 
325 void TBranchObject::SetAddress(void* add)
326 {
327  if (TestBit(kDoNotProcess)) {
328  return;
329  }
330 
331  // Special case when called from code generated by TTree::MakeClass.
332  if (Long_t(add) == -1) {
333  SetBit(kWarn);
334  return;
335  }
336 
337  fReadEntry = -1;
338  Int_t nbranches = fBranches.GetEntriesFast();
339 
340  TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(0);
341  if (leaf) {
342  leaf->SetAddress(add);
343  }
344 
345  fAddress = (char*) add;
346  char** ppointer = (char**) add;
347 
348  char* obj = 0;
349  if (ppointer) {
350  obj = *ppointer;
351  }
352 
353  TClass* cl = TClass::GetClass(fClassName.Data());
354 
355  if (!cl) {
356  for (Int_t i = 0; i < nbranches; ++i) {
357  TBranch* br = (TBranch*) fBranches[i];
358  br->SetAddress(obj);
359  }
360  return;
361  }
362 
363  if (ppointer && !obj) {
364  obj = (char*) cl->New();
365  *ppointer = obj;
366  }
367 
368  if (!cl->GetListOfRealData()) {
369  cl->BuildRealData(obj);
370  }
371 
372  if (cl->InheritsFrom(TClonesArray::Class())) {
373  if (ppointer) {
374  TClonesArray* clones = (TClonesArray*) *ppointer;
375  if (!clones) {
376  Error("SetAddress", "Pointer to TClonesArray is null");
377  return;
378  }
379  TClass* clm = clones->GetClass();
380  if (clm) {
381  clm->BuildRealData(); //just in case clm derives from an abstract class
382  clm->GetStreamerInfo();
383  }
384  }
385  }
386 
387  //
388  // Loop over our data members looking
389  // for sub-branches for them. If we
390  // find one, set its address.
391  //
392 
393  char* fullname = new char[200];
394 
395  const char* bname = GetName();
396 
397  Int_t isDot = 0;
398  if (bname[strlen(bname)-1] == '.') {
399  isDot = 1;
400  }
401 
402  char* pointer = 0;
403  TRealData* rd = 0;
404  TIter next(cl->GetListOfRealData());
405  while ((rd = (TRealData*) next())) {
406  if (rd->TestBit(TRealData::kTransient)) continue;
407 
408  TDataMember* dm = rd->GetDataMember();
409  if (!dm || !dm->IsPersistent()) {
410  continue;
411  }
412  const char* rdname = rd->GetName();
413  TDataType* dtype = dm->GetDataType();
414  Int_t code = 0;
415  if (dtype) {
416  code = dm->GetDataType()->GetType();
417  }
418  Int_t offset = rd->GetThisOffset();
419  if (ppointer) {
420  pointer = obj + offset;
421  }
422  TBranch* branch = 0;
423  if (dm->IsaPointer()) {
424  TClass* clobj = 0;
425  if (!dm->IsBasic()) {
426  clobj = TClass::GetClass(dm->GetTypeName());
427  }
428  if (clobj && clobj->InheritsFrom(TClonesArray::Class())) {
429  if (isDot) {
430  snprintf(fullname,200, "%s%s", bname, &rdname[1]);
431  } else {
432  snprintf(fullname,200, "%s", &rdname[1]);
433  }
434  branch = (TBranch*) fBranches.FindObject(fullname);
435  } else {
436  if (!clobj) {
437  // this is a basic type we can handle only if
438  // it has a dimension:
439  const char* index = dm->GetArrayIndex();
440  if (!index[0]) {
441  if (code == 1) {
442  // Case of a string ... we do not need the size
443  if (isDot) {
444  snprintf(fullname,200, "%s%s", bname, &rdname[0]);
445  } else {
446  snprintf(fullname,200, "%s", &rdname[0]);
447  }
448  } else {
449  continue;
450  }
451  }
452  if (isDot) {
453  snprintf(fullname,200, "%s%s", bname, &rdname[0]);
454  } else {
455  snprintf(fullname,200, "%s", &rdname[0]);
456  }
457  // let's remove the stars!
458  UInt_t cursor;
459  UInt_t pos;
460  for (cursor = 0, pos = 0; cursor < strlen(fullname); ++cursor) {
461  if (fullname[cursor] != '*') {
462  fullname[pos++] = fullname[cursor];
463  }
464  }
465  fullname[pos] = '\0';
466  branch = (TBranch*) fBranches.FindObject(fullname);
467  } else {
468  if (!clobj->IsTObject()) {
469  continue;
470  }
471  if (isDot) {
472  snprintf(fullname,200, "%s%s", bname, &rdname[1]);
473  } else {
474  snprintf(fullname,200, "%s", &rdname[1]);
475  }
476  branch = (TBranch*) fBranches.FindObject(fullname);
477  }
478  }
479  } else {
480  if (dm->IsBasic()) {
481  if (isDot) {
482  snprintf(fullname,200, "%s%s", bname, &rdname[0]);
483  } else {
484  snprintf(fullname,200, "%s", &rdname[0]);
485  }
486  branch = (TBranch*) fBranches.FindObject(fullname);
487  }
488  }
489  if (branch) {
490  branch->SetAddress(pointer);
491  }
492  }
493 
494  delete[] fullname;
495 }
496 
497 ////////////////////////////////////////////////////////////////////////////////
498 /// Set the AutoDelete bit.
499 ///
500 /// This function can be used to instruct Root in TBranchObject::ReadBasket
501 /// to not delete the object referenced by a branchobject before reading a
502 /// new entry. By default, the object is deleted.
503 /// - If autodel is kTRUE, this existing object will be deleted, a new object
504 /// created by the default constructor, then object->Streamer called.
505 /// - If autodel is kFALSE, the existing object is not deleted. Root assumes
506 /// that the user is taking care of deleting any internal object or array
507 /// This can be done in Streamer itself.
508 /// - If this branch has sub-branches, the function sets autodel for these
509 /// branches as well.
510 /// We STRONGLY suggest to activate this option by default when you create
511 /// the top level branch. This will make the read phase more efficient
512 /// because it minimizes the numbers of new/delete operations.
513 /// Once this option has been set and the Tree is written to a file, it is
514 /// not necessary to specify the option again when reading, unless you
515 /// want to set the opposite mode.
516 
517 void TBranchObject::SetAutoDelete(Bool_t autodel)
518 {
519  TBranch::SetAutoDelete(autodel);
520 
521  Int_t nbranches = fBranches.GetEntriesFast();
522  for (Int_t i=0;i<nbranches;i++) {
523  TBranch *branch = (TBranch*)fBranches[i];
524  branch->SetAutoDelete(autodel);
525  }
526 }
527 
528 ////////////////////////////////////////////////////////////////////////////////
529 /// Reset basket size for all subbranches of this branch.
530 
531 void TBranchObject::SetBasketSize(Int_t buffsize)
532 {
533  TBranch::SetBasketSize(buffsize);
534 
535  Int_t nbranches = fBranches.GetEntriesFast();
536  for (Int_t i = 0; i < nbranches; ++i) {
537  TBranch* branch = (TBranch*) fBranches[i];
538  branch->SetBasketSize(fBasketSize);
539  }
540 }
541 
542 ////////////////////////////////////////////////////////////////////////////////
543 /// Stream an object of class TBranchObject.
544 
545 void TBranchObject::Streamer(TBuffer& R__b)
546 {
547  if (R__b.IsReading()) {
548  R__b.ReadClassBuffer(TBranchObject::Class(), this);
549  // We should rewarn in this process.
550  ResetBit(kWarn);
551  ResetBit(kOldWarn);
552  } else {
553  TDirectory* dirsav = fDirectory;
554  fDirectory = 0; // to avoid recursive calls
555 
556  R__b.WriteClassBuffer(TBranchObject::Class(), this);
557 
558  // make sure that all TStreamerInfo objects referenced by
559  // this class are written to the file
560  R__b.ForceWriteInfo(TClass::GetClass(fClassName.Data())->GetStreamerInfo(), kTRUE);
561 
562  // if branch is in a separate file save this branch
563  // as an independent key
564  if (!dirsav) {
565  return;
566  }
567  if (!dirsav->IsWritable()) {
568  fDirectory = dirsav;
569  return;
570  }
571  TDirectory* pdirectory = fTree->GetDirectory();
572  if (!pdirectory) {
573  fDirectory = dirsav;
574  return;
575  }
576  const char* treeFileName = pdirectory->GetFile()->GetName();
577  TBranch* mother = GetMother();
578  const char* motherFileName = treeFileName;
579  if (mother && (mother != this)) {
580  motherFileName = mother->GetFileName();
581  }
582  if ((fFileName.Length() > 0) && strcmp(motherFileName, fFileName.Data())) {
583  dirsav->WriteTObject(this);
584  }
585  fDirectory = dirsav;
586  }
587 }
588 
589 ////////////////////////////////////////////////////////////////////////////////
590 /// -- If the branch address is not set, we set all addresses starting with
591 /// the top level parent branch. This is required to be done in order for
592 /// GetOffset to be correct and for GetEntry to run.
593 
594 void TBranchObject::SetupAddresses()
595 {
596  if (fAddress == 0) {
597  // try to create object
598  if (!TestBit(kWarn)) {
599  TClass* cl = TClass::GetClass(fClassName);
600  if (cl) {
601  TObject** voidobj = (TObject**) new Long_t[1];
602  *voidobj = (TObject*) cl->New();
603  SetAddress(voidobj);
604  } else {
605  Warning("GetEntry", "Cannot get class: %s", fClassName.Data());
606  SetBit(kWarn);
607  }
608  }
609  }
610 }
611 
612 ////////////////////////////////////////////////////////////////////////////////
613 /// Update branch addresses if a new object was created.
614 
615 void TBranchObject::UpdateAddress()
616 {
617  void** ppointer = (void**) fAddress;
618  if (!ppointer) {
619  return;
620  }
621  TObject* obj = (TObject*) (*ppointer);
622  if (obj != fOldObject) {
623  fOldObject = obj;
624  SetAddress(fAddress);
625  }
626 }
627