Logo ROOT  
Reference Guide
TTreeReaderValue.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 "TTreeReaderValue.h"
13
14#include "TTreeReader.h"
15#include "TBranchClones.h"
16#include "TBranchElement.h"
17#include "TBranchRef.h"
18#include "TBranchSTL.h"
19#include "TBranchObject.h"
21#include "TClassEdit.h"
22#include "TFriendElement.h"
23#include "TFriendProxy.h"
24#include "TLeaf.h"
25#include "TTreeProxyGenerator.h"
26#include "TRegexp.h"
27#include "TStreamerInfo.h"
28#include "TStreamerElement.h"
29#include "TNtuple.h"
30#include "TROOT.h"
31#include <vector>
32
33// clang-format off
34/**
35 * \class TTreeReaderValue
36 * \ingroup treeplayer
37 * \brief An interface for reading values stored in ROOT columnar datasets
38 *
39 * The TTreeReaderValue is a type-safe tool to be used in association with a TTreeReader
40 * to access the values stored in TTree, TNtuple and TChain datasets.
41 * TTreeReaderValue can be also used to access collections such as `std::vector`s or TClonesArray
42 * stored in columnar datasets but it is recommended to use TTreeReaderArray instead as it offers
43 * several advantages.
44 *
45 * See the documentation of TTreeReader for more details and examples.
46*/
47// clang-format on
48
50
51////////////////////////////////////////////////////////////////////////////////
52/// Construct a tree value reader and register it with the reader object.
53
55 const char* branchname /*= 0*/,
56 TDictionary* dict /*= 0*/):
57 fHaveLeaf(0),
58 fHaveStaticClassOffsets(0),
59 fReadStatus(kReadNothingYet),
60 fBranchName(branchname),
61 fTreeReader(reader),
62 fDict(dict)
63{
65}
66
67////////////////////////////////////////////////////////////////////////////////
68/// Copy-construct.
69
71 fHaveLeaf(rhs.fHaveLeaf),
72 fHaveStaticClassOffsets(rhs.fHaveStaticClassOffsets),
73 fReadStatus(rhs.fReadStatus),
74 fSetupStatus(rhs.fSetupStatus),
75 fBranchName(rhs.fBranchName),
76 fLeafName(rhs.fLeafName),
77 fTreeReader(rhs.fTreeReader),
78 fDict(rhs.fDict),
79 fProxy(rhs.fProxy),
80 fLeaf(rhs.fLeaf),
81 fStaticClassOffsets(rhs.fStaticClassOffsets)
82{
84}
85
86////////////////////////////////////////////////////////////////////////////////
87/// Copy-assign.
88
91 if (&rhs != this) {
92 fHaveLeaf = rhs.fHaveLeaf;
93 fHaveStaticClassOffsets = rhs.fHaveStaticClassOffsets;
94 fBranchName = rhs.fBranchName;
95 fLeafName = rhs.fLeafName;
96 if (fTreeReader != rhs.fTreeReader) {
97 if (fTreeReader)
98 fTreeReader->DeregisterValueReader(this);
99 fTreeReader = rhs.fTreeReader;
100 RegisterWithTreeReader();
101 }
102 fDict = rhs.fDict;
103 fProxy = rhs.fProxy;
104 fLeaf = rhs.fLeaf;
105 fSetupStatus = rhs.fSetupStatus;
106 fReadStatus = rhs.fReadStatus;
107 fStaticClassOffsets = rhs.fStaticClassOffsets;
108 }
109 return *this;
110}
111
112////////////////////////////////////////////////////////////////////////////////
113/// Unregister from tree reader, cleanup.
114
116{
117 if (fTreeReader) fTreeReader->DeregisterValueReader(this);
118 R__ASSERT((fLeafName.Length() == 0 ) == !fHaveLeaf
119 && "leafness disagreement");
120 R__ASSERT(fStaticClassOffsets.empty() == !fHaveStaticClassOffsets
121 && "static class offset disagreement");
122}
123
124////////////////////////////////////////////////////////////////////////////////
125/// Register with tree reader.
126
128 if (fTreeReader) {
129 if (!fTreeReader->RegisterValueReader(this)) {
130 fTreeReader = nullptr;
131 }
132 }
133}
134
135////////////////////////////////////////////////////////////////////////////////
136/// Try to read the value from the TBranchProxy, returns
137/// the status of the read.
138
139
140
141template <ROOT::Internal::TTreeReaderValueBase::BranchProxyRead_t Func>
143{
144 if ((fProxy->*Func)()) {
145 fReadStatus = kReadSuccess;
146 } else {
147 fReadStatus = kReadError;
148 }
149 return fReadStatus;
150}
151
154 if (!fProxy) return kReadNothingYet;
155 if (fProxy->IsInitialized() || fProxy->Setup()) {
156
158 using TBranchPoxy = ROOT::Detail::TBranchProxy;
159
160 EReadType readtype = EReadType::kNoDirector;
161 if (fProxy) readtype = fProxy->GetReadType();
162
163 switch (readtype) {
164 case EReadType::kNoDirector:
165 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoDirector>;
166 break;
167 case EReadType::kReadParentNoCollection:
168 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentNoCollection>;
169 break;
170 case EReadType::kReadParentCollectionNoPointer:
171 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentCollectionNoPointer>;
172 break;
173 case EReadType::kReadParentCollectionPointer:
174 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentCollectionPointer>;
175 break;
176 case EReadType::kReadNoParentNoBranchCountCollectionPointer:
177 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountCollectionPointer>;
178 break;
179 case EReadType::kReadNoParentNoBranchCountCollectionNoPointer:
180 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountCollectionNoPointer>;
181 break;
182 case EReadType::kReadNoParentNoBranchCountNoCollection:
183 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountNoCollection>;
184 break;
185 case EReadType::kReadNoParentBranchCountCollectionPointer:
186 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountCollectionPointer>;
187 break;
188 case EReadType::kReadNoParentBranchCountCollectionNoPointer:
189 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountCollectionNoPointer>;
190 break;
191 case EReadType::kReadNoParentBranchCountNoCollection:
192 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountNoCollection>;
193 break;
195 // intentional fall through.
196 default: fProxyReadFunc = &TTreeReaderValueBase::ProxyReadDefaultImpl;
197 }
198 return (this->*fProxyReadFunc)();
199 }
200
201 // If somehow the Setup fails call the original Read to
202 // have the proper error handling (message only if the Setup fails
203 // and the current proxy entry is different than the TTree's current entry)
204 if (fProxy->Read()) {
205 fReadStatus = kReadSuccess;
206 } else {
207 fReadStatus = kReadError;
208 }
209 return fReadStatus;
210}
211
212////////////////////////////////////////////////////////////////////////////////
213/// Stringify the template argument.
214std::string ROOT::Internal::TTreeReaderValueBase::GetElementTypeName(const std::type_info& ti) {
215 int err;
216 char* buf = TClassEdit::DemangleTypeIdName(ti, err);
217 std::string ret = buf;
218 free(buf);
219 return ret;
220}
221
222////////////////////////////////////////////////////////////////////////////////
223/// The TTreeReader has switched to a new TTree. Update the leaf.
224
226 // Since the TTree structure might have change, let's make sure we
227 // use the right reading function.
229
230 if (!fHaveLeaf || !newTree) {
231 fLeaf = nullptr;
232 return;
233 }
234
235 TBranch *myBranch = newTree->GetBranch(fBranchName);
236
237 if (!myBranch) {
238 fReadStatus = kReadError;
239 Error("TTreeReaderValueBase::GetLeaf()", "Unable to get the branch from the tree");
240 return;
241 }
242
243 fLeaf = myBranch->GetLeaf(fLeafName);
244 if (!fLeaf) {
245 Error("TTreeReaderValueBase::GetLeaf()", "Failed to get the leaf from the branch");
246 }
247}
248
249////////////////////////////////////////////////////////////////////////////////
250/// Returns the memory address of the object being read.
251
253 if (ProxyRead() != kReadSuccess) return 0;
254
255 if (fHaveLeaf){
256 if (GetLeaf()){
257 return fLeaf->GetValuePointer();
258 }
259 else {
260 fReadStatus = kReadError;
261 Error("TTreeReaderValueBase::GetAddress()", "Unable to get the leaf");
262 return 0;
263 }
264 }
265 if (fHaveStaticClassOffsets){ // Follow all the pointers
266 Byte_t *address = (Byte_t*)fProxy->GetWhere();
267
268 for (unsigned int i = 0; i < fStaticClassOffsets.size() - 1; ++i){
269 address = *(Byte_t**)(address + fStaticClassOffsets[i]);
270 }
271
272 return address + fStaticClassOffsets.back();
273 }
274 return (Byte_t*)fProxy->GetWhere();
275}
276
277////////////////////////////////////////////////////////////////////////////////
278/// \brief Search a branch the name of which contains a "."
279/// \param[out] myLeaf The leaf identified by the name if found (can be untouched).
280/// \param[out] branchActualType Dictionary associated to the type of the leaf (can be untouched).
281/// \param[out] errMsg The error message (can be untouched).
282/// \return The address of the branch if found, nullptr otherwise
283/// This method allows to efficiently search for branches which have names which
284/// contain "dots", for example "w.v.a" or "v.a".
285/// Therefore, it allows to support names such as v.a where the branch was
286/// created with this syntax:
287/// ```{.cpp}
288/// myTree->Branch("v", &v, "a/I:b:/I")
289/// ```
290/// The method has some side effects, namely it can modify fSetupStatus, fProxy
291/// and fStaticClassOffsets/fHaveStaticClassOffsets.
293{
294 TRegexp leafNameExpression ("\\.[a-zA-Z0-9_]+$");
295 TString leafName (fBranchName(leafNameExpression));
296 TString branchName = fBranchName(0, fBranchName.Length() - leafName.Length());
297 auto branch = fTreeReader->GetTree()->GetBranch(branchName);
298 if (!branch){
299 std::vector<TString> nameStack;
300 nameStack.push_back(TString()); //Trust me
301 nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
302 leafName = branchName(leafNameExpression);
303 branchName = branchName(0, branchName.Length() - leafName.Length());
304
305 branch = fTreeReader->GetTree()->GetBranch(branchName);
306 if (!branch) branch = fTreeReader->GetTree()->GetBranch(branchName + ".");
307 if (leafName.Length()) nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
308
309 while (!branch && branchName.Contains(".")){
310 leafName = branchName(leafNameExpression);
311 branchName = branchName(0, branchName.Length() - leafName.Length());
312 branch = fTreeReader->GetTree()->GetBranch(branchName);
313 if (!branch) branch = fTreeReader->GetTree()->GetBranch(branchName + ".");
314 nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
315 }
316
317 if (branch && branch->IsA() == TBranchElement::Class()){
318 TBranchElement *myBranchElement = (TBranchElement*)branch;
319
320 TString traversingBranch = nameStack.back();
321 nameStack.pop_back();
322
323 bool found = true;
324
325 TDataType *finalDataType = 0;
326
327 std::vector<Long64_t> offsets;
328 Long64_t offset = 0;
329 TClass *elementClass = 0;
330
331 TObjArray *myObjArray = myBranchElement->GetInfo()->GetElements();
332 TVirtualStreamerInfo *myInfo = myBranchElement->GetInfo();
333
334 while (nameStack.size() && found){
335 found = false;
336
337 for (int i = 0; i < myObjArray->GetEntries(); ++i){
338
339 TStreamerElement *tempStreamerElement = (TStreamerElement*)myObjArray->At(i);
340
341 if (!strcmp(tempStreamerElement->GetName(), traversingBranch.Data())){
342 offset += myInfo->GetElementOffset(i);
343
344 traversingBranch = nameStack.back();
345 nameStack.pop_back();
346
347 elementClass = tempStreamerElement->GetClass();
348 if (elementClass) {
349 myInfo = elementClass->GetStreamerInfo(0);
350 myObjArray = myInfo->GetElements();
351 // FIXME: this is odd, why is 'i' not also reset????
352 }
353 else {
354 finalDataType = TDataType::GetDataType((EDataType)tempStreamerElement->GetType());
355 if (!finalDataType) {
356 TDictionary* seType = TDictionary::GetDictionary(tempStreamerElement->GetTypeName());
357 if (seType && seType->IsA() == TDataType::Class()) {
358 finalDataType = TDataType::GetDataType((EDataType)((TDataType*)seType)->GetType());
359 }
360 }
361 }
362
363 if (tempStreamerElement->IsaPointer()){
364 offsets.push_back(offset);
365 offset = 0;
366 }
367
368 found = true;
369 break;
370 }
371 }
372 }
373
374 offsets.push_back(offset);
375
376 if (found){
377 fStaticClassOffsets = offsets;
378 fHaveStaticClassOffsets = 1;
379
380 if (fDict != finalDataType && fDict != elementClass){
381 errMsg = "Wrong data type ";
382 errMsg += finalDataType ? finalDataType->GetName() : elementClass ? elementClass->GetName() : "UNKNOWN";
383 fSetupStatus = kSetupMismatch;
384 fProxy = 0;
385 return nullptr;
386 }
387 }
388 }
389
390
391 if (!fHaveStaticClassOffsets) {
392 errMsg = "The tree does not have a branch called ";
393 errMsg += fBranchName;
394 errMsg += ". You could check with TTree::Print() for available branches.";
395 fSetupStatus = kSetupMissingBranch;
396 fProxy = 0;
397 return nullptr;
398 }
399 }
400 else {
401 myLeaf = branch->GetLeaf(TString(leafName(1, leafName.Length())));
402 if (!myLeaf){
403 errMsg = "The tree does not have a branch, nor a sub-branch called ";
404 errMsg += fBranchName;
405 errMsg += ". You could check with TTree::Print() for available branches.";
406 fSetupStatus = kSetupMissingBranch;
407 fProxy = 0;
408 return nullptr;
409 }
410 else {
411 TDataType *tempDict = gROOT->GetType(myLeaf->GetTypeName());
412 if (tempDict && fDict->IsA() == TDataType::Class() && tempDict->GetType() == ((TDataType*)fDict)->GetType()) {
413 //fLeafOffset = myLeaf->GetOffset() / 4;
414 branchActualType = fDict;
415 fLeaf = myLeaf;
416 fBranchName = branchName;
417 fLeafName = leafName(1, leafName.Length());
418 fHaveLeaf = fLeafName.Length() > 0;
419 fSetupStatus = kSetupMatchLeaf;
420 }
421 else {
422 errMsg = "Leaf of type ";
423 errMsg += myLeaf->GetTypeName();
424 errMsg += " cannot be read by TTreeReaderValue<";
425 errMsg += fDict->GetName();
426 errMsg += ">.";
427 fSetupStatus = kSetupMismatch;
428 return nullptr;
429 }
430 }
431 }
432
433 return branch;
434}
435
436////////////////////////////////////////////////////////////////////////////////
437/// Create the proxy object for our branch.
438
440
441 constexpr const char* errPrefix = "TTreeReaderValueBase::CreateProxy()";
442
443 if (fProxy) {
444 return;
445 }
446
447 fSetupStatus = kSetupInternalError; // Fallback; set to something concrete below.
448 if (!fTreeReader) {
449 Error(errPrefix, "TTreeReader object not set / available for branch %s!",
450 fBranchName.Data());
451 fSetupStatus = kSetupTreeDestructed;
452 return;
453 }
454
455 auto branchFromFullName = fTreeReader->GetTree()->GetBranch(fBranchName);
456 if (branchFromFullName == nullptr) // use the slower but more thorough FindBranch as fallback
457 branchFromFullName = fTreeReader->GetTree()->FindBranch(fBranchName);
458
459 if (!fDict) {
460 const char* brDataType = "{UNDETERMINED}";
461 if (branchFromFullName) {
462 TDictionary* brDictUnused = 0;
463 brDataType = GetBranchDataType(branchFromFullName, brDictUnused, fDict);
464 }
465 Error(errPrefix, "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.",
466 GetDerivedTypeName(), fBranchName.Data(), brDataType);
467 fSetupStatus = kSetupMissingDictionary;
468 return;
469 }
470
471 // Search for the branchname, determine what it contains, and wire the
472 // TBranchProxy representing it to us so we can access its data.
473
474 TNamedBranchProxy* namedProxy = fTreeReader->FindProxy(fBranchName);
475 if (namedProxy && namedProxy->GetDict() == fDict) {
476 fProxy = namedProxy->GetProxy();
477 // But go on: we need to set fLeaf etc!
478 }
479
480 const std::string originalBranchName = fBranchName.Data();
481
482 TLeaf *myLeaf = nullptr;
483 TDictionary* branchActualType = nullptr;
484 std::string errMsg;
485
486 TBranch *branch = nullptr;
487 // If the branch name contains at least a dot, we analyse it in detail and
488 // we give priority to the branch identified over the one which is found
489 // with the TTree::GetBranch method. This allows to correctly pick the desired
490 // branch in cases where a TTree has two branches, one called for example
491 // "w.v.a" and another one called "v.a".
492 // This behaviour is described in ROOT-9312.
493 if (fBranchName.Contains(".")) {
494 branch = SearchBranchWithCompositeName(myLeaf, branchActualType, errMsg);
495 // In rare cases where leaves contain the name of the branch as part of their
496 // name and a dot in the branch name (such as: branch "b." and leaf "b.a")
497 // the previous method may return the branch name ("b.") rather than the
498 // leaf name ("b.a") as we expect.
499 // For these cases, we do not have to give priority to the previously
500 // identified branch since we are in a different situation.
501 // This behaviour is described in ROOT-9757.
502 if (branch && branch->IsA() == TBranchElement::Class() && branchFromFullName){
503 branch = branchFromFullName;
504 fStaticClassOffsets = {};
505 fHaveStaticClassOffsets = 0;
506 }
507 }
508
509 if (!branch) {
510 // We had an error, the branch name had no "." or we simply did not find anything.
511 // We check if we had a branch found with the full name with a dot in it.
512 branch = branchFromFullName;
513 if (!branch) {
514 // Also that one was empty. We need to error out. We do it properly: at
515 // first we check if the routine to find branches with names with a "."
516 // provided a specific error message. If not, we go with a generic message.
517 if (errMsg.empty()) {
518 errMsg = "The tree does not have a branch called ";
519 errMsg += fBranchName.Data();
520 errMsg += ". You could check with TTree::Print() for available branches.";
521 }
522#if !defined(_MSC_VER)
523#pragma GCC diagnostic push
524#pragma GCC diagnostic ignored "-Wformat-security"
525#endif
526 Error(errPrefix, errMsg.c_str());
527#if !defined(_MSC_VER)
528#pragma GCC diagnostic pop
529#endif
530 return;
531 } else {
532 // The branch found with the simplest search approach was successful.
533 // We reset the state, we continue
534 fSetupStatus = kSetupInternalError;
535 fStaticClassOffsets = {};
536 fHaveStaticClassOffsets = 0;
537 }
538 }
539
540 if (!myLeaf && !fHaveStaticClassOffsets) {
541 // The following two lines cannot be swapped. The GetBranchDataType can
542 // change the value of branchActualType
543 const char* branchActualTypeName = GetBranchDataType(branch, branchActualType, fDict);
544 if (!branchActualType) {
545 Error(errPrefix, "The branch %s contains data of type %s, which does not have a dictionary.",
546 fBranchName.Data(), branchActualTypeName ? branchActualTypeName : "{UNDETERMINED TYPE}");
547 fProxy = 0;
548 return;
549 }
550
551 // Check if the dictionaries are TClass instances and if there is inheritance
552 // because in this case, we can read the values.
553 auto dictAsClass = dynamic_cast<TClass*>(fDict);
554 auto branchActualTypeAsClass = dynamic_cast<TClass*>(branchActualType);
555 auto inheritance = dictAsClass && branchActualTypeAsClass && branchActualTypeAsClass->InheritsFrom(dictAsClass);
556
557 if (fDict != branchActualType && !inheritance) {
558 TDataType *dictdt = dynamic_cast<TDataType*>(fDict);
559 TDataType *actualdt = dynamic_cast<TDataType*>(branchActualType);
560 bool complainAboutMismatch = true;
561 if (dictdt && actualdt) {
562 if (dictdt->GetType() > 0 && dictdt->GetType() == actualdt->GetType()) {
563 // Same numerical type but different TDataType, likely Long64_t
564 complainAboutMismatch = false;
565 } else if ((actualdt->GetType() == kDouble32_t && dictdt->GetType() == kDouble_t)
566 || (actualdt->GetType() == kFloat16_t && dictdt->GetType() == kFloat_t)) {
567 // Double32_t and Float16_t never "decay" to their underlying type;
568 // we need to identify them manually here (ROOT-8731).
569 complainAboutMismatch = false;
570 }
571 }
572 if (complainAboutMismatch) {
573 Error(errPrefix,
574 "The branch %s contains data of type %s. It cannot be accessed by a TTreeReaderValue<%s>",
575 fBranchName.Data(), branchActualType->GetName(),
576 fDict->GetName());
577 return;
578 }
579 }
580 }
581
582 if (!namedProxy) {
583 // Search for the branchname, determine what it contains, and wire the
584 // TBranchProxy representing it to us so we can access its data.
585 // A proxy for branch must not have been created before (i.e. check
586 // fProxies before calling this function!)
587
588 TString membername;
589
590 bool isTopLevel = branch->GetMother() == branch;
591 if (!isTopLevel) {
592 membername = strrchr(branch->GetName(), '.');
593 if (membername.IsNull()) {
594 membername = branch->GetName();
595 }
596 }
597 auto director = fTreeReader->fDirector;
598 // Determine if the branch is actually in a Friend TTree and if so which.
599 if (branch->GetTree() != fTreeReader->GetTree()->GetTree()) {
600 // It is in a friend, let's find the 'index' in the list of friend ...
601 int index = -1;
602 int current = 0;
603 TFriendElement *fe_found = nullptr;
604 for(auto fe : TRangeDynCast<TFriendElement>( fTreeReader->GetTree()->GetTree()->GetListOfFriends())) {
605 if (branch->GetTree() == fe->GetTree()) {
606 index = current;
607 fe_found = fe;
608 break;
609 }
610 ++current;
611 }
612 if (index == -1) {
613 Error(errPrefix, "The branch %s is contained in a Friend TTree that is not directly attached to the main.\n"
614 "This is not yet supported by TTreeReader.",
615 fBranchName.Data());
616 return;
617 }
618 const char *localBranchName = originalBranchName.c_str();
619 if (branch != branch->GetTree()->GetBranch(localBranchName)) {
620 // Try removing the name of the TTree.
621 auto len = strlen( branch->GetTree()->GetName());
622 if (strncmp(localBranchName, branch->GetTree()->GetName(), len) == 0
623 && localBranchName[len] == '.'
624 && branch != branch->GetTree()->GetBranch(localBranchName+len+1)) {
625 localBranchName = localBranchName + len + 1;
626 } else {
627 len = strlen(fe_found->GetName());
628 if (strncmp(localBranchName, fe_found->GetName(), len) == 0
629 && localBranchName[len] == '.'
630 && branch != branch->GetTree()->GetBranch(localBranchName+len+1)) {
631 localBranchName = localBranchName + len + 1;
632 }
633 }
634 }
635 TFriendProxy *feproxy = nullptr;
636 if ((size_t)index < fTreeReader->fFriendProxies.size()) {
637 feproxy = fTreeReader->fFriendProxies.at(index);
638 }
639 if (!feproxy) {
640 feproxy = new ROOT::Internal::TFriendProxy(director, fTreeReader->GetTree(), index);
641 fTreeReader->fFriendProxies.resize(index+1);
642 fTreeReader->fFriendProxies.at(index) = feproxy;
643 }
644 namedProxy = new TNamedBranchProxy(feproxy->GetDirector(), branch, originalBranchName.c_str(), branch->GetName(), membername);
645 } else {
646 namedProxy = new TNamedBranchProxy(director, branch, originalBranchName.c_str(), membername);
647 }
648 fTreeReader->AddProxy(namedProxy);
649 }
650
651 // Update named proxy's dictionary
652 if (!namedProxy->GetDict())
653 namedProxy->SetDict(fDict);
654
655 fProxy = namedProxy->GetProxy();
656 if (fProxy) {
657 fSetupStatus = kSetupMatch;
658 } else {
659 fSetupStatus = kSetupMismatch;
660 }
661}
662
663////////////////////////////////////////////////////////////////////////////////
664/// Retrieve the type of data stored by branch; put its dictionary into
665/// dict, return its type name. If no dictionary is available, at least
666/// its type name should be returned.
667
669 TDictionary* &dict,
670 TDictionary const *curDict)
671{
672 dict = 0;
673 if (branch->IsA() == TBranchElement::Class()) {
674 TBranchElement* brElement = (TBranchElement*)branch;
675
676 auto ResolveTypedef = [&]() -> void {
677 if (dict->IsA() != TDataType::Class())
678 return;
679 // Resolve the typedef.
680 dict = TDictionary::GetDictionary(((TDataType*)dict)->GetTypeName());
681 if (dict->IsA() != TDataType::Class()) {
682 // Might be a class.
683 if (dict != curDict) {
684 dict = TClass::GetClass(brElement->GetTypeName());
685 }
686 if (dict != curDict) {
687 dict = brElement->GetCurrentClass();
688 }
689 }
690 };
691
692 if (brElement->GetType() == TBranchElement::kSTLNode ||
693 brElement->GetType() == TBranchElement::kLeafNode ||
694 brElement->GetType() == TBranchElement::kObjectNode) {
695
696 TStreamerInfo *streamerInfo = brElement->GetInfo();
697 Int_t id = brElement->GetID();
698
699 if (id >= 0){
700 TStreamerElement *element = (TStreamerElement*)streamerInfo->GetElements()->At(id);
701 if (element->IsA() == TStreamerSTL::Class()){
702 TStreamerSTL *myStl = (TStreamerSTL*)element;
703 dict = myStl->GetClass();
704 return 0;
705 }
706 }
707
708 if (brElement->GetType() == 3 || brElement->GetType() == 4) {
709 dict = brElement->GetCurrentClass();
710 return brElement->GetTypeName();
711 }
712
713 if (brElement->GetTypeName())
714 dict = TDictionary::GetDictionary(brElement->GetTypeName());
715
716 if (dict)
718 else
719 dict = brElement->GetCurrentClass();
720
721 return brElement->GetTypeName();
722 } else if (brElement->GetType() == TBranchElement::kClonesNode) {
723 dict = TClonesArray::Class();
724 return "TClonesArray";
725 } else if (brElement->GetType() == 31
726 || brElement->GetType() == 41) {
727 // it's a member, extract from GetClass()'s streamer info
728 Error("TTreeReaderValueBase::GetBranchDataType()", "Must use TTreeReaderArray to access a member of an object that is stored in a collection.");
729 } else if (brElement->GetType() == -1 && brElement->GetTypeName()) {
730 dict = TDictionary::GetDictionary(brElement->GetTypeName());
732 return brElement->GetTypeName();
733 } else {
734 Error("TTreeReaderValueBase::GetBranchDataType()", "Unknown type and class combination: %i, %s", brElement->GetType(), brElement->GetClassName());
735 }
736 return 0;
737 } else if (branch->IsA() == TBranch::Class()
738 || branch->IsA() == TBranchObject::Class()
739 || branch->IsA() == TBranchSTL::Class()) {
740 if (branch->GetTree()->IsA() == TNtuple::Class()){
742 return dict->GetName();
743 }
744 const char* dataTypeName = branch->GetClassName();
745 if ((!dataTypeName || !dataTypeName[0])
746 && branch->IsA() == TBranch::Class()) {
747 TLeaf *myLeaf = branch->GetLeaf(branch->GetName());
748 if (myLeaf){
749 TDictionary *myDataType = TDictionary::GetDictionary(myLeaf->GetTypeName());
750 if (myDataType && myDataType->IsA() == TDataType::Class()){
751 if (myLeaf->GetLeafCount() != nullptr || myLeaf->GetLenStatic() > 1) {
752 Error("TTreeReaderValueBase::GetBranchDataType()", "Must use TTreeReaderArray to read branch %s: it contains an array or a collection.", branch->GetName());
753 return 0;
754 }
755 dict = TDataType::GetDataType((EDataType)((TDataType*)myDataType)->GetType());
756 return myLeaf->GetTypeName();
757 }
758 }
759
760 // leaflist. Can't represent.
761 Error("TTreeReaderValueBase::GetBranchDataType()", "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());
762 TIter iLeaves(branch->GetListOfLeaves());
763 TLeaf* leaf = 0;
764 while ((leaf = (TLeaf*) iLeaves())) {
765 Error("TTreeReaderValueBase::GetBranchDataType()", " %s.%s", branch->GetName(), leaf->GetName());
766 }
767 return 0;
768 }
769 if (dataTypeName) dict = TDictionary::GetDictionary(dataTypeName);
770 return dataTypeName;
771 } else if (branch->IsA() == TBranchClones::Class()) {
772 dict = TClonesArray::Class();
773 return "TClonesArray";
774 } else if (branch->IsA() == TBranchRef::Class()) {
775 // Can't represent.
776 Error("TTreeReaderValueBase::GetBranchDataType()", "The branch %s is a TBranchRef and cannot be represented as a C++ type.", branch->GetName());
777 return 0;
778 } else {
779 Error("TTreeReaderValueBase::GetBranchDataType()", "The branch %s is of type %s - something that is not handled yet.", branch->GetName(), branch->IsA()->GetName());
780 return 0;
781 }
782
783 return 0;
784}
void Class()
Definition: Class.C:29
unsigned char Byte_t
Definition: RtypesCore.h:62
long long Long64_t
Definition: RtypesCore.h:71
#define ClassImp(name)
Definition: Rtypes.h:361
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
#define R__ASSERT(e)
Definition: TError.h:96
void Error(const char *location, const char *msgfmt,...)
#define gROOT
Definition: TROOT.h:406
@ kDefault
Definition: TSystem.h:228
#define free
Definition: civetweb.c:1539
Base class for all the proxy object.
Definition: TBranchProxy.h:68
TBranchProxyDirector * GetDirector()
Definition: TFriendProxy.h:31
void SetDict(TDictionary *dict)
const Detail::TBranchProxy * GetProxy() const
Base class of TTreeReaderValue.
void RegisterWithTreeReader()
Register with tree reader.
void NotifyNewTree(TTree *newTree)
The TTreeReader has switched to a new TTree. Update the leaf.
void * GetAddress()
Returns the memory address of the object being read.
static std::string GetElementTypeName(const std::type_info &ti)
Stringify the template argument.
TTreeReaderValueBase(TTreeReader *reader, const char *branchname, TDictionary *dict)
Construct a tree value reader and register it with the reader object.
ROOT::Internal::TTreeReaderValueBase::EReadStatus ProxyReadTemplate()
Try to read the value from the TBranchProxy, returns the status of the read.
TTreeReaderValueBase & operator=(const TTreeReaderValueBase &)
Copy-assign.
virtual ~TTreeReaderValueBase()
Unregister from tree reader, cleanup.
virtual void CreateProxy()
Create the proxy object for our branch.
std::vector< Long64_t > fStaticClassOffsets
TBranch * SearchBranchWithCompositeName(TLeaf *&myleaf, TDictionary *&branchActualType, std::string &err)
Search a branch the name of which contains a ".".
static const char * GetBranchDataType(TBranch *branch, TDictionary *&dict, TDictionary const *curDict)
Retrieve the type of data stored by branch; put its dictionary into dict, return its type name.
A Branch for the case of an object.
Int_t GetID() const
TStreamerInfo * GetInfo() const
Get streamer info for the branch class.
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, 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.
Int_t GetType() const
A TTree is a list of TBranches.
Definition: TBranch.h:91
virtual TLeaf * GetLeaf(const char *name) const
Return pointer to the 1st Leaf named name in thisBranch.
Definition: TBranch.cxx:1919
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any.
Definition: TBranch.cxx:1312
TTree * GetTree() const
Definition: TBranch.h:250
TObjArray * GetListOfLeaves()
Definition: TBranch.h:245
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition: TBranch.cxx:1991
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition: TClass.cxx:4562
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4837
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2948
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
Int_t GetType() const
Definition: TDataType.h:68
static TDataType * GetDataType(EDataType type)
Given a EDataType type, get the TDataType* that represents it.
Definition: TDataType.cxx:443
This class defines an abstract interface that must be implemented by all classes that contain diction...
Definition: TDictionary.h:166
static TDictionary * GetDictionary(const char *name)
Definition: TDictionary.cxx:84
A TFriendElement TF describes a TTree object TF in a file.
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:49
virtual const char * GetTypeName() const
Definition: TLeaf.h:130
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:112
virtual Int_t GetLenStatic() const
Return the fixed length of this leaf.
Definition: TLeaf.h:123
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:523
TObject * At(Int_t idx) const
Definition: TObjArray.h:166
TRangeDynCast is an adaptater class that allows the typed iteration through a TCollection.
Definition: TCollection.h:411
Regular expression class.
Definition: TRegexp.h:31
Int_t GetType() const
virtual Bool_t IsaPointer() const
const char * GetTypeName() const
TClass * GetClass() const
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:46
TObjArray * GetElements() const
Basic string class.
Definition: TString.h:131
Ssiz_t Length() const
Definition: TString.h:405
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1106
const char * Data() const
Definition: TString.h:364
@ kBoth
Definition: TString.h:262
Bool_t IsNull() const
Definition: TString.h:402
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:619
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition: TTreeReader.h:43
A TTree represents a columnar dataset.
Definition: TTree.h:78
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition: TTree.cxx:5209
virtual TTree * GetTree() const
Definition: TTree.h:511
Abstract Interface class describing Streamer information for one class.
virtual TObjArray * GetElements() const =0
virtual Int_t GetElementOffset(Int_t id) const =0
Type GetType(const std::string &Name)
Definition: Systematics.cxx:34
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.