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
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 =
549
550 if (!branch) {
551 // We had an error, the branch name had no "." or we simply did not find anything.
552 // We check if we had a branch found with the full name with a dot in it.
554 if (!branch) {
555 // Also that one was empty. We need to error out, but only if the user
556 // did not explicitly request to avoid errors about missing branches
557 fSetupStatus = kSetupMissingBranch;
558 fProxy = nullptr;
560 return;
561
562 // Now we error out, first checking if we did not get a more specific
563 // error message from SearchBranchWithCompositeName. If not, we go with
564 // a generic message.
565 if (errMsg.empty()) {
566 errMsg = "The tree does not have a branch called ";
567 errMsg += fBranchName.Data();
568 errMsg += ". You could check with TTree::Print() for available branches.";
569 }
570#if !defined(_MSC_VER)
571#pragma GCC diagnostic push
572#pragma GCC diagnostic ignored "-Wformat-security"
573#endif
574 Error(errPrefix, errMsg.c_str());
575#if !defined(_MSC_VER)
576#pragma GCC diagnostic pop
577#endif
578 return;
579 }
580 // The branch found with the simplest search approach was successful.
581 // We reset the state, we continue
582 fSetupStatus = kSetupInternalError;
583 fStaticClassOffsets = {};
584 fHaveStaticClassOffsets = false;
585 }
586
587 if (!myLeaf && !fHaveStaticClassOffsets) {
588 // The following two lines cannot be swapped. The GetBranchDataType can
589 // change the value of branchActualType
590 const char *branchActualTypeName = GetBranchDataType(branch, branchActualType, fDict);
591 if (!branchActualType) {
592 Error(errPrefix, "The branch %s contains data of type %s, which does not have a dictionary.",
593 fBranchName.Data(), branchActualTypeName ? branchActualTypeName : "{UNDETERMINED TYPE}");
594 fProxy = nullptr;
595 return;
596 }
597
598 // Check if the dictionaries are TClass instances and if there is inheritance
599 // because in this case, we can read the values.
600 auto dictAsClass = dynamic_cast<TClass *>(fDict);
601 auto branchActualTypeAsClass = dynamic_cast<TClass *>(branchActualType);
603 bool typeinfoMatch = dictAsClass && dictAsClass->GetTypeInfo() &&
604 dictAsClass->GetTypeInfo() == branchActualTypeAsClass->GetTypeInfo();
605
606 if (!inheritance && !typeinfoMatch && fDict != branchActualType) {
607 TDataType *dictdt = dynamic_cast<TDataType *>(fDict);
608 TDataType *actualdt = dynamic_cast<TDataType *>(branchActualType);
609 TEnum *dictenum = dynamic_cast<TEnum *>(fDict);
610 TEnum *actualenum = dynamic_cast<TEnum *>(branchActualType);
611 bool complainAboutMismatch = true;
612 if (dictdt && actualdt) {
613 if (dictdt->GetType() > 0 && dictdt->GetType() == actualdt->GetType()) {
614 // Same numerical type but different TDataType, likely Long64_t
615 complainAboutMismatch = false;
616 } else if ((actualdt->GetType() == kDouble32_t && dictdt->GetType() == kDouble_t) ||
617 (actualdt->GetType() == kFloat16_t && dictdt->GetType() == kFloat_t)) {
618 // Double32_t and Float16_t never "decay" to their underlying type;
619 // we need to identify them manually here (ROOT-8731).
620 complainAboutMismatch = false;
621 }
622 } else if ((dictdt || dictenum) && (actualdt || actualenum)) {
623 if ((dictdt && dictdt->GetType() == kInt_t && actualenum) ||
624 (actualdt && actualdt->GetType() == kInt_t && dictenum))
625 complainAboutMismatch = false;
626 if ((dictdt && actualenum && dictdt->GetType() == actualenum->GetUnderlyingType()) ||
627 (actualdt && dictenum && actualdt->GetType() == dictenum->GetUnderlyingType()))
628 complainAboutMismatch = false;
629 }
631 Error(errPrefix, "The branch %s contains data of type %s. It cannot be accessed by a TTreeReaderValue<%s>",
632 fBranchName.Data(), branchActualType->GetName(), fDict->GetName());
633 return;
634 }
635 }
636 }
637
638 if (!namedProxy) {
639 // Search for the branchname, determine what it contains, and wire the
640 // TBranchProxy representing it to us so we can access its data.
641 // A proxy for branch must not have been created before (i.e. check
642 // fProxies before calling this function!)
643
645
646 bool isTopLevel = branch->GetMother() == branch;
647 if (!isTopLevel) {
648 membername = strrchr(branch->GetName(), '.');
649 if (membername.IsNull()) {
650 membername = branch->GetName();
651 }
652 }
653 auto director = fTreeReader->fDirector.get();
654 // Determine if the branch is actually in a Friend TTree and if so which.
655 if (branch->GetTree() != fTreeReader->GetTree()->GetTree()) {
656 // It is in a friend, let's find the 'index' in the list of friend ...
657 std::optional<std::size_t> index;
658 std::size_t current{};
659 auto &&friends = fTreeReader->GetTree()->GetTree()->GetListOfFriends();
661 if (branch->GetTree() == fe->GetTree()) {
662 index = current;
663 break;
664 }
665 ++current;
666 }
667 if (!index.has_value()) {
669 "The branch %s is contained in a Friend TTree that is not directly attached to the main.\n"
670 "This is not yet supported by TTreeReader.",
671 fBranchName.Data());
672 return;
673 }
674 auto &&friendProxy = fTreeReader->AddFriendProxy(index.value());
675 fTreeReader->AddProxy(std::make_unique<TNamedBranchProxy>(friendProxy.GetDirector(), branch,
676 originalBranchName.c_str(), branch->GetName(),
678 } else {
679 fTreeReader->AddProxy(std::make_unique<TNamedBranchProxy>(director, branch, originalBranchName.c_str(),
681 }
682 namedProxy = fTreeReader->FindProxy(originalBranchName.c_str());
683 }
684
685 // Update named proxy's dictionary
686 if (!namedProxy->GetDict())
687 namedProxy->SetDict(fDict);
688
689 fProxy = namedProxy->GetProxy();
690 if (fProxy) {
691 fSetupStatus = kSetupMatch;
692 } else {
693 fSetupStatus = kSetupMismatch;
694 }
695}
696
697////////////////////////////////////////////////////////////////////////////////
698/// Retrieve the type of data stored by branch; put its dictionary into
699/// dict, return its type name. If no dictionary is available, at least
700/// its type name should be returned.
701
702const char *
704{
705 dict = nullptr;
706 if (branch->IsA() == TBranchElement::Class()) {
708
709 auto ResolveTypedef = [&]() -> void {
710 if (dict->IsA() != TDataType::Class())
711 return;
712 // Resolve the typedef.
713 dict = TDictionary::GetDictionary(((TDataType *)dict)->GetTypeName());
714 if (dict->IsA() != TDataType::Class()) {
715 // Might be a class.
716 if (dict != curDict) {
717 dict = TClass::GetClass(brElement->GetTypeName());
718 }
719 if (dict != curDict) {
720 dict = brElement->GetCurrentClass();
721 }
722 }
723 };
724
725 if (brElement->GetType() == TBranchElement::kSTLNode || brElement->GetType() == TBranchElement::kLeafNode ||
727
729 Int_t id = brElement->GetID();
730
731 if (id >= 0) {
732 TStreamerElement *element = (TStreamerElement *)streamerInfo->GetElements()->At(id);
733 if (element->IsA() == TStreamerSTL::Class()) {
735 dict = myStl->GetClass();
736 return nullptr;
737 }
738 }
739
740 if (brElement->GetType() == 3 || brElement->GetType() == 4) {
741 dict = brElement->GetCurrentClass();
742 return brElement->GetTypeName();
743 }
744
745 if (brElement->GetTypeName())
746 dict = TDictionary::GetDictionary(brElement->GetTypeName());
747
748 if (dict)
749 ResolveTypedef();
750 else
751 dict = brElement->GetCurrentClass();
752
753 return brElement->GetTypeName();
754 } else if (brElement->GetType() == TBranchElement::kClonesNode) {
755 dict = TClonesArray::Class();
756 return "TClonesArray";
757 } else if (brElement->GetType() == 31 || brElement->GetType() == 41) {
758 // it's a member, extract from GetClass()'s streamer info
759 Error("TTreeReaderValueBase::GetBranchDataType()",
760 "Must use TTreeReaderArray to access a member of an object that is stored in a collection.");
761 } else if (brElement->GetType() == -1 && brElement->GetTypeName()) {
762 dict = TDictionary::GetDictionary(brElement->GetTypeName());
763 ResolveTypedef();
764 return brElement->GetTypeName();
765 } else {
766 Error("TTreeReaderValueBase::GetBranchDataType()", "Unknown type and class combination: %i, %s",
767 brElement->GetType(), brElement->GetClassName());
768 }
769 return nullptr;
770 } else if (branch->IsA() == TBranch::Class() || branch->IsA() == TBranchObject::Class() ||
771 branch->IsA() == TBranchSTL::Class()) {
772 if (branch->GetTree()->IsA() == TNtuple::Class()) {
774 return dict->GetName();
775 }
776 const char *dataTypeName = branch->GetClassName();
777 if ((!dataTypeName || !dataTypeName[0]) && branch->IsA() == TBranch::Class()) {
778 TLeaf *myLeaf = branch->GetLeaf(branch->GetName());
779 if (!myLeaf) {
780 myLeaf = branch->FindLeaf(branch->GetName());
781 }
782 if (!myLeaf && branch->GetListOfLeaves()->GetEntries() == 1) {
783 myLeaf = static_cast<TLeaf *>(branch->GetListOfLeaves()->UncheckedAt(0));
784 }
785 if (myLeaf) {
787 if (myDataType && myDataType->IsA() == TDataType::Class()) {
788 if (myLeaf->GetLeafCount() != nullptr || myLeaf->GetLenStatic() > 1) {
789 Error("TTreeReaderValueBase::GetBranchDataType()",
790 "Must use TTreeReaderArray to read branch %s: it contains an array or a collection.",
791 branch->GetName());
792 return nullptr;
793 }
794 dict = TDataType::GetDataType((EDataType)((TDataType *)myDataType)->GetType());
795 return myLeaf->GetTypeName();
796 }
797 }
798
799 // leaflist. Can't represent.
800 Error("TTreeReaderValueBase::GetBranchDataType()",
801 "The branch %s was created using a leaf list and cannot be represented as a C++ type. Please access one "
802 "of its siblings using a TTreeReaderArray:",
803 branch->GetName());
804 TIter iLeaves(branch->GetListOfLeaves());
805 TLeaf *leaf = nullptr;
806 while ((leaf = (TLeaf *)iLeaves())) {
807 Error("TTreeReaderValueBase::GetBranchDataType()", " %s.%s", branch->GetName(), leaf->GetName());
808 }
809 return nullptr;
810 }
811 if (dataTypeName)
813 return dataTypeName;
814 } else if (branch->IsA() == TBranchClones::Class()) {
815 dict = TClonesArray::Class();
816 return "TClonesArray";
817 } else if (branch->IsA() == TBranchRef::Class()) {
818 // Can't represent.
819 Error("TTreeReaderValueBase::GetBranchDataType()",
820 "The branch %s is a TBranchRef and cannot be represented as a C++ type.", branch->GetName());
821 return nullptr;
822 } else {
823 Error("TTreeReaderValueBase::GetBranchDataType()",
824 "The branch %s is of type %s - something that is not handled yet.", branch->GetName(),
825 branch->IsA()->GetName());
826 return nullptr;
827 }
828
829 return nullptr;
830}
831
833{
834 // Print the error only if the branch name does not appear in the list of
835 // missing proxies that the user explicitly requested not to error about
836 if (std::find(fTreeReader->fMissingProxies.cbegin(), fTreeReader->fMissingProxies.cend(), fBranchName.Data()) ==
837 fTreeReader->fMissingProxies.cend())
838 Error("TTreeReaderValue::Get()", "Value reader not properly initialized, did you call "
839 "TTreeReader::Set(Next)Entry() or TTreeReader::Next()?");
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:3069
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:47
static TClass * Class()
An array of TObjects.
Definition TObjArray.h:31
Regular expression class.
Definition TRegexp.h:31
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:45
@ 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.