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