Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/podio/detail/LinkCollectionImpl.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 #ifndef PODIO_DETAIL_LINKCOLLECTIONIMPL_H
0002 #define PODIO_DETAIL_LINKCOLLECTIONIMPL_H
0003 
0004 #include "podio/detail/Link.h"
0005 #include "podio/detail/LinkCollectionData.h"
0006 #include "podio/detail/LinkCollectionIterator.h"
0007 #include "podio/detail/LinkFwd.h"
0008 #include "podio/detail/LinkObj.h"
0009 
0010 #include "podio/CollectionBase.h"
0011 #include "podio/CollectionBufferFactory.h"
0012 #include "podio/CollectionBuffers.h"
0013 #include "podio/DatamodelRegistry.h"
0014 #include "podio/ICollectionProvider.h"
0015 #include "podio/SchemaEvolution.h"
0016 #include "podio/utilities/MaybeSharedPtr.h"
0017 #include "podio/utilities/TypeHelpers.h"
0018 
0019 #ifdef PODIO_JSON_OUTPUT
0020   #include "nlohmann/json.hpp"
0021 #endif
0022 
0023 #include <iomanip>
0024 #include <memory>
0025 #include <mutex>
0026 #include <ostream>
0027 #include <string>
0028 #include <type_traits>
0029 
0030 namespace podio {
0031 
0032 template <typename FromT, typename ToT>
0033 class LinkCollection : public podio::CollectionBase {
0034   static_assert(std::is_same_v<FromT, detail::GetDefaultHandleType<FromT>>,
0035                 "Links need to be instantiated with the default types!");
0036   static_assert(std::is_same_v<ToT, detail::GetDefaultHandleType<ToT>>,
0037                 "Links need to be instantiated with the default types!");
0038 
0039   // convenience typedefs
0040   using CollectionDataT = podio::LinkCollectionData<FromT, ToT>;
0041 
0042 public:
0043   using from_type = FromT;
0044   using to_type = ToT;
0045   using value_type = Link<FromT, ToT>;
0046   using mutable_type = MutableLink<FromT, ToT>;
0047   using const_iterator = LinkCollectionIterator<FromT, ToT>;
0048   using iterator = LinkMutableCollectionIterator<FromT, ToT>;
0049   using difference_type = ptrdiff_t;
0050   using size_type = size_t;
0051 
0052   LinkCollection() = default;
0053 
0054   LinkCollection(CollectionDataT&& data, bool isSubsetColl) :
0055       m_isSubsetColl(isSubsetColl), m_collectionID(0), m_storage(std::move(data)) {
0056   }
0057 
0058   // Move-only type
0059   LinkCollection(const LinkCollection&) = delete;
0060   LinkCollection& operator=(const LinkCollection&) = delete;
0061   LinkCollection(LinkCollection&&) = default;
0062   LinkCollection& operator=(LinkCollection&&) = default;
0063 
0064   ~LinkCollection() {
0065     // Need to tell the storage how to clean up
0066     m_storage.clear(m_isSubsetColl);
0067   }
0068 
0069   /// Append a new link to the collection and return this object
0070   mutable_type create() {
0071     if (m_isSubsetColl) {
0072       throw std::logic_error("Cannot create new elements on a subset collection");
0073     }
0074 
0075     auto obj = m_storage.entries.emplace_back(new LinkObj<FromT, ToT>());
0076     obj->id = {int(m_storage.entries.size() - 1), m_collectionID};
0077     return mutable_type(podio::utils::MaybeSharedPtr(obj));
0078   }
0079 
0080   /// Returns the immutable object of given index
0081   value_type operator[](unsigned int index) const {
0082     return value_type(m_storage.entries[index]);
0083   }
0084   /// Returns the mutable object of given index
0085   mutable_type operator[](unsigned int index) {
0086     return mutable_type(podio::utils::MaybeSharedPtr(m_storage.entries[index]));
0087   }
0088   /// Returns the immutable object of given index
0089   value_type at(unsigned int index) const {
0090     return value_type(m_storage.entries.at(index));
0091   }
0092   /// Returns the mutable object of given index
0093   mutable_type at(unsigned int index) {
0094     return mutable_type(podio::utils::MaybeSharedPtr(m_storage.at(index)));
0095   }
0096 
0097   void push_back(mutable_type object) {
0098     // We have to do different things here depending on whether this is a
0099     // subset collection or not. A normal collection cannot collect objects
0100     // that are already part of another collection, while a subset collection
0101     // can only collect such objects
0102     if (!m_isSubsetColl) {
0103       auto obj = object.m_obj;
0104       if (obj->id.index == podio::ObjectID::untracked) {
0105         const auto size = m_storage.entries.size();
0106         obj->id = {(int)size, m_collectionID};
0107         m_storage.entries.push_back(obj.release());
0108       } else {
0109         throw std::invalid_argument("Object already in a collection. Cannot add it to a second collection");
0110       }
0111 
0112     } else {
0113       push_back(value_type(object));
0114     }
0115   }
0116 
0117   void push_back(value_type object) {
0118     if (!m_isSubsetColl) {
0119       throw std::invalid_argument("Can only add immutable objects to subset collections");
0120     }
0121     auto obj = object.m_obj;
0122     if (obj->id.index < 0) {
0123       throw std::invalid_argument(
0124           "Object needs to be tracked by another collection in order for it to be storable in a subset collection");
0125     }
0126     m_storage.entries.push_back(obj.release());
0127   }
0128 
0129   /// Number of elements in the collection
0130   size_t size() const override {
0131     return m_storage.entries.size();
0132   }
0133 
0134   /// maximal number of elements in the collection
0135   std::size_t max_size() const override {
0136     return m_storage.entries.max_size();
0137   }
0138 
0139   /// Is the collection empty
0140   bool empty() const override {
0141     return m_storage.entries.empty();
0142   }
0143 
0144   void clear() override {
0145     m_storage.clear(m_isSubsetColl);
0146     m_isPrepared = false;
0147   }
0148 
0149   void print(std::ostream& os = std::cout, bool flush = true) const override {
0150     os << *this;
0151     if (flush) {
0152       os.flush();
0153     }
0154   }
0155 
0156   // support for the iterator protocol
0157   const_iterator begin() const {
0158     return const_iterator(0, &m_storage.entries);
0159   }
0160   const_iterator cbegin() const {
0161     return begin();
0162   }
0163   const_iterator end() const {
0164     return const_iterator(m_storage.entries.size(), &m_storage.entries);
0165   }
0166   const_iterator cend() const {
0167     return end();
0168   }
0169   iterator begin() {
0170     return iterator(0, &m_storage.entries);
0171   }
0172   iterator end() {
0173     return iterator(m_storage.entries.size(), &m_storage.entries);
0174   }
0175 
0176   bool isValid() const override {
0177     return m_isValid;
0178   }
0179 
0180   podio::CollectionWriteBuffers getBuffers() override {
0181     return m_storage.getCollectionBuffers(m_isSubsetColl);
0182   }
0183 
0184   const std::string_view getTypeName() const override {
0185     return podio::detail::linkCollTypeName<FromT, ToT>();
0186   }
0187 
0188   const std::string_view getValueTypeName() const override {
0189     return podio::detail::linkTypeName<FromT, ToT>();
0190   }
0191 
0192   const std::string_view getDataTypeName() const override {
0193     return "podio::LinkData";
0194   }
0195 
0196   bool isSubsetCollection() const override {
0197     return m_isSubsetColl;
0198   }
0199 
0200   void setSubsetCollection(bool setSubset = true) override {
0201     if (m_isSubsetColl != setSubset && !m_storage.entries.empty()) {
0202       throw std::logic_error("Cannot change the character of a collection that already contains elements");
0203     }
0204 
0205     if (setSubset) {
0206       m_storage.makeSubsetCollection();
0207     }
0208     m_isSubsetColl = setSubset;
0209   }
0210 
0211   void setID(unsigned id) override {
0212     m_collectionID = id;
0213   }
0214 
0215   unsigned getID() const override {
0216     return m_collectionID;
0217   }
0218 
0219   void prepareForWrite() const override {
0220     // TODO: Replace this double locking pattern with an atomic and only one
0221     // lock. Problem: std::atomic is not default movable
0222     {
0223       std::lock_guard lock{*m_storageMtx};
0224       // If the collection has been prepared already there is nothing to do
0225       if (m_isPrepared) {
0226         return;
0227       }
0228     }
0229 
0230     std::lock_guard lock{*m_storageMtx};
0231     // by the time we acquire the lock another thread might have already
0232     // succeeded, so we need to check again now
0233     if (m_isPrepared) {
0234       return;
0235     }
0236     m_storage.prepareForWrite(m_isSubsetColl);
0237     m_isPrepared = true;
0238   }
0239 
0240   void prepareAfterRead() override {
0241     // No need to go through this again if we have already done it
0242     if (m_isPrepared) {
0243       return;
0244     }
0245 
0246     if (!m_isSubsetColl) {
0247       // Subset collections do not store any data that would require post-processing
0248       m_storage.prepareAfterRead(m_collectionID);
0249     }
0250     // Preparing a collection doesn't affect the underlying I/O buffers, so this
0251     // collection is still prepared
0252     m_isPrepared = true;
0253   }
0254 
0255   bool setReferences(const ICollectionProvider* collectionProvider) override {
0256     return m_storage.setReferences(collectionProvider, m_isSubsetColl);
0257   }
0258 
0259   static constexpr SchemaVersionT schemaVersion = 1;
0260 
0261   SchemaVersionT getSchemaVersion() const override {
0262     return schemaVersion;
0263   }
0264 
0265   size_t getDatamodelRegistryIndex() const override {
0266     return podio::DatamodelRegistry::NoDefinitionNecessary;
0267   }
0268 
0269 private:
0270   // For setReferences, we need to give our own CollectionData access to our
0271   // private entries. Otherwise we would need to expose a public member function
0272   // that gives access to the Obj* which is definitely not what we want
0273   friend CollectionDataT;
0274 
0275   bool m_isValid{false};
0276   mutable bool m_isPrepared{false};
0277   bool m_isSubsetColl{false};
0278   uint32_t m_collectionID{0};
0279   mutable std::unique_ptr<std::mutex> m_storageMtx{std::make_unique<std::mutex>()};
0280   mutable CollectionDataT m_storage{};
0281 };
0282 
0283 template <typename FromT, typename ToT>
0284 std::ostream& operator<<(std::ostream& o, const LinkCollection<FromT, ToT>& v) {
0285   const auto old_flags = o.flags();
0286   o << "          id:      weight:" << '\n';
0287   for (const auto&& el : v) {
0288     o << std::scientific << std::showpos << std::setw(12) << el.id() << " " << std::setw(12) << " " << el.getWeight()
0289       << '\n';
0290 
0291     o << "     from : ";
0292     o << el.getFrom().id() << std::endl;
0293     o << "       to : ";
0294     o << el.getTo().id() << std::endl;
0295   }
0296 
0297   o.flags(old_flags);
0298   return o;
0299 }
0300 
0301 namespace detail {
0302   template <typename FromT, typename ToT>
0303   podio::CollectionReadBuffers createLinkBuffers(bool subsetColl) {
0304     auto readBuffers = podio::CollectionReadBuffers{};
0305     readBuffers.type = podio::detail::linkCollTypeName<FromT, ToT>();
0306     readBuffers.schemaVersion = podio::LinkCollection<FromT, ToT>::schemaVersion;
0307     readBuffers.data = subsetColl ? nullptr : new LinkDataContainer();
0308 
0309     // Either it is a subset collection or we have two relations
0310     const auto nRefs = subsetColl ? 1 : 2;
0311     readBuffers.references = new podio::CollRefCollection(nRefs);
0312     for (auto& ref : *readBuffers.references) {
0313       // Make sure to place usable buffer pointers here
0314       ref = std::make_unique<std::vector<podio::ObjectID>>();
0315     }
0316 
0317     readBuffers.createCollection = [](podio::CollectionReadBuffers buffers, bool isSubsetColl) {
0318       LinkCollectionData<FromT, ToT> data(buffers, isSubsetColl);
0319       return std::make_unique<LinkCollection<FromT, ToT>>(std::move(data), isSubsetColl);
0320     };
0321 
0322     readBuffers.recast = [](podio::CollectionReadBuffers& buffers) {
0323       if (buffers.data) {
0324         buffers.data = podio::CollectionWriteBuffers::asVector<float>(buffers.data);
0325       }
0326     };
0327 
0328     readBuffers.deleteBuffers = [](podio::CollectionReadBuffers& buffers) {
0329       if (buffers.data) {
0330         // If we have data then we are not a subset collection and we have
0331         // to clean up all type erased buffers by casting them back to
0332         // something that we can delete
0333         delete static_cast<LinkDataContainer*>(buffers.data);
0334       }
0335       delete buffers.references;
0336       delete buffers.vectorMembers;
0337     };
0338 
0339     return readBuffers;
0340   }
0341 
0342   template <typename FromT, typename ToT>
0343   bool registerLinkCollection(const std::string_view linkTypeName) {
0344     const static auto reg = [&linkTypeName]() {
0345       const auto schemaVersion = LinkCollection<FromT, ToT>::schemaVersion;
0346 
0347       auto& factory = CollectionBufferFactory::mutInstance();
0348       factory.registerCreationFunc(std::string(linkTypeName), schemaVersion, createLinkBuffers<FromT, ToT>);
0349 
0350       // For now passing the same schema version for from and current version
0351       // simply to make SchemaEvolution aware of LinkCollections
0352       podio::SchemaEvolution::mutInstance().registerEvolutionFunc(std::string(linkTypeName), schemaVersion,
0353                                                                   schemaVersion, SchemaEvolution::noOpSchemaEvolution,
0354                                                                   SchemaEvolution::Priority::AutoGenerated);
0355 
0356       return true;
0357     }();
0358     return reg;
0359   }
0360 } // namespace detail
0361 
0362 #if defined(PODIO_JSON_OUTPUT) && !defined(__CLING__)
0363 template <typename FromT, typename ToT>
0364 void to_json(nlohmann::json& j, const podio::LinkCollection<FromT, ToT>& collection) {
0365   j = nlohmann::json::array();
0366   for (auto&& elem : collection) {
0367     j.emplace_back(elem);
0368   }
0369 }
0370 #endif
0371 
0372 } // namespace podio
0373 
0374 #endif // PODIO_DETAIL_LINKCOLLECTIONIMPL_H