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