1 |
loizides |
1.1 |
//
|
2 |
|
|
// $Id: TAMTreeBranchLoader.cxx 5120 2008-05-07 18:17:33Z loizides $
|
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 = fBranch->GetEntry(entry);
|
300 |
|
|
if(ret<0) {
|
301 |
|
|
Error("GetEntry",
|
302 |
|
|
"I/O error in file [%s] (at entry %lld) "
|
303 |
|
|
"when accessing branch with name [%s] in requested branch list.",
|
304 |
|
|
(fBranch->GetFileName()!=0) ? (fBranch->GetFileName()) : "null",
|
305 |
|
|
entry, fBranch->GetName());
|
306 |
|
|
}
|
307 |
|
|
|
308 |
|
|
return ret;
|
309 |
|
|
}
|
310 |
|
|
|
311 |
|
|
|
312 |
|
|
//______________________________________________________________________________
|
313 |
|
|
Bool_t TAMTreeBranchLoader::Notify(TTree* tree)
|
314 |
|
|
{
|
315 |
|
|
// Notify via TAMSelector and TAMBranchInfo that a tree is
|
316 |
|
|
// being connected from a (new) file.
|
317 |
|
|
// Therefore get branch information and perform type checking.
|
318 |
|
|
// Set branch address if CheckBrType() was successful.
|
319 |
|
|
|
320 |
|
|
R__ASSERT( tree != 0 );
|
321 |
|
|
|
322 |
|
|
// get branch with requested branch name
|
323 |
|
|
// first check if given name is alias
|
324 |
|
|
TString brname(tree->GetAlias(GetBInfo()->GetName()));
|
325 |
|
|
if(brname.IsNull())
|
326 |
|
|
brname=GetBInfo()->GetName();
|
327 |
|
|
fBranch = tree->GetBranch(brname);
|
328 |
|
|
|
329 |
|
|
if (fBranch == 0) {
|
330 |
|
|
Error("Notify", "GetBranch(%s) failed.", GetBInfo()->GetName());
|
331 |
|
|
return kFALSE;
|
332 |
|
|
}
|
333 |
|
|
|
334 |
|
|
// get branch information and check if types match
|
335 |
|
|
if (CheckBrTypeAllModules()==kFALSE) {
|
336 |
|
|
Error("Notify", "CheckBrTypeAllModules failed.");
|
337 |
|
|
return kFALSE;
|
338 |
|
|
}
|
339 |
|
|
|
340 |
|
|
// allocate memory on heap at fBAddr
|
341 |
|
|
if(!fBAddr)
|
342 |
|
|
AllocateMemory();
|
343 |
|
|
|
344 |
|
|
// set the branch address to point to fBAddr
|
345 |
|
|
SetBranchAddress();
|
346 |
|
|
|
347 |
|
|
return kTRUE;
|
348 |
|
|
}
|
349 |
|
|
|
350 |
|
|
|
351 |
|
|
//______________________________________________________________________________
|
352 |
|
|
void TAMTreeBranchLoader::SetBranchAddress()
|
353 |
|
|
{
|
354 |
|
|
// Set the branch address to point to our memory (fBAddr).
|
355 |
|
|
|
356 |
|
|
if (fIsClass) {
|
357 |
|
|
// branch stores object
|
358 |
|
|
fBranch->SetAddress( &(fBAddr) );
|
359 |
|
|
} else {
|
360 |
|
|
// branch stores fundamentals
|
361 |
|
|
if (fLeafSizeConst) {
|
362 |
|
|
fBranch->SetAddress(fBAddr);
|
363 |
|
|
} else {
|
364 |
|
|
SetLeafAddresses();
|
365 |
|
|
}
|
366 |
|
|
}
|
367 |
|
|
}
|
368 |
|
|
|
369 |
|
|
|
370 |
|
|
//______________________________________________________________________________
|
371 |
|
|
void TAMTreeBranchLoader::SetLeafAddresses()
|
372 |
|
|
{
|
373 |
|
|
// Loop over the leaves in the branch and the data members of
|
374 |
|
|
// a (typical) struct/class used to read the branch
|
375 |
|
|
// assign the individual leaves to have address corresponding to
|
376 |
|
|
// fBAddr + (offset of each data member). This function is
|
377 |
|
|
// only used when the data members of the struct have different sizes and
|
378 |
|
|
// assumes that each module's pointer references a class or struct that
|
379 |
|
|
// is organized in the same way as any other module.
|
380 |
|
|
// CheckBrStruct() assures that this really is the case.
|
381 |
|
|
|
382 |
|
|
const type_info& usrAdrType = GetBInfo()->GetType();
|
383 |
|
|
TClass* cls = TClass::GetClass(usrAdrType);
|
384 |
|
|
if (cls!=0) {
|
385 |
|
|
TList* members = cls->GetListOfDataMembers();
|
386 |
|
|
if ( (members!=0) && (members->IsEmpty()==kFALSE) ) {
|
387 |
|
|
TObjArray* lvs = fBranch->GetListOfLeaves();
|
388 |
|
|
if (lvs!=0) {
|
389 |
|
|
if (members->GetSize() == lvs->GetEntriesFast()) {
|
390 |
|
|
TIter nextlf(lvs);
|
391 |
|
|
TIter nextmem(members);
|
392 |
|
|
TDataMember* dm = dynamic_cast<TDataMember*>(nextmem());
|
393 |
|
|
TLeaf* lf = dynamic_cast<TLeaf*>(nextlf());
|
394 |
|
|
for (; ( (lf!=0) && (dm!=0) );
|
395 |
|
|
dm = dynamic_cast<TDataMember*>(nextmem()),
|
396 |
|
|
lf = dynamic_cast<TLeaf*>(nextlf()) ) {
|
397 |
|
|
// the cast is just to prevent compiler warnings
|
398 |
|
|
lf->SetAddress( static_cast<Char_t*>(fBAddr)
|
399 |
|
|
+ dm->GetOffset() );
|
400 |
|
|
}
|
401 |
|
|
} else {
|
402 |
|
|
Error("SetLeafAddresses",
|
403 |
|
|
"Class [%s] has [%d] members, while branch [%s] "
|
404 |
|
|
"has [%d] leaves.",
|
405 |
|
|
cls->GetName(), members->GetSize(),
|
406 |
|
|
fBranch->GetName(), lvs->GetEntriesFast());
|
407 |
|
|
}
|
408 |
|
|
} else {
|
409 |
|
|
Error("SetLeafAddresses",
|
410 |
|
|
"Could not get list of leaves for branch [%s].",
|
411 |
|
|
fBranch->GetName());
|
412 |
|
|
}
|
413 |
|
|
} else {
|
414 |
|
|
Error("SetLeafAddresses",
|
415 |
|
|
"Could not get list of data members for class [%s].",
|
416 |
|
|
cls->GetName());
|
417 |
|
|
}
|
418 |
|
|
} else {
|
419 |
|
|
Error("SetLeafAddresses",
|
420 |
|
|
"Could not get class for pointer of type [%s].",
|
421 |
|
|
usrAdrType.name());
|
422 |
|
|
}
|
423 |
|
|
}
|