49 ClassImp(ROOT::Internal::TTreeReaderValueBase);
54 ROOT::Internal::TTreeReaderValueBase::TTreeReaderValueBase(TTreeReader* reader ,
55 const char* branchname ,
58 fHaveStaticClassOffsets(0),
59 fReadStatus(kReadNothingYet),
60 fBranchName(branchname),
64 RegisterWithTreeReader();
70 ROOT::Internal::TTreeReaderValueBase::TTreeReaderValueBase(
const TTreeReaderValueBase& rhs):
71 fHaveLeaf(rhs.fHaveLeaf),
72 fHaveStaticClassOffsets(rhs.fHaveStaticClassOffsets),
73 fReadStatus(rhs.fReadStatus),
74 fSetupStatus(rhs.fSetupStatus),
75 fBranchName(rhs.fBranchName),
76 fLeafName(rhs.fLeafName),
77 fTreeReader(rhs.fTreeReader),
81 fStaticClassOffsets(rhs.fStaticClassOffsets)
83 RegisterWithTreeReader();
89 ROOT::Internal::TTreeReaderValueBase&
90 ROOT::Internal::TTreeReaderValueBase::operator=(
const TTreeReaderValueBase& rhs) {
92 fHaveLeaf = rhs.fHaveLeaf;
93 fHaveStaticClassOffsets = rhs.fHaveStaticClassOffsets;
94 fBranchName = rhs.fBranchName;
95 fLeafName = rhs.fLeafName;
96 if (fTreeReader != rhs.fTreeReader) {
98 fTreeReader->DeregisterValueReader(
this);
99 fTreeReader = rhs.fTreeReader;
100 RegisterWithTreeReader();
105 fSetupStatus = rhs.fSetupStatus;
106 fReadStatus = rhs.fReadStatus;
107 fStaticClassOffsets = rhs.fStaticClassOffsets;
115 ROOT::Internal::TTreeReaderValueBase::~TTreeReaderValueBase()
117 if (fTreeReader) fTreeReader->DeregisterValueReader(
this);
118 R__ASSERT((fLeafName.Length() == 0 ) == !fHaveLeaf
119 &&
"leafness disagreement");
120 R__ASSERT(fStaticClassOffsets.empty() == !fHaveStaticClassOffsets
121 &&
"static class offset disagreement");
127 void ROOT::Internal::TTreeReaderValueBase::RegisterWithTreeReader() {
129 if (!fTreeReader->RegisterValueReader(
this)) {
130 fTreeReader =
nullptr;
141 template <ROOT::Internal::TTreeReaderValueBase::BranchProxyRead_t Func>
142 ROOT::Internal::TTreeReaderValueBase::EReadStatus ROOT::Internal::TTreeReaderValueBase::ProxyReadTemplate()
144 if ((fProxy->*Func)()) {
145 fReadStatus = kReadSuccess;
147 fReadStatus = kReadError;
152 ROOT::Internal::TTreeReaderValueBase::EReadStatus
153 ROOT::Internal::TTreeReaderValueBase::ProxyReadDefaultImpl() {
154 if (!fProxy)
return kReadNothingYet;
155 if (fProxy->IsInitialized() || fProxy->Setup()) {
157 using EReadType = ROOT::Detail::TBranchProxy::EReadType;
158 using TBranchPoxy = ROOT::Detail::TBranchProxy;
160 EReadType readtype = EReadType::kNoDirector;
161 if (fProxy) readtype = fProxy->GetReadType();
164 case EReadType::kNoDirector:
165 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoDirector>;
167 case EReadType::kReadParentNoCollection:
168 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentNoCollection>;
170 case EReadType::kReadParentCollectionNoPointer:
171 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentCollectionNoPointer>;
173 case EReadType::kReadParentCollectionPointer:
174 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadParentCollectionPointer>;
176 case EReadType::kReadNoParentNoBranchCountCollectionPointer:
177 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountCollectionPointer>;
179 case EReadType::kReadNoParentNoBranchCountCollectionNoPointer:
180 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountCollectionNoPointer>;
182 case EReadType::kReadNoParentNoBranchCountNoCollection:
183 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentNoBranchCountNoCollection>;
185 case EReadType::kReadNoParentBranchCountCollectionPointer:
186 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountCollectionPointer>;
188 case EReadType::kReadNoParentBranchCountCollectionNoPointer:
189 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountCollectionNoPointer>;
191 case EReadType::kReadNoParentBranchCountNoCollection:
192 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadTemplate<&TBranchPoxy::ReadNoParentBranchCountNoCollection>;
194 case EReadType::kDefault:
196 default: fProxyReadFunc = &TTreeReaderValueBase::ProxyReadDefaultImpl;
198 return (this->*fProxyReadFunc)();
204 if (fProxy->Read()) {
205 fReadStatus = kReadSuccess;
207 fReadStatus = kReadError;
214 std::string ROOT::Internal::TTreeReaderValueBase::GetElementTypeName(
const std::type_info& ti) {
216 char* buf = TClassEdit::DemangleTypeIdName(ti, err);
217 std::string ret = buf;
225 void ROOT::Internal::TTreeReaderValueBase::NotifyNewTree(TTree* newTree) {
228 fProxyReadFunc = &TTreeReaderValueBase::ProxyReadDefaultImpl;
230 if (!fHaveLeaf || !newTree) {
235 TBranch *myBranch = newTree->GetBranch(fBranchName);
238 fReadStatus = kReadError;
239 Error(
"TTreeReaderValueBase::GetLeaf()",
"Unable to get the branch from the tree");
243 fLeaf = myBranch->GetLeaf(fLeafName);
245 Error(
"TTreeReaderValueBase::GetLeaf()",
"Failed to get the leaf from the branch");
252 void* ROOT::Internal::TTreeReaderValueBase::GetAddress() {
253 if (ProxyRead() != kReadSuccess)
return 0;
257 return fLeaf->GetValuePointer();
260 fReadStatus = kReadError;
261 Error(
"TTreeReaderValueBase::GetAddress()",
"Unable to get the leaf");
265 if (fHaveStaticClassOffsets){
266 Byte_t *address = (Byte_t*)fProxy->GetWhere();
268 for (
unsigned int i = 0; i < fStaticClassOffsets.size() - 1; ++i){
269 address = *(Byte_t**)(address + fStaticClassOffsets[i]);
272 return address + fStaticClassOffsets.back();
274 return (Byte_t*)fProxy->GetWhere();
292 TBranch *ROOT::Internal::TTreeReaderValueBase::SearchBranchWithCompositeName(TLeaf *&myLeaf, TDictionary *&branchActualType, std::string &errMsg)
294 TRegexp leafNameExpression (
"\\.[a-zA-Z0-9_]+$");
295 TString leafName (fBranchName(leafNameExpression));
296 TString branchName = fBranchName(0, fBranchName.Length() - leafName.Length());
297 auto branch = fTreeReader->GetTree()->GetBranch(branchName);
299 std::vector<TString> nameStack;
300 nameStack.push_back(TString());
301 nameStack.push_back(leafName.Strip(TString::kBoth,
'.'));
302 leafName = branchName(leafNameExpression);
303 branchName = branchName(0, branchName.Length() - leafName.Length());
305 branch = fTreeReader->GetTree()->GetBranch(branchName);
306 if (!branch) branch = fTreeReader->GetTree()->GetBranch(branchName +
".");
307 if (leafName.Length()) nameStack.push_back(leafName.Strip(TString::kBoth,
'.'));
309 while (!branch && branchName.Contains(
".")){
310 leafName = branchName(leafNameExpression);
311 branchName = branchName(0, branchName.Length() - leafName.Length());
312 branch = fTreeReader->GetTree()->GetBranch(branchName);
313 if (!branch) branch = fTreeReader->GetTree()->GetBranch(branchName +
".");
314 nameStack.push_back(leafName.Strip(TString::kBoth,
'.'));
317 if (branch && branch->IsA() == TBranchElement::Class()){
318 TBranchElement *myBranchElement = (TBranchElement*)branch;
320 TString traversingBranch = nameStack.back();
321 nameStack.pop_back();
325 TDataType *finalDataType = 0;
327 std::vector<Long64_t> offsets;
329 TClass *elementClass = 0;
331 TObjArray *myObjArray = myBranchElement->GetInfo()->GetElements();
332 TVirtualStreamerInfo *myInfo = myBranchElement->GetInfo();
334 while (nameStack.size() && found){
337 for (
int i = 0; i < myObjArray->GetEntries(); ++i){
339 TStreamerElement *tempStreamerElement = (TStreamerElement*)myObjArray->At(i);
341 if (!strcmp(tempStreamerElement->GetName(), traversingBranch.Data())){
342 offset += myInfo->GetElementOffset(i);
344 traversingBranch = nameStack.back();
345 nameStack.pop_back();
347 elementClass = tempStreamerElement->GetClass();
349 myInfo = elementClass->GetStreamerInfo(0);
350 myObjArray = myInfo->GetElements();
354 finalDataType = TDataType::GetDataType((EDataType)tempStreamerElement->GetType());
355 if (!finalDataType) {
356 TDictionary* seType = TDictionary::GetDictionary(tempStreamerElement->GetTypeName());
357 if (seType && seType->IsA() == TDataType::Class()) {
358 finalDataType = TDataType::GetDataType((EDataType)((TDataType*)seType)->GetType());
363 if (tempStreamerElement->IsaPointer()){
364 offsets.push_back(offset);
374 offsets.push_back(offset);
377 fStaticClassOffsets = offsets;
378 fHaveStaticClassOffsets = 1;
380 if (fDict != finalDataType && fDict != elementClass){
381 errMsg =
"Wrong data type ";
382 errMsg += finalDataType ? finalDataType->GetName() : elementClass ? elementClass->GetName() :
"UNKNOWN";
383 fSetupStatus = kSetupMismatch;
391 if (!fHaveStaticClassOffsets) {
392 errMsg =
"The tree does not have a branch called ";
393 errMsg += fBranchName;
394 errMsg +=
". You could check with TTree::Print() for available branches.";
395 fSetupStatus = kSetupMissingBranch;
401 myLeaf = branch->GetLeaf(TString(leafName(1, leafName.Length())));
403 errMsg =
"The tree does not have a branch, nor a sub-branch called ";
404 errMsg += fBranchName;
405 errMsg +=
". You could check with TTree::Print() for available branches.";
406 fSetupStatus = kSetupMissingBranch;
411 TDataType *tempDict = gROOT->GetType(myLeaf->GetTypeName());
412 if (tempDict && fDict->IsA() == TDataType::Class() && tempDict->GetType() == ((TDataType*)fDict)->GetType()) {
414 branchActualType = fDict;
416 fBranchName = branchName;
417 fLeafName = leafName(1, leafName.Length());
418 fHaveLeaf = fLeafName.Length() > 0;
419 fSetupStatus = kSetupMatchLeaf;
422 errMsg =
"Leaf of type ";
423 errMsg += myLeaf->GetTypeName();
424 errMsg +=
" cannot be read by TTreeReaderValue<";
425 errMsg += fDict->GetName();
427 fSetupStatus = kSetupMismatch;
439 void ROOT::Internal::TTreeReaderValueBase::CreateProxy() {
441 constexpr
const char* errPrefix =
"TTreeReaderValueBase::CreateProxy()";
447 fSetupStatus = kSetupInternalError;
449 Error(errPrefix,
"TTreeReader object not set / available for branch %s!",
451 fSetupStatus = kSetupTreeDestructed;
455 auto branchFromFullName = fTreeReader->GetTree()->GetBranch(fBranchName);
458 const char* brDataType =
"{UNDETERMINED}";
459 if (branchFromFullName) {
460 TDictionary* brDictUnused = 0;
461 brDataType = GetBranchDataType(branchFromFullName, brDictUnused, fDict);
463 Error(errPrefix,
"The template argument type T of %s accessing branch %s (which contains data of type %s) is not known to ROOT. You will need to create a dictionary for it.",
464 GetDerivedTypeName(), fBranchName.Data(), brDataType);
465 fSetupStatus = kSetupMissingDictionary;
472 TNamedBranchProxy* namedProxy = fTreeReader->FindProxy(fBranchName);
473 if (namedProxy && namedProxy->GetDict() == fDict) {
474 fProxy = namedProxy->GetProxy();
478 const std::string originalBranchName = fBranchName.Data();
480 TLeaf *myLeaf =
nullptr;
481 TDictionary* branchActualType =
nullptr;
484 TBranch *branch =
nullptr;
491 if (fBranchName.Contains(
".")) {
492 branch = SearchBranchWithCompositeName(myLeaf, branchActualType, errMsg);
500 if (branch && branch->IsA() == TBranchElement::Class() && branchFromFullName){
501 branch = branchFromFullName;
502 fStaticClassOffsets = {};
503 fHaveStaticClassOffsets = 0;
510 branch = branchFromFullName;
515 if (errMsg.empty()) {
516 errMsg =
"The tree does not have a branch called ";
517 errMsg += fBranchName.Data();
518 errMsg +=
". You could check with TTree::Print() for available branches.";
520 #if !defined(_MSC_VER)
521 #pragma GCC diagnostic push
522 #pragma GCC diagnostic ignored "-Wformat-security"
524 Error(errPrefix, errMsg.c_str());
525 #if !defined(_MSC_VER)
526 #pragma GCC diagnostic pop
532 fSetupStatus = kSetupInternalError;
533 fStaticClassOffsets = {};
534 fHaveStaticClassOffsets = 0;
538 if (!myLeaf && !fHaveStaticClassOffsets) {
541 const char* branchActualTypeName = GetBranchDataType(branch, branchActualType, fDict);
542 if (!branchActualType) {
543 Error(errPrefix,
"The branch %s contains data of type %s, which does not have a dictionary.",
544 fBranchName.Data(), branchActualTypeName ? branchActualTypeName :
"{UNDETERMINED TYPE}");
551 auto dictAsClass =
dynamic_cast<TClass*
>(fDict);
552 auto branchActualTypeAsClass =
dynamic_cast<TClass*
>(branchActualType);
553 auto inheritance = dictAsClass && branchActualTypeAsClass && branchActualTypeAsClass->InheritsFrom(dictAsClass);
555 if (fDict != branchActualType && !inheritance) {
556 TDataType *dictdt =
dynamic_cast<TDataType*
>(fDict);
557 TDataType *actualdt =
dynamic_cast<TDataType*
>(branchActualType);
558 bool complainAboutMismatch =
true;
559 if (dictdt && actualdt) {
560 if (dictdt->GetType() > 0 && dictdt->GetType() == actualdt->GetType()) {
562 complainAboutMismatch =
false;
563 }
else if ((actualdt->GetType() == kDouble32_t && dictdt->GetType() == kDouble_t)
564 || (actualdt->GetType() == kFloat16_t && dictdt->GetType() == kFloat_t)) {
567 complainAboutMismatch =
false;
570 if (complainAboutMismatch) {
572 "The branch %s contains data of type %s. It cannot be accessed by a TTreeReaderValue<%s>",
573 fBranchName.Data(), branchActualType->GetName(),
588 bool isTopLevel = branch->GetMother() == branch;
590 membername = strrchr(branch->GetName(),
'.');
591 if (membername.IsNull()) {
592 membername = branch->GetName();
595 auto director = fTreeReader->fDirector;
597 if (branch->GetTree() != fTreeReader->GetTree()->GetTree()) {
601 TFriendElement *fe_found =
nullptr;
602 for(
auto fe : TRangeDynCast<TFriendElement>( fTreeReader->GetTree()->GetTree()->GetListOfFriends())) {
603 if (branch->GetTree() == fe->GetTree()) {
611 Error(errPrefix,
"The branch %s is contained in a Friend TTree that is not directly attached to the main.\n"
612 "This is not yet supported by TTreeReader.",
616 const char *localBranchName = originalBranchName.c_str();
617 if (branch != branch->GetTree()->GetBranch(localBranchName)) {
619 auto len = strlen( branch->GetTree()->GetName());
620 if (strncmp(localBranchName, branch->GetTree()->GetName(), len) == 0
621 && localBranchName[len] ==
'.'
622 && branch != branch->GetTree()->GetBranch(localBranchName+len+1)) {
623 localBranchName = localBranchName + len + 1;
625 len = strlen(fe_found->GetName());
626 if (strncmp(localBranchName, fe_found->GetName(), len) == 0
627 && localBranchName[len] ==
'.'
628 && branch != branch->GetTree()->GetBranch(localBranchName+len+1)) {
629 localBranchName = localBranchName + len + 1;
633 TFriendProxy *feproxy =
nullptr;
634 if ((
size_t)index < fTreeReader->fFriendProxies.size()) {
635 feproxy = fTreeReader->fFriendProxies.at(index);
638 feproxy =
new ROOT::Internal::TFriendProxy(director, fTreeReader->GetTree(), index);
639 fTreeReader->fFriendProxies.resize(index+1);
640 fTreeReader->fFriendProxies.at(index) = feproxy;
642 namedProxy =
new TNamedBranchProxy(feproxy->GetDirector(), branch, originalBranchName.c_str(), branch->GetName(), membername);
644 namedProxy =
new TNamedBranchProxy(director, branch, originalBranchName.c_str(), membername);
646 fTreeReader->AddProxy(namedProxy);
650 if (!namedProxy->GetDict())
651 namedProxy->SetDict(fDict);
653 fProxy = namedProxy->GetProxy();
655 fSetupStatus = kSetupMatch;
657 fSetupStatus = kSetupMismatch;
666 const char* ROOT::Internal::TTreeReaderValueBase::GetBranchDataType(TBranch* branch,
668 TDictionary
const *curDict)
671 if (branch->IsA() == TBranchElement::Class()) {
672 TBranchElement* brElement = (TBranchElement*)branch;
674 auto ResolveTypedef = [&]() ->
void {
675 if (dict->IsA() != TDataType::Class())
678 dict = TDictionary::GetDictionary(((TDataType*)dict)->GetTypeName());
679 if (dict->IsA() != TDataType::Class()) {
681 if (dict != curDict) {
682 dict = TClass::GetClass(brElement->GetTypeName());
684 if (dict != curDict) {
685 dict = brElement->GetCurrentClass();
690 if (brElement->GetType() == TBranchElement::kSTLNode ||
691 brElement->GetType() == TBranchElement::kLeafNode ||
692 brElement->GetType() == TBranchElement::kObjectNode) {
694 TStreamerInfo *streamerInfo = brElement->GetInfo();
695 Int_t
id = brElement->GetID();
698 TStreamerElement *element = (TStreamerElement*)streamerInfo->GetElements()->At(
id);
699 if (element->IsA() == TStreamerSTL::Class()){
700 TStreamerSTL *myStl = (TStreamerSTL*)element;
701 dict = myStl->GetClass();
706 if (brElement->GetType() == 3 || brElement->GetType() == 4) {
707 dict = brElement->GetCurrentClass();
708 return brElement->GetTypeName();
711 if (brElement->GetTypeName())
712 dict = TDictionary::GetDictionary(brElement->GetTypeName());
717 dict = brElement->GetCurrentClass();
719 return brElement->GetTypeName();
720 }
else if (brElement->GetType() == TBranchElement::kClonesNode) {
721 dict = TClonesArray::Class();
722 return "TClonesArray";
723 }
else if (brElement->GetType() == 31
724 || brElement->GetType() == 41) {
726 Error(
"TTreeReaderValueBase::GetBranchDataType()",
"Must use TTreeReaderArray to access a member of an object that is stored in a collection.");
727 }
else if (brElement->GetType() == -1 && brElement->GetTypeName()) {
728 dict = TDictionary::GetDictionary(brElement->GetTypeName());
730 return brElement->GetTypeName();
732 Error(
"TTreeReaderValueBase::GetBranchDataType()",
"Unknown type and class combination: %i, %s", brElement->GetType(), brElement->GetClassName());
735 }
else if (branch->IsA() == TBranch::Class()
736 || branch->IsA() == TBranchObject::Class()
737 || branch->IsA() == TBranchSTL::Class()) {
738 if (branch->GetTree()->IsA() == TNtuple::Class()){
739 dict = TDataType::GetDataType(kFloat_t);
740 return dict->GetName();
742 const char* dataTypeName = branch->GetClassName();
743 if ((!dataTypeName || !dataTypeName[0])
744 && branch->IsA() == TBranch::Class()) {
745 TLeaf *myLeaf = branch->GetLeaf(branch->GetName());
747 TDictionary *myDataType = TDictionary::GetDictionary(myLeaf->GetTypeName());
748 if (myDataType && myDataType->IsA() == TDataType::Class()){
749 if (myLeaf->GetLeafCount() !=
nullptr || myLeaf->GetLenStatic() > 1) {
750 Error(
"TTreeReaderValueBase::GetBranchDataType()",
"Must use TTreeReaderArray to read branch %s: it contains an array or a collection.", branch->GetName());
753 dict = TDataType::GetDataType((EDataType)((TDataType*)myDataType)->GetType());
754 return myLeaf->GetTypeName();
759 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());
760 TIter iLeaves(branch->GetListOfLeaves());
762 while ((leaf = (TLeaf*) iLeaves())) {
763 Error(
"TTreeReaderValueBase::GetBranchDataType()",
" %s.%s", branch->GetName(), leaf->GetName());
767 if (dataTypeName) dict = TDictionary::GetDictionary(dataTypeName);
769 }
else if (branch->IsA() == TBranchClones::Class()) {
770 dict = TClonesArray::Class();
771 return "TClonesArray";
772 }
else if (branch->IsA() == TBranchRef::Class()) {
774 Error(
"TTreeReaderValueBase::GetBranchDataType()",
"The branch %s is a TBranchRef and cannot be represented as a C++ type.", branch->GetName());
777 Error(
"TTreeReaderValueBase::GetBranchDataType()",
"The branch %s is of type %s - something that is not handled yet.", branch->GetName(), branch->IsA()->GetName());