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