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