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
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
0059 LinkCollection(const LinkCollection&) = delete;
0060 LinkCollection& operator=(const LinkCollection&) = delete;
0061 LinkCollection(LinkCollection&&) = default;
0062 LinkCollection& operator=(LinkCollection&&) = default;
0063
0064 ~LinkCollection() {
0065
0066 m_storage.clear(m_isSubsetColl);
0067 }
0068
0069
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
0081 value_type operator[](unsigned int index) const {
0082 return value_type(m_storage.entries[index]);
0083 }
0084
0085 mutable_type operator[](unsigned int index) {
0086 return mutable_type(podio::utils::MaybeSharedPtr(m_storage.entries[index]));
0087 }
0088
0089 value_type at(unsigned int index) const {
0090 return value_type(m_storage.entries.at(index));
0091 }
0092
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
0099
0100
0101
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
0130 size_t size() const override {
0131 return m_storage.entries.size();
0132 }
0133
0134
0135 std::size_t max_size() const override {
0136 return m_storage.entries.max_size();
0137 }
0138
0139
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
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
0221
0222 {
0223 std::lock_guard lock{*m_storageMtx};
0224
0225 if (m_isPrepared) {
0226 return;
0227 }
0228 }
0229
0230 std::lock_guard lock{*m_storageMtx};
0231
0232
0233 if (m_isPrepared) {
0234 return;
0235 }
0236 m_storage.prepareForWrite(m_isSubsetColl);
0237 m_isPrepared = true;
0238 }
0239
0240 void prepareAfterRead() override {
0241
0242 if (m_isPrepared) {
0243 return;
0244 }
0245
0246 if (!m_isSubsetColl) {
0247
0248 m_storage.prepareAfterRead(m_collectionID);
0249 }
0250
0251
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
0271
0272
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
0310 const auto nRefs = subsetColl ? 1 : 2;
0311 readBuffers.references = new podio::CollRefCollection(nRefs);
0312 for (auto& ref : *readBuffers.references) {
0313
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
0331
0332
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
0351
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 }
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 }
0373
0374 #endif