Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 09:18:10

0001 
0002 // Copyright 2020, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 
0005 #pragma once
0006 
0007 #include <JANA/JObject.h>
0008 #include <JANA/JException.h>
0009 #include <JANA/JFactoryT.h>
0010 #include <JANA/JFactorySet.h>
0011 #include <JANA/JLogger.h>
0012 #include <JANA/JVersion.h>
0013 
0014 #include <JANA/Components/JLightweightDatabundle.h>
0015 #if JANA2_HAVE_PODIO
0016 #include <JANA/Components/JPodioDatabundle.h>
0017 #endif
0018 
0019 #include <JANA/Utils/JEventLevel.h>
0020 #include <JANA/Utils/JTypeInfo.h>
0021 #include <JANA/Utils/JCpuInfo.h>
0022 #include <JANA/Utils/JCallGraphRecorder.h>
0023 #include <JANA/Utils/JCallGraphEntryMaker.h>
0024 #include <JANA/Utils/JInspector.h>
0025 
0026 #include <typeindex>
0027 #include <cstdint>
0028 #include <vector>
0029 #include <memory>
0030 #include <atomic>
0031 
0032 
0033 class JApplication;
0034 class JEventSource;
0035 
0036 
0037 class JEvent : public std::enable_shared_from_this<JEvent> {
0038 
0039 private:
0040     JApplication* mApplication = nullptr;
0041     int32_t mRunNumber = 0;
0042     uint64_t mEventNumber = 0;
0043     mutable JFactorySet mFactorySet;
0044     mutable JCallGraphRecorder mCallGraph;
0045     mutable JInspector mInspector;
0046     mutable std::string mEventStamp;
0047     bool mUseDefaultTags = false;
0048     std::map<std::string, std::string> mDefaultTags;
0049     JEventSource* mEventSource = nullptr;
0050     bool mIsBarrierEvent = false;
0051     bool mIsWarmedUp = false;
0052 
0053     // Hierarchical event memory management
0054     std::vector<std::pair<JEventLevel, std::pair<JEvent*, uint64_t>>> mParents;
0055     std::atomic_int mReferenceCount {0};
0056     int64_t mEventIndex = -1;
0057 
0058     void MakeEventStamp() const;
0059 
0060 public:
0061     JEvent();
0062     explicit JEvent(JApplication* app);
0063     virtual ~JEvent();
0064 
0065     void SetRunNumber(int32_t aRunNumber){mRunNumber = aRunNumber; MakeEventStamp(); }
0066     void SetEventNumber(uint64_t aEventNumber){mEventNumber = aEventNumber; MakeEventStamp(); }
0067     void SetJApplication(JApplication* app){mApplication = app;}
0068     void SetJEventSource(JEventSource* aSource){mEventSource = aSource;}
0069     void SetDefaultTags(std::map<std::string, std::string> aDefaultTags){mDefaultTags=aDefaultTags; mUseDefaultTags = !mDefaultTags.empty();}
0070     void SetSequential(bool isSequential) {mIsBarrierEvent = isSequential;}
0071 
0072     JFactorySet* GetFactorySet() const { return &mFactorySet; }
0073     int32_t GetRunNumber() const {return mRunNumber;}
0074     uint64_t GetEventNumber() const {return mEventNumber;}
0075     JApplication* GetJApplication() const {return mApplication;}
0076     JEventSource* GetJEventSource() const {return mEventSource; }
0077     JCallGraphRecorder* GetJCallGraphRecorder() const {return &mCallGraph;}
0078     JInspector* GetJInspector() const {return &mInspector;}
0079     void Inspect() const { mInspector.Loop();}
0080     bool GetSequential() const {return mIsBarrierEvent;}
0081     bool IsWarmedUp() { return mIsWarmedUp; }
0082 
0083     // Hierarchical
0084     JEventLevel GetLevel() const { return mFactorySet.GetLevel(); }
0085     void SetLevel(JEventLevel level) { mFactorySet.SetLevel(level); }
0086     void SetEventIndex(int event_index) { mEventIndex = event_index; }
0087     int64_t GetEventIndex() const { return mEventIndex; }
0088     const std::string& GetEventStamp() const;
0089 
0090     bool HasParent(JEventLevel level) const;
0091     const JEvent& GetParent(JEventLevel level) const;
0092     void SetParent(JEvent* parent);
0093     JEvent* ReleaseParent(JEventLevel level);
0094     std::vector<JEvent*> ReleaseAllParents();
0095     int GetChildCount();
0096     uint64_t GetParentNumber(JEventLevel level) const;
0097     void SetParentNumber(JEventLevel level, uint64_t number);
0098 
0099     void TakeRefToSelf();
0100     int ReleaseRefToSelf();
0101 
0102     // Lifecycle
0103     void Clear(bool processed_successfully=true);
0104     void Finish();
0105 
0106     JFactory* GetFactory(const std::string& object_name, const std::string& tag) const;
0107     std::vector<JFactory*> GetAllFactories() const;
0108 
0109 
0110     template<class T> JFactoryT<T>* GetFactory(const std::string& tag = "", bool throw_on_missing=false) const;
0111     template<class T> JLightweightDatabundleT<T>* GetLightweightDatabundle(const std::string& tag, bool throw_on_missing, bool call_factory_create) const;
0112     template<class T> std::vector<JFactoryT<T>*> GetFactoryAll(bool throw_on_missing = false) const;
0113 
0114     // C style getters
0115     template<class T> JFactoryT<T>* GetSingle(const T* &t, const char *tag="", bool exception_if_not_one=true) const;
0116     template<class T> JFactoryT<T>* Get(const T** item, const std::string& tag="") const;
0117     template<class T> JFactoryT<T>* Get(std::vector<const T*> &vec, const std::string& tag = "", bool strict=true) const;
0118     template<class T> void GetAll(std::vector<const T*> &vec) const;
0119 
0120     // C++ style getters
0121     template<class T> const T* GetSingle(const std::string& tag = "") const;
0122     template<class T> const T* GetSingleStrict(const std::string& tag = "") const;
0123     template<class T> std::vector<const T*> Get(const std::string& tag = "", bool strict=true) const;
0124     template<class T> typename JFactoryT<T>::PairType GetIterators(const std::string& aTag = "") const;
0125     template<class T> std::vector<const T*> GetAll() const;
0126     template<class T> std::map<std::pair<std::string,std::string>,std::vector<T*>> GetAllChildren() const;
0127 
0128     // Insert
0129     template <class T> JFactoryT<T>* Insert(T* item, const std::string& aTag = "") const;
0130     template <class T> JFactoryT<T>* Insert(const std::vector<T*>& items, const std::string& tag = "") const;
0131 
0132     // PODIO
0133 #if JANA2_HAVE_PODIO
0134     std::vector<std::string> GetAllCollectionNames() const;
0135     const podio::CollectionBase* GetCollectionBase(std::string name, bool throw_on_missing=true) const;
0136     template <typename T> const typename T::collection_type* GetCollection(std::string name, bool throw_on_missing=true) const;
0137     template <typename T> void InsertCollection(typename T::collection_type&& collection, std::string name);
0138     template <typename T> void InsertCollectionAlreadyInFrame(const podio::CollectionBase* collection, std::string name);
0139 #endif
0140 
0141 
0142 };
0143 
0144 
0145 /// GetFactory() should be used with extreme care because it subverts the JEvent abstraction.
0146 /// Most historical uses of GetFactory are far better served by JMultifactory.
0147 template<class T>
0148 inline JFactoryT<T>* JEvent::GetFactory(const std::string& tag, bool throw_on_missing) const
0149 {
0150     std::string resolved_tag = tag;
0151     if (mUseDefaultTags && tag.empty()) {
0152         auto defaultTag = mDefaultTags.find(JTypeInfo::demangle<T>());
0153         if (defaultTag != mDefaultTags.end()) resolved_tag = defaultTag->second;
0154     }
0155     auto* databundle = mFactorySet.GetDatabundle(std::type_index(typeid(T)), resolved_tag);
0156     if (databundle == nullptr) {
0157         if (throw_on_missing) {
0158             JException ex("Could not find databundle with type_index=" + JTypeInfo::demangle<T>() + " and tag=" + tag);
0159             ex.show_stacktrace = false;
0160             mFactorySet.Print();
0161             throw ex;
0162         }
0163         return nullptr;
0164     };
0165     auto* factory = databundle->GetFactory();
0166     if (factory == nullptr) {
0167         if (throw_on_missing) {
0168             JException ex("No factory provided for databundle with type_index=" + JTypeInfo::demangle<T>() + " and tag=" + tag);
0169             ex.show_stacktrace = false;
0170             mFactorySet.Print();
0171             throw ex;
0172         }
0173         return nullptr;
0174     };
0175     auto* typed_factory = dynamic_cast<JFactoryT<T>*>(databundle->GetFactory());
0176     if (typed_factory == nullptr) {
0177         if (throw_on_missing) {
0178             JException ex("Factory does not inherit from JFactoryT<T> for databundle with type_index=" + JTypeInfo::demangle<T>() + " and tag=" + tag);
0179             ex.show_stacktrace = false;
0180             mFactorySet.Print();
0181             throw ex;
0182         }
0183         return nullptr;
0184     };
0185     return typed_factory;
0186 }
0187 
0188 template<class T>
0189 JLightweightDatabundleT<T>* JEvent::GetLightweightDatabundle(const std::string& tag, bool throw_on_missing, bool call_factory_create) const {
0190     std::string resolved_tag = tag;
0191     if (mUseDefaultTags && tag.empty()) {
0192         auto defaultTag = mDefaultTags.find(JTypeInfo::demangle<T>());
0193         if (defaultTag != mDefaultTags.end()) resolved_tag = defaultTag->second;
0194     }
0195     auto* databundle = mFactorySet.GetDatabundle(std::type_index(typeid(T)), resolved_tag);
0196     if (databundle == nullptr) {
0197         if (throw_on_missing) {
0198             JException ex("Could not find databundle with type_index=" + JTypeInfo::demangle<T>() + " and tag=" + tag);
0199             ex.show_stacktrace = false;
0200             mFactorySet.Print();
0201             throw ex;
0202         }
0203         return nullptr;
0204     };
0205     auto* typed_databundle = dynamic_cast<JLightweightDatabundleT<T>*>(databundle);
0206     if (typed_databundle == nullptr) {
0207         if (throw_on_missing) {
0208             JException ex("Databundle with shortname '%s' does not inherit from JLightweightDatabundleT<%s>", tag.c_str(), JTypeInfo::demangle<T>().c_str());
0209             ex.show_stacktrace = false;
0210             mFactorySet.Print();
0211             throw ex;
0212         }
0213         return nullptr;
0214     }
0215     auto factory = databundle->GetFactory();
0216     if (call_factory_create && factory != nullptr) {
0217         // Always call JFactory::Create if we have it, because REGENERATE and GetObjects logic is extremely complex and might override databundle contents
0218         JCallGraphEntryMaker cg_entry(mCallGraph, factory); // times execution until this goes out of scope
0219         factory->Create(*this);
0220     }
0221     return typed_databundle;
0222 }
0223 
0224 
0225 /// GetFactoryAll returns all JFactoryT's for type T (each corresponds to a different tag).
0226 /// This is useful when there are many different tags, or the tags are unknown, and the user
0227 /// wishes to examine them all together.
0228 template<class T>
0229 inline std::vector<JFactoryT<T>*> JEvent::GetFactoryAll(bool throw_on_missing) const {
0230     std::vector<JFactoryT<T>*> factories;
0231     for (auto* factory : mFactorySet.GetAllFactories()) {
0232         auto typed_factory = dynamic_cast<JFactoryT<T>*>(factory);
0233         if (typed_factory != nullptr) {
0234             factories.push_back(typed_factory);
0235         }
0236     }
0237     if (factories.size() == 0) {
0238         if (throw_on_missing) {
0239             JException ex("Could not find any JFactoryT<" + JTypeInfo::demangle<T>() + "> (from any tag)");
0240             throw ex;
0241         }
0242     };
0243     return factories;
0244 }
0245 
0246 
0247 /// C-style getters
0248 
0249 template<class T>
0250 JFactoryT<T>* JEvent::GetSingle(const T* &t, const char *tag, bool exception_if_not_one) const {
0251     /// This is a convenience method that can be used to get a pointer to the single
0252     /// object of type T from the specified factory. It simply calls the Get(vector<...>) method
0253     /// and copies the first pointer into "t" (or NULL if something other than 1 object is returned).
0254     ///
0255     /// This is intended to address the common situation in which there is an interest
0256     /// in the event if and only if there is exactly 1 object of type T. If the event
0257     /// has no objects of that type or more than 1 object of that type (for the specified
0258     /// factory) then an exception of type "unsigned long" is thrown with the value
0259     /// being the number of objects of type T. You can supress the exception by setting
0260     /// exception_if_not_one to false. In that case, you will have to check if t==NULL to
0261     /// know if the call succeeded.
0262 
0263     auto* databundle = GetLightweightDatabundle<T>(tag, true, true); // throw exception if databundle not found
0264     if (databundle->GetSize() != 1) {
0265         t = nullptr;
0266         if (exception_if_not_one) {
0267             throw JException("GetSingle<%s>: Databundle has wrong number of items: 1 expected, %d found.", JTypeInfo::demangle<T>().c_str(), databundle->GetSize());
0268         }
0269     }
0270     else {
0271         t = databundle->GetData().at(0);
0272     }
0273     return dynamic_cast<JFactoryT<T>*>(databundle->GetFactory());
0274 }
0275 
0276 /// Get conveniently returns one item from inside the JFactory. This should be used when the data in question
0277 /// is optional and the caller wants to examine the result and decide how to proceed. The caller should embed this
0278 /// inside an if-block. Get updates the `destination` out parameter and returns a pointer to the enclosing JFactory.
0279 /// - If the factory is missing, GetSingle throws an exception.
0280 /// - If the factory exists but contains no items, GetSingle updates the `destination` to point to nullptr.
0281 /// - If the factory contains exactly one item, GetSingle updates the `destination` to point to that item.
0282 /// - If the factory contains more than one item, GetSingle updates the `destination` to point to the first time.
0283 template<class T>
0284 JFactoryT<T>* JEvent::Get(const T** destination, const std::string& tag) const {
0285     auto* databundle = GetLightweightDatabundle<T>(tag, true, true); // throw exception if databundle not found
0286     if (databundle->GetSize() == 0) {
0287         *destination = nullptr;
0288     }
0289     else {
0290         *destination = databundle->GetData().at(0);
0291     }
0292     return dynamic_cast<JFactoryT<T>*>(databundle->GetFactory());
0293 }
0294 
0295 
0296 template<class T>
0297 JFactoryT<T>* JEvent::Get(std::vector<const T*>& destination, const std::string& tag, bool strict) const
0298 {
0299     auto* databundle = GetLightweightDatabundle<T>(tag, strict, true); // throw exception if databundle not found
0300     if (databundle != nullptr) {
0301         for (auto* item : databundle->GetData()) {
0302             destination.push_back(item);
0303         }
0304     }
0305     return dynamic_cast<JFactoryT<T>*>(databundle->GetFactory());
0306 }
0307 
0308 
0309 /// GetAll returns all JObjects of (child) type T, regardless of tag.
0310 template<class T>
0311 void JEvent::GetAll(std::vector<const T*>& destination) const {
0312     auto factories = GetFactoryAll<T>(true);
0313     for (auto factory : factories) {
0314         auto iterators = factory->CreateAndGetData(*this);
0315         for (auto it = iterators.first; it != iterators.second; it++) {
0316             destination.push_back(*it);
0317         }
0318     }
0319 }
0320 
0321 
0322 
0323 /// C++ style getters
0324 
0325 /// GetSingle conveniently returns one item from inside the JFactory. This should be used when the data in question
0326 /// is optional and the caller wants to examine the result and decide how to proceed. The caller should embed this
0327 /// inside an if-block.
0328 /// - If the factory is missing, GetSingle throws an exception
0329 /// - If the factory exists but contains no items, GetSingle returns nullptr
0330 /// - If the factory contains more than one item, GetSingle returns the first item
0331 
0332 template<class T> const T* JEvent::GetSingle(const std::string& tag) const {
0333 
0334     auto databundle = GetLightweightDatabundle<T>(tag, true, true); // Excepts rather than returns nullptr
0335     if (databundle->GetSize() == 0) {
0336         return nullptr;
0337     }
0338     return databundle->GetData().at(0);
0339 }
0340 
0341 
0342 
0343 /// GetSingleStrict conveniently returns one item from inside the JFactory. This should be used when the data in
0344 /// question is mandatory, and its absence indicates an error which should stop execution. The caller does not need
0345 /// to embed this in an if- or try-catch block; it can be a one-liner.
0346 /// - If the factory is missing, GetSingleStrict throws an exception
0347 /// - If the factory exists but contains no items, GetSingleStrict throws an exception
0348 /// - If the factory contains more than one item, GetSingleStrict throws an exception
0349 template<class T> const T* JEvent::GetSingleStrict(const std::string& tag) const {
0350 
0351     auto databundle = GetLightweightDatabundle<T>(tag, true, true); // Excepts rather than returns nullptr
0352     if (databundle->GetSize() == 0) {
0353         JException ex("GetSingle failed due to missing %d", NAME_OF(T));
0354         ex.show_stacktrace = false;
0355         throw ex;
0356         return nullptr;
0357     }
0358     else if (databundle->GetSize() > 1) {
0359         JException ex("GetSingle failed due to too many %d", NAME_OF(T));
0360         ex.show_stacktrace = false;
0361         throw ex;
0362     }
0363     return databundle->GetData().at(0);
0364 }
0365 
0366 template<class T>
0367 std::vector<const T*> JEvent::Get(const std::string& tag, bool strict) const {
0368 
0369     auto databundle = GetLightweightDatabundle<T>(tag, strict, true);
0370     std::vector<const T*> vec;
0371     if (databundle != nullptr) { // databundle might be nullptr if strict=false
0372         for (auto x: databundle->GetData()) {
0373             vec.push_back(x);
0374         }
0375     }
0376     return vec;
0377 }
0378 
0379 template<class T>
0380 typename JFactoryT<T>::PairType JEvent::GetIterators(const std::string& tag) const {
0381 
0382     auto databundle = GetLightweightDatabundle<T>(tag, true, true);
0383     auto& data = databundle->GetData();
0384     return std::make_pair(data.cbegin(), data.cend());
0385 }
0386 
0387 /// GetAll returns all JObjects of (child) type T, regardless of tag.
0388 template<class T>
0389 std::vector<const T*> JEvent::GetAll() const {
0390 
0391     std::vector<const T*> results;
0392 
0393     for (auto databundle : mFactorySet.GetDatabundles(std::type_index(typeid(T)))) {
0394         auto fac = databundle->GetFactory();
0395         if (fac != nullptr) {
0396             fac->Create(*this);
0397         }
0398         auto typed_databundle = dynamic_cast<JLightweightDatabundleT<T>*>(databundle);
0399         if (typed_databundle != nullptr) {
0400             for (auto* item : typed_databundle->GetData()) {
0401                 results.push_back(item);
0402             }
0403         }
0404     }
0405     return results;
0406 }
0407 
0408 // GetAllChildren will furnish a map { (type_name,tag_name) : [BaseClass*] } containing all JFactoryT<T> data where
0409 // T inherits from BaseClass. Note that this _won't_ compute any results (unlike GetAll) because this is meant for
0410 // things like visualizing and persisting DSTs.
0411 // TODO: This is conceptually inconsistent with GetAll. Reconcile.
0412 
0413 template<class S>
0414 std::map<std::pair<std::string, std::string>, std::vector<S*>> JEvent::GetAllChildren() const {
0415     std::map<std::pair<std::string, std::string>, std::vector<S*>> results;
0416     for (JFactory* factory : mFactorySet.GetAllFactories()) {
0417         auto val = factory->GetAs<S>();
0418         if (!val.empty()) {
0419             auto key = std::make_pair(factory->GetObjectName(), factory->GetTag());
0420             results.insert(std::make_pair(key, val));
0421         }
0422     }
0423     return results;
0424 }
0425 
0426 
0427 
0428 /// Insert() allows an EventSource to insert items directly into the JEvent,
0429 /// removing the need for user-extended JEvents and/or JEventSource::GetObjects(...)
0430 /// Repeated calls to Insert() will append to the previous data rather than overwrite it,
0431 /// which saves the user from having to allocate a throwaway vector and requires less error handling.
0432 template <class T>
0433 inline JFactoryT<T>* JEvent::Insert(T* item, const std::string& tag) const {
0434 
0435     auto* databundle = GetLightweightDatabundle<T>(tag, false, false);
0436 
0437     if (databundle == nullptr) {
0438         auto* factory = new JFactoryT<T>;
0439         factory->SetTag(tag);
0440         factory->SetLevel(mFactorySet.GetLevel());
0441         mFactorySet.Add(factory);
0442         databundle = GetLightweightDatabundle<T>(tag, false, false);
0443     }
0444 
0445     databundle->SetStatus(JDatabundle::Status::Inserted);
0446     databundle->GetData().push_back(item);
0447 
0448     auto* factory = databundle->GetFactory();
0449     if (factory != nullptr) {
0450         factory->SetStatus(JFactory::Status::Inserted); // for when items is empty
0451         factory->SetCreationStatus(JFactory::CreationStatus::Inserted); // for when items is empty
0452         factory->SetInsertOrigin( mCallGraph.GetInsertDataOrigin() ); // (see note at top of JCallGraphRecorder.h)
0453         return dynamic_cast<JFactoryT<T>*>(factory);
0454     }
0455     throw JException("Attempted to call JEvent::Insert without an underlying JFactoryT. Hint: Did you previously use Output<T>?");
0456     // TODO: Have Insert() return the databundle instead of the factory
0457 }
0458 
0459 template <class T>
0460 inline JFactoryT<T>* JEvent::Insert(const std::vector<T*>& items, const std::string& tag) const {
0461 
0462     auto* databundle = GetLightweightDatabundle<T>(tag, false, false);
0463 
0464     if (databundle == nullptr) {
0465         auto* factory = new JFactoryT<T>;
0466         factory->SetTag(tag);
0467         factory->SetLevel(mFactorySet.GetLevel());
0468         mFactorySet.Add(factory);
0469         databundle = GetLightweightDatabundle<T>(tag, false, false);
0470     }
0471 
0472     databundle->SetStatus(JDatabundle::Status::Inserted);
0473     databundle->GetData() = items;
0474 
0475     auto* factory = databundle->GetFactory();
0476     if (factory != nullptr) {
0477         factory->SetStatus(JFactory::Status::Inserted); // for when items is empty
0478         factory->SetCreationStatus(JFactory::CreationStatus::Inserted); // for when items is empty
0479         factory->SetInsertOrigin( mCallGraph.GetInsertDataOrigin() ); // (see note at top of JCallGraphRecorder.h)
0480         return dynamic_cast<JFactoryT<T>*>(factory);
0481     }
0482     throw JException("Attempted to call JEvent::Insert without an underlying JFactoryT. Hint: Did you previously use Output<T>?");
0483     // TODO: Have Insert() return the databundle instead of the factory
0484 }
0485 
0486 
0487 
0488 #if JANA2_HAVE_PODIO
0489 
0490 inline std::vector<std::string> JEvent::GetAllCollectionNames() const {
0491     std::vector<std::string> unique_names;
0492     for (auto databundle : mFactorySet.GetAllDatabundles()) {
0493         if (dynamic_cast<JPodioDatabundle*>(databundle) != nullptr) {
0494             unique_names.push_back(databundle->GetUniqueName());
0495         }
0496     }
0497     return unique_names;
0498 }
0499 
0500 inline const podio::CollectionBase* JEvent::GetCollectionBase(std::string unique_name, bool throw_on_missing) const {
0501     auto* bundle = mFactorySet.GetDatabundle(unique_name);
0502     if (bundle == nullptr) {
0503         if (throw_on_missing) {
0504             throw JException("Missing databundle with uniquename '%s'", unique_name.c_str());
0505         }
0506         return nullptr;
0507     }
0508 
0509     auto* typed_bundle = dynamic_cast<JPodioDatabundle*>(bundle);
0510     if (typed_bundle == nullptr) {
0511         if (throw_on_missing) {
0512             throw JException("Databundle with uniquename '%s' is not a JPodioDatabundle", unique_name.c_str());
0513         }
0514         return nullptr;
0515     }
0516 
0517     if (typed_bundle->GetStatus() == JDatabundle::Status::Empty) {
0518         auto* fac = typed_bundle->GetFactory();
0519         if (fac != nullptr) {
0520             JCallGraphEntryMaker cg_entry(mCallGraph, fac); // times execution until this goes out of scope
0521             fac->Create(*this);
0522         }
0523     }
0524 
0525     return typed_bundle->GetCollection();
0526 }
0527 
0528 
0529 template <typename T>
0530 const typename T::collection_type* JEvent::GetCollection(std::string name, bool throw_on_missing) const {
0531 
0532     auto collection = GetCollectionBase(name, throw_on_missing);
0533     auto* typed_collection = dynamic_cast<const typename T::collection_type*>(collection);
0534     if (throw_on_missing && typed_collection == nullptr) {
0535         throw JException("Databundle with uniquename '%s' does not contain %s", JTypeInfo::demangle<typename T::collection_type>().c_str());
0536     }
0537     return typed_collection;
0538 }
0539 
0540 
0541 template <typename T>
0542 void JEvent::InsertCollection(typename T::collection_type&& collection, std::string name) {
0543     /// InsertCollection inserts the provided PODIO collection into both the podio::Frame and then a JPodioDatabundle
0544 
0545     if (name.empty()) {
0546         throw JException("JEvent::InsertCollection: Podio collection names must be non-empty!");
0547     }
0548 
0549     podio::Frame* frame = nullptr;
0550     auto* bundle = mFactorySet.GetDatabundle("podio::Frame");
0551 
0552     if (bundle == nullptr) {
0553         //LOG << "No frame databundle found, inserting new dummy JFactoryT.";
0554         frame = new podio::Frame();
0555         Insert(frame, ""); 
0556         // Eventually we'll insert a databundle directly without the dummy JFactoryT
0557         // However, we obviously need JEvent::GetSingle<podio::Frame>() to work, which 
0558         // requires re-plumbing all or most of the Get*() methods to no longer rely on JFactoryT.
0559     }
0560     else {
0561         JLightweightDatabundleT<podio::Frame>* typed_bundle = nullptr;
0562         typed_bundle = dynamic_cast<JLightweightDatabundleT<podio::Frame>*>(bundle);
0563         if (typed_bundle == nullptr) {
0564             throw JException("Databundle with unique_name 'podio::Frame' is not a JLightweightDatabundleT");
0565         }
0566         if (typed_bundle->GetSize() == 0) {
0567             //LOG << "Found typed bundle with no frame. Creating new frame.";
0568             typed_bundle->GetData().push_back(new podio::Frame);
0569             typed_bundle->SetStatus(JDatabundle::Status::Inserted);
0570         }
0571         frame = typed_bundle->GetData().at(0);
0572     }
0573 
0574     const auto& owned_collection = frame->put(std::move(collection), name);
0575     InsertCollectionAlreadyInFrame<T>(&owned_collection, name);
0576 }
0577 
0578 
0579 template <typename T>
0580 void JEvent::InsertCollectionAlreadyInFrame(const podio::CollectionBase* collection, std::string unique_name) {
0581     /// InsertCollection inserts the provided PODIO collection into a JPodioDatabundle. It assumes that the collection pointer
0582     /// is _already_ owned by the podio::Frame corresponding to this JEvent. This is meant to be used if you are starting out
0583     /// with a PODIO frame (e.g. a JEventSource that uses podio::ROOTReader).
0584 
0585     const auto* typed_collection = dynamic_cast<const typename T::collection_type*>(collection);
0586     if (typed_collection == nullptr) {
0587         mFactorySet.Print();
0588         throw JException("Attempted to insert a collection of the wrong type! name='%s', expected type='%s', actual type='%s'",
0589             unique_name.c_str(), JTypeInfo::demangle<typename T::collection_type>().c_str(), collection->getDataTypeName().data());
0590     }
0591 
0592     // Users are allowed to Insert with tag="" if and only if that tag gets resolved by default tags.
0593     if (mUseDefaultTags && unique_name.empty()) {
0594         auto defaultTag = mDefaultTags.find(JTypeInfo::demangle<T>());
0595         if (defaultTag != mDefaultTags.end()) unique_name = defaultTag->second;
0596     }
0597 
0598     // Retrieve factory if it already exists, else create it
0599 
0600     JDatabundle* bundle = mFactorySet.GetDatabundle(unique_name);
0601     JPodioDatabundle* typed_bundle = nullptr;
0602 
0603     if (bundle == nullptr) {
0604         typed_bundle = new JPodioDatabundle();
0605         typed_bundle->SetUniqueName(unique_name);
0606         typed_bundle->SetTypeIndex(std::type_index(typeid(T)));
0607         typed_bundle->SetTypeName(JTypeInfo::demangle<T>());
0608         mFactorySet.Add(typed_bundle); 
0609         // Note that this transfers ownership to the JFactorySet because there's no corresponding JFactory
0610     }
0611     else {
0612         typed_bundle = dynamic_cast<JPodioDatabundle*>(bundle);
0613         if (typed_bundle == nullptr) {
0614             mFactorySet.Print();
0615             throw JException("Databundle with unique_name='%s' must be a JPodioDatabundle in order to insert a Podio collection", unique_name.c_str());
0616         }
0617         if (typed_bundle->GetStatus() != JDatabundle::Status::Empty) {
0618             // PODIO collections can only be inserted once, unlike regular JANA factories.
0619             mFactorySet.Print();
0620             throw JException("A Podio collection with unique_name='%s' is already present and cannot be overwritten", unique_name.c_str());
0621         }
0622     }
0623 
0624     typed_bundle->SetStatus(JDatabundle::Status::Inserted);
0625     typed_bundle->SetCollection(typed_collection);
0626     auto fac = typed_bundle->GetFactory();
0627     if (fac) {
0628         fac->SetStatus(JFactory::Status::Inserted);
0629     }
0630 }
0631 
0632 #endif // JANA2_HAVE_PODIO
0633 
0634 
0635