ATLAS Offline Software
Loading...
Searching...
No Matches
TAuxStore.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3// Local include(s).
5
6#include "isRegisteredType.h"
7#include "lookupVectorType.h"
12
13// Athena include(s).
22
23// ROOT include(s).
24#include <TBranch.h>
25#include <TBranchElement.h>
26#include <TClass.h>
27#include <TError.h>
28#include <TROOT.h>
29#include <TStreamerElement.h>
30#include <TStreamerInfo.h>
31#include <TString.h>
32#include <TTree.h>
33#include <TVirtualCollectionProxy.h>
34
35// System include(s):
36#include <cassert>
37#include <format>
38#include <sstream>
39#include <stdexcept>
40
41namespace {
42
44bool isPrimitiveBranch(TBranch& br) {
45
46 // The variables needed for the check:
47 ::TClass* cl = nullptr;
48 ::EDataType dType = kOther_t;
49
50 // Get the variable type from the branch:
51 if (br.GetExpectedType(cl, dType)) {
52 ::Error("::isPrimitiveBranch",
53 XAOD_MESSAGE("Couldn't determine the type of branch "
54 "\"%s\""),
55 br.GetName());
56 return false;
57 }
58
59 // The check is made using the data type variable:
60 return ((dType != kOther_t) && (dType != kNoType_t) && (dType != kVoid_t));
61}
62
80bool isContainerBranch(TBranch& br, SG::auxid_t auxid) {
81
82 // For unknown types it doesn't matter if the branch describes a
83 // container or a single element.
85 return true;
86 }
87
88 // The variables needed for the check:
89 ::TClass* cl = nullptr;
90 ::EDataType dType = kOther_t;
91
92 // Get the variable type from the branch:
93 if (br.GetExpectedType(cl, dType)) {
94 ::Error("::isContainerBranch",
95 XAOD_MESSAGE("Couldn't determine the type of branch \"%s\""),
96 br.GetName());
97 return false;
98 }
99
100 // If there is no class associated with the branch then it should be
101 // a branch describing a standalone object. (As it should be a
102 // "primitive" branch in this case.)
103 if (!cl) {
104 return false;
105 }
106
107 // If there is a class, ask for the type_info of its type:
108 const std::type_info* root_ti = cl->GetTypeInfo();
109 if (!root_ti) {
110 // This may be an emulated class. One known case is when the type name
111 // is saved as "basic_string<char>" rather than "string" by Athena I/O.
112 // (It's not fully understood why this happens for dynamic branches...)
113 // So, let's see if we can get a functional TClass by massaging the
114 // type name a bit.
115 ::TString typeName(cl->GetName());
116 typeName.ReplaceAll("basic_string<char>", "string");
117 ::TClass* newCl = ::TClass::GetClass(typeName);
118 if (newCl) {
119 root_ti = newCl->GetTypeInfo();
120 }
121 }
122 if (!root_ti) {
123 ::Error("::isContainerBranch",
124 XAOD_MESSAGE("Couldn't get an std::type_info object out of "
125 "branch \"%s\" of type \"%s\""),
126 br.GetName(), cl->GetName());
127 return false;
128 }
129
130 // Ask for the auxiliary type infos:
131 const std::type_info* aux_obj_ti =
133 if (!aux_obj_ti) {
134 ::Error("::isContainerBranch",
135 XAOD_MESSAGE("Couldn't get std::type_info object for "
136 "auxiliary id: %i"),
137 static_cast<int>(auxid));
138 return false;
139 }
140 const std::type_info* aux_vec_ti =
142 if (!aux_vec_ti) {
143 ::Error("::isContainerBranch",
144 XAOD_MESSAGE("Couldn't get std::type_info object for "
145 "auxiliary id: %i"),
146 static_cast<int>(auxid));
147 return false;
148 }
149
150 // Check which one the ROOT type info agrees with:
151 if (*root_ti == *aux_obj_ti) {
152 // This branch describes a single object:
153 return false;
154 } else if (*root_ti == *aux_vec_ti) {
155 // This branch describes a container of objects:
156 return true;
157 }
158
159 // For enum and vector<enum> types (PFO...) the type given by
160 // the aux type registry is vector<int>. We have to take it into account
161 // here...
162 if (cl->GetCollectionProxy() && (*aux_vec_ti == typeid(std::vector<int>))) {
163 return true;
164 }
165
166 TClass* cl2 = xAOD::details::lookupVectorType(*cl);
167 if (cl2) {
168 if (*cl2->GetTypeInfo() == *aux_vec_ti) {
169 return true;
170 }
171 }
172
173 // If we got this far, the branch may have undergone schema evolution. If
174 // it's one that ROOT can deal with itself, then we should still be able
175 // to read the branch with this code.
176 //
177 // Note that even after looking at the ROOT source code, I'm still not
178 // 100% sure whether we would need to delete the objects returned by
179 // TClass::GetConversionStreamerInfo(...) in this code. :-( But based on
180 // general experience with the ROOT code, I'm going to say no...
181 TClass* aux_vec_cl =
182 TClass::GetClass(xAOD::Utils::getTypeName(*aux_vec_ti).c_str());
183 if (aux_vec_cl &&
184 aux_vec_cl->GetConversionStreamerInfo(cl, cl->GetClassVersion())) {
185 return true;
186 }
187 TClass* aux_obj_cl =
188 TClass::GetClass(xAOD::Utils::getTypeName(*aux_obj_ti).c_str());
189 if (aux_obj_cl &&
190 aux_obj_cl->GetConversionStreamerInfo(cl, cl->GetClassVersion())) {
191 return false;
192 }
193
194 // If neither, then something went wrong...
195 ::Error("::isContainerBranch",
196 XAOD_MESSAGE("Couldn't determine if branch describes a single "
197 "object or a container"));
198 ::Error("::isContainerBranch", XAOD_MESSAGE("ROOT type : %s"),
199 xAOD::Utils::getTypeName(*root_ti).c_str());
200 ::Error(":isContainerBranch", XAOD_MESSAGE("Object type: %s"),
201 xAOD::Utils::getTypeName(*aux_obj_ti).c_str());
202 ::Error("::isContainerBranch", XAOD_MESSAGE("Vector type: %s"),
203 xAOD::Utils::getTypeName(*aux_vec_ti).c_str());
204 return false;
205}
206
212class TBranchHandle {
213
214 public:
216 TBranchHandle(bool staticBranch, bool primitiveBranch,
217 const std::type_info* ti, void* obj, SG::auxid_t auxid,
218 std::string_view prefix)
219 : m_branch(0),
220 m_entry(0),
221 m_object(obj),
222 m_static(staticBranch),
223 m_primitive(primitiveBranch),
224 m_typeInfo(ti),
225 m_needsRead(true),
226 m_auxid(auxid),
227 m_prefix(prefix) {}
228
236 ::Int_t getEntry() {
237
238 // A little sanity check:
239 if (!m_branch) {
240 // This is no longer an error. We can have such objects for
241 // decorations, which don't exist on the input.
242 return 0;
243 }
244
245 // Update the I/O monitoring:
246 xAOD::IOStats::instance().stats().readBranch(std::string{m_prefix},
247 m_auxid);
248
249 // Make sure that the branch is associated to a tree
250 // as the entry to be read is retrieved from the tree
251 if (!m_branch->GetTree()) {
252 Error(
253 "xAOD::TAuxStore::TBranchHandle::getEntry",
254 XAOD_MESSAGE("Branch=%s is not associated to any tree while reading "
255 "of branches within this class relies on that"),
256 m_branch->GetName());
257 return -1;
258 }
259
260 // Get the entry that should be read
261 // The entry to be read is set with TTree::LoadTree()
262 // NB: for a branch from a friend tree and if the friend tree has an index
263 // built, then the entry to read is found when calling the TTree::LoadTree()
264 // function that matches the major and minor values between the main tree
265 // and the friend tree
266 ::Long64_t entry = m_branch->GetTree()->GetReadEntry();
267
268 if (entry < 0) {
269 // Raise error as it implies
270 // either that the TTree::LoadTree() function has not been called
271 // or
272 // the entry requested to be read by the user
273 // is not corresponding to any entry for the friend tree
274 Error("xAOD::TAuxStore::TBranchHandle::getEntry",
276 "Entry to read is not set for branch=%s from tree=%s. "
277 "It is either because TTree::LoadTree(entry) was not called "
278 "beforehand in the TEvent class OR "
279 "the entry requested to be read for the main tree is not "
280 "corresponding to an event for the friend tree"),
281 m_branch->GetName(), m_branch->GetTree()->GetName());
282 return -1;
283 }
284
285 // Check if anything needs to be done:
286 if ((entry == m_entry) && (!m_needsRead)) {
287 return 0;
288 }
289
290 // Switch the branch in the right mode:
291 if (!m_primitive) {
292 if ((m_branch->GetMakeClass() != m_static) &&
293 (!m_branch->SetMakeClass(m_static))) {
294 ::Error("xAOD::TAuxStore::TBranchHandle::getEntry",
295 XAOD_MESSAGE("Failed to call SetMakeClass(%i) on "
296 "branch \"%s\""),
297 static_cast<int>(m_static), m_branch->GetName());
298 return -1;
299 }
300 }
301
302 // Load the entry.
303 const ::Int_t nbytes = m_branch->GetEntry(entry);
304
305 // If the load was successful, remember that we loaded this entry.
306 if (nbytes >= 0) {
307 m_entry = entry;
308 // The reading will now be done:
309 m_needsRead = false;
310 }
311
312 // Return the number of bytes read.
313 return nbytes;
314 }
315
324 ::TBranch** branchPtr() { return &m_branch; }
325
334 void* objectPtr() { return m_object; }
335
353 void* inputObjectPtr() {
354 // Return the correct pointer:
355 if (m_static || m_primitive) {
356 return m_object;
357 } else {
358 return &m_object;
359 }
360 }
372 void* outputObjectPtr() {
373 // Return the correct pointer:
374 if (m_primitive) {
375 return m_object;
376 } else {
377 return &m_object;
378 }
379 }
381 const std::type_info* typeInfo() const { return m_typeInfo; }
395 void reset() { m_needsRead = true; }
396
397 private:
399 ::TBranch* m_branch;
401 ::Long64_t m_entry;
403 void* m_object;
405 bool m_static;
407 bool m_primitive;
409 const std::type_info* m_typeInfo;
411 bool m_needsRead;
413 SG::auxid_t m_auxid;
415 std::string_view m_prefix;
416
417}; // class TBranchHandle
418
419} // namespace
420
421namespace xAOD {
422
424
442 StatusCode scanInputTree() {
443
444 // Check if an input tree is even available:
445 if (!m_inTree) {
446 // It's not an error if it isn't.
447 return StatusCode::SUCCESS;
448 }
449
450 // Check if the input was already scanned:
451 if (m_inputScanned) {
452 return StatusCode::SUCCESS;
453 }
454
455 // Get a list of all branches in the tree:
456 TObjArray* branches = m_inTree->GetListOfBranches();
457
458 // Check each of them:
459 for (Int_t i = 0; i < branches->GetEntriesFast(); ++i) {
460
461 // The name of this top-level branch:
462 const TString brName = branches->At(i)->GetName();
463
464 // Access the branch pointer:
465 TBranch* br = dynamic_cast<TBranch*>(branches->At(i));
466 if (!br) {
467 ::Fatal("xAOD::TAuxStore::impl::scanInputTree",
468 XAOD_MESSAGE("Logic error detected"));
469 }
470
471 // For top-level stores let's scan the static branches as well:
472 if (m_data.m_topStore && (brName == m_data.m_prefix)) {
473
474 // Make sure the object has been instantiated so that aux data
475 // registrations will have been done.
476 br->SetAddress(0);
477
478 // Get a list of its sub-branches:
479 TObjArray* sbranches = br->GetListOfBranches();
480
481 // ...and then loop over them:
482 for (Int_t j = 0; j < sbranches->GetEntriesFast(); ++j) {
483
484 // The name of the sub-branch:
485 const TString brName = sbranches->At(j)->GetName();
486
487 // Try to make a variable name out of the branch name:
488 const TString auxName =
489 brName(brName.Index(".") + 1, brName.Length());
490
491 // Skip this entry if it refers to a base class:
492 if (auxName.BeginsWith("xAOD::") || auxName.BeginsWith("SG::") ||
493 (auxName == "ILockable")) {
494 continue;
495 }
496
497 // The sub-branch:
498 ::TBranch* sbr = dynamic_cast< ::TBranch*>(sbranches->At(j));
499 if (!sbr) {
500 ::Fatal("xAOD::TAuxStore::impl::scanInputTree",
501 XAOD_MESSAGE("Logic error detected"));
502 }
503
504 // Leave the rest up to the function that is shared with the
505 // dynamic branches:
506 //cppcheck-suppress nullPointerRedundantCheck
507 RETURN_CHECK("xAOD::TAuxStore::impl::scanInputTree",setupAuxBranch(*sbr, auxName, true));
508 }
509
510 // Don't check the rest of the loop's body:
511 continue;
512 }
513
514 // Check if it has the right prefix to be a dynamic variable:
515 if (!brName.BeginsWith(m_data.m_dynPrefix.data())) {
516 continue;
517 }
518 // It's possible to create dynamic variables with an empty name
519 // as well. Which is a bug. Such variables are just ignored
520 // for now.
521 if (brName == m_data.m_dynPrefix) {
522 ::Warning("xAOD::TAuxStore::impl::scanInputTree",
523 "Dynamic branch with empty name found on container: %s",
524 m_data.m_prefix.data());
525 continue;
526 }
527
528 // The auxiliary property name:
529 const TString auxName = brName(brName.Index(".") + 1, brName.Length());
530
531 // Leave the rest up to the function that is shared with the
532 // dynamic branches:
533 RETURN_CHECK("xAOD::TAuxStore::impl::scanInputTree",
534 setupAuxBranch(*br, auxName, false));
535 }
536
537 // Okay, the input was successfully scanned:
538 m_inputScanned = true;
539
540 // Return gracefully:
541 return StatusCode::SUCCESS;
542 }
543
545 const std::type_info* auxBranchType(
546 ::TBranch& br, std::string_view auxName, bool staticBranch,
547 std::string* expectedClassName = nullptr) {
548
549 // Get the branch's type:
550 ::TClass* expectedClass = nullptr;
551 ::EDataType expectedType = kOther_t;
552 if (br.GetExpectedType(expectedClass, expectedType) &&
553 ((!staticBranch) || (!auxName.starts_with("m_")))) {
554 ::Warning("xAOD::TAuxStore::impl::auxBranchType",
555 "Couldn't get the type of branch \"%s\"", br.GetName());
556 }
557
558 // Check for schema evolution:
559 // If a branch has automatic schema evolution from one class to another,
560 // then what we get from GetExpectedType will be the on-disk class.
561 // What we have in memory is given by GetCurrentClass.
562 if (expectedClass) {
563 if (TBranchElement* bre = dynamic_cast<TBranchElement*>(&br)) {
564 TClass* newClass = bre->GetCurrentClass();
565 if (newClass && newClass != expectedClass) {
566 expectedClass = newClass;
567 }
568 }
569 if (expectedClassName) {
570 *expectedClassName = expectedClass->GetName();
571 }
572 }
573
574 // If this is a primitive variable, and we're still not sure whether this
575 // is a store for an object or a container, the answer is given...
576 if ((!expectedClass) &&
577 (m_data.m_structMode == EStructMode::kUndefinedStore)) {
578 m_data.m_structMode = EStructMode::kObjectStore;
579 }
580
581 // Get the type_info of the branch.
582 const std::type_info* ti = nullptr;
583 if (m_data.m_structMode == EStructMode::kObjectStore) {
584 if (expectedClass) {
585 ti = expectedClass->GetTypeInfo();
586 } else {
587 ti = &(Utils::getTypeInfo(expectedType));
588 }
589 } else {
590 if (!expectedClass) {
591 if ((!staticBranch) || (!auxName.starts_with("m_"))) {
592 ::Warning("xAOD::TAuxStore::impl::auxBranchType",
593 "Couldn't get the type of branch \"%s\"", br.GetName());
594 }
595 } else {
596 ::TVirtualCollectionProxy* prox = expectedClass->GetCollectionProxy();
597
598 if (!prox) {
599 TClass* cl2 = details::lookupVectorType(*expectedClass);
600 if (cl2) {
601 prox = cl2->GetCollectionProxy();
602 }
603 }
604
605 if (!prox) {
606 if ((!staticBranch) || (!auxName.starts_with("m_"))) {
607 ::Warning("xAOD::TAuxStore::impl::auxBranchType",
608 "Couldn't get the type of branch \"%s\"", br.GetName());
609 }
610 } else {
611 if (prox->GetValueClass()) {
612 ti = prox->GetValueClass()->GetTypeInfo();
613 } else {
614 ti = &(Utils::getTypeInfo(prox->GetType()));
615 }
616 }
617 }
618 }
619
620 return ti;
621 }
622
641 StatusCode setupAuxBranch(::TBranch& br, std::string_view auxName,
642 bool staticBranch) {
643
644 // Get the (on disk) type of the branch.
645 std::string expectedClassName;
646 const std::type_info* ti =
647 auxBranchType(br, auxName, staticBranch, &expectedClassName);
648 if (ti == nullptr) {
649 // If we didn't find a type_info for the branch, give up now...
650 return StatusCode::SUCCESS;
651 }
652
653 // Get the registry:
655
656 // Check if the registry already knows this variable name. If yes, let's
657 // use the type known by the registry. To be able to deal with simple
658 // schema evolution in dynamic branches.
659 if (const SG::auxid_t regAuxid = registry.findAuxID(std::string{auxName});
660 regAuxid != SG::null_auxid) {
661 m_data.m_auxIDs.insert(regAuxid);
662 return StatusCode::SUCCESS;
663 }
664
665 SG::AuxVarFlags flags = SG::AuxVarFlags::SkipNameCheck;
666 SG::auxid_t linked_auxid = SG::null_auxid;
667
668 if (SG::AuxTypeRegistry::isLinkedName(std::string{auxName})) {
669 flags |= SG::AuxVarFlags::Linked;
670 } else if (SG::AuxTypeRegistry::classNameHasLink(expectedClassName)) {
671 std::string linkedAttr =
672 SG::AuxTypeRegistry::linkedName(std::string{auxName});
673 std::string linkedBranch = SG::AuxTypeRegistry::linkedName(br.GetName());
674 ::TBranch* lbr = m_inTree->GetBranch(linkedBranch.c_str());
675 const std::type_info* lti = nullptr;
676 if (lbr) {
677 lti = auxBranchType(*lbr, linkedAttr, staticBranch);
678 }
679 if (lti) {
680 linked_auxid = registry.getAuxID(
681 *lti, linkedAttr, "",
682 SG::AuxVarFlags::SkipNameCheck | SG::AuxVarFlags::Linked);
683 }
684 if (linked_auxid == SG::null_auxid) {
685 ::Error("xAOD::TAuxStore::impl::setupAuxBranch",
686 "Could not find linked variable for %s type %s", auxName.data(),
687 expectedClassName.c_str());
688 }
689 }
690
691 // Check for an auxiliary ID for this branch:
692 SG::auxid_t auxid =
693 registry.getAuxID(*ti, std::string{auxName}, "", flags, linked_auxid);
694
695 // First try to find a compiled factory for the vector type:
696 if (auxid == SG::null_auxid) {
697
698 // Construct the name of the factory's class:
699 // But be careful --- if we don't exactly match the name
700 // in TClassTable, then we may trigger autoparsing. Besides the
701 // resource usage that implies, that can lead to crashes in dbg
702 // builds due to cling bugs.
703 std::string tn = Utils::getTypeName(*ti);
704 if (tn.starts_with("std::vector<")) {
705 tn.erase(0, 5);
706 }
707 std::string fac_class_name =
708 "SG::AuxTypeVectorFactory<" + tn + ",allocator<" + tn;
709 if (fac_class_name[fac_class_name.size() - 1] == '>') {
710 fac_class_name += ' ';
711 }
712 fac_class_name += "> >";
713
714 // Look for the dictionary of this type:
715 ::TClass* fac_class = TClass::GetClass(fac_class_name.c_str());
716 if (fac_class && fac_class->IsLoaded()) {
717 ::TClass* base_class = ::TClass::GetClass("SG::IAuxTypeVectorFactory");
718 if (base_class && base_class->IsLoaded()) {
719 const Int_t offs = fac_class->GetBaseClassOffset(base_class);
720 if (offs >= 0) {
721 void* fac_vp = fac_class->New();
722 if (fac_vp) {
723 unsigned long tmp =
724 reinterpret_cast<unsigned long>(fac_vp) + offs;
726 reinterpret_cast<SG::IAuxTypeVectorFactory*>(tmp);
727 registry.addFactory(
728 *ti, *fac->tiAlloc(),
729 std::unique_ptr<SG::IAuxTypeVectorFactory>(fac));
730 auxid = registry.getAuxID(*ti, std::string{auxName}, "", flags,
731 linked_auxid);
732 }
733 }
734 }
735 }
736 }
737
738 // If that didn't succeed, let's assign a generic factory to this type:
739 if (auxid == SG::null_auxid && linked_auxid == SG::null_auxid) {
740
741 // Construct the name of the vector type:
742 std::string vec_class_name = "std::vector<" + Utils::getTypeName(*ti);
743 if (vec_class_name[vec_class_name.size() - 1] == '>') {
744 vec_class_name += ' ';
745 }
746 vec_class_name += '>';
747
748 // Get the dictionary for the type:
749 ::TClass* vec_class = ::TClass::GetClass(vec_class_name.c_str());
750 if (vec_class && vec_class->IsLoaded()) {
751 auto fac = std::make_unique<TAuxVectorFactory>(vec_class);
752 if (fac->tiAlloc()) {
753 const std::type_info* tiAlloc = fac->tiAlloc();
754 registry.addFactory(*ti, *tiAlloc, std::move(fac));
755 } else {
756 std::string tiAllocName = fac->tiAllocName();
757 registry.addFactory(*ti, tiAllocName, std::move(fac));
758 }
759 auxid = registry.getAuxID(*ti, std::string{auxName}, "",
760 SG::AuxVarFlags::SkipNameCheck);
761 } else {
762 ::Warning("xAOD::TAuxStore::impl::setupAuxBranch",
763 "Couldn't find dictionary for type: %s",
764 vec_class_name.c_str());
765 }
766 }
767
768 // Check if we succeeded:
769 if (auxid == SG::null_auxid) {
770 if (linked_auxid != SG::null_auxid) {
771 ::Error("xAOD::TAuxStore::impl::setupAuxBranch",
772 XAOD_MESSAGE("Dynamic ROOT vector factory not implemented for "
773 "linked types; branch "
774 "\"%s\""),
775 br.GetName());
776 } else {
777 ::Error("xAOD::TAuxStore::impl::setupAuxBranch",
778 XAOD_MESSAGE("Couldn't assign auxiliary ID to branch "
779 "\"%s\""),
780 br.GetName());
781 }
782 return StatusCode::FAILURE;
783 }
784
785 // Remember the auxiliary ID:
786 m_data.m_auxIDs.insert(auxid);
787 return StatusCode::SUCCESS;
788 }
789
791 // cppcheck-suppress uninitMemberVarNoCtor
793
795 int m_basketSize = 2048;
798
800 ::TTree* m_inTree = nullptr;
802 ::TTree* m_outTree = nullptr;
803
805 bool m_inputScanned = false;
806
808 std::vector<std::unique_ptr<TBranchHandle> > m_branches;
810 std::vector<bool> m_branchesWritten;
813 std::vector<bool> m_missingBranches;
814
817};
818
819TAuxStore::TAuxStore(std::string_view prefix, bool topStore, EStructMode mode,
820 int basketSize, int splitLevel)
821 : details::AuxStoreBase(topStore, mode),
822 m_impl{std::make_unique<impl>(m_data, basketSize, splitLevel)} {
823
825}
826
827TAuxStore::~TAuxStore() = default;
828
829void TAuxStore::setPrefix(std::string_view prefix) {
830
831 m_data.m_prefix = prefix;
832 m_data.m_dynPrefix = Utils::dynBranchPrefix(m_data.m_prefix);
833 reset();
834}
835
837
838 assert(m_impl);
839 return m_impl->m_basketSize;
840}
841
843
844 assert(m_impl);
845 m_impl->m_basketSize = value;
846}
847
849
850 assert(m_impl);
851 return m_impl->m_splitLevel;
852}
853
855
856 assert(m_impl);
857 m_impl->m_splitLevel = value;
858}
859
865StatusCode TAuxStore::readFrom(::TTree& tree, bool printWarnings) {
866
867 assert(m_impl);
868
869 // Make sure that everything will be re-read after this:
870 reset();
871
872 // We will need to check again which branches are available:
873 m_impl->m_missingBranches.clear();
874
875 // Remember the tree:
876 m_impl->m_inTree = &tree;
877
878 // Catalogue all the branches:
879 RETURN_CHECK("xAOD::TAuxStore::readFrom", m_impl->scanInputTree());
880
881 // Check if we'll be likely to be able to read the "static"
882 // variables:
883 assert(m_impl->m_inTree != nullptr);
884 TBranch* br = m_impl->m_inTree->GetBranch(m_data.m_prefix.data());
885 if (br == nullptr) {
886 // We might not even have static branches, so this is not an error
887 // by itself...
888 return StatusCode::SUCCESS;
889 }
890 // In order to read complex objects, like smart pointers from an
891 // auxiliary container variable-by-variable, the split level of the
892 // branch must be exactly 1.
893 if ((br->GetSplitLevel() != 1) && m_data.m_topStore && printWarnings) {
894 ::Warning("xAOD::TAuxStore::readFrom",
895 "Static branch (%s) with split level %i discovered",
896 m_data.m_prefix.data(), br->GetSplitLevel());
897 ::Warning("xAOD::TAuxStore::readFrom",
898 "The reading of complex variables from it may/will fail!");
899 }
900
901 // Return gracefully.
902 return StatusCode::SUCCESS;
903}
904
910StatusCode TAuxStore::writeTo(::TTree& tree) {
911
912 assert(m_impl);
913
914 // Look for any auxiliary branches that have not been connected to yet:
915 RETURN_CHECK("xAOD::TAuxStore::writeTo", m_impl->scanInputTree());
916
917 // Store the TTree pointer:
918 m_impl->m_outTree = &tree;
919
920 // Create all the variables that we already know about. Notice that the
921 // code makes a copy of the auxid set on purpose. Because the underlying
922 // AuxSelection object gets modified while doing the for loop.
923 const SG::auxid_set_t selAuxIDs = getSelectedAuxIDs();
924 for (SG::auxid_t id : selAuxIDs) {
925 RETURN_CHECK("xAOD::TAuxStore::writeTo", setupOutputData(id));
926 }
927
928 // Return gracefully.
929 return StatusCode::SUCCESS;
930}
931
932int TAuxStore::getEntry(int getall) {
933
934 assert(m_impl);
935
936 // Guard against multi-threaded execution:
937 guard_t guard(m_impl->m_mutex);
938
939 // Reset the transient store. TEvent::fill() calls this function with
940 // getall==99. When that is happening, we need to keep the transient
941 // store still around. Since the user may want to interact with the
942 // object after it was written out. (And since TEvent::fill() asks for
943 // the transient decorations after calling getEntry(...).)
944 if (m_data.m_transientStore && (getall != 99)) {
945 // Remove the transient auxiliary IDs from the internal list:
946 m_data.m_auxIDs -= m_data.m_transientStore->getAuxIDs();
947 m_data.m_decorIDs -= m_data.m_transientStore->getDecorIDs();
948 // Delete the object:
949 m_data.m_transientStore.reset();
950 }
951
952 // Now remove the IDs of the decorations that are getting persistified:
953 if (getall != 99) {
954 for (SG::auxid_t auxid = 0; auxid < m_data.m_isDecoration.size(); ++auxid) {
955 if (!m_data.m_isDecoration[auxid]) {
956 continue;
957 }
958 m_data.m_auxIDs.erase(auxid);
959 m_data.m_decorIDs.erase(auxid);
960 }
961 }
962
963 // If we don't need everything loaded, return now:
964 if (!getall) {
965 return 0;
966 }
967
968 // Get all the variables at once:
969 int bytesRead = 0;
970 for (auto& branchHandle : m_impl->m_branches) {
971 if (branchHandle) {
972 bytesRead += branchHandle->getEntry();
973 }
974 }
975 return bytesRead;
976}
977
979
980 assert(m_impl);
981
982 for (auto& branchHandle : m_impl->m_branches) {
983 if (branchHandle) {
984 branchHandle->reset();
985 }
986 }
987 m_impl->m_inputScanned = false;
988}
989
991
992 assert(m_impl);
993 return ((m_impl->m_branches.size() > auxid) && m_impl->m_branches[auxid]);
994}
995
997
998 assert(m_impl);
999 assert(m_impl->m_branches.size() > auxid);
1000 assert(m_impl->m_branches[auxid]);
1001 const ::Int_t readBytes = m_impl->m_branches[auxid]->getEntry();
1002 if (readBytes < 0) {
1003 ::Error("xAOD::TAuxStore::getEntryFor",
1004 XAOD_MESSAGE("Couldn't read in variable %s"),
1005 SG::AuxTypeRegistry::instance().getName(auxid).c_str());
1006 return StatusCode::FAILURE;
1007 }
1008 return StatusCode::SUCCESS;
1009}
1010
1012
1013 assert(m_impl);
1014 return (m_impl->m_outTree != nullptr);
1015}
1016
1028
1029 assert(m_impl);
1030
1031 // Return right away if we already know that the branch is missing.
1032 if ((auxid < m_impl->m_missingBranches.size()) &&
1033 m_impl->m_missingBranches[auxid]) {
1034 return StatusCode::RECOVERABLE;
1035 }
1036
1037 // Make sure the internal storage is large enough:
1038 if (m_data.m_vecs.size() <= auxid) {
1039 m_data.m_vecs.resize(auxid + 1);
1040 }
1041 if (m_impl->m_branches.size() <= auxid) {
1042 m_impl->m_branches.resize(auxid + 1);
1043 }
1044
1045 // Check if we need to do anything:
1046 if (m_data.m_vecs[auxid] && m_impl->m_branches[auxid]) {
1047 return StatusCode::SUCCESS;
1048 }
1049
1050 // A little sanity check.
1051 if (m_impl->m_inTree == nullptr) {
1052 ::Error("xAOD::TAuxStore::setupInputData",
1053 XAOD_MESSAGE("No input TTree set up!"));
1054 return StatusCode::FAILURE;
1055 }
1056
1057 // Another sanity check.
1058 if (m_data.m_vecs[auxid] || m_impl->m_branches[auxid]) {
1059 ::Error("xAOD::TAuxStore::setupInputData",
1060 XAOD_MESSAGE("Internal logic error!"));
1061 return StatusCode::FAILURE;
1062 }
1063
1064 // Convenience access to the registry.
1066
1067 // Get the property name:
1068 const TString statBrName =
1069 std::format("{}{}", m_data.m_prefix, r.getName(auxid));
1070 const TString dynBrName =
1071 std::format("{}{}", m_data.m_dynPrefix, r.getName(auxid));
1072
1073 // Check if the branch exists:
1074 Bool_t staticBranch = true;
1075 TString brName = statBrName;
1076
1077 TBranch* br = m_impl->m_inTree->GetBranch(statBrName);
1078 if (!br) {
1079 br = m_impl->m_inTree->GetBranch(dynBrName);
1080 if (!br) {
1081 // Since TTree::GetBranch / TTObjArray::FindObject is expensive,
1082 // remember that we didn't find this branch in this file.
1083 if (m_impl->m_missingBranches.size() <= auxid) {
1084 m_impl->m_missingBranches.resize(auxid + 1);
1085 }
1086 m_impl->m_missingBranches[auxid] = true;
1087 // The branch doesn't exist, but this is not an error per se.
1088 // The user may just be calling isAvailable(...) on the variable.
1089 return StatusCode::RECOVERABLE;
1090 }
1091 // We have a dynamic branch:
1092 staticBranch = false;
1093 brName = dynBrName;
1094 }
1095
1096 // Check if it's a "primitive branch":
1097 const Bool_t primitiveBranch = isPrimitiveBranch(*br);
1098 // Check if it's a "container branch":
1099 const Bool_t containerBranch =
1100 (primitiveBranch ? false : isContainerBranch(*br, auxid));
1101
1102 // Set the structure mode if it has not been defined externally:
1103 if (m_data.m_structMode == EStructMode::kUndefinedStore) {
1104 m_data.m_structMode = (containerBranch ? EStructMode::kContainerStore
1106 }
1107
1108 // Check that the branch type makes sense:
1109 if ((containerBranch &&
1110 (m_data.m_structMode != EStructMode::kContainerStore) &&
1111 !r.isLinked(auxid)) ||
1112 ((!containerBranch) &&
1113 (m_data.m_structMode != EStructMode::kObjectStore))) {
1114 ::Error("xAOD::TAuxStore::setupInputData",
1115 XAOD_MESSAGE("Branch type and requested structure mode "
1116 "differ for branch: %s"),
1117 brName.Data());
1118 return StatusCode::FAILURE;
1119 }
1120
1121 // Check what variable it is:
1122 ::TClass* clDummy = 0;
1123 ::EDataType dType = kOther_t;
1124 if (br->GetExpectedType(clDummy, dType)) {
1125 ::Error("xAOD::TAuxStore::setupInputData",
1126 XAOD_MESSAGE("Couldn't determine the type of branch \"%s\""),
1127 brName.Data());
1128 return StatusCode::FAILURE;
1129 }
1130
1131 // Get the property type:
1132 const std::type_info* brType = 0;
1133 if (details::isRegisteredType(auxid)) {
1134 // Get the type from the auxiliary type registry:
1135 brType = (containerBranch ? r.getVecType(auxid) : r.getType(auxid));
1136 } else {
1137 // Get the type from the input branch itself:
1138 brType = (clDummy ? clDummy->GetTypeInfo() : &(Utils::getTypeInfo(dType)));
1139 }
1140 if (!brType) {
1141 ::Error("xAOD::TAuxStore::setupInputData",
1142 XAOD_MESSAGE("Can't read/copy variable %s (%s)"), brName.Data(),
1143 clDummy->GetName());
1144 return StatusCode::RECOVERABLE;
1145 }
1146 const TString brTypeName = Utils::getTypeName(*brType).c_str();
1147
1148 // Check if we have the needed dictionary for an object branch:
1149 ::TClass* brClass = 0;
1150 if (!primitiveBranch) {
1151 // Get the property's class:
1152 brClass = ::TClass::GetClass(*brType, true, true);
1153 if (!brClass) {
1154 brClass = ::TClass::GetClass(brTypeName);
1155 }
1156 if (!brClass) {
1157 ::Error("xAOD::TAuxStore::setupInputData",
1158 XAOD_MESSAGE("No dictionary available for class \"%s\""),
1159 brTypeName.Data());
1160 return StatusCode::FAILURE;
1161 }
1162 }
1163
1164 // Create the smart object holding this vector:
1165 if (details::isRegisteredType(auxid)) {
1166 m_data.m_vecs[auxid] = r.makeVector(auxid, (size_t)0, (size_t)0);
1167 if (!containerBranch) {
1168 m_data.m_vecs[auxid]->resize(1);
1169 }
1170 if (clDummy &&
1171 strncmp(clDummy->GetName(), "SG::PackedContainer<", 20) == 0) {
1172 std::unique_ptr<SG::IAuxTypeVector> packed =
1173 m_data.m_vecs[auxid]->toPacked();
1174 std::swap(m_data.m_vecs[auxid], packed);
1175 }
1176 } else {
1177 ::Error("xAOD::TAuxStore::setupInputData",
1178 XAOD_MESSAGE("Couldn't create in-memory vector for "
1179 "variable %s (%i)"),
1180 brName.Data(), static_cast<int>(auxid));
1181 return StatusCode::FAILURE;
1182 }
1183
1184 // Create a new branch handle:
1185 const std::type_info* objType = brType;
1186 if (containerBranch) {
1187 objType = m_data.m_vecs[auxid]->objType();
1188 if (!objType)
1189 objType = r.getType(auxid);
1190 }
1191 m_impl->m_branches[auxid] = std::make_unique<TBranchHandle>(
1192 staticBranch, primitiveBranch, objType,
1193 (containerBranch ? m_data.m_vecs[auxid]->toVector()
1194 : m_data.m_vecs[auxid]->toPtr()),
1195 auxid, m_data.m_prefix);
1196
1197 // Set the tree/branch in the "right mode":
1198 if (staticBranch) {
1199 br->SetMakeClass();
1200 }
1201
1202 // Connect to the branch:
1203 ::Int_t status = 0;
1204 if (clDummy && ::TString(clDummy->GetName()).Contains("basic_string<char>")) {
1205 // This is pretty much just a hack. As it happens, Athena I/O can
1206 // create dynamic branches that consider themselves to be of type
1207 // "vector<basic_string<char> >" and similar. (Instead of the
1208 // canonical "vector<string>" name.) When we encounter such a branch,
1209 // we just connect to it without performing any compatibility checks.
1210 // Since we don't need to apply any read rules in this case anyway.
1211 status = m_impl->m_inTree->SetBranchAddress(
1212 brName, m_impl->m_branches[auxid]->inputObjectPtr(),
1213 m_impl->m_branches[auxid]->branchPtr());
1214 } else {
1215 status = m_impl->m_inTree->SetBranchAddress(
1216 brName, m_impl->m_branches[auxid]->inputObjectPtr(),
1217 m_impl->m_branches[auxid]->branchPtr(), brClass, dType,
1218 ((!staticBranch) && (!primitiveBranch)));
1219 }
1220 if (status < 0) {
1221 ::Error("xAOD::TAuxStore::setupInputData",
1222 XAOD_MESSAGE("Coulnd't connect to branch \"%s\""), brName.Data());
1223 ::Error("xAOD::TAuxStore::setupInputData", XAOD_MESSAGE("Return code: %i"),
1224 status);
1225 m_data.m_vecs[auxid].reset();
1226 m_impl->m_branches[auxid].reset();
1227 return StatusCode::FAILURE;
1228 }
1229
1230 // Get the current entry:
1231 m_impl->m_branches[auxid]->getEntry();
1232
1233 // Remember which variable got created:
1234 m_data.m_auxIDs.insert(auxid);
1235
1236 // Check if we just replaced a generic object:
1237 if (details::isRegisteredType(auxid)) {
1238 // The name of the variable we just created:
1239 const std::string auxname = r.getName(auxid);
1240 // Check if there's another variable with this name already:
1241 for (SG::auxid_t i = 0; i < m_data.m_vecs.size(); ++i) {
1242 // Check if we have this aux ID:
1243 if (!m_data.m_vecs[i]) {
1244 continue;
1245 }
1246 // Ingore the object that we *just* created:
1247 if (i == auxid) {
1248 continue;
1249 }
1250 // The name of the variable:
1251 const std::string testname = r.getName(i);
1252 // Check if it has the same name:
1253 if (testname != auxname) {
1254 continue;
1255 }
1256 // Check that the other one is a non-registered type:
1258 ::Error("xAOD::TAuxStore::setupInputData",
1259 XAOD_MESSAGE("Internal logic error!"));
1260 continue;
1261 }
1262 // Okay, we do need to remove this object:
1263 m_data.m_vecs[i].reset();
1264 m_impl->m_branches[i].reset();
1265 m_data.m_auxIDs.erase(i);
1266 }
1267 }
1268
1269 SG::auxid_t linked_auxid = r.linkedVariable(auxid);
1270 if (linked_auxid != SG::null_auxid) {
1271 return setupInputData(linked_auxid);
1272 }
1273
1274 // Return gracefully.
1275 return StatusCode::SUCCESS;
1276}
1277
1288
1289 assert(m_impl);
1290
1291 // Check whether we need to do anything:
1292 if (!m_impl->m_outTree) {
1293 return StatusCode::SUCCESS;
1294 }
1295
1296 // Check if the variable needs to be written out:
1297 if (!isAuxIDSelected(auxid)) {
1298 return StatusCode::SUCCESS;
1299 }
1300
1301 // Make sure that containers are large enough:
1302 if (m_data.m_vecs.size() <= auxid) {
1303 m_data.m_vecs.resize(auxid + 1);
1304 }
1305 if (m_impl->m_branches.size() <= auxid) {
1306 m_impl->m_branches.resize(auxid + 1);
1307 }
1308 if (m_impl->m_branchesWritten.size() <= auxid) {
1309 m_impl->m_branchesWritten.resize(auxid + 1);
1310 }
1311
1312 // Check if this auxiliary variable is already in the output:
1313 if (m_impl->m_branchesWritten[auxid]) {
1314 return StatusCode::SUCCESS;
1315 }
1316
1317 // The registry:
1319
1320 // Check if the variable was put into the transient store as a
1321 // decoration, and now needs to be put into the output file:
1322 if ((!m_data.m_vecs[auxid]) && m_data.m_transientStore &&
1323 (m_data.m_transientStore->getAuxIDs().test(auxid))) {
1324
1325 // Get the variable from the transient store:
1326 const void* pptr = m_data.m_transientStore->getData(auxid);
1327 if (!pptr) {
1328 ::Fatal("xAOD::TAuxStore::setupOutputData",
1329 XAOD_MESSAGE("Internal logic error detected"));
1330 return StatusCode::FAILURE;
1331 }
1332
1333 // Create the new object:
1334 m_data.m_vecs[auxid] = reg.makeVector(auxid, m_data.m_size, m_data.m_size);
1335 void* ptr = m_data.m_vecs[auxid]->toPtr();
1336 if (!ptr) {
1337 ::Error("xAOD::TAuxStore::setupOutputData",
1338 XAOD_MESSAGE("Couldn't create decoration in memory "
1339 "for writing"));
1340 return StatusCode::FAILURE;
1341 }
1342
1343 // Get the type of this variable:
1344 const std::type_info* type = reg.getType(auxid);
1345 if (!type) {
1346 ::Error("xAOD::TAuxStore::setupOutputData",
1347 XAOD_MESSAGE("Couldn't get the type of transient "
1348 "variable %i"),
1349 static_cast<int>(auxid));
1350 return StatusCode::FAILURE;
1351 }
1352 // Now get the factory for this variable:
1353 const SG::IAuxTypeVectorFactory* factory = reg.getFactory(auxid);
1354 if (!factory) {
1355 ::Error("xAOD::TAuxStore::setupOutputData",
1356 XAOD_MESSAGE("No factory found for transient variable "
1357 "%i"),
1358 static_cast<int>(auxid));
1359 return StatusCode::FAILURE;
1360 }
1361
1362 // Mark it as a decoration already, otherwise the copy may fail.
1363 if (m_data.m_isDecoration.size() <= auxid) {
1364 m_data.m_isDecoration.resize(auxid + 1);
1365 }
1366 m_data.m_isDecoration[auxid] = true;
1367
1368 // Finally, do the copy:
1369 factory->copy(auxid, SG::AuxVectorInterface(*this), 0,
1370 SG::AuxVectorInterface(*m_data.m_transientStore), 0,
1371 m_data.m_size);
1372 }
1373
1374 // Check if we know about this variable to be on the input,
1375 // but haven't connected to it yet:
1376 if ((m_data.m_auxIDs.test(auxid)) && (!m_data.m_vecs[auxid]) &&
1377 (!m_impl->m_branches[auxid])) {
1378 RETURN_CHECK("xAOD::TAuxStore::setupOutputData", setupInputData(auxid));
1379 }
1380
1381 // Check that we know the store's type:
1382 if ((m_data.m_structMode != EStructMode::kContainerStore) &&
1383 (m_data.m_structMode != EStructMode::kObjectStore)) {
1384 ::Error("xAOD::TAuxStore::setupOutputData",
1385 XAOD_MESSAGE("Structure mode unknown for variable %s"),
1386 SG::AuxTypeRegistry::instance().getName(auxid).c_str());
1387 return StatusCode::FAILURE;
1388 }
1389
1390 // Check if the variable exists already in memory:
1391 if (!m_data.m_vecs[auxid]) {
1392 m_data.m_vecs[auxid] =
1393 SG::AuxTypeRegistry::instance().makeVector(auxid, (size_t)0, (size_t)0);
1394 if (m_data.m_structMode == EStructMode::kObjectStore) {
1395 m_data.m_vecs[auxid]->resize(1);
1396 }
1397 }
1398
1399 // Check if the branch handle exists already:
1400 if (!m_impl->m_branches[auxid]) {
1401 // Get the property type:
1402 const std::type_info* brType =
1403 (m_data.m_structMode == EStructMode::kContainerStore
1406 // Create the handle object:
1407 bool primitiveBranch = (strlen(brType->name()) == 1);
1408 m_impl->m_branches[auxid] = std::make_unique<TBranchHandle>(
1409 false, (strlen(brType->name()) == 1),
1410 (primitiveBranch ? brType : m_data.m_vecs[auxid]->objType()),
1411 (m_data.m_structMode == EStructMode::kObjectStore
1412 ? m_data.m_vecs[auxid]->toPtr()
1413 : m_data.m_vecs[auxid]->toVector()),
1414 auxid, m_data.m_prefix);
1415 }
1416
1417 // Construct a name for the branch:
1418 const TString brName =
1419 std::format("{}{}", m_data.m_dynPrefix,
1420 SG::AuxTypeRegistry::instance().getName(auxid));
1421
1422 // If the output branch exists already, assume that it was us making
1423 // it:
1424 ::TBranch* br = m_impl->m_outTree->GetBranch(brName);
1425 if (br) {
1426 // Apparently a branch that was already set up for copying as a basic
1427 // variable, now got accessed explicitly. So let's update the output
1428 // branch to point to this new location now.
1429 br->SetAddress(m_impl->m_branches[auxid]->outputObjectPtr());
1430 // Update the cache. Notice that the "write status" of the typeless
1431 // auxiliary ID is not turned off. But it shouldn't matter, as the
1432 // variable will not be accessed in a typeless way anymore.
1433 m_impl->m_branchesWritten[auxid] = true;
1434 // Return gracefully:
1435 return StatusCode::SUCCESS;
1436 }
1437
1438 // Check that we know the type of the branch:
1439 const std::type_info* brType = m_impl->m_branches[auxid]->typeInfo();
1440 if (!brType) {
1441 ::Error("xAOD::TAuxStore::setupOutputData",
1442 XAOD_MESSAGE("There's an internal logic error in the "
1443 "code"));
1444 return StatusCode::FAILURE;
1445 }
1446 const std::string brTypeName = Utils::getTypeName(*brType);
1447
1448 // Decide if this is a primitive branch:
1449 const Bool_t primitiveBranch = (strlen(brType->name()) == 1);
1450
1451 // Let's create the branch now:
1452 if (primitiveBranch) {
1453
1454 // Get the "ROOT type" belonging to this primitive:
1455 const char rootType = Utils::rootType(brType->name()[0]);
1456 if (rootType == '\0') {
1457 ::Error("xAOD::TAuxStore::setupOutputData",
1458 XAOD_MESSAGE("Type not known for variable \"%s\" "
1459 "of type \"%s\""),
1460 brName.Data(), brTypeName.c_str());
1461 return StatusCode::FAILURE;
1462 }
1463
1464 // Construct the type description:
1465 std::ostringstream typeDesc;
1466 typeDesc << brName << "/" << rootType;
1467
1468 // Create the branch:
1469 br = m_impl->m_outTree->Branch(
1470 brName, m_impl->m_branches[auxid]->outputObjectPtr(),
1471 typeDesc.str().c_str(), m_impl->m_basketSize);
1472
1473 } else {
1474
1475 // Access the dictionary for the type:
1476 TClass* cl = TClass::GetClass(*brType);
1477 if (!cl) {
1478 cl = TClass::GetClass(brTypeName.c_str());
1479 }
1480 if (!cl) {
1481 ::Error("xAOD::TAuxStore::setupOutputData",
1482 XAOD_MESSAGE("Couldn't find dictionary for type: %s"),
1483 brTypeName.c_str());
1484 return StatusCode::FAILURE;
1485 }
1486 if (!cl->GetStreamerInfo()) {
1487 ::Error("xAOD::TAuxStore::setupOutputData",
1488 XAOD_MESSAGE("No streamer info available for type %s"),
1489 cl->GetName());
1490 return StatusCode::FAILURE;
1491 }
1492
1493 // Create the branch:
1494 br = m_impl->m_outTree->Branch(brName, cl->GetName(),
1495 m_impl->m_branches[auxid]->outputObjectPtr(),
1496 m_impl->m_basketSize, m_impl->m_splitLevel);
1497 }
1498
1499 // Check if we succeeded:
1500 if (!br) {
1501 ::Error("xAOD::TAuxStore::setupOutputData",
1502 XAOD_MESSAGE("Failed creating branch \"%s\" of type "
1503 "\"%s\""),
1504 brName.Data(), brTypeName.c_str());
1505 return StatusCode::FAILURE;
1506 }
1507
1508 // If this is not the first event, fill up the branch with dummy
1509 // info:
1510 for (Long64_t i = 0; i < m_impl->m_outTree->GetEntries(); ++i) {
1511 br->Fill();
1512 }
1513
1514 // Update the cache:
1515 m_impl->m_branchesWritten[auxid] = true;
1516
1517 // Also, remember that we now handle this variable:
1518 m_data.m_auxIDs.insert(auxid);
1519
1520 // We were successful:
1521 return StatusCode::SUCCESS;
1522}
1523
1524const void* TAuxStore::getInputObject(SG::auxid_t auxid) const {
1525
1526 assert(m_impl);
1527 assert(m_impl->m_branches.size() > auxid);
1528 assert(m_impl->m_branches[auxid]);
1529 return m_impl->m_branches[auxid]->objectPtr();
1530}
1531
1532const std::type_info* TAuxStore::getInputType(SG::auxid_t auxid) const {
1533
1534 assert(m_impl);
1535 assert(m_impl->m_branches.size() > auxid);
1536 assert(m_impl->m_branches[auxid]);
1537 return m_impl->m_branches[auxid]->typeInfo();
1538}
1539
1540} // namespace xAOD
An auxiliary data store that holds data internally.
Handle mappings between names and auxid_t.
Make an AuxVectorData object from either a raw vector or an aux store.
Exceptions that can be thrown from AthContainers.
#define XAOD_MESSAGE(MESSAGE)
Simple macro for printing error/verbose messages.
#define RETURN_CHECK(CONTEXT, EXP)
Helper macro for checking return codes in a compact form in the code.
Definition ReturnCheck.h:26
Helper for getting a const version of a pointer.
Define macros for attributes used to control the static checker.
Handle mappings between names and auxid_t.
const std::type_info * getType(SG::auxid_t auxid) const
Return the type of an aux data item.
SG::auxid_t getAuxID(const std::string &name, const std::string &clsname="", const Flags flags=Flags::None, const SG::auxid_t linkedVariable=SG::null_auxid)
Look up a name -> auxid_t mapping.
SG::auxid_t findAuxID(const std::string &name, const std::string &clsname="") const
Look up a name -> auxid_t mapping.
static bool isLinkedName(const std::string &name)
Test if a variable name corresponds to a linked variable.
static std::string linkedName(const std::string &name)
Given a variable name, return the name of the corresponding linked variable.
const std::type_info * getVecType(SG::auxid_t auxid) const
Return the type of the STL vector used to hold an aux data item.
static bool classNameHasLink(const std::string &className)
Test to see if a class name corresponds to a class with a linked variable.
static AuxTypeRegistry & instance()
Return the singleton registry instance.
const IAuxTypeVectorFactory * addFactory(const std::type_info &ti, const std::type_info &ti_alloc, std::unique_ptr< const IAuxTypeVectorFactory > factory)
Add a new type -> factory mapping.
std::unique_ptr< IAuxTypeVector > makeVector(SG::auxid_t auxid, size_t size, size_t capacity) const
Construct a new vector to hold an aux item.
Make an AuxVectorData object from either a raw array or an aux store.
Interface for factory objects that create vectors.
virtual const std::type_info * tiAlloc() const =0
Return the type_info of the vector allocator.
virtual void copy(SG::auxid_t auxid, AuxVectorData &dst, size_t dst_index, const AuxVectorData &src, size_t src_index, size_t n) const =0
Copy elements between vectors.
A set of aux data identifiers.
Definition AuxTypes.h:47
ReadStats & stats()
Access the object belonging to the current thread.
Definition IOStats.cxx:17
static IOStats & instance()
Singleton object accessor.
Definition IOStats.cxx:11
void readBranch(const std::string &prefix, SG::auxid_t auxid)
Function incrementing the read counter on a specific branch.
int getEntry(int getall=0)
Read the values from the TTree entry that was loaded with TTree::LoadTree().
virtual ~TAuxStore()
Destructor.
virtual const std::type_info * getInputType(SG::auxid_t auxid) const override
Get the type of an input object, for getIOType().
virtual void reset() override
Tell the object that all branches will need to be re-read.
virtual bool hasEntryFor(SG::auxid_t auxid) const override
Check if a given variable is available from the input.
virtual bool hasOutput() const override
Check if an output is being written by the object.
void setSplitLevel(int value)
Set the split level of the output branches.
TAuxStore(std::string_view prefix="", bool topStore=true, EStructMode mode=EStructMode::kUndefinedStore, int basketSize=2048, int splitLevel=0)
Constructor.
virtual StatusCode setupInputData(SG::auxid_t auxid) override
Connect a variable to the input.
StatusCode readFrom(::TTree &tree, bool printWarnings=true)
Connect the object to an input TTree.
int splitLevel() const
Get the split level of the output branches.
virtual StatusCode setupOutputData(SG::auxid_t auxid) override
Connect a variable to the output.
virtual void setPrefix(std::string_view prefix) override
Set the object name prefix.
StatusCode writeTo(::TTree &tree)
Connect the object to an output TTree.
virtual StatusCode getEntryFor(SG::auxid_t auxid) override
Load a single variable from the input.
std::unique_ptr< impl > m_impl
Pointer to the internal object.
Definition TAuxStore.h:91
void setBasketSize(int value)
Set the size of the baskets created for the output branches.
int basketSize() const
Get the size of the baskets created for the output branches.
virtual const void * getInputObject(SG::auxid_t auxid) const override
Get a pointer to an input object, as it is in memory, for getIOData().
const std::string & prefix() const
Get the currently configured object name prefix.
bool isAuxIDSelected(SG::auxid_t auxid) const
Check if an auxiliary variable is selected for ouput writing.
virtual SG::auxid_set_t getSelectedAuxIDs() const override
Get the IDs of the selected aux variables.
AthContainers_detail::mutex mutex_t
Mutex type for multithread synchronization.
EStructMode
"Structural" modes of the object
@ kUndefinedStore
The structure mode is not defined.
@ kObjectStore
The object describes a single object.
@ kContainerStore
The object describes an entire container.
AuxStoreBase(bool topStore=true, EStructMode mode=EStructMode::kUndefinedStore)
Constructor.
Members m_data
Member variables of the base class.
AthContainers_detail::lock_guard< mutex_t > guard_t
Guard type for multithreaded synchronisation.
int r
Definition globals.cxx:22
Error
The different types of error that can be flagged in the L1TopoRDO.
Definition Error.h:16
AuxVarFlags
Additional flags to qualify an auxiliary variable.
Definition AuxTypes.h:58
static const auxid_t null_auxid
To signal no aux data item.
Definition AuxTypes.h:30
SG::auxid_t auxid() const
Return the aux id for this variable.
virtual void reset() override
Free all allocated elements.
size_t auxid_t
Identifier for a particular aux data item.
Definition AuxTypes.h:27
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
STL namespace.
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
const std::type_info & getTypeInfo(EDataType type)
This function is used when reading a primitive branch from an input file without the user explicitly ...
std::string dynBranchPrefix(const std::string &key)
This function is used to figure out what to name dynamic auxiliary branches coming from a container c...
char rootType(char typeidType)
This function is used internally in the code when creating primitive dynamic auxiliary branches.
std::string getTypeName(const std::type_info &ti)
This function is necessary in order to create type names that ROOT can understand.
TClass * lookupVectorType(TClass &cl)
Internal function used by xAOD::TAuxStore and xAOD::RAuxStore.
bool isRegisteredType(SG::auxid_t auxid)
Check if the auxiliary variable has a registered type.
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
int m_basketSize
The basket size for the output branches.
Members & m_data
Variables coming from AuxStoreBase.
StatusCode setupAuxBranch(::TBranch &br, std::string_view auxName, bool staticBranch)
Register one input branch as an available auxiliary variable.
std::vector< bool > m_branchesWritten
"Write status" of the different variables
std::vector< bool > m_missingBranches
Mark branches we've found to be missing.
StatusCode scanInputTree()
Scan the input TTree for auxiliary branches.
::TTree * m_inTree
The TTree being read from.
std::vector< std::unique_ptr< TBranchHandle > > m_branches
Branches reading the various auxiliary variables.
mutex_t m_mutex
Mutex object used for multithreaded synchronisation.
const std::type_info * auxBranchType(::TBranch &br, std::string_view auxName, bool staticBranch, std::string *expectedClassName=nullptr)
Find the type_info to use as the aux type for a given branch.
bool m_inputScanned
"Scan status" of the input TTree
::TTree * m_outTree
The TTree being written to.
int m_splitLevel
The split level for the output branches.
Struct collecting all member variables of this base class.
TChain * tree