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