1 |
//
|
2 |
// $Id: TAMTreeBranchLoader.cxx,v 1.1 2008/05/27 19:13:21 loizides Exp $
|
3 |
//
|
4 |
|
5 |
#include "TAMTreeBranchLoader.h"
|
6 |
|
7 |
|
8 |
#ifndef ROOT_RVersion
|
9 |
#include <RVersion.h>
|
10 |
#endif
|
11 |
#ifndef ROOT_TError
|
12 |
#include "TError.h"
|
13 |
#endif
|
14 |
#ifndef ROOT_TClass
|
15 |
#include "TClass.h"
|
16 |
#endif
|
17 |
#ifndef ROOT_TList
|
18 |
#include "TList.h"
|
19 |
#endif
|
20 |
#ifndef ROOT_TFile
|
21 |
#include "TFile.h"
|
22 |
#endif
|
23 |
#ifndef ROOT_TBranch
|
24 |
#include "TBranch.h"
|
25 |
#endif
|
26 |
#ifndef ROOT_TLeaf
|
27 |
#include "TLeaf.h"
|
28 |
#endif
|
29 |
#ifndef ROOT_TDataMember
|
30 |
#include "TDataMember.h"
|
31 |
#endif
|
32 |
#ifndef ROOT_TDataType
|
33 |
#include "TDataType.h"
|
34 |
#endif
|
35 |
#ifndef ROOT_TTree
|
36 |
#include "TTree.h"
|
37 |
#endif
|
38 |
#ifndef ROOT_TROOT
|
39 |
#include "TROOT.h"
|
40 |
#endif
|
41 |
#ifndef ROOT_TClonesArray
|
42 |
#include "TClonesArray.h"
|
43 |
#endif
|
44 |
|
45 |
|
46 |
//////////////////////////////////////////////////////////////////////////
|
47 |
// //
|
48 |
// TAMTreeBranchLoader //
|
49 |
// //
|
50 |
// Default TAM plugin that loads data from single tree branches //
|
51 |
// into memory. //
|
52 |
// //
|
53 |
// Author : Corey Reed 07/20/2004 //
|
54 |
// Maarten Ballintijn 12/06/2005 //
|
55 |
// Constantin Loizides 12/06/2005 //
|
56 |
// //
|
57 |
//////////////////////////////////////////////////////////////////////////
|
58 |
|
59 |
ClassImp(TAMTreeBranchLoader)
|
60 |
|
61 |
|
62 |
#if ROOT_VERSION_CODE < ROOT_VERSION(5,11,3)
|
63 |
#define R__ASSERT(e) \
|
64 |
if (!(e)) Fatal("", kAssertMsg, _QUOTE_(e), __LINE__, __FILE__)
|
65 |
#endif
|
66 |
|
67 |
|
68 |
//______________________________________________________________________________
|
69 |
TAMTreeBranchLoader::TAMTreeBranchLoader(TAMBranchInfo *binfo)
|
70 |
: TAMVirtualBranchLoader(binfo), fBAddr(0), fIsClass(kFALSE),
|
71 |
fLeafSizeConst(kTRUE), fBranch(0), fClass(0)
|
72 |
{
|
73 |
// Default constructor.
|
74 |
}
|
75 |
|
76 |
|
77 |
//______________________________________________________________________________
|
78 |
TAMTreeBranchLoader::~TAMTreeBranchLoader()
|
79 |
{
|
80 |
// Destructor.
|
81 |
|
82 |
DeleteMemory();
|
83 |
fClass = 0;
|
84 |
fBranch = 0;
|
85 |
}
|
86 |
|
87 |
|
88 |
//______________________________________________________________________________
|
89 |
void TAMTreeBranchLoader::AllocateMemory()
|
90 |
{
|
91 |
// Allocate memory on heap.
|
92 |
|
93 |
R__ASSERT(fClass != 0);
|
94 |
|
95 |
if(fBAddr!=0) {
|
96 |
Fatal("AllocateMemory", "Address already allocated! Must call DeleteMemory() first!");
|
97 |
return;
|
98 |
}
|
99 |
|
100 |
fBAddr = fClass->New();
|
101 |
}
|
102 |
|
103 |
|
104 |
//______________________________________________________________________________
|
105 |
Bool_t TAMTreeBranchLoader::CheckBrClass(const type_info& ptrtype, const TClass& cls)
|
106 |
{
|
107 |
// Check if the tree stores a class of the specified type
|
108 |
// ptrtype is user type and cls is type found in branch.
|
109 |
|
110 |
// check for equality
|
111 |
const type_info *clt = cls.GetTypeInfo();
|
112 |
|
113 |
if (clt!=0) {
|
114 |
if ( (*clt) == ptrtype ) return kTRUE;
|
115 |
} else {
|
116 |
Error("CheckBrClass",
|
117 |
"Could not get type_info for first leaf in branch [%s] "
|
118 |
"of type [%s].",fBranch->GetName(), fBranch->GetClassName());
|
119 |
return kFALSE;
|
120 |
}
|
121 |
|
122 |
// check for inheritance hierachy
|
123 |
const TClass *ptrcls = gROOT->GetClass(ptrtype);
|
124 |
|
125 |
if ( ptrcls!=0 ) {
|
126 |
if ( cls.InheritsFrom(ptrcls) ) return kTRUE;
|
127 |
} else {
|
128 |
Error("CheckBrClass",
|
129 |
"Could not get pointer to TClass for first leaf in branch [%s] "
|
130 |
"of type [%s].",fBranch->GetName(), fBranch->GetClassName());
|
131 |
return kFALSE;
|
132 |
}
|
133 |
|
134 |
Error("CheckBrClass",
|
135 |
"Class of first leaf in branch [%s] is [%s], "
|
136 |
"different (not equal/derived) from pointer type [%s].",
|
137 |
fBranch->GetName(), clt->name(), ptrtype.name());
|
138 |
return kFALSE;
|
139 |
}
|
140 |
|
141 |
|
142 |
//______________________________________________________________________________
|
143 |
Bool_t TAMTreeBranchLoader::CheckBrStruct(TClass& cls)
|
144 |
{
|
145 |
// Given pointer is a class/struct type for a list of fundamental leaves:
|
146 |
// Check that the members correspond to the leaves,
|
147 |
// also check that the size of the members does not change
|
148 |
// (the compiler may buffer the memory between different sized
|
149 |
// members, which causes SetBranchAddress to give unexpected results).
|
150 |
|
151 |
TList* members = cls.GetListOfDataMembers();
|
152 |
if ( (members!=0) && (members->IsEmpty()==kFALSE) ) {
|
153 |
TObjArray* lvs = fBranch->GetListOfLeaves();
|
154 |
if (lvs!=0) {
|
155 |
if (members->GetSize() == lvs->GetEntriesFast()) {
|
156 |
TIter nextlf(lvs);
|
157 |
TIter nextmem(members);
|
158 |
TDataMember* dm = dynamic_cast<TDataMember*>(nextmem());
|
159 |
TLeaf* lf = dynamic_cast<TLeaf*>(nextlf());
|
160 |
const Int_t size = dm->GetUnitSize();
|
161 |
for (; ( (lf!=0) && (dm!=0) );
|
162 |
dm = dynamic_cast<TDataMember*>(nextmem()),
|
163 |
lf = dynamic_cast<TLeaf*>(nextlf()) ) {
|
164 |
if (strcmp(lf->GetTypeName(),dm->GetTypeName())!=0) {
|
165 |
Error("CheckBrStruct",
|
166 |
"Member [%s] of class [%s] is of type [%s], "
|
167 |
"while leaf [%s] if of type [%s].",
|
168 |
dm->GetName(), cls.GetName(),
|
169 |
dm->GetTypeName(), lf->GetName(),
|
170 |
lf->GetTypeName());
|
171 |
return kFALSE;
|
172 |
} else {
|
173 |
fLeafSizeConst &= (size == dm->GetUnitSize());
|
174 |
}
|
175 |
}
|
176 |
return kTRUE;
|
177 |
} else {
|
178 |
Error("CheckBrStruct",
|
179 |
"Pointer of type [%s] has [%d] members, while branch "
|
180 |
"[%s] has [%d] leaves.",
|
181 |
cls.GetName(), members->GetSize(),
|
182 |
fBranch->GetName(), lvs->GetEntriesFast());
|
183 |
}
|
184 |
} else {
|
185 |
Error("CheckBrStruct",
|
186 |
"Could not get list of leaves for branch [%s].",
|
187 |
fBranch->GetName());
|
188 |
}
|
189 |
} else {
|
190 |
Error("CheckBrStruct",
|
191 |
"Could not get list of members for type [%s].",
|
192 |
cls.GetName());
|
193 |
}
|
194 |
|
195 |
return kFALSE;
|
196 |
}
|
197 |
|
198 |
|
199 |
//______________________________________________________________________________
|
200 |
Bool_t TAMTreeBranchLoader::CheckBrType(const type_info& ptrtype)
|
201 |
{
|
202 |
// Check that the specified type (of the user's pointer) corresponds with
|
203 |
// what is in the tree:
|
204 |
// 1. Check if the tree stores a class of the specified type
|
205 |
// 2. Check the specified type is a class/struct (that is in the TClass
|
206 |
// dictionary!!) whose members correspond to the leaves in the branch.
|
207 |
|
208 |
R__ASSERT(gROOT!=0);
|
209 |
|
210 |
// first try the branch (works only for classes)
|
211 |
TClass* cls = gROOT->GetClass(fBranch->GetClassName());
|
212 |
if (cls!=0) {
|
213 |
// known class
|
214 |
fIsClass = kTRUE;
|
215 |
fClass = cls;
|
216 |
return CheckBrClass(ptrtype, *cls);
|
217 |
} else {
|
218 |
// pointer is a class/struct, branch is list of fundamentals
|
219 |
cls = TClass::GetClass(ptrtype);
|
220 |
if (cls!=0) {
|
221 |
fClass = cls;
|
222 |
return CheckBrStruct(*cls);
|
223 |
} else {
|
224 |
// pointer is a fundamental type (or else unknown type)
|
225 |
Error("CheckBrType",
|
226 |
"Pointer for branch [%s] is of fundamental type [%d], or "
|
227 |
"is a class/struct which is not in the TClass dictionary. "
|
228 |
"This is not supported. See documentation.",
|
229 |
fBranch->GetName(),
|
230 |
static_cast<Int_t>(TDataType::GetType(ptrtype)));
|
231 |
}
|
232 |
}
|
233 |
return kFALSE;
|
234 |
}
|
235 |
|
236 |
//______________________________________________________________________________
|
237 |
Bool_t TAMTreeBranchLoader::CheckBrTypeAllModules()
|
238 |
{
|
239 |
// Loop over each user address and check that it's of the correct type
|
240 |
// for the data contained in this branch.
|
241 |
|
242 |
Bool_t isok=kTRUE;
|
243 |
vector<TAMBranchInfo::BranchPtr_t*>::const_iterator end =
|
244 |
GetBInfo()->fUsrAddresses.end();
|
245 |
for (vector<TAMBranchInfo::BranchPtr_t*>::const_iterator ptr =
|
246 |
GetBInfo()->fUsrAddresses.begin(); (ptr!=end) && isok; ptr++) {
|
247 |
isok &= CheckBrType((*ptr)->GetType());
|
248 |
}
|
249 |
return isok;
|
250 |
}
|
251 |
|
252 |
//______________________________________________________________________________
|
253 |
void TAMTreeBranchLoader::Clear(Option_t */*option*/)
|
254 |
{
|
255 |
// Clear objects in TClonesArrays that allocated memory on the heap.
|
256 |
|
257 |
if(!fIsClass || !fBAddr)
|
258 |
return;
|
259 |
|
260 |
TString classname(fBranch->GetClassName());
|
261 |
if (classname.CompareTo("TClonesArray")==0) {
|
262 |
TClonesArray* ca = reinterpret_cast<TClonesArray*>(fBAddr);
|
263 |
if (ca!=0) {
|
264 |
ca->Clear("C");
|
265 |
} else {
|
266 |
Error("Clear", "Could not clear the clones array for branch %s",
|
267 |
fBranch->GetName());
|
268 |
}
|
269 |
}
|
270 |
}
|
271 |
|
272 |
|
273 |
//______________________________________________________________________________
|
274 |
void TAMTreeBranchLoader::DeleteMemory()
|
275 |
{
|
276 |
// Delete (previously) allocated memory on heap.
|
277 |
|
278 |
if(fClass && fBAddr) {
|
279 |
fClass->Destructor(fBAddr);
|
280 |
fBAddr = 0;
|
281 |
}
|
282 |
}
|
283 |
|
284 |
|
285 |
//______________________________________________________________________________
|
286 |
void* TAMTreeBranchLoader::GetAddress() const
|
287 |
{
|
288 |
// Return the branch address.
|
289 |
|
290 |
return fBAddr;
|
291 |
}
|
292 |
|
293 |
|
294 |
//______________________________________________________________________________
|
295 |
Int_t TAMTreeBranchLoader::GetEntry(Long64_t entry)
|
296 |
{
|
297 |
// Get requested entry.
|
298 |
|
299 |
Int_t ret = 0;
|
300 |
|
301 |
// do not reread branch
|
302 |
if (entry!=fBranch->GetReadEntry())
|
303 |
ret = fBranch->GetEntry(entry);
|
304 |
|
305 |
if(ret<0) {
|
306 |
Error("GetEntry",
|
307 |
"I/O error in file [%s] (at entry %lld) "
|
308 |
"when accessing branch with name [%s] in requested branch list.",
|
309 |
(fBranch->GetFileName()!=0) ? (fBranch->GetFileName()) : "null",
|
310 |
entry, fBranch->GetName());
|
311 |
}
|
312 |
|
313 |
return ret;
|
314 |
}
|
315 |
|
316 |
|
317 |
//______________________________________________________________________________
|
318 |
Bool_t TAMTreeBranchLoader::Notify(TTree* tree)
|
319 |
{
|
320 |
// Notify via TAMSelector and TAMBranchInfo that a tree is
|
321 |
// being connected from a (new) file.
|
322 |
// Therefore get branch information and perform type checking.
|
323 |
// Set branch address if CheckBrType() was successful.
|
324 |
|
325 |
R__ASSERT( tree != 0 );
|
326 |
|
327 |
// get branch with requested branch name
|
328 |
// first check if given name is alias
|
329 |
TString brname(tree->GetAlias(GetBInfo()->GetName()));
|
330 |
if (brname.IsNull())
|
331 |
brname=GetBInfo()->GetName();
|
332 |
fBranch = tree->GetBranch(brname);
|
333 |
|
334 |
if (fBranch == 0) {
|
335 |
Error("Notify", "GetBranch(%s) failed.", GetBInfo()->GetName());
|
336 |
return kFALSE;
|
337 |
}
|
338 |
|
339 |
if (GetBInfo()->fUsrAddresses.size()) {
|
340 |
// get branch information and check if types match
|
341 |
if (CheckBrTypeAllModules()==kFALSE) {
|
342 |
Error("Notify", "CheckBrTypeAllModules failed.");
|
343 |
return kFALSE;
|
344 |
}
|
345 |
} else {
|
346 |
// zero usr addresses (only possible for autoloading)
|
347 |
TClass* cls = gROOT->GetClass(fBranch->GetClassName());
|
348 |
if (cls!=0) { // known class
|
349 |
fIsClass = kTRUE;
|
350 |
fClass = cls;
|
351 |
}
|
352 |
}
|
353 |
|
354 |
// allocate memory on heap at fBAddr
|
355 |
if(!fBAddr)
|
356 |
AllocateMemory();
|
357 |
|
358 |
// set the branch address to point to fBAddr
|
359 |
SetBranchAddress();
|
360 |
|
361 |
return kTRUE;
|
362 |
}
|
363 |
|
364 |
|
365 |
//______________________________________________________________________________
|
366 |
void TAMTreeBranchLoader::SetBranchAddress()
|
367 |
{
|
368 |
// Set the branch address to point to our memory (fBAddr).
|
369 |
|
370 |
if (fIsClass) {
|
371 |
// branch stores object
|
372 |
fBranch->SetAddress( &(fBAddr) );
|
373 |
} else {
|
374 |
// branch stores fundamentals
|
375 |
if (fLeafSizeConst) {
|
376 |
fBranch->SetAddress(fBAddr);
|
377 |
} else {
|
378 |
SetLeafAddresses();
|
379 |
}
|
380 |
}
|
381 |
}
|
382 |
|
383 |
|
384 |
//______________________________________________________________________________
|
385 |
void TAMTreeBranchLoader::SetLeafAddresses()
|
386 |
{
|
387 |
// Loop over the leaves in the branch and the data members of
|
388 |
// a (typical) struct/class used to read the branch
|
389 |
// assign the individual leaves to have address corresponding to
|
390 |
// fBAddr + (offset of each data member). This function is
|
391 |
// only used when the data members of the struct have different sizes and
|
392 |
// assumes that each module's pointer references a class or struct that
|
393 |
// is organized in the same way as any other module.
|
394 |
// CheckBrStruct() assures that this really is the case.
|
395 |
|
396 |
const type_info& usrAdrType = GetBInfo()->GetType();
|
397 |
TClass* cls = TClass::GetClass(usrAdrType);
|
398 |
if (cls!=0) {
|
399 |
TList* members = cls->GetListOfDataMembers();
|
400 |
if ( (members!=0) && (members->IsEmpty()==kFALSE) ) {
|
401 |
TObjArray* lvs = fBranch->GetListOfLeaves();
|
402 |
if (lvs!=0) {
|
403 |
if (members->GetSize() == lvs->GetEntriesFast()) {
|
404 |
TIter nextlf(lvs);
|
405 |
TIter nextmem(members);
|
406 |
TDataMember* dm = dynamic_cast<TDataMember*>(nextmem());
|
407 |
TLeaf* lf = dynamic_cast<TLeaf*>(nextlf());
|
408 |
for (; ( (lf!=0) && (dm!=0) );
|
409 |
dm = dynamic_cast<TDataMember*>(nextmem()),
|
410 |
lf = dynamic_cast<TLeaf*>(nextlf()) ) {
|
411 |
// the cast is just to prevent compiler warnings
|
412 |
lf->SetAddress( static_cast<Char_t*>(fBAddr)
|
413 |
+ dm->GetOffset() );
|
414 |
}
|
415 |
} else {
|
416 |
Error("SetLeafAddresses",
|
417 |
"Class [%s] has [%d] members, while branch [%s] "
|
418 |
"has [%d] leaves.",
|
419 |
cls->GetName(), members->GetSize(),
|
420 |
fBranch->GetName(), lvs->GetEntriesFast());
|
421 |
}
|
422 |
} else {
|
423 |
Error("SetLeafAddresses",
|
424 |
"Could not get list of leaves for branch [%s].",
|
425 |
fBranch->GetName());
|
426 |
}
|
427 |
} else {
|
428 |
Error("SetLeafAddresses",
|
429 |
"Could not get list of data members for class [%s].",
|
430 |
cls->GetName());
|
431 |
}
|
432 |
} else {
|
433 |
Error("SetLeafAddresses",
|
434 |
"Could not get class for pointer of type [%s].",
|
435 |
usrAdrType.name());
|
436 |
}
|
437 |
}
|