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
57ROOT::Internal::TTreeReaderValueBase::TTreeReaderValueBase(TTreeReader *reader /*= 0*/, const char *branchname /*= 0*/,
58 TDictionary *dict /*= 0*/, bool opaqueRead)
59 : fHaveLeaf(false),
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),
87 fProxy(rhs.fProxy),
88 fLeaf(rhs.fLeaf),
90{
92}
93
94////////////////////////////////////////////////////////////////////////////////
95/// Copy-assign.
96
98{
99 if (&rhs != this) {
100 fHaveLeaf = rhs.fHaveLeaf;
103 fLeafName = rhs.fLeafName;
104 if (fTreeReader != rhs.fTreeReader) {
105 if (fTreeReader)
106 fTreeReader->DeregisterValueReader(this);
109 }
112 fLeaf = rhs.fLeaf;
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}
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>
157
159{
160 if (!fProxy)
161 return kReadNothingYet;
162 if (fProxy->IsInitialized() || fProxy->Setup()) {
163
165 using TBranchPoxy = ROOT::Detail::TBranchProxy;
166
167 EReadType readtype = EReadType::kNoDirector;
168 if (fProxy)
169 readtype = fProxy->GetReadType();
170
171 switch (readtype) {
172 case EReadType::kNoDirector:
174 break;
175 case EReadType::kReadParentNoCollection:
177 break;
178 case EReadType::kReadParentCollectionNoPointer:
180 break;
181 case EReadType::kReadParentCollectionPointer:
183 break;
184 case EReadType::kReadNoParentNoBranchCountCollectionPointer:
187 break;
188 case EReadType::kReadNoParentNoBranchCountCollectionNoPointer:
191 break;
192 case EReadType::kReadNoParentNoBranchCountNoCollection:
194 break;
195 case EReadType::kReadNoParentBranchCountCollectionPointer:
198 break;
199 case EReadType::kReadNoParentBranchCountCollectionNoPointer:
202 break;
203 case EReadType::kReadNoParentBranchCountNoCollection:
205 break;
206 case EReadType::kDefault:
207 // intentional fall through.
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()) {
218 } else {
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) {
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 {
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.
316 TDictionary *&branchActualType,
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()) {
346 TBranchElement *myBranchElement = (TBranchElement *)branch;
347
348 TString traversingBranch = nameStack.back();
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();
360 TVirtualStreamerInfo *myInfo = myBranchElement->GetInfo();
361
362 while (!nameStack.empty() && found) {
363 found = false;
364
365 for (int i = 0; i < myObjArray->GetEntries(); ++i) {
366
367 TStreamerElement *tempStreamerElement = (TStreamerElement *)myObjArray->At(i);
368
369 if (!strcmp(tempStreamerElement->GetName(), traversingBranch.Data())) {
370 offset += myInfo->GetElementOffset(i);
371
372 traversingBranch = nameStack.back();
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 {
381 finalDataType = TDataType::GetDataType((EDataType)tempStreamerElement->GetType());
382 if (!finalDataType) {
383 TDictionary *seType = TDictionary::GetDictionary(tempStreamerElement->GetTypeName());
384 if (seType && seType->IsA() == TDataType::Class()) {
385 finalDataType = TDataType::GetDataType((EDataType)((TDataType *)seType)->GetType());
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;
406
407 if (fDict != finalDataType && fDict != elementClass) {
408 errMsg = "Wrong data type ";
409 errMsg += finalDataType ? finalDataType->GetName() : elementClass ? elementClass->GetName() : "UNKNOWN";
411 fProxy = nullptr;
412 return nullptr;
413 }
414 }
415 }
416
418 errMsg = "The tree does not have a branch called ";
419 errMsg += fBranchName;
420 errMsg += ". You could check with TTree::Print() for available branches.";
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.";
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;
441 fLeafName = leafName(1, leafName.Length());
442 fHaveLeaf = fLeafName.Length() > 0;
444 } else {
445 errMsg = "Leaf of type ";
446 errMsg += myLeaf->GetTypeName();
447 errMsg += " cannot be read by TTreeReaderValue<";
448 errMsg += fDict->GetName();
449 errMsg += ">.";
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());
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 }
489 Error(errPrefix,
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);
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.
535 if (branch && branch->IsA() == TBranchElement::Class() && branchFromFullName) {
536 branch = branchFromFullName;
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 =
552 (suppressErrorsForMissingBranches.find(originalBranchName) != suppressErrorsForMissingBranches.cend());
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.
557 branch = branchFromFullName;
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
562 fProxy = nullptr;
563 if (suppressErrorsForThisBranch)
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
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);
606 auto inheritance = dictAsClass && branchActualTypeAsClass && branchActualTypeAsClass->InheritsFrom(dictAsClass);
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 }
634 if (complainAboutMismatch) {
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
648 TString membername;
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();
664 for (auto fe : TRangeDynCast<TFriendElement>(friends)) {
665 if (branch->GetTree() == fe->GetTree()) {
666 index = current;
667 break;
668 }
669 ++current;
670 }
671 if (!index.has_value()) {
672 Error(errPrefix,
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(),
681 membername, suppressErrorsForThisBranch));
682 } else {
683 fTreeReader->AddProxy(std::make_unique<TNamedBranchProxy>(director, branch, originalBranchName.c_str(),
684 membername, suppressErrorsForThisBranch));
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.
700 else
702 } else {
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()) {
717 TBranchElement *brElement = (TBranchElement *)branch;
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 ||
736 brElement->GetType() == TBranchElement::kObjectNode) {
737
738 TStreamerInfo *streamerInfo = brElement->GetInfo();
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()) {
744 TStreamerSTL *myStl = (TStreamerSTL *)element;
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) {
796 TDictionary *myDataType = TDictionary::GetDictionary(myLeaf->GetTypeName());
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)
822 dict = TDictionary::GetDictionary(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
char * ret
Definition Rotated.cxx:221
unsigned char Byte_t
Byte (8 bits) (unsigned char).
Definition RtypesCore.h:78
int Int_t
Signed integer 4 bytes (int).
Definition RtypesCore.h:59
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
Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.", GetName(), objname)
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Double_t err
#define gROOT
Definition TROOT.h:417
#define free
Definition civetweb.c:1578
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.
@ kSetupInternalError
Some other error - hopefully the error message helps.
@ kSetupMissingBranch
The specified branch cannot be found.
@ kSetupMatchButEntryBeyondEnd
This branch has been setup, branch data type and reader template type match, but nothing can be read ...
@ kSetupMissingDictionary
To read this branch, we need a dictionary.
@ kSetupMismatch
Mismatch of branch type and reader template type.
@ kSetupTreeDestructed
The TTreeReader has been destructed / not set.
@ kSetupMatchLeaf
This branch (or TLeaf, really) has been set up, reading should succeed.
@ kSetupMatch
This branch has been set up, branch data type and reader template type match, reading should succeed.
Read_t fProxyReadFunc
! Pointer to the Read implementation to use.
bool fOpaqueRead
If true, the reader will not do any type-checking against the actual type held by the branch.
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.
@ kReadNothingYet
Data now yet accessed.
static std::string GetElementTypeName(const std::type_info &ti)
Stringify the template argument.
virtual const char * GetDerivedTypeName() const =0
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.
TLeaf * GetLeaf()
If we are reading a leaf, return the corresponding TLeaf.
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
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:2054
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any.
Definition TBranch.cxx:1323
TTree * GetTree() const
Definition TBranch.h:261
static TClass * Class()
TClass * IsA() const override
Definition TBranch.h:304
virtual TLeaf * FindLeaf(const char *name)
Find the leaf corresponding to the name 'searchname'.
Definition TBranch.cxx:1080
TObjArray * GetListOfLeaves()
Definition TBranch.h:256
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition TBranch.cxx:2126
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
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:4657
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4932
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
Int_t GetType() const
Definition TDataType.h:71
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
EDataType GetUnderlyingType() const
Get the underlying integer type of the enum: enum E { kOne }; // ==> int enum F: long; // ==> long Re...
Definition TEnum.h:81
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:142
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:124
virtual Int_t GetLenStatic() const
Return the fixed length of this leaf.
Definition TLeaf.h:135
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
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:170
Regular expression class.
Definition TRegexp.h:31
Describe one element (data member) to be Streamed.
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:138
Ssiz_t Length() const
Definition TString.h:425
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1170
const char * Data() const
Definition TString.h:384
@ kBoth
Definition TString.h:284
Bool_t IsNull() const
Definition TString.h:422
@ 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
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5430
virtual TTree * GetTree() const
Definition TTree.h:604
TClass * IsA() const override
Definition TTree.h:757
Abstract Interface class describing Streamer information for one class.
virtual TObjArray * GetElements() const =0
virtual Int_t GetElementOffset(Int_t id) const =0
void PrintWriteStlWithoutProxyMsg(const char *where, const char *clName, const char *BranchName)
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.