Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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
33#include <optional>
34#include <vector>
35
36// clang-format off
37/**
38 * \class TTreeReaderValue
39 * \ingroup treeplayer
40 * \brief An interface for reading values stored in ROOT columnar datasets
41 *
42 * The TTreeReaderValue is a type-safe tool to be used in association with a TTreeReader
43 * to access the values stored in TTree, TNtuple and TChain datasets.
44 * TTreeReaderValue can be also used to access collections such as `std::vector`s or TClonesArray
45 * stored in columnar datasets but it is recommended to use TTreeReaderArray instead as it offers
46 * several advantages.
47 *
48 * See the documentation of TTreeReader for more details and examples.
49*/
50// clang-format on
51
53
54////////////////////////////////////////////////////////////////////////////////
55/// Construct a tree value reader and register it with the reader object.
56
58 TDictionary *dict /*= 0*/, bool opaqueRead)
59 : fHaveLeaf(false),
60 fHaveStaticClassOffsets(false),
61 fReadStatus(kReadNothingYet),
62 fBranchName(branchname),
63 fTreeReader(reader),
64 fDict(dict),
65 fOpaqueRead(opaqueRead)
66{
68}
69
70////////////////////////////////////////////////////////////////////////////////
71/// Copy-construct.
72
74 : fHaveLeaf(rhs.fHaveLeaf),
75 fHaveStaticClassOffsets(rhs.fHaveStaticClassOffsets),
76 fReadStatus(rhs.fReadStatus),
77 fSetupStatus(rhs.fSetupStatus),
78 fBranchName(rhs.fBranchName),
79 fLeafName(rhs.fLeafName),
80 fTreeReader(rhs.fTreeReader),
81 fDict(rhs.fDict),
82 fProxy(rhs.fProxy),
83 fLeaf(rhs.fLeaf),
84 fStaticClassOffsets(rhs.fStaticClassOffsets)
85{
87}
88
89////////////////////////////////////////////////////////////////////////////////
90/// Copy-assign.
91
93{
94 if (&rhs != this) {
95 fHaveLeaf = rhs.fHaveLeaf;
96 fHaveStaticClassOffsets = rhs.fHaveStaticClassOffsets;
97 fBranchName = rhs.fBranchName;
98 fLeafName = rhs.fLeafName;
99 if (fTreeReader != rhs.fTreeReader) {
100 if (fTreeReader)
101 fTreeReader->DeregisterValueReader(this);
102 fTreeReader = rhs.fTreeReader;
103 RegisterWithTreeReader();
104 }
105 fDict = rhs.fDict;
106 fProxy = rhs.fProxy;
107 fLeaf = rhs.fLeaf;
108 fSetupStatus = rhs.fSetupStatus;
109 fReadStatus = rhs.fReadStatus;
110 fStaticClassOffsets = rhs.fStaticClassOffsets;
111 }
112 return *this;
113}
114
115////////////////////////////////////////////////////////////////////////////////
116/// Unregister from tree reader, cleanup.
117
119{
120 if (fTreeReader)
121 fTreeReader->DeregisterValueReader(this);
122 R__ASSERT((fLeafName.Length() == 0) == !fHaveLeaf && "leafness disagreement");
123 R__ASSERT(fStaticClassOffsets.empty() == !fHaveStaticClassOffsets && "static class offset disagreement");
124}
125
126////////////////////////////////////////////////////////////////////////////////
127/// Register with tree reader.
128
130{
131 if (fTreeReader) {
132 if (!fTreeReader->RegisterValueReader(this)) {
133 fTreeReader = nullptr;
134 }
135 }
136}
137
138////////////////////////////////////////////////////////////////////////////////
139/// Try to read the value from the TBranchProxy, returns
140/// the status of the read.
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
154{
155 if (!fProxy)
156 return kReadNothingYet;
157 if (fProxy->IsInitialized() || fProxy->Setup()) {
158
161
162 EReadType readtype = EReadType::kNoDirector;
163 if (fProxy)
164 readtype = fProxy->GetReadType();
165
166 switch (readtype) {
167 case EReadType::kNoDirector:
168 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoDirector>;
169 break;
170 case EReadType::kReadParentNoCollection:
171 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentNoCollection>;
172 break;
173 case EReadType::kReadParentCollectionNoPointer:
174 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentCollectionNoPointer>;
175 break;
176 case EReadType::kReadParentCollectionPointer:
177 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentCollectionPointer>;
178 break;
179 case EReadType::kReadNoParentNoBranchCountCollectionPointer:
180 fProxyReadFunc =
181 &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountCollectionPointer>;
182 break;
183 case EReadType::kReadNoParentNoBranchCountCollectionNoPointer:
184 fProxyReadFunc =
185 &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountCollectionNoPointer>;
186 break;
187 case EReadType::kReadNoParentNoBranchCountNoCollection:
188 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountNoCollection>;
189 break;
190 case EReadType::kReadNoParentBranchCountCollectionPointer:
191 fProxyReadFunc =
192 &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountCollectionPointer>;
193 break;
194 case EReadType::kReadNoParentBranchCountCollectionNoPointer:
195 fProxyReadFunc =
196 &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountCollectionNoPointer>;
197 break;
198 case EReadType::kReadNoParentBranchCountNoCollection:
199 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountNoCollection>;
200 break;
201 case EReadType::kDefault:
202 // intentional fall through.
203 default: fProxyReadFunc = &TTreeReaderValueBase::ProxyReadDefaultImpl;
204 }
205 return (this->*fProxyReadFunc)();
206 }
207
208 // If somehow the Setup fails call the original Read to
209 // have the proper error handling (message only if the Setup fails
210 // and the current proxy entry is different than the TTree's current entry)
211 if (fProxy->Read()) {
212 fReadStatus = kReadSuccess;
213 } else {
214 fReadStatus = kReadError;
215 }
216 return fReadStatus;
217}
218
219////////////////////////////////////////////////////////////////////////////////
220/// Stringify the template argument.
222{
223 int err;
224 char *buf = TClassEdit::DemangleTypeIdName(ti, err);
225 std::string ret = buf;
226 free(buf);
227 return ret;
228}
229
230////////////////////////////////////////////////////////////////////////////////
231/// The TTreeReader has switched to a new TTree. Update the leaf.
232
234{
235 // Since the TTree structure might have change, let's make sure we
236 // use the right reading function.
238
239 if (!fHaveLeaf || !newTree) {
240 fLeaf = nullptr;
241 return;
242 }
243
244 TBranch *myBranch = newTree->GetBranch(fBranchName);
245
246 if (!myBranch) {
247 fReadStatus = kReadError;
248 Error("TTreeReaderValueBase::GetLeaf()", "Unable to get the branch from the tree");
249 return;
250 }
251
252 fLeaf = myBranch->GetLeaf(fLeafName);
253 if (!fLeaf) {
254 Error("TTreeReaderValueBase::GetLeaf()", "Failed to get the leaf from the branch");
255 }
256}
257
258////////////////////////////////////////////////////////////////////////////////
259/// Returns the memory address of the object being read.
260
262{
263
264 // If an indexed friend did not match the current entry and if this reader
265 // is associated with that friend (i.e. its active read entry is -1), avoid
266 // reading altogether
267 if (fTreeReader->GetEntryStatus() == TTreeReader::kIndexedFriendNoMatch && fProxy &&
268 fProxy->fDirector->GetReadEntry() == -1)
269 return nullptr;
270
271 if (ProxyRead() != kReadSuccess)
272 return nullptr;
273
274 if (fHaveLeaf) {
275 if (GetLeaf()) {
276 return fLeaf->GetValuePointer();
277 } else {
278 fReadStatus = kReadError;
279 Error("TTreeReaderValueBase::GetAddress()", "Unable to get the leaf");
280 return nullptr;
281 }
282 }
283 if (fHaveStaticClassOffsets) { // Follow all the pointers
284 Byte_t *address = (Byte_t *)fProxy->GetWhere();
285
286 for (unsigned int i = 0; i < fStaticClassOffsets.size() - 1; ++i) {
287 address = *(Byte_t **)(address + fStaticClassOffsets[i]);
288 }
289
290 return address + fStaticClassOffsets.back();
291 }
292 return (Byte_t *)fProxy->GetWhere();
293}
294
295////////////////////////////////////////////////////////////////////////////////
296/// \brief Search a branch the name of which contains a "."
297/// \param[out] myLeaf The leaf identified by the name if found (can be untouched).
298/// \param[out] branchActualType Dictionary associated to the type of the leaf (can be untouched).
299/// \param[out] errMsg The error message (can be untouched).
300/// \return The address of the branch if found, nullptr otherwise
301/// This method allows to efficiently search for branches which have names which
302/// contain "dots", for example "w.v.a" or "v.a".
303/// Therefore, it allows to support names such as v.a where the branch was
304/// created with this syntax:
305/// ```{.cpp}
306/// myTree->Branch("v", &v, "a/I:b:/I")
307/// ```
308/// The method has some side effects, namely it can modify fSetupStatus, fProxy
309/// and fStaticClassOffsets/fHaveStaticClassOffsets.
312 std::string &errMsg)
313{
314 TRegexp leafNameExpression("\.[a-zA-Z0-9_]+$");
315 TString leafName(fBranchName(leafNameExpression));
316 TString branchName = fBranchName(0, fBranchName.Length() - leafName.Length());
317 auto branch = fTreeReader->GetTree()->GetBranch(branchName);
318 if (!branch) {
319 std::vector<TString> nameStack;
320 nameStack.push_back(TString()); // Trust me
321 nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
323 branchName = branchName(0, branchName.Length() - leafName.Length());
324
325 branch = fTreeReader->GetTree()->GetBranch(branchName);
326 if (!branch)
327 branch = fTreeReader->GetTree()->GetBranch(branchName + ".");
328 if (leafName.Length())
329 nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
330
331 while (!branch && branchName.Contains(".")) {
333 branchName = branchName(0, branchName.Length() - leafName.Length());
334 branch = fTreeReader->GetTree()->GetBranch(branchName);
335 if (!branch)
336 branch = fTreeReader->GetTree()->GetBranch(branchName + ".");
337 nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
338 }
339
340 if (branch && branch->IsA() == TBranchElement::Class()) {
342
344 nameStack.pop_back();
345
346 bool found = true;
347
348 TDataType *finalDataType = nullptr;
349
350 std::vector<Long64_t> offsets;
351 Long64_t offset = 0;
352 TClass *elementClass = nullptr;
353
354 TObjArray *myObjArray = myBranchElement->GetInfo()->GetElements();
356
357 while (!nameStack.empty() && found) {
358 found = false;
359
360 for (int i = 0; i < myObjArray->GetEntries(); ++i) {
361
363
364 if (!strcmp(tempStreamerElement->GetName(), traversingBranch.Data())) {
365 offset += myInfo->GetElementOffset(i);
366
368 nameStack.pop_back();
369
370 elementClass = tempStreamerElement->GetClass();
371 if (elementClass) {
372 myInfo = elementClass->GetStreamerInfo(0);
373 myObjArray = myInfo->GetElements();
374 // FIXME: this is odd, why is 'i' not also reset????
375 } else {
377 if (!finalDataType) {
379 if (seType && seType->IsA() == TDataType::Class()) {
381 }
382 }
383 }
384
385 if (tempStreamerElement->IsaPointer()) {
386 offsets.push_back(offset);
387 offset = 0;
388 }
389
390 found = true;
391 break;
392 }
393 }
394 }
395
396 offsets.push_back(offset);
397
398 if (found) {
399 fStaticClassOffsets = offsets;
400 fHaveStaticClassOffsets = true;
401
402 if (fDict != finalDataType && fDict != elementClass) {
403 errMsg = "Wrong data type ";
404 errMsg += finalDataType ? finalDataType->GetName() : elementClass ? elementClass->GetName() : "UNKNOWN";
405 fSetupStatus = kSetupMismatch;
406 fProxy = nullptr;
407 return nullptr;
408 }
409 }
410 }
411
412 if (!fHaveStaticClassOffsets) {
413 errMsg = "The tree does not have a branch called ";
414 errMsg += fBranchName;
415 errMsg += ". You could check with TTree::Print() for available branches.";
416 fSetupStatus = kSetupMissingBranch;
417 fProxy = nullptr;
418 return nullptr;
419 }
420 } else {
421 myLeaf = branch->GetLeaf(TString(leafName(1, leafName.Length())));
422 if (!myLeaf) {
423 errMsg = "The tree does not have a branch, nor a sub-branch called ";
424 errMsg += fBranchName;
425 errMsg += ". You could check with TTree::Print() for available branches.";
426 fSetupStatus = kSetupMissingBranch;
427 fProxy = nullptr;
428 return nullptr;
429 } else {
430 TDataType *tempDict = gROOT->GetType(myLeaf->GetTypeName());
431 if (tempDict && fDict->IsA() == TDataType::Class() && tempDict->GetType() == ((TDataType *)fDict)->GetType()) {
432 // fLeafOffset = myLeaf->GetOffset() / 4;
433 branchActualType = fDict;
434 fLeaf = myLeaf;
435 fBranchName = branchName;
436 fLeafName = leafName(1, leafName.Length());
437 fHaveLeaf = fLeafName.Length() > 0;
438 fSetupStatus = kSetupMatchLeaf;
439 } else {
440 errMsg = "Leaf of type ";
441 errMsg += myLeaf->GetTypeName();
442 errMsg += " cannot be read by TTreeReaderValue<";
443 errMsg += fDict->GetName();
444 errMsg += ">.";
445 fSetupStatus = kSetupMismatch;
446 return nullptr;
447 }
448 }
449 }
450
451 return branch;
452}
453
454////////////////////////////////////////////////////////////////////////////////
455/// Create the proxy object for our branch.
456
458{
459
460 constexpr const char *errPrefix = "TTreeReaderValueBase::CreateProxy()";
461
462 if (fProxy) {
463 return;
464 }
465
466 fSetupStatus = kSetupInternalError; // Fallback; set to something concrete below.
467 if (!fTreeReader) {
468 Error(errPrefix, "TTreeReader object not set / available for branch %s!", fBranchName.Data());
469 fSetupStatus = kSetupTreeDestructed;
470 return;
471 }
472
473 auto branchFromFullName = fTreeReader->GetTree()->GetBranch(fBranchName);
474 if (branchFromFullName == nullptr) // use the slower but more thorough FindBranch as fallback
475 branchFromFullName = fTreeReader->GetTree()->FindBranch(fBranchName);
476
477 if (!fDict) {
478 if (!fOpaqueRead) {
479 const char *brDataType = "{UNDETERMINED}";
480 if (branchFromFullName) {
481 TDictionary *brDictUnused = nullptr;
482 brDataType = GetBranchDataType(branchFromFullName, brDictUnused, fDict);
483 }
485 "The template argument type T of %s accessing branch %s (which contains data of type %s) is not known "
486 "to ROOT. You will need to create a dictionary for it.",
487 GetDerivedTypeName(), fBranchName.Data(), brDataType);
488 fSetupStatus = kSetupMissingDictionary;
489 return;
490 } else {
491 // We do not care about the branch data type in this case, so we can
492 // generate the dictionary from the branch directly
493 if (branchFromFullName) {
494 GetBranchDataType(branchFromFullName, fDict, nullptr);
495 }
496 }
497 }
498
499 // Search for the branchname, determine what it contains, and wire the
500 // TBranchProxy representing it to us so we can access its data.
501
502 TNamedBranchProxy *namedProxy = fTreeReader->FindProxy(fBranchName);
503 if (namedProxy && namedProxy->GetDict() == fDict) {
504 fProxy = namedProxy->GetProxy();
505 // But go on: we need to set fLeaf etc!
506 }
507
508 const std::string originalBranchName = fBranchName.Data();
509
510 TLeaf *myLeaf = nullptr;
511 TDictionary *branchActualType = nullptr;
512 std::string errMsg;
513
514 TBranch *branch = nullptr;
515 // If the branch name contains at least a dot, we analyse it in detail and
516 // we give priority to the branch identified over the one which is found
517 // with the TTree::GetBranch method. This allows to correctly pick the desired
518 // branch in cases where a TTree has two branches, one called for example
519 // "w.v.a" and another one called "v.a".
520 // This behaviour is described in ROOT-9312.
521 if (fBranchName.Contains(".")) {
522 branch = SearchBranchWithCompositeName(myLeaf, branchActualType, errMsg);
523 // In rare cases where leaves contain the name of the branch as part of their
524 // name and a dot in the branch name (such as: branch "b." and leaf "b.a")
525 // the previous method may return the branch name ("b.") rather than the
526 // leaf name ("b.a") as we expect.
527 // For these cases, we do not have to give priority to the previously
528 // identified branch since we are in a different situation.
529 // This behaviour is described in ROOT-9757.
532 fStaticClassOffsets = {};
533 fHaveStaticClassOffsets = false;
534 }
535 }
536
537 // Check whether the user wants to suppress errors for this specific branch
538 // if it is missing. We have to use this information differently in two
539 // different situations:
540 // - If the branch was present in the first tree of the chain, but missing
541 // when switching to a new tree
542 // - If the branch is missing from the first tree already. In this case we
543 // also need to postpone the creation of the branch proxy until at least
544 // one tree in the chain has that branch
545 const auto &suppressErrorsForMissingBranches = fTreeReader->fSuppressErrorsForMissingBranches;
546 const bool suppressErrorsForThisBranch =
548
549 if (!branch) {
550 // We had an error, the branch name had no "." or we simply did not find anything.
551 // We check if we had a branch found with the full name with a dot in it.
553 if (!branch) {
554 // Also that one was empty. We need to error out, but only if the user
555 // did not explicitly request to avoid errors about missing branches
556 fSetupStatus = kSetupMissingBranch;
557 fProxy = nullptr;
559 return;
560
561 // Now we error out, first checking if we did not get a more specific
562 // error message from SearchBranchWithCompositeName. If not, we go with
563 // a generic message.
564 if (errMsg.empty()) {
565 errMsg = "The tree does not have a branch called ";
566 errMsg += fBranchName.Data();
567 errMsg += ". You could check with TTree::Print() for available branches.";
568 }
569#if !defined(_MSC_VER)
570#pragma GCC diagnostic push
571#pragma GCC diagnostic ignored "-Wformat-security"
572#endif
573 Error(errPrefix, errMsg.c_str());
574#if !defined(_MSC_VER)
575#pragma GCC diagnostic pop
576#endif
577 return;
578 }
579 // The branch found with the simplest search approach was successful.
580 // We reset the state, we continue
581 fSetupStatus = kSetupInternalError;
582 fStaticClassOffsets = {};
583 fHaveStaticClassOffsets = false;
584 }
585
586 if (!myLeaf && !fHaveStaticClassOffsets) {
587 // The following two lines cannot be swapped. The GetBranchDataType can
588 // change the value of branchActualType
589 const char *branchActualTypeName = GetBranchDataType(branch, branchActualType, fDict);
590 if (!branchActualType) {
591 Error(errPrefix, "The branch %s contains data of type %s, which does not have a dictionary.",
592 fBranchName.Data(), branchActualTypeName ? branchActualTypeName : "{UNDETERMINED TYPE}");
593 fProxy = nullptr;
594 return;
595 }
596
597 // Check if the dictionaries are TClass instances and if there is inheritance
598 // because in this case, we can read the values.
599 auto dictAsClass = dynamic_cast<TClass *>(fDict);
600 auto branchActualTypeAsClass = dynamic_cast<TClass *>(branchActualType);
602 bool typeinfoMatch = dictAsClass && dictAsClass->GetTypeInfo() &&
603 dictAsClass->GetTypeInfo() == branchActualTypeAsClass->GetTypeInfo();
604
605 if (!inheritance && !typeinfoMatch && fDict != branchActualType) {
606 TDataType *dictdt = dynamic_cast<TDataType *>(fDict);
607 TDataType *actualdt = dynamic_cast<TDataType *>(branchActualType);
608 TEnum *dictenum = dynamic_cast<TEnum *>(fDict);
609 TEnum *actualenum = dynamic_cast<TEnum *>(branchActualType);
610 bool complainAboutMismatch = true;
611 if (dictdt && actualdt) {
612 if (dictdt->GetType() > 0 && dictdt->GetType() == actualdt->GetType()) {
613 // Same numerical type but different TDataType, likely Long64_t
614 complainAboutMismatch = false;
615 } else if ((actualdt->GetType() == kDouble32_t && dictdt->GetType() == kDouble_t) ||
616 (actualdt->GetType() == kFloat16_t && dictdt->GetType() == kFloat_t)) {
617 // Double32_t and Float16_t never "decay" to their underlying type;
618 // we need to identify them manually here (ROOT-8731).
619 complainAboutMismatch = false;
620 }
621 } else if ((dictdt || dictenum) && (actualdt || actualenum)) {
622 if ((dictdt && dictdt->GetType() == kInt_t && actualenum) ||
623 (actualdt && actualdt->GetType() == kInt_t && dictenum))
624 complainAboutMismatch = false;
625 if ((dictdt && actualenum && dictdt->GetType() == actualenum->GetUnderlyingType()) ||
626 (actualdt && dictenum && actualdt->GetType() == dictenum->GetUnderlyingType()))
627 complainAboutMismatch = false;
628 }
630 Error(errPrefix, "The branch %s contains data of type %s. It cannot be accessed by a TTreeReaderValue<%s>",
631 fBranchName.Data(), branchActualType->GetName(), fDict->GetName());
632 return;
633 }
634 }
635 }
636
637 if (!namedProxy) {
638 // Search for the branchname, determine what it contains, and wire the
639 // TBranchProxy representing it to us so we can access its data.
640 // A proxy for branch must not have been created before (i.e. check
641 // fProxies before calling this function!)
642
644
645 bool isTopLevel = branch->GetMother() == branch;
646 if (!isTopLevel) {
647 membername = strrchr(branch->GetName(), '.');
648 if (membername.IsNull()) {
649 membername = branch->GetName();
650 }
651 }
652 auto director = fTreeReader->fDirector.get();
653 // Determine if the branch is actually in a Friend TTree and if so which.
654 if (branch->GetTree() != fTreeReader->GetTree()->GetTree()) {
655 // It is in a friend, let's find the 'index' in the list of friend ...
656 std::optional<std::size_t> index;
657 std::size_t current{};
658 auto &&friends = fTreeReader->GetTree()->GetTree()->GetListOfFriends();
660 if (branch->GetTree() == fe->GetTree()) {
661 index = current;
662 break;
663 }
664 ++current;
665 }
666 if (!index.has_value()) {
668 "The branch %s is contained in a Friend TTree that is not directly attached to the main.\n"
669 "This is not yet supported by TTreeReader.",
670 fBranchName.Data());
671 return;
672 }
673 auto &&friendProxy = fTreeReader->AddFriendProxy(index.value());
674 fTreeReader->AddProxy(std::make_unique<TNamedBranchProxy>(friendProxy.GetDirector(), branch,
675 originalBranchName.c_str(), branch->GetName(),
677 } else {
678 fTreeReader->AddProxy(std::make_unique<TNamedBranchProxy>(director, branch, originalBranchName.c_str(),
680 }
681 namedProxy = fTreeReader->FindProxy(originalBranchName.c_str());
682 }
683
684 // Update named proxy's dictionary
685 if (!namedProxy->GetDict())
686 namedProxy->SetDict(fDict);
687
688 fProxy = namedProxy->GetProxy();
689 if (fProxy) {
690 fSetupStatus = kSetupMatch;
691 } else {
692 fSetupStatus = kSetupMismatch;
693 }
694}
695
696////////////////////////////////////////////////////////////////////////////////
697/// Retrieve the type of data stored by branch; put its dictionary into
698/// dict, return its type name. If no dictionary is available, at least
699/// its type name should be returned.
700
701const char *
703{
704 dict = nullptr;
705 if (branch->IsA() == TBranchElement::Class()) {
707
708 auto ResolveTypedef = [&]() -> void {
709 if (dict->IsA() != TDataType::Class())
710 return;
711 // Resolve the typedef.
712 dict = TDictionary::GetDictionary(((TDataType *)dict)->GetTypeName());
713 if (dict->IsA() != TDataType::Class()) {
714 // Might be a class.
715 if (dict != curDict) {
716 dict = TClass::GetClass(brElement->GetTypeName());
717 }
718 if (dict != curDict) {
719 dict = brElement->GetCurrentClass();
720 }
721 }
722 };
723
724 if (brElement->GetType() == TBranchElement::kSTLNode || brElement->GetType() == TBranchElement::kLeafNode ||
726
728 Int_t id = brElement->GetID();
729
730 if (id >= 0) {
731 TStreamerElement *element = (TStreamerElement *)streamerInfo->GetElements()->At(id);
732 if (element->IsA() == TStreamerSTL::Class()) {
734 dict = myStl->GetClass();
735 return nullptr;
736 }
737 }
738
739 if (brElement->GetType() == 3 || brElement->GetType() == 4) {
740 dict = brElement->GetCurrentClass();
741 return brElement->GetTypeName();
742 }
743
744 if (brElement->GetTypeName())
745 dict = TDictionary::GetDictionary(brElement->GetTypeName());
746
747 if (dict)
748 ResolveTypedef();
749 else
750 dict = brElement->GetCurrentClass();
751
752 return brElement->GetTypeName();
753 } else if (brElement->GetType() == TBranchElement::kClonesNode) {
754 dict = TClonesArray::Class();
755 return "TClonesArray";
756 } else if (brElement->GetType() == 31 || brElement->GetType() == 41) {
757 // it's a member, extract from GetClass()'s streamer info
758 Error("TTreeReaderValueBase::GetBranchDataType()",
759 "Must use TTreeReaderArray to access a member of an object that is stored in a collection.");
760 } else if (brElement->GetType() == -1 && brElement->GetTypeName()) {
761 dict = TDictionary::GetDictionary(brElement->GetTypeName());
762 ResolveTypedef();
763 return brElement->GetTypeName();
764 } else {
765 Error("TTreeReaderValueBase::GetBranchDataType()", "Unknown type and class combination: %i, %s",
766 brElement->GetType(), brElement->GetClassName());
767 }
768 return nullptr;
769 } else if (branch->IsA() == TBranch::Class() || branch->IsA() == TBranchObject::Class() ||
770 branch->IsA() == TBranchSTL::Class()) {
771 if (branch->GetTree()->IsA() == TNtuple::Class()) {
773 return dict->GetName();
774 }
775 const char *dataTypeName = branch->GetClassName();
776 if ((!dataTypeName || !dataTypeName[0]) && branch->IsA() == TBranch::Class()) {
777 TLeaf *myLeaf = branch->GetLeaf(branch->GetName());
778 if (!myLeaf) {
779 myLeaf = branch->FindLeaf(branch->GetName());
780 }
781 if (!myLeaf && branch->GetListOfLeaves()->GetEntries() == 1) {
782 myLeaf = static_cast<TLeaf *>(branch->GetListOfLeaves()->UncheckedAt(0));
783 }
784 if (myLeaf) {
786 if (myDataType && myDataType->IsA() == TDataType::Class()) {
787 if (myLeaf->GetLeafCount() != nullptr || myLeaf->GetLenStatic() > 1) {
788 Error("TTreeReaderValueBase::GetBranchDataType()",
789 "Must use TTreeReaderArray to read branch %s: it contains an array or a collection.",
790 branch->GetName());
791 return nullptr;
792 }
793 dict = TDataType::GetDataType((EDataType)((TDataType *)myDataType)->GetType());
794 return myLeaf->GetTypeName();
795 }
796 }
797
798 // leaflist. Can't represent.
799 Error("TTreeReaderValueBase::GetBranchDataType()",
800 "The branch %s was created using a leaf list and cannot be represented as a C++ type. Please access one "
801 "of its siblings using a TTreeReaderArray:",
802 branch->GetName());
803 TIter iLeaves(branch->GetListOfLeaves());
804 TLeaf *leaf = nullptr;
805 while ((leaf = (TLeaf *)iLeaves())) {
806 Error("TTreeReaderValueBase::GetBranchDataType()", " %s.%s", branch->GetName(), leaf->GetName());
807 }
808 return nullptr;
809 }
810 if (dataTypeName)
812 return dataTypeName;
813 } else if (branch->IsA() == TBranchClones::Class()) {
814 dict = TClonesArray::Class();
815 return "TClonesArray";
816 } else if (branch->IsA() == TBranchRef::Class()) {
817 // Can't represent.
818 Error("TTreeReaderValueBase::GetBranchDataType()",
819 "The branch %s is a TBranchRef and cannot be represented as a C++ type.", branch->GetName());
820 return nullptr;
821 } else {
822 Error("TTreeReaderValueBase::GetBranchDataType()",
823 "The branch %s is of type %s - something that is not handled yet.", branch->GetName(),
824 branch->IsA()->GetName());
825 return nullptr;
826 }
827
828 return nullptr;
829}
830
832{
833 // Print the error only if the branch name does not appear in the list of
834 // missing proxies that the user explicitly requested not to error about
835 if (!fTreeReader || fTreeReader->fMissingProxies.count(fBranchName.Data()) == 0)
836 Error("TTreeReaderValue::Get()",
837 "Value reader for branch %s not properly initialized, did you call "
838 "TTreeReader::Set(Next)Entry() or TTreeReader::Next()?",
839 fBranchName.Data());
840}
841
842namespace cling {
843// The value printers of TTreeReaderValue and TTreeReaderArray rely on the
844// one of TTreeReaderValueBase, from which they both inherit.
845// This is why we use RTTI inside the function, avoiding to duplicate code.
846// The performance penalty is irrelevant because we are already printing
847// the objects in an interactive environment.
848std::string printValue(ROOT::Internal::TTreeReaderValueBase *val)
849{
850 auto cl = TClass::GetClass(typeid(*val));
851 std::string str = cl->GetName();
852 str += " instance associated to column ";
853 str += val->GetBranchName();
854 return str;
855}
856} // namespace cling
long long Long64_t
Definition RtypesCore.h:69
#define ClassImp(name)
Definition Rtypes.h:374
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
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
#define gROOT
Definition TROOT.h:406
#define free
Definition civetweb.c:1539
Base class for all the proxy object.
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.
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.
TTreeReaderValueBase(TTreeReader *reader, const char *branchname, TDictionary *dict, bool opaqueRead=false)
Construct a tree value reader and register it with the reader object.
virtual void CreateProxy()
Create the proxy object for our branch.
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()
static TClass * Class()
static TClass * Class()
static TClass * Class()
A TTree is a list of TBranches.
Definition TBranch.h:93
static TClass * Class()
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
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:3073
static TClass * Class()
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
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 TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
static TClass * Class()
An array of TObjects.
Definition TObjArray.h:31
Regular expression class.
Definition TRegexp.h:31
Describe one element (data member) to be Streamed.
Describes a persistent version of a class.
static TClass * Class()
Basic string class.
Definition TString.h:139
@ kBoth
Definition TString.h:276
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition TTreeReader.h:46
@ kIndexedFriendNoMatch
A friend with TTreeIndex doesn't have an entry for this index.
A TTree represents a columnar dataset.
Definition TTree.h:79
Abstract Interface class describing Streamer information for one class.
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.