Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-05 09:39:47

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