Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:36:43

0001 // Copyright 2024, Jefferson Science Associates, LLC.
0002 // Subject to the terms in the LICENSE file found in the top-level directory.
0003 
0004 #pragma once
0005 
0006 #include <JANA/Utils/JAny.h>
0007 #include <JANA/Utils/JCallGraphRecorder.h>
0008 
0009 #include <string>
0010 #include <functional>
0011 #include <typeindex>
0012 #include <vector>
0013 #include <memory>
0014 #include <unordered_map>
0015 
0016 
0017 class JFactory;
0018 
0019 class JDatabundle {
0020 public:
0021     // Typedefs
0022     enum class Status { Empty, Created, Inserted, Excepted };
0023     struct NoTypeProvided {}; // This gives us a default value for m_type_index
0024 
0025 private:
0026     // Fields
0027     Status m_status = Status::Empty;
0028     std::string m_unique_name;
0029     std::string m_short_name;
0030     bool m_has_short_name = true;
0031     std::string m_type_name;
0032     JFactory* m_factory = nullptr;
0033     std::type_index m_inner_type_index = std::type_index(typeid(NoTypeProvided));
0034     mutable JCallGraphRecorder::JDataOrigin m_insert_origin = JCallGraphRecorder::ORIGIN_NOT_AVAILABLE;
0035 
0036 
0037 protected:
0038     std::shared_ptr<std::unordered_map<std::type_index, std::unique_ptr<JAny>>> m_upcast_fns;
0039 
0040 public:
0041     // Interface
0042     JDatabundle() {
0043         m_upcast_fns = std::make_shared<std::unordered_map<std::type_index, std::unique_ptr<JAny>>>();
0044     }
0045     JDatabundle(const JDatabundle& other) {
0046         m_status = other.m_status;
0047         m_unique_name = other.m_unique_name;
0048         m_short_name = other.m_short_name;
0049         m_type_name = other.m_type_name;
0050         m_factory = nullptr;
0051         // We do NOT propagate m_factory because JFactorySet assumes that
0052         // m_factory is this object's owner.
0053 
0054         m_inner_type_index = other.m_inner_type_index;
0055         m_insert_origin = JCallGraphRecorder::ORIGIN_NOT_AVAILABLE;
0056         m_upcast_fns = other.m_upcast_fns;
0057         // We use shared_ptr for upcast functions so that we can
0058         // call EnableGetAs<> once from a JEventSource or JEventUnfolder ctor,
0059         // and GetAs<> from JEventProcessor::Process succeeds
0060     }
0061     virtual ~JDatabundle() = default;
0062     virtual size_t GetSize() const = 0;
0063     virtual void ClearData() = 0;
0064 
0065     // Getters
0066     Status GetStatus() const { return m_status; }
0067     std::string GetUniqueName() const { return m_unique_name; }
0068     std::string GetShortName() const { return m_short_name; }
0069     bool HasShortName() const { return m_has_short_name; }
0070     std::string GetTypeName() const { return m_type_name; }
0071     std::type_index GetTypeIndex() const { return m_inner_type_index; }
0072     JCallGraphRecorder::JDataOrigin GetInsertOrigin() const { return m_insert_origin; } ///< If objects were placed here by JEvent::Insert() this records whether that call was made from a source or factory.
0073     JFactory* GetFactory() const { return m_factory; }
0074 
0075     // Setters
0076     void SetStatus(Status s) { m_status = s;}
0077     void SetUniqueName(std::string unique_name);
0078     void SetShortName(std::string short_name);
0079     void SetTypeName(std::string type_name);
0080     void SetTypeIndex(std::type_index index) { m_inner_type_index = index; }
0081     void SetInsertOrigin(JCallGraphRecorder::JDataOrigin origin) { m_insert_origin = origin; } ///< Called automatically by JEvent::Insert() to records whether that call was made by a source or factory.
0082     void SetFactory(JFactory* fac) { m_factory = fac; }
0083 
0084     // Templates 
0085     //
0086     /// Generically access the encapsulated data, performing an upcast if necessary. This is useful for extracting data from
0087     /// all JFactories<T> where T extends a parent class S, such as JObject or TObject, in contexts where T is not known
0088     /// or it would introduce an unwanted coupling. The main application is for building DSTs.
0089     ///
0090     /// Be aware of the following caveats:
0091     /// - The factory's object type must not use virtual inheritance.
0092     /// - If JFactory::Process hasn't already been called, this will return an empty vector. This will NOT call JFactory::Process.
0093     /// - Someone must call JFactoryT<T>::EnableGetAs<S>, preferably the constructor. Otherwise, this will return an empty vector.
0094     /// - If S isn't a base class of T, this will return an empty vector.
0095     template<typename S>
0096     std::vector<S*> GetAs();
0097 
0098 };
0099 
0100 
0101 
0102 // Because C++ doesn't support templated virtual functions, we implement our own dispatch table, m_upcast_fns.
0103 // This means that the JFactoryT is forced to manually populate this table by calling JFactoryT<T>::EnableGetAs.
0104 // We have the option to make the vtable be a static member of JFactoryT<T>, but we have chosen not to because:
0105 //
0106 //   1. It would be inconsistent with the fact that the user is supposed to call EnableGetAs in the ctor
0107 //   2. People in the future may want to generalize GetAs to support user-defined S* -> T* conversions (which I don't recommend)
0108 //   3. The size of the vtable is expected to be very small (<10 elements, most likely 2)
0109 
0110 template<typename S>
0111 std::vector<S*> JDatabundle::GetAs() {
0112     std::vector<S*> results;
0113     auto ti = std::type_index(typeid(S));
0114     auto search = m_upcast_fns->find(ti);
0115     if (search != m_upcast_fns->end()) {
0116         using upcast_fn_t = std::function<std::vector<S*>()>;
0117         auto temp = static_cast<JAnyT<upcast_fn_t>*>(&(*search->second));
0118         upcast_fn_t upcast_fn = temp->t;
0119         results = upcast_fn();
0120     }
0121     return results;
0122 }
0123 
0124