Logo ROOT  
Reference Guide
TTreeReaderArray.cxx
Go to the documentation of this file.
1// @(#)root/treeplayer:$Id$
2// Author: Axel Naumann, 2011-09-28
3
4/*************************************************************************
5 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers and al. *
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#include "TTreeReaderArray.h"
13
14#include "TBranchClones.h"
15#include "TBranchElement.h"
16#include "TBranchRef.h"
17#include "TBranchSTL.h"
18#include "TBranchObject.h"
20#include "TClassEdit.h"
21#include "TFriendElement.h"
22#include "TFriendProxy.h"
23#include "TLeaf.h"
24#include "TList.h"
25#include "TROOT.h"
26#include "TStreamerInfo.h"
27#include "TStreamerElement.h"
28#include "TTreeReader.h"
29#include "TGenCollectionProxy.h"
30#include "TRegexp.h"
31
32#include <memory>
33
34// pin vtable
36
37namespace {
38 using namespace ROOT::Internal;
39
40 // Reader interface for clones arrays
41 class TClonesReader: public TVirtualCollectionReader {
42 public:
43 ~TClonesReader() {}
45 if (!proxy->Read()){
47 Error("TClonesReader::GetCA()", "Read error in TBranchProxy.");
48 return 0;
49 }
51 return (TClonesArray*) proxy->GetWhere();
52 }
53 virtual size_t GetSize(ROOT::Detail::TBranchProxy* proxy) {
54 TClonesArray *myClonesArray = GetCA(proxy);
55 if (myClonesArray){
56 return myClonesArray->GetEntries();
57 }
58 else return 0;
59 }
60 virtual void* At(ROOT::Detail::TBranchProxy* proxy, size_t idx) {
61 TClonesArray *myClonesArray = GetCA(proxy);
62 if (myClonesArray){
63 return myClonesArray->UncheckedAt(idx);
64 }
65 else return 0;
66 }
67 };
68
69 // Reader interface for STL
70 class TSTLReader final: public TVirtualCollectionReader {
71 public:
72 ~TSTLReader() {}
74 if (!proxy->Read()) {
76 Error("TSTLReader::GetCP()", "Read error in TBranchProxy.");
77 return 0;
78 }
79 if (!proxy->GetWhere()) {
80 Error("TSTLReader::GetCP()", "Logic error, proxy object not set in TBranchProxy.");
81 return 0;
82 }
84 return (TVirtualCollectionProxy*) proxy->GetCollection();
85 }
86
87 virtual size_t GetSize(ROOT::Detail::TBranchProxy* proxy) {
88 TVirtualCollectionProxy *myCollectionProxy = GetCP(proxy);
89 if (!myCollectionProxy) return 0;
90 return myCollectionProxy->Size();
91 }
92
93 virtual void* At(ROOT::Detail::TBranchProxy* proxy, size_t idx) {
94 TVirtualCollectionProxy *myCollectionProxy = GetCP(proxy);
95 if (!myCollectionProxy) return 0;
96 if (myCollectionProxy->HasPointers()){
97 return *(void**)myCollectionProxy->At(idx);
98 }
99 else {
100 return myCollectionProxy->At(idx);
101 }
102 }
103 };
104
105 class TCollectionLessSTLReader final: public TVirtualCollectionReader {
106 private:
107 TVirtualCollectionProxy *fLocalCollection;
108 public:
109 TCollectionLessSTLReader(TVirtualCollectionProxy *proxy) : fLocalCollection(proxy) {}
110
112 if (!proxy->Read()) {
114 Error("TCollectionLessSTLReader::GetCP()", "Read error in TBranchProxy.");
115 return 0;
116 }
117 if (!proxy->GetWhere()) {
118 Error("TCollectionLessSTLReader::GetCP()", "Logic error, proxy object not set in TBranchProxy.");
119 return 0;
120 }
122 return fLocalCollection;
123 }
124
125 virtual size_t GetSize(ROOT::Detail::TBranchProxy* proxy) {
126 TVirtualCollectionProxy *myCollectionProxy = GetCP(proxy);
127 if (!myCollectionProxy) return 0;
128 /// In the case of std::vector<bool> `PushProxy` also creates a temporary bool variable the address of which
129 /// is returned from these calls.
130 myCollectionProxy->PopProxy();
131 myCollectionProxy->PushProxy(proxy->GetWhere());
132 return myCollectionProxy->Size();
133 }
134
135 virtual void* At(ROOT::Detail::TBranchProxy* proxy, size_t idx) {
136 TVirtualCollectionProxy *myCollectionProxy = GetCP(proxy);
137 if (!myCollectionProxy) return 0;
138 // Here we do not use a RAII but we empty the proxy to then fill it.
139 // This is done because we are returning a pointer and we need to keep
140 // alive the memory it points to.
141 myCollectionProxy->PopProxy();
142 myCollectionProxy->PushProxy(proxy->GetWhere());
143 if (myCollectionProxy->HasPointers()){
144 return *(void**)myCollectionProxy->At(idx);
145 } else {
146 return myCollectionProxy->At(idx);
147 }
148 }
149 };
150
151
152 // Reader interface for leaf list
153 // SEE TTreeProxyGenerator.cxx:1319: '//We have a top level raw type'
154 class TObjectArrayReader: public TVirtualCollectionReader {
155 private:
156 Int_t fBasicTypeSize;
157 public:
158 TObjectArrayReader() : fBasicTypeSize(-1) { }
159 ~TObjectArrayReader() {}
161 if (!proxy->Read()){
163 Error("TObjectArrayReader::GetCP()", "Read error in TBranchProxy.");
164 return 0;
165 }
167 return (TVirtualCollectionProxy*) proxy->GetCollection();
168 }
169 virtual size_t GetSize(ROOT::Detail::TBranchProxy* proxy) {
170 TVirtualCollectionProxy *myCollectionProxy = GetCP(proxy);
171 if (!myCollectionProxy) return 0;
172 return myCollectionProxy->Size();
173 }
174 virtual void* At(ROOT::Detail::TBranchProxy* proxy, size_t idx) {
175 if (!proxy->Read()) return 0;
176
177 Int_t objectSize;
178 void *array = (void*)proxy->GetStart();
179
180 if (fBasicTypeSize == -1){
181 TClass *myClass = proxy->GetClass();
182 if (!myClass){
183 Error("TObjectArrayReader::At()", "Cannot get class info from branch proxy.");
184 return 0;
185 }
186 objectSize = myClass->GetClassSize();
187 }
188 else {
189 objectSize = fBasicTypeSize;
190 }
191 return (void*)((Byte_t*)array + (objectSize * idx));
192 }
193
194 void SetBasicTypeSize(Int_t size){
195 fBasicTypeSize = size;
196 }
197 };
198
199 template <class BASE>
200 class TDynamicArrayReader : public BASE {
201
202 // TVirtualSizeReaderImpl and TSizeReaderImpl type-erase the reading of the size leaf.
203 class TVirtualSizeReaderImpl {
204 public:
205 virtual ~TVirtualSizeReaderImpl() = default;
206 virtual size_t GetSize() = 0;
207 };
208
209 template <typename T>
210 class TSizeReaderImpl final : public TVirtualSizeReaderImpl {
211 TTreeReaderValue<T> fSizeReader;
212
213 public:
214 TSizeReaderImpl(TTreeReader &r, const char *leafName) : fSizeReader(r, leafName) {}
215 size_t GetSize() final { return *fSizeReader; }
216 };
217
218 std::unique_ptr<TVirtualSizeReaderImpl> fSizeReader;
219
220 public:
221 template <class... ARGS>
222 TDynamicArrayReader(TTreeReader *treeReader, const char *leafName, ARGS &&...args)
223 : BASE(std::forward<ARGS>(args)...)
224 {
225 std::string foundLeafName = leafName;
226 TLeaf* sizeLeaf = treeReader->GetTree()->FindLeaf(foundLeafName.c_str());
227
228 if (!sizeLeaf) {
229 // leafName might be "top.currentParent.N". But "N" might really be "top.N"!
230 // Strip parents until we find the leaf.
231 std::string leafNameNoParent = leafName;
232 std::string parent;
233 auto posLastDot = leafNameNoParent.rfind('.');
234 if (posLastDot != leafNameNoParent.npos) {
235 parent = leafNameNoParent.substr(0, posLastDot);
236 leafNameNoParent.erase(0, posLastDot + 1);
237 }
238
239 do {
240 if (!sizeLeaf && !parent.empty()) {
241 auto posLastDotParent = parent.rfind('.');
242 if (posLastDotParent != parent.npos)
243 parent = parent.substr(0, posLastDot);
244 else
245 parent.clear();
246 }
247
248 foundLeafName = parent;
249 if (!parent.empty())
250 foundLeafName += ".";
251 foundLeafName += leafNameNoParent;
252 sizeLeaf = treeReader->GetTree()->FindLeaf(foundLeafName.c_str());
253 } while (!sizeLeaf && !parent.empty());
254 }
255
256 if (!sizeLeaf) {
257 Error("TDynamicArrayReader ", "Cannot find leaf count for %s or any parent branch!", leafName);
258 return;
259 }
260
261 const std::string leafType = sizeLeaf->GetTypeName();
262 if (leafType == "Int_t") {
263 fSizeReader.reset(new TSizeReaderImpl<Int_t>(*treeReader, foundLeafName.c_str()));
264 } else if (leafType == "UInt_t") {
265 fSizeReader.reset(new TSizeReaderImpl<UInt_t>(*treeReader, foundLeafName.c_str()));
266 } else if (leafType == "Short_t") {
267 fSizeReader.reset(new TSizeReaderImpl<Short_t>(*treeReader, foundLeafName.c_str()));
268 } else if (leafType == "UShort_t") {
269 fSizeReader.reset(new TSizeReaderImpl<UShort_t>(*treeReader, foundLeafName.c_str()));
270 } else if (leafType == "Long_t") {
271 fSizeReader.reset(new TSizeReaderImpl<Long_t>(*treeReader, foundLeafName.c_str()));
272 } else if (leafType == "ULong_t") {
273 fSizeReader.reset(new TSizeReaderImpl<ULong_t>(*treeReader, foundLeafName.c_str()));
274 } else if (leafType == "Long64_t") {
275 fSizeReader.reset(new TSizeReaderImpl<Long64_t>(*treeReader, foundLeafName.c_str()));
276 } else if (leafType == "ULong64_t") {
277 fSizeReader.reset(new TSizeReaderImpl<ULong64_t>(*treeReader, foundLeafName.c_str()));
278 } else {
279 Error("TDynamicArrayReader ",
280 "Unsupported size type for leaf %s. Supported types are int, short int, long int, long long int and "
281 "their unsigned counterparts.",
282 leafName);
283 }
284 }
285
286 size_t GetSize(ROOT::Detail::TBranchProxy * /*proxy*/) override { return fSizeReader->GetSize(); }
287 };
288
289 class TArrayParameterSizeReader : public TDynamicArrayReader<TObjectArrayReader> {
290 public:
291 TArrayParameterSizeReader(TTreeReader *treeReader, const char *branchName)
292 : TDynamicArrayReader<TObjectArrayReader>(treeReader, branchName)
293 {
294 }
295 };
296
297 // Reader interface for fixed size arrays
298 class TArrayFixedSizeReader : public TObjectArrayReader {
299 private:
300 Int_t fSize;
301
302 public:
303 TArrayFixedSizeReader(Int_t sizeArg) : fSize(sizeArg) {}
304
305 virtual size_t GetSize(ROOT::Detail::TBranchProxy* /*proxy*/) { return fSize; }
306 };
307
308 class TBasicTypeArrayReader final: public TVirtualCollectionReader {
309 public:
310 ~TBasicTypeArrayReader() {}
311
313 if (!proxy->Read()){
315 Error("TBasicTypeArrayReader::GetCP()", "Read error in TBranchProxy.");
316 return 0;
317 }
319 return (TVirtualCollectionProxy*) proxy->GetCollection();
320 }
321
322 virtual size_t GetSize(ROOT::Detail::TBranchProxy* proxy){
323 TVirtualCollectionProxy *myCollectionProxy = GetCP(proxy);
324 if (!myCollectionProxy) return 0;
325 return myCollectionProxy->Size();
326 }
327
328 virtual void* At(ROOT::Detail::TBranchProxy* proxy, size_t idx){
329 TVirtualCollectionProxy *myCollectionProxy = GetCP(proxy);
330 if (!myCollectionProxy) return 0;
331 return (Byte_t*)myCollectionProxy->At(idx) + proxy->GetOffset();
332 }
333 };
334
335 class TBasicTypeClonesReader final: public TClonesReader {
336 private:
337 Int_t fOffset;
338 public:
339 TBasicTypeClonesReader(Int_t offsetArg) : fOffset(offsetArg) {}
340
341 virtual void* At(ROOT::Detail::TBranchProxy* proxy, size_t idx){
342 TClonesArray *myClonesArray = GetCA(proxy);
343 if (!myClonesArray) return 0;
344 return (Byte_t*)myClonesArray->At(idx) + fOffset;
345 }
346 };
347
348 class TLeafReader : public TVirtualCollectionReader {
349 private:
350 TTreeReaderValueBase *fValueReader;
351 Int_t fElementSize;
352 public:
353 TLeafReader(TTreeReaderValueBase *valueReaderArg) : fValueReader(valueReaderArg), fElementSize(-1) {}
354
355 virtual size_t GetSize(ROOT::Detail::TBranchProxy* /*proxy*/){
356 TLeaf *myLeaf = fValueReader->GetLeaf();
357 return myLeaf ? myLeaf->GetLen() : 0; // Error will be printed by GetLeaf
358 }
359
360 virtual void* At(ROOT::Detail::TBranchProxy* /*proxy*/, size_t idx){
361 ProxyRead();
362 void *address = fValueReader->GetAddress();
363 if (fElementSize == -1){
364 TLeaf *myLeaf = fValueReader->GetLeaf();
365 if (!myLeaf) return 0; // Error will be printed by GetLeaf
366 fElementSize = myLeaf->GetLenType();
367 }
368 return (Byte_t*)address + (fElementSize * idx);
369 }
370
371 protected:
372 void ProxyRead(){
373 fValueReader->ProxyRead();
374 }
375 };
376
377 class TLeafParameterSizeReader : public TDynamicArrayReader<TLeafReader> {
378 public:
379 TLeafParameterSizeReader(TTreeReader *treeReader, const char *leafName, TTreeReaderValueBase *valueReaderArg)
380 : TDynamicArrayReader<TLeafReader>(treeReader, leafName, valueReaderArg)
381 {
382 }
383
384 size_t GetSize(ROOT::Detail::TBranchProxy* proxy) override {
385 ProxyRead();
386 return TDynamicArrayReader<TLeafReader>::GetSize(proxy);
387 }
388 };
389}
390
391
392
394
395////////////////////////////////////////////////////////////////////////////////
396/// Create the proxy object for our branch.
397
399{
400 if (fProxy) {
401 return;
402 }
403
404 fSetupStatus = kSetupInternalError; // Fallback; set to something concrete below.
405 if (!fTreeReader) {
406 Error("TTreeReaderArrayBase::CreateProxy()", "TTreeReader object not set / available for branch %s!",
407 fBranchName.Data());
408 fSetupStatus = kSetupTreeDestructed;
409 return;
410 }
411 if (!fDict) {
412 TBranch* br = fTreeReader->GetTree()->GetBranch(fBranchName);
413 const char* brDataType = "{UNDETERMINED}";
414 if (br) {
415 TDictionary* dictUnused = 0;
416 brDataType = GetBranchDataType(br, dictUnused, fDict);
417 }
418 Error("TTreeReaderArrayBase::CreateProxy()", "The template argument type T of %s accessing branch %s (which contains data of type %s) is not known to ROOT. You will need to create a dictionary for it.",
419 GetDerivedTypeName(), fBranchName.Data(), brDataType);
420 fSetupStatus = kSetupMissingDictionary;
421 return;
422 }
423
424 // Access a branch's collection content (not the collection itself)
425 // through a proxy.
426 // Search for the branchname, determine what it contains, and wire the
427 // TBranchProxy representing it to us so we can access its data.
428
429 TDictionary* branchActualType = 0;
430 TBranch* branch = nullptr;
431 TLeaf *myLeaf = nullptr;
432 if (!GetBranchAndLeaf(branch, myLeaf, branchActualType))
433 return;
434
435 if (!fDict) {
436 Error("TTreeReaderArrayBase::CreateProxy()",
437 "No dictionary for branch %s.", fBranchName.Data());
438 return;
439 }
440
441 TNamedBranchProxy* namedProxy = fTreeReader->FindProxy(fBranchName);
442 if (namedProxy) {
443 if (namedProxy->GetContentDict() == fDict) {
444 fSetupStatus = kSetupMatch;
445 fProxy = namedProxy->GetProxy();
446 SetImpl(branch, myLeaf);
447 return;
448 }
449
450 // Update named proxy's dictionary
451 if (!namedProxy->GetContentDict()) {
452 namedProxy->SetContentDict(fDict);
453 fProxy = namedProxy->GetProxy();
454 if (fProxy)
455 fSetupStatus = kSetupMatch;
456 } else {
457 Error("TTreeReaderArrayBase::CreateProxy()",
458 "Type ambiguity (want %s, have %s) for branch %s.",
459 fDict->GetName(), namedProxy->GetContentDict()->GetName(), fBranchName.Data());
460 }
461 }
462 else {
463 TString membername;
464
465 bool isTopLevel = branch->GetMother() == branch;
466 if (!isTopLevel) {
467 membername = strrchr(branch->GetName(), '.');
468 if (membername.IsNull()) {
469 membername = branch->GetName();
470 }
471 }
472 auto director = fTreeReader->fDirector;
473 // Determine if the branch is actually in a Friend TTree and if so which.
474 if (branch->GetTree() != fTreeReader->GetTree()->GetTree()) {
475 // It is in a friend, let's find the 'index' in the list of friend ...
476 int index = -1;
477 int current = 0;
478 for(auto fe : TRangeDynCast<TFriendElement>( fTreeReader->GetTree()->GetTree()->GetListOfFriends())) {
479 if (branch->GetTree() == fe->GetTree()) {
480 index = current;
481 }
482 ++current;
483 }
484 if (index == -1) {
485 Error("TTreeReaderArrayBase::CreateProxy()", "The branch %s is contained in a Friend TTree that is not directly attached to the main.\n"
486 "This is not yet supported by TTreeReader.",
487 fBranchName.Data());
488 return;
489 }
490 TFriendProxy *feproxy = nullptr;
491 if ((size_t)index < fTreeReader->fFriendProxies.size()) {
492 feproxy = fTreeReader->fFriendProxies.at(index);
493 }
494 if (!feproxy) {
495 feproxy = new ROOT::Internal::TFriendProxy(director, fTreeReader->GetTree(), index);
496 fTreeReader->fFriendProxies.resize(index+1);
497 fTreeReader->fFriendProxies.at(index) = feproxy;
498 }
499 director = feproxy->GetDirector();
500 }
501 namedProxy = new TNamedBranchProxy(director, branch, fBranchName, membername);
502 fTreeReader->AddProxy(namedProxy);
503 fProxy = namedProxy->GetProxy();
504 if (fProxy)
505 fSetupStatus = kSetupMatch;
506 else
507 fSetupStatus = kSetupMismatch;
508 }
509
510 if (!myLeaf){
511 TString branchActualTypeName;
512 const char* nonCollTypeName = GetBranchContentDataType(branch, branchActualTypeName, branchActualType);
513 if (nonCollTypeName) {
514 Error("TTreeReaderArrayBase::CreateContentProxy()", "The branch %s contains data of type %s, which should be accessed through a TTreeReaderValue< %s >.",
515 fBranchName.Data(), nonCollTypeName, nonCollTypeName);
516 if (fSetupStatus == kSetupInternalError)
517 fSetupStatus = kSetupNotACollection;
518 fProxy = 0;
519 return;
520 }
521 if (!branchActualType) {
522 if (branchActualTypeName.IsNull()) {
523 Error("TTreeReaderArrayBase::CreateContentProxy()", "Cannot determine the type contained in the collection of branch %s. That's weird - please report!",
524 fBranchName.Data());
525 } else {
526 Error("TTreeReaderArrayBase::CreateContentProxy()", "The branch %s contains data of type %s, which does not have a dictionary.",
527 fBranchName.Data(), branchActualTypeName.Data());
528 if (fSetupStatus == kSetupInternalError)
529 fSetupStatus = kSetupMissingDictionary;
530 }
531 fProxy = 0;
532 return;
533 }
534
535 auto matchingDataType = [](TDictionary *left, TDictionary *right) -> bool {
536 if (left == right)
537 return true;
538 if (!left || !right)
539 return false;
540 auto left_datatype = dynamic_cast<TDataType *>(left);
541 auto right_datatype = dynamic_cast<TDataType *>(right);
542 if (!left_datatype || !right_datatype)
543 return false;
544 auto l = left_datatype->GetType();
545 auto r = right_datatype->GetType();
546 if ( l > 0 && l == r)
547 return true;
548 else
549 return ( (l == kDouble32_t && r == kDouble_t)
550 || (l == kDouble_t && r == kDouble32_t)
551 || (l == kFloat16_t && r == kFloat_t)
552 || (l == kFloat_t && r == kFloat16_t));
553 };
554
555 if (! matchingDataType(fDict, branchActualType)) {
556 Error("TTreeReaderArrayBase::CreateContentProxy()", "The branch %s contains data of type %s. It cannot be accessed by a TTreeReaderArray<%s>",
557 fBranchName.Data(), branchActualType->GetName(), fDict->GetName());
558 if (fSetupStatus == kSetupInternalError || fSetupStatus >= 0)
559 fSetupStatus = kSetupMismatch;
560
561 // Update named proxy's dictionary
562 if (!namedProxy->GetContentDict()) {
563 namedProxy->SetContentDict(fDict);
564 }
565
566 // fProxy = 0;
567 // return;
568 }
569 }
570
571 SetImpl(branch, myLeaf);
572}
573
574////////////////////////////////////////////////////////////////////////////////
575/// Determine the branch / leaf and its type; reset fProxy / fSetupStatus on error.
576
578 TDictionary* &branchActualType) {
579 myLeaf = nullptr;
580 branch = fTreeReader->GetTree()->GetBranch(fBranchName);
581 if (branch)
582 return true;
583
584 if (!fBranchName.Contains(".")) {
585 Error("TTreeReaderArrayBase::GetBranchAndLeaf()", "The tree does not have a branch called %s. You could check with TTree::Print() for available branches.", fBranchName.Data());
586 fSetupStatus = kSetupMissingBranch;
587 fProxy = 0;
588 return false;
589 }
590
591 TRegexp leafNameExpression ("\\.[a-zA-Z0-9_]+$");
592 TString leafName (fBranchName(leafNameExpression));
593 TString branchName = fBranchName(0, fBranchName.Length() - leafName.Length());
594 branch = fTreeReader->GetTree()->GetBranch(branchName);
595 if (!branch){
596 Error("TTreeReaderArrayBase::GetBranchAndLeaf()", "The tree does not have a branch called %s. You could check with TTree::Print() for available branches.", fBranchName.Data());
597 fSetupStatus = kSetupMissingBranch;
598 fProxy = 0;
599 return false;
600 }
601
602 myLeaf = branch->GetLeaf(TString(leafName(1, leafName.Length())));
603 if (!myLeaf){
604 Error("TTreeReaderArrayBase::GetBranchAndLeaf()", "The tree does not have a branch, nor a sub-branch called %s. You could check with TTree::Print() for available branches.", fBranchName.Data());
605 fSetupStatus = kSetupMissingBranch;
606 fProxy = 0;
607 return false;
608 }
609
611 if (!tempDict){
612 Error("TTreeReaderArrayBase::GetBranchAndLeaf()", "Failed to get the dictionary for %s.", myLeaf->GetTypeName());
613 fSetupStatus = kSetupMissingDictionary;
614 fProxy = 0;
615 return false;
616 }
617
618 if (tempDict->IsA() == TDataType::Class() && TDictionary::GetDictionary(((TDataType*)tempDict)->GetTypeName()) == fDict){
619 //fLeafOffset = myLeaf->GetOffset() / 4;
620 branchActualType = fDict;
621 fLeaf = myLeaf;
622 fBranchName = branchName;
623 fLeafName = leafName(1, leafName.Length());
624 fHaveLeaf = (fLeafName.Length() > 0);
625 fSetupStatus = kSetupMatchLeaf;
626 }
627 else {
628 Error("TTreeReaderArrayBase::GetBranchAndLeaf()", "Leaf of type %s cannot be read by TTreeReaderValue<%s>.", myLeaf->GetTypeName(), fDict->GetName());
629 fProxy = 0;
630 fSetupStatus = kSetupMismatch;
631 return false;
632 }
633 return true;
634}
635
636
637
638
639////////////////////////////////////////////////////////////////////////////////
640/// Create the TVirtualCollectionReader object for our branch.
641
643{
644 if (fImpl)
645 return;
646
647 // Access a branch's collection content (not the collection itself)
648 // through a proxy.
649 // Search for the branchname, determine what it contains, and wire the
650 // TBranchProxy representing it to us so we can access its data.
651 // A proxy for branch must not have been created before (i.e. check
652 // fProxies before calling this function!)
653
654 if (myLeaf){
655 if (!myLeaf->GetLeafCount()){
656 fImpl = std::make_unique<TLeafReader>(this);
657 }
658 else {
659 TString leafFullName = myLeaf->GetBranch()->GetName();
660 leafFullName += ".";
661 leafFullName += myLeaf->GetLeafCount()->GetName();
662 fImpl = std::make_unique<TLeafParameterSizeReader>(fTreeReader, leafFullName.Data(), this);
663 }
664 fSetupStatus = kSetupMatchLeaf;
665 }
666 else if (branch->IsA() == TBranchElement::Class()) {
667 TBranchElement* branchElement = ((TBranchElement*)branch);
668
669 TStreamerInfo *streamerInfo = branchElement->GetInfo();
670 Int_t id = branchElement->GetID();
671
672 if (id >= 0){ // Not root node?
673 // Int_t offset = streamerInfo->GetOffsets()[id];
674 TStreamerElement *element = (TStreamerElement*)streamerInfo->GetElements()->At(id);
675 // Bool_t isPointer = element->IsaPointer();
676 // TClass *classPointer = element->GetClassPointer();
677
678 if (fSetupStatus == kSetupInternalError)
679 fSetupStatus = kSetupMatch;
680 if (element->IsA() == TStreamerSTL::Class()){
681 fImpl = std::make_unique<TSTLReader>();
682 }
683 else if (element->IsA() == TStreamerObject::Class()){
684 //fImpl = new TObjectArrayReader(); // BArray[12]
685
686 if (element->GetClass() == TClonesArray::Class()){
687 fImpl = std::make_unique<TClonesReader>();
688 }
689 else if (branchElement->GetType() == TBranchElement::kSTLMemberNode){
690 fImpl = std::make_unique<TBasicTypeArrayReader>();
691 }
692 else if (branchElement->GetType() == TBranchElement::kClonesMemberNode){
693 // TBasicTypeClonesReader should work for object
694 fImpl = std::make_unique<TBasicTypeClonesReader>(element->GetOffset());
695 }
696 else {
697 fImpl = std::make_unique<TArrayFixedSizeReader>(element->GetArrayLength());
698 }
699 }
700 else if (element->IsA() == TStreamerLoop::Class()) {
701 fImpl = std::make_unique<TArrayParameterSizeReader>(fTreeReader, branchElement->GetBranchCount()->GetName());
702 }
703 else if (element->IsA() == TStreamerBasicType::Class()){
704 if (branchElement->GetType() == TBranchElement::kSTLMemberNode){
705 fImpl = std::make_unique<TBasicTypeArrayReader>();
706 }
707 else if (branchElement->GetType() == TBranchElement::kClonesMemberNode){
708 fImpl = std::make_unique<TBasicTypeClonesReader>(element->GetOffset());
709 }
710 else {
711 fImpl = std::make_unique<TArrayFixedSizeReader>(element->GetArrayLength());
712 ((TObjectArrayReader*)fImpl.get())->SetBasicTypeSize(((TDataType*)fDict)->Size());
713 }
714 }
715 else if (element->IsA() == TStreamerBasicPointer::Class()) {
716 fImpl = std::make_unique<TArrayParameterSizeReader>(fTreeReader, branchElement->GetBranchCount()->GetName());
717 ((TArrayParameterSizeReader*)fImpl.get())->SetBasicTypeSize(((TDataType*)fDict)->Size());
718 }
719 else if (element->IsA() == TStreamerBase::Class()){
720 fImpl = std::make_unique<TClonesReader>();
721 } else {
722 Error("TTreeReaderArrayBase::SetImpl()",
723 "Cannot read branch %s: unhandled streamer element type %s",
724 fBranchName.Data(), element->IsA()->GetName());
725 fSetupStatus = kSetupInternalError;
726 }
727 }
728 else { // We are at root node?
729 if (branchElement->GetClass()->GetCollectionProxy()){
730 fImpl = std::make_unique<TCollectionLessSTLReader>(branchElement->GetClass()->GetCollectionProxy());
731 }
732 }
733 } else if (branch->IsA() == TBranch::Class()) {
734 auto topLeaf = branch->GetLeaf(branch->GetName());
735 if (!topLeaf) {
736 Error("TTreeReaderArrayBase::SetImpl", "Failed to get the top leaf from the branch");
737 fSetupStatus = kSetupMissingBranch;
738 return;
739 }
740 // We could have used GetLeafCounter, but it does not work well with Double32_t and Float16_t: ROOT-10149
741 auto sizeLeaf = topLeaf->GetLeafCount();
742 if (fSetupStatus == kSetupInternalError)
743 fSetupStatus = kSetupMatch;
744 if (!sizeLeaf) {
745 fImpl = std::make_unique<TArrayFixedSizeReader>(topLeaf->GetLenStatic());
746 }
747 else {
748 fImpl = std::make_unique<TArrayParameterSizeReader>(fTreeReader, sizeLeaf->GetName());
749 }
750 ((TObjectArrayReader*)fImpl.get())->SetBasicTypeSize(((TDataType*)fDict)->Size());
751 } else if (branch->IsA() == TBranchClones::Class()) {
752 Error("TTreeReaderArrayBase::SetImpl", "Support for branches of type TBranchClones not implemented");
753 fSetupStatus = kSetupInternalError;
754 } else if (branch->IsA() == TBranchObject::Class()) {
755 Error("TTreeReaderArrayBase::SetImpl", "Support for branches of type TBranchObject not implemented");
756 fSetupStatus = kSetupInternalError;
757 } else if (branch->IsA() == TBranchSTL::Class()) {
758 Error("TTreeReaderArrayBase::SetImpl", "Support for branches of type TBranchSTL not implemented");
759 fImpl = std::make_unique<TSTLReader>();
760 fSetupStatus = kSetupInternalError;
761 } else if (branch->IsA() == TBranchRef::Class()) {
762 Error("TTreeReaderArrayBase::SetImpl", "Support for branches of type TBranchRef not implemented");
763 fSetupStatus = kSetupInternalError;
764 }
765}
766
767////////////////////////////////////////////////////////////////////////////////
768/// Access a branch's collection content (not the collection itself)
769/// through a proxy.
770/// Retrieve the type of data contained in the collection stored by branch;
771/// put its dictionary into dict, If there is no dictionary, put its type
772/// name into contentTypeName.
773/// The contentTypeName is set to NULL if the branch does not
774/// contain a collection; in that case, the type of the branch is returned.
775/// In all other cases, NULL is returned.
776
778 TString& contentTypeName,
779 TDictionary* &dict)
780{
781 dict = nullptr;
782 contentTypeName = "";
783 if (branch->IsA() == TBranchElement::Class()) {
784 TBranchElement* brElement = (TBranchElement*)branch;
785 if (brElement->GetType() == 4
786 || brElement->GetType() == 3) {
787 TVirtualCollectionProxy* collProxy = brElement->GetCollectionProxy();
788 if (collProxy) {
789 TClass *myClass = collProxy->GetValueClass();
790 if (!myClass){
791 Error("TTreeReaderArrayBase::GetBranchContentDataType()", "Could not get value class.");
792 return 0;
793 }
794 dict = TDictionary::GetDictionary(myClass->GetName());
795 if (!dict) dict = TDataType::GetDataType(collProxy->GetType());
796 }
797 if (!dict) {
798 // We don't know the dictionary, thus we need the content's type name.
799 // Determine it.
800 if (brElement->GetType() == 3) {
801 contentTypeName = brElement->GetClonesName();
802 dict = TDictionary::GetDictionary(brElement->GetClonesName());
803 return 0;
804 }
805 // STL:
806 TClassEdit::TSplitType splitType(brElement->GetClassName());
807 int isSTLCont = splitType.IsSTLCont();
808 if (!isSTLCont) {
809 Error("TTreeReaderArrayBase::GetBranchContentDataType()", "Cannot determine STL collection type of %s stored in branch %s", brElement->GetClassName(), branch->GetName());
810 return brElement->GetClassName();
811 }
812 bool isMap = isSTLCont == ROOT::kSTLmap
813 || isSTLCont == ROOT::kSTLmultimap;
814 if (isMap) contentTypeName = "std::pair< ";
815 contentTypeName += splitType.fElements[1];
816 if (isMap) {
817 contentTypeName += splitType.fElements[2];
818 contentTypeName += " >";
819 }
820 return 0;
821 }
822 return 0;
823 } else if (brElement->GetType() == 31
824 || brElement->GetType() == 41) {
825 // it's a member, extract from GetClass()'s streamer info
826 TClass* clData = 0;
827 EDataType dtData = kOther_t;
828 int ExpectedTypeRet = brElement->GetExpectedType(clData, dtData);
829 if (ExpectedTypeRet == 0) {
830 dict = clData;
831 if (!dict) {
832 if (dtData == kFloat16_t) {
833 dtData = kFloat_t;
834 }
835 if (dtData == kDouble32_t) {
836 dtData = kDouble_t;
837 }
838 dict = TDataType::GetDataType(dtData);
839 }
840 if (!dict) {
841 Error("TTreeReaderArrayBase::GetBranchContentDataType()", "The branch %s contains a data type %d for which the dictionary cannot be retrieved.",
842 branch->GetName(), (int)dtData);
843 contentTypeName = TDataType::GetTypeName(dtData);
844 return 0;
845 }
846 return 0;
847 } else if (ExpectedTypeRet == 1) {
848 int brID = brElement->GetID();
849 if (brID == -1) {
850 // top
851 Error("TTreeReaderArrayBase::GetBranchContentDataType()", "The branch %s contains data of type %s for which the dictionary does not exist. It's needed.",
852 branch->GetName(), brElement->GetClassName());
853 contentTypeName = brElement->GetClassName();
854 return 0;
855 }
856 // Either the data type name doesn't have an EDataType entry
857 // or the streamer info doesn't have a TClass* attached.
858 TStreamerElement* element =
859 (TStreamerElement*) brElement->GetInfo()->GetElement(brID);
860 contentTypeName = element->GetTypeName();
861 return 0;
862 }
863 /* else (ExpectedTypeRet == 2)*/
864 // The streamer info entry cannot be found.
865 // TBranchElement::GetExpectedType() has already complained.
866 return "{CANNOT DETERMINE TBranchElement DATA TYPE}";
867 }
868 else if (brElement->GetType() == TBranchElement::kLeafNode){
869 TStreamerInfo *streamerInfo = brElement->GetInfo();
870 Int_t id = brElement->GetID();
871
872 if (id >= 0){
873 TStreamerElement *element = (TStreamerElement*)streamerInfo->GetElements()->At(id);
874
875 if (element->IsA() == TStreamerSTL::Class()){
876 TClass *myClass = brElement->GetCurrentClass();
877 if (!myClass){
878 Error("TTreeReaderArrayBase::GetBranchDataType()", "Could not get class from branch element.");
879 return 0;
880 }
881 TVirtualCollectionProxy *myCollectionProxy = myClass->GetCollectionProxy();
882 if (!myCollectionProxy){
883 Error("TTreeReaderArrayBase::GetBranchDataType()", "Could not get collection proxy from STL class");
884 return 0;
885 }
886 // Try getting the contained class
887 dict = myCollectionProxy->GetValueClass();
888 // If it fails, try to get the contained type as a primitive type
889 if (!dict) dict = TDataType::GetDataType(myCollectionProxy->GetType());
890 if (!dict){
891 Error("TTreeReaderArrayBase::GetBranchDataType()", "Could not get valueClass from collectionProxy.");
892 return 0;
893 }
894 contentTypeName = dict->GetName();
895 return 0;
896 }
897 else if (element->IsA() == TStreamerObject::Class() && !strcmp(element->GetTypeName(), "TClonesArray")){
898 if (!fProxy->Setup() || !fProxy->Read()){
899 Error("TTreeReaderArrayBase::GetBranchContentDataType()", "Failed to get type from proxy, unable to check type");
900 contentTypeName = "UNKNOWN";
901 dict = 0;
902 return contentTypeName;
903 }
904 TClonesArray *myArray = (TClonesArray*)fProxy->GetWhere();
905 dict = myArray->GetClass();
906 contentTypeName = dict->GetName();
907 return 0;
908 }
909 else {
910 dict = brElement->GetCurrentClass();
911 if (!dict) {
912 TDictionary *myDataType = TDictionary::GetDictionary(brElement->GetTypeName());
913 dict = TDataType::GetDataType((EDataType)((TDataType*)myDataType)->GetType());
914 }
915 contentTypeName = brElement->GetTypeName();
916 return 0;
917 }
918 }
919 if (brElement->GetCurrentClass() == TClonesArray::Class()){
920 contentTypeName = "TClonesArray";
921 Warning("TTreeReaderArrayBase::GetBranchContentDataType()", "Not able to check type correctness, ignoring check");
922 dict = fDict;
923 fSetupStatus = kSetupNoCheck;
924 }
925 else if (!dict && (branch->GetSplitLevel() == 0 || brElement->GetClass()->GetCollectionProxy())){
926 // Try getting the contained class
927 dict = brElement->GetClass()->GetCollectionProxy()->GetValueClass();
928 // If it fails, try to get the contained type as a primitive type
929 if (!dict) dict = TDataType::GetDataType(brElement->GetClass()->GetCollectionProxy()->GetType());
930 if (dict) contentTypeName = dict->GetName();
931 return 0;
932 }
933 else if (!dict){
934 dict = brElement->GetClass();
935 contentTypeName = dict->GetName();
936 return 0;
937 }
938
939 return 0;
940 }
941 return 0;
942 } else if (branch->IsA() == TBranch::Class()
943 || branch->IsA() == TBranchObject::Class()
944 || branch->IsA() == TBranchSTL::Class()) {
945 const char* dataTypeName = branch->GetClassName();
946 if ((!dataTypeName || !dataTypeName[0])
947 && branch->IsA() == TBranch::Class()) {
948 auto myLeaf = branch->GetLeaf(branch->GetName());
949 if (myLeaf){
950 auto myDataType = TDictionary::GetDictionary(myLeaf->GetTypeName());
951 if (myDataType && myDataType->IsA() == TDataType::Class()){
952 auto typeEnumConstant = EDataType(((TDataType*)myDataType)->GetType());
953 // We need to consider Double32_t and Float16_t as dounle and float respectively
954 // since this is the type the user uses to instantiate the TTreeReaderArray template.
955 if (typeEnumConstant == kDouble32_t) typeEnumConstant = kDouble_t;
956 else if (typeEnumConstant == kFloat16_t) typeEnumConstant = kFloat_t;
957 dict = TDataType::GetDataType(typeEnumConstant);
958 contentTypeName = myLeaf->GetTypeName();
959 return 0;
960 }
961 }
962
963 // leaflist. Can't represent.
964 Error("TTreeReaderArrayBase::GetBranchContentDataType()", "The branch %s was created using a leaf list and cannot be represented as a C++ type. Please access one of its siblings using a TTreeReaderArray:", branch->GetName());
965 TIter iLeaves(branch->GetListOfLeaves());
966 TLeaf* leaf = 0;
967 while ((leaf = (TLeaf*) iLeaves())) {
968 Error("TTreeReaderArrayBase::GetBranchContentDataType()", " %s.%s", branch->GetName(), leaf->GetName());
969 }
970 return 0;
971 }
972 if (dataTypeName) dict = TDictionary::GetDictionary(dataTypeName);
973 if (branch->IsA() == TBranchSTL::Class()){
974 Warning("TTreeReaderArrayBase::GetBranchContentDataType()", "Not able to check type correctness, ignoring check");
975 dict = fDict;
976 fSetupStatus = kSetupNoCheck;
977 return 0;
978 }
979 return dataTypeName;
980 } else if (branch->IsA() == TBranchClones::Class()) {
981 dict = TClonesArray::Class();
982 return "TClonesArray";
983 } else if (branch->IsA() == TBranchRef::Class()) {
984 // Can't represent.
985 Error("TTreeReaderArrayBase::GetBranchContentDataType()", "The branch %s is a TBranchRef and cannot be represented as a C++ type.", branch->GetName());
986 return 0;
987 } else {
988 Error("TTreeReaderArrayBase::GetBranchContentDataType()", "The branch %s is of type %s - something that is not handled yet.", branch->GetName(), branch->IsA()->GetName());
989 return 0;
990 }
991
992 return 0;
993}
size_t fSize
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
unsigned char Byte_t
Definition: RtypesCore.h:64
#define ClassImp(name)
Definition: Rtypes.h:375
EDataType
Definition: TDataType.h:28
@ kFloat_t
Definition: TDataType.h:31
@ kDouble32_t
Definition: TDataType.h:31
@ kDouble_t
Definition: TDataType.h:31
@ kFloat16_t
Definition: TDataType.h:33
@ kOther_t
Definition: TDataType.h:32
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:188
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition: TError.cxx:232
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Base class for all the proxy object.
Definition: TBranchProxy.h:74
virtual void * GetStart(UInt_t=0)
Definition: TBranchProxy.h:413
TVirtualCollectionProxy * GetCollection()
Definition: TBranchProxy.h:410
TBranchProxyDirector * GetDirector()
Definition: TFriendProxy.h:31
const Detail::TBranchProxy * GetProxy() const
TDictionary * GetContentDict() const
void SetContentDict(TDictionary *dict)
Base class of TTreeReaderArray.
bool GetBranchAndLeaf(TBranch *&branch, TLeaf *&myLeaf, TDictionary *&branchActualType)
Determine the branch / leaf and its type; reset fProxy / fSetupStatus on error.
virtual void CreateProxy()
Create the proxy object for our branch.
void SetImpl(TBranch *branch, TLeaf *myLeaf)
Create the TVirtualCollectionReader object for our branch.
const char * GetBranchContentDataType(TBranch *branch, TString &contentTypeName, TDictionary *&dict)
Access a branch's collection content (not the collection itself) through a proxy.
Base class of TTreeReaderValue.
void * GetAddress()
Returns the memory address of the object being read.
TLeaf * GetLeaf()
If we are reading a leaf, return the corresponding TLeaf.
static TClass * Class()
A Branch for the case of an object.
TBranchElement * GetBranchCount() const
static TClass * Class()
Int_t GetID() const
const char * GetClassName() const override
Return the name of the user class whose content is stored in this branch, if any.
TStreamerInfo * GetInfo() const
Get streamer info for the branch class.
TVirtualCollectionProxy * GetCollectionProxy()
Return the collection proxy describing the branch content, if any.
TClass * GetCurrentClass()
Return a pointer to the current type of the data member corresponding to branch element.
virtual const char * GetTypeName() const
Return type name of element in the branch.
virtual const char * GetClonesName() const
virtual TClass * GetClass() const
Int_t GetType() const
Int_t GetExpectedType(TClass *&clptr, EDataType &type) override
Fill expectedClass and expectedType with information on the data type of the object/values contained ...
static TClass * Class()
static TClass * Class()
static TClass * Class()
A TTree is a list of TBranches.
Definition: TBranch.h:89
virtual TLeaf * GetLeaf(const char *name) const
Return pointer to the 1st Leaf named name in thisBranch.
Definition: TBranch.cxx:2001
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any.
Definition: TBranch.cxx:1324
TTree * GetTree() const
Definition: TBranch.h:248
static TClass * Class()
Int_t GetSplitLevel() const
Definition: TBranch.h:246
TClass * IsA() const override
Definition: TBranch.h:291
TObjArray * GetListOfLeaves()
Definition: TBranch.h:243
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition: TBranch.cxx:2073
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:81
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2897
Int_t GetClassSize() const
Definition: TClass.h:423
An array of clone (identical) objects.
Definition: TClonesArray.h:29
TClass * GetClass() const
Definition: TClonesArray.h:53
static TClass * Class()
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
static TClass * Class()
TString GetTypeName()
Get basic type of typedef, e,g.: "class TDirectory*" -> "TDirectory".
Definition: TDataType.cxx:149
static TDataType * GetDataType(EDataType type)
Given a EDataType type, get the TDataType* that represents it.
Definition: TDataType.cxx:451
This class defines an abstract interface that must be implemented by all classes that contain diction...
Definition: TDictionary.h:167
TClass * IsA() const override
Definition: TDictionary.h:224
static TDictionary * GetDictionary(const char *name)
Retrieve the type (class, fundamental type, typedef etc) named "name".
Definition: TDictionary.cxx:89
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:57
virtual Int_t GetLenType() const
Definition: TLeaf.h:133
virtual const char * GetTypeName() const
Definition: TLeaf.h:139
virtual Int_t GetLen() const
Return the number of effective elements of this leaf, for the current entry.
Definition: TLeaf.cxx:404
virtual TLeaf * GetLeafCount() const
If this leaf stores a variable-sized array or a multi-dimensional array whose last dimension has vari...
Definition: TLeaf.h:121
TBranch * GetBranch() const
Definition: TLeaf.h:116
const char * GetName() const override
Returns name of object.
Definition: TNamed.h:47
Int_t GetEntries() const override
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:523
TObject * At(Int_t idx) const override
Definition: TObjArray.h:164
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:84
Regular expression class.
Definition: TRegexp.h:31
static TClass * Class()
static TClass * Class()
static TClass * Class()
Int_t GetArrayLength() const
const char * GetTypeName() const
TClass * GetClass() const
TClass * IsA() const override
Int_t GetOffset() const
Describes a persistent version of a class.
Definition: TStreamerInfo.h:39
TStreamerElement * GetElement(Int_t id) const override
TObjArray * GetElements() const override
static TClass * Class()
static TClass * Class()
static TClass * Class()
Basic string class.
Definition: TString.h:136
Ssiz_t Length() const
Definition: TString.h:410
const char * Data() const
Definition: TString.h:369
Bool_t IsNull() const
Definition: TString.h:407
An interface for reading values stored in ROOT columnar datasets.
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition: TTreeReader.h:44
TTree * GetTree() const
Definition: TTreeReader.h:181
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition: TTree.cxx:5262
virtual TTree * GetTree() const
Definition: TTree.h:513
virtual TLeaf * FindLeaf(const char *name)
Find leaf..
Definition: TTree.cxx:4884
virtual void PushProxy(void *objectstart)=0
virtual EDataType GetType() const =0
virtual void PopProxy()=0
virtual TClass * GetValueClass() const =0
virtual void * At(UInt_t idx)=0
virtual UInt_t Size() const =0
virtual Bool_t HasPointers() const =0
@ kSTLmap
Definition: ESTLType.h:33
@ kSTLmultimap
Definition: ESTLType.h:34
Type GetType(const std::string &Name)
Definition: Systematics.cxx:34
void forward(const LAYERDATA &prevLayerData, LAYERDATA &currLayerData)
apply the weights (and functions) in forward direction of the DNN
Definition: NeuralNet.icc:546
const char * Size
Definition: TXMLSetup.cxx:56
int IsSTLCont(int testAlloc=0) const
type : type name: vector<list<classA,allocator>,allocator> testAlloc: if true, we test allocator,...
Definition: TClassEdit.cxx:206
std::vector< std::string > fElements
Definition: TClassEdit.h:141
TLine l
Definition: textangle.C:4
#define ARGS(alist)
Definition: gifencode.c:10