File indexing completed on 2025-09-18 09:25:07
0001 #ifndef PODIO_DETAIL_LINKCOLLECTIONIMPL_H
0002 #define PODIO_DETAIL_LINKCOLLECTIONIMPL_H
0003
0004 #include "podio/ObjectID.h"
0005 #include "podio/detail/Link.h"
0006 #include "podio/detail/LinkCollectionData.h"
0007 #include "podio/detail/LinkCollectionIterator.h"
0008 #include "podio/detail/LinkFwd.h"
0009 #include "podio/detail/LinkObj.h"
0010
0011 #include "podio/CollectionBase.h"
0012 #include "podio/CollectionBufferFactory.h"
0013 #include "podio/CollectionBuffers.h"
0014 #include "podio/DatamodelRegistry.h"
0015 #include "podio/ICollectionProvider.h"
0016 #include "podio/SchemaEvolution.h"
0017 #include "podio/utilities/MaybeSharedPtr.h"
0018 #include "podio/utilities/StaticConcatenate.h"
0019 #include "podio/utilities/TypeHelpers.h"
0020
0021 #include <iterator>
0022 #include <string_view>
0023
0024 #ifdef PODIO_JSON_OUTPUT
0025 #include "nlohmann/json.hpp"
0026 #endif
0027
0028 #include <iomanip>
0029 #include <memory>
0030 #include <mutex>
0031 #include <ostream>
0032 #include <string>
0033 #include <type_traits>
0034
0035 namespace podio {
0036
0037 template <typename FromT, typename ToT>
0038 class LinkCollection : public podio::CollectionBase {
0039 static_assert(std::is_same_v<FromT, detail::GetDefaultHandleType<FromT>>,
0040 "Links need to be instantiated with the default types!");
0041 static_assert(std::is_same_v<ToT, detail::GetDefaultHandleType<ToT>>,
0042 "Links need to be instantiated with the default types!");
0043
0044
0045 using CollectionDataT = podio::LinkCollectionData<FromT, ToT>;
0046
0047 public:
0048 using from_type = FromT;
0049 using to_type = ToT;
0050 using value_type = Link<FromT, ToT>;
0051 using mutable_type = MutableLink<FromT, ToT>;
0052 using const_iterator = LinkCollectionIterator<FromT, ToT>;
0053 using iterator = LinkMutableCollectionIterator<FromT, ToT>;
0054 using difference_type = ptrdiff_t;
0055 using size_type = size_t;
0056 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0057 using reverse_iterator = std::reverse_iterator<iterator>;
0058
0059 LinkCollection() = default;
0060
0061 LinkCollection(CollectionDataT&& data, bool isSubsetColl) :
0062 m_isSubsetColl(isSubsetColl), m_collectionID(0), m_storage(std::move(data)) {
0063 }
0064
0065
0066 LinkCollection(const LinkCollection&) = delete;
0067 LinkCollection& operator=(const LinkCollection&) = delete;
0068 LinkCollection(LinkCollection&&) = default;
0069 LinkCollection& operator=(LinkCollection&&) = default;
0070
0071 ~LinkCollection() {
0072
0073 m_storage.clear(m_isSubsetColl);
0074 }
0075
0076
0077 mutable_type create() {
0078 if (m_isSubsetColl) {
0079 throw std::logic_error("Cannot create new elements on a subset collection");
0080 }
0081
0082 auto obj = m_storage.entries.emplace_back(new LinkObj<FromT, ToT>());
0083 obj->id = {int(m_storage.entries.size() - 1), m_collectionID};
0084 return mutable_type(podio::utils::MaybeSharedPtr(obj));
0085 }
0086
0087
0088 value_type operator[](unsigned int index) const {
0089 return value_type(m_storage.entries[index]);
0090 }
0091
0092 mutable_type operator[](unsigned int index) {
0093 return mutable_type(podio::utils::MaybeSharedPtr(m_storage.entries[index]));
0094 }
0095
0096 value_type at(unsigned int index) const {
0097 return value_type(m_storage.entries.at(index));
0098 }
0099
0100 mutable_type at(unsigned int index) {
0101 return mutable_type(podio::utils::MaybeSharedPtr(m_storage.at(index)));
0102 }
0103
0104 void push_back(mutable_type object) {
0105
0106
0107
0108
0109 if (!m_isSubsetColl) {
0110 auto obj = object.m_obj;
0111 if (obj->id.index == podio::ObjectID::untracked) {
0112 const auto size = m_storage.entries.size();
0113 obj->id = {(int)size, m_collectionID};
0114 m_storage.entries.push_back(obj.release());
0115 } else {
0116 throw std::invalid_argument("Object already in a collection. Cannot add it to a second collection");
0117 }
0118
0119 } else {
0120 push_back(value_type(object));
0121 }
0122 }
0123
0124 void push_back(value_type object) {
0125 if (!m_isSubsetColl) {
0126 throw std::invalid_argument("Can only add immutable objects to subset collections");
0127 }
0128 auto obj = object.m_obj;
0129 if (obj->id.index < 0) {
0130 throw std::invalid_argument(
0131 "Object needs to be tracked by another collection in order for it to be storable in a subset collection");
0132 }
0133 m_storage.entries.push_back(obj.release());
0134 }
0135
0136
0137 size_t size() const override {
0138 return m_storage.entries.size();
0139 }
0140
0141
0142 std::size_t max_size() const override {
0143 const auto maxStorage = m_storage.entries.max_size();
0144 if (!m_isSubsetColl) {
0145
0146 const auto maxIndex = std::numeric_limits<decltype(ObjectID::index)>::max();
0147 return std::min<size_t>(maxIndex, maxStorage);
0148 }
0149 return maxStorage;
0150 }
0151
0152
0153 bool empty() const override {
0154 return m_storage.entries.empty();
0155 }
0156
0157 void clear() override {
0158 m_storage.clear(m_isSubsetColl);
0159 m_isPrepared = false;
0160 }
0161
0162 void print(std::ostream& os = std::cout, bool flush = true) const override {
0163 os << *this;
0164 if (flush) {
0165 os.flush();
0166 }
0167 }
0168
0169
0170 const_iterator begin() const {
0171 return const_iterator(0, &m_storage.entries);
0172 }
0173 const_iterator cbegin() const {
0174 return begin();
0175 }
0176 const_iterator end() const {
0177 return const_iterator(m_storage.entries.size(), &m_storage.entries);
0178 }
0179 const_iterator cend() const {
0180 return end();
0181 }
0182 iterator begin() {
0183 return iterator(0, &m_storage.entries);
0184 }
0185 iterator end() {
0186 return iterator(m_storage.entries.size(), &m_storage.entries);
0187 }
0188
0189 reverse_iterator rbegin() {
0190 return reverse_iterator(end());
0191 }
0192 const_reverse_iterator rbegin() const {
0193 return const_reverse_iterator(end());
0194 }
0195 const_reverse_iterator crbegin() const {
0196 return rbegin();
0197 }
0198 reverse_iterator rend() {
0199 return reverse_iterator(begin());
0200 }
0201 const_reverse_iterator rend() const {
0202 return const_reverse_iterator(begin());
0203 }
0204 const_reverse_iterator crend() const {
0205 return rend();
0206 }
0207
0208 bool isValid() const override {
0209 return m_isValid;
0210 }
0211
0212 podio::CollectionWriteBuffers getBuffers() override {
0213 return m_storage.getCollectionBuffers(m_isSubsetColl);
0214 }
0215
0216 constexpr static std::string_view typeName =
0217 podio::utils::static_concatenate_v<podio::detail::link_coll_name_prefix, FromT::typeName,
0218 podio::detail::link_name_infix, ToT::typeName,
0219 podio::detail::link_name_suffix>;
0220
0221 constexpr static std::string_view valueTypeName = value_type::typeName;
0222 constexpr static std::string_view dataTypeName = "podio::LinkData";
0223
0224 const std::string_view getTypeName() const override {
0225 return typeName;
0226 }
0227
0228 const std::string_view getValueTypeName() const override {
0229 return valueTypeName;
0230 }
0231
0232 const std::string_view getDataTypeName() const override {
0233 return dataTypeName;
0234 }
0235
0236 bool isSubsetCollection() const override {
0237 return m_isSubsetColl;
0238 }
0239
0240 void setSubsetCollection(bool setSubset = true) override {
0241 if (m_isSubsetColl != setSubset && !m_storage.entries.empty()) {
0242 throw std::logic_error("Cannot change the character of a collection that already contains elements");
0243 }
0244
0245 if (setSubset) {
0246 m_storage.makeSubsetCollection();
0247 }
0248 m_isSubsetColl = setSubset;
0249 }
0250
0251 void setID(unsigned id) override {
0252 m_collectionID = id;
0253 if (!m_isSubsetColl) {
0254 std::ranges::for_each(m_storage.entries, [id](auto* obj) { obj->id = {obj->id.index, id}; });
0255 }
0256 m_isValid = true;
0257 }
0258
0259 unsigned getID() const override {
0260 return m_collectionID;
0261 }
0262
0263 void prepareForWrite() const override {
0264 std::lock_guard lock{*m_storageMtx};
0265
0266
0267 if (m_isPrepared) {
0268 return;
0269 }
0270 m_storage.prepareForWrite(m_isSubsetColl);
0271 m_isPrepared = true;
0272 }
0273
0274 void prepareAfterRead() override {
0275
0276 if (m_isPrepared) {
0277 return;
0278 }
0279
0280 if (!m_isSubsetColl) {
0281
0282 m_storage.prepareAfterRead(m_collectionID);
0283 }
0284
0285
0286 m_isPrepared = true;
0287 }
0288
0289 bool setReferences(const ICollectionProvider* collectionProvider) override {
0290 return m_storage.setReferences(collectionProvider, m_isSubsetColl);
0291 }
0292
0293 static constexpr SchemaVersionT schemaVersion = 1;
0294
0295 SchemaVersionT getSchemaVersion() const override {
0296 return schemaVersion;
0297 }
0298
0299 size_t getDatamodelRegistryIndex() const override {
0300 return podio::DatamodelRegistry::NoDefinitionNecessary;
0301 }
0302
0303 private:
0304
0305
0306
0307 friend CollectionDataT;
0308
0309 bool m_isValid{false};
0310 mutable bool m_isPrepared{false};
0311 bool m_isSubsetColl{false};
0312 uint32_t m_collectionID{0};
0313 mutable std::unique_ptr<std::mutex> m_storageMtx{std::make_unique<std::mutex>()};
0314 mutable CollectionDataT m_storage{};
0315 };
0316
0317 template <typename FromT, typename ToT>
0318 std::ostream& operator<<(std::ostream& o, const LinkCollection<FromT, ToT>& v) {
0319 const auto old_flags = o.flags();
0320 o << " id: weight:" << '\n';
0321 for (const auto&& el : v) {
0322 o << std::scientific << std::showpos << std::setw(12) << el.id() << " " << std::setw(12) << " " << el.getWeight()
0323 << '\n';
0324
0325 o << " from : ";
0326 o << el.getFrom().id() << std::endl;
0327 o << " to : ";
0328 o << el.getTo().id() << std::endl;
0329 }
0330
0331 o.flags(old_flags);
0332 return o;
0333 }
0334
0335 namespace detail {
0336 template <typename FromT, typename ToT>
0337 podio::CollectionReadBuffers createLinkBuffers(bool subsetColl) {
0338 auto readBuffers = podio::CollectionReadBuffers{};
0339 readBuffers.type = podio::LinkCollection<FromT, ToT>::typeName;
0340 readBuffers.schemaVersion = podio::LinkCollection<FromT, ToT>::schemaVersion;
0341 readBuffers.data = subsetColl ? nullptr : new LinkDataContainer();
0342
0343
0344 const auto nRefs = subsetColl ? 1 : 2;
0345 readBuffers.references = new podio::CollRefCollection(nRefs);
0346 for (auto& ref : *readBuffers.references) {
0347
0348 ref = std::make_unique<std::vector<podio::ObjectID>>();
0349 }
0350
0351 readBuffers.createCollection = [](podio::CollectionReadBuffers buffers, bool isSubsetColl) {
0352 LinkCollectionData<FromT, ToT> data(buffers, isSubsetColl);
0353 return std::make_unique<LinkCollection<FromT, ToT>>(std::move(data), isSubsetColl);
0354 };
0355
0356 readBuffers.recast = [](podio::CollectionReadBuffers& buffers) {
0357 if (buffers.data) {
0358 buffers.data = podio::CollectionWriteBuffers::asVector<float>(buffers.data);
0359 }
0360 };
0361
0362 readBuffers.deleteBuffers = [](const podio::CollectionReadBuffers& buffers) {
0363 if (buffers.data) {
0364
0365
0366
0367 delete static_cast<LinkDataContainer*>(buffers.data);
0368 }
0369 delete buffers.references;
0370 delete buffers.vectorMembers;
0371 };
0372
0373 return readBuffers;
0374 }
0375
0376 template <typename FromT, typename ToT>
0377 bool registerLinkCollection(const std::string_view linkTypeName) {
0378 const static auto reg = [&linkTypeName]() {
0379 const auto schemaVersion = LinkCollection<FromT, ToT>::schemaVersion;
0380
0381 auto& factory = CollectionBufferFactory::mutInstance();
0382 factory.registerCreationFunc(std::string(linkTypeName), schemaVersion, createLinkBuffers<FromT, ToT>);
0383
0384
0385
0386 podio::SchemaEvolution::mutInstance().registerEvolutionFunc(std::string(linkTypeName), schemaVersion,
0387 schemaVersion, SchemaEvolution::noOpSchemaEvolution,
0388 SchemaEvolution::Priority::AutoGenerated);
0389
0390 return true;
0391 }();
0392 return reg;
0393 }
0394 }
0395
0396 #if defined(PODIO_JSON_OUTPUT) && !defined(__CLING__)
0397 template <typename FromT, typename ToT>
0398 void to_json(nlohmann::json& j, const podio::LinkCollection<FromT, ToT>& collection) {
0399 j = nlohmann::json::array();
0400 for (auto&& elem : collection) {
0401 j.emplace_back(elem);
0402 }
0403 }
0404 #endif
0405
0406 }
0407
0408 #endif