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