File indexing completed on 2025-09-18 09:25:08
0001 #ifndef PODIO_FRAME_H
0002 #define PODIO_FRAME_H
0003
0004 #include "podio/CollectionBase.h"
0005 #include "podio/CollectionIDTable.h"
0006 #include "podio/FrameCategories.h" // mainly for convenience
0007 #include "podio/GenericParameters.h"
0008 #include "podio/ICollectionProvider.h"
0009 #include "podio/SchemaEvolution.h"
0010 #include "podio/utilities/TypeHelpers.h"
0011
0012 #include <initializer_list>
0013 #include <memory>
0014 #include <mutex>
0015 #include <optional>
0016 #include <set>
0017 #include <stdexcept>
0018 #include <string>
0019 #include <type_traits>
0020 #include <unordered_map>
0021 #include <vector>
0022
0023 namespace podio {
0024
0025
0026 template <typename T>
0027 concept CollectionRValueType = CollectionType<T> && !std::is_lvalue_reference_v<T>;
0028
0029
0030 template <typename T>
0031 concept RValueType = !std::is_lvalue_reference_v<T>;
0032
0033 namespace detail {
0034
0035 struct EmptyFrameData {
0036 podio::CollectionIDTable getIDTable() const {
0037 return {};
0038 }
0039
0040
0041 std::optional<podio::CollectionReadBuffers> getCollectionBuffers(const std::string&) {
0042 return std::nullopt;
0043 }
0044
0045
0046 std::vector<std::string> getAvailableCollections() const {
0047 return {};
0048 }
0049
0050
0051 std::unique_ptr<podio::GenericParameters> getParameters() {
0052 return std::make_unique<podio::GenericParameters>();
0053 }
0054 };
0055 }
0056
0057 template <typename FrameDataT>
0058 std::optional<podio::CollectionReadBuffers> unpack(FrameDataT* data, const std::string& name) {
0059 return data->getCollectionBuffers(name);
0060 }
0061
0062
0063
0064
0065
0066
0067 class Frame {
0068
0069
0070 struct FrameConcept {
0071 virtual ~FrameConcept() = default;
0072 virtual const podio::CollectionBase* get(const std::string& name) const = 0;
0073 virtual const podio::CollectionBase* put(std::unique_ptr<podio::CollectionBase> coll, const std::string& name) = 0;
0074 virtual podio::GenericParameters& parameters() = 0;
0075 virtual const podio::GenericParameters& parameters() const = 0;
0076
0077 virtual std::vector<std::string> availableCollections() const = 0;
0078
0079
0080
0081 virtual podio::CollectionIDTable getIDTable() const = 0;
0082 };
0083
0084
0085
0086 template <typename FrameDataT>
0087 struct FrameModel final : FrameConcept, public ICollectionProvider {
0088
0089 FrameModel(std::unique_ptr<FrameDataT> data);
0090 ~FrameModel() = default;
0091 FrameModel(const FrameModel&) = delete;
0092 FrameModel& operator=(const FrameModel&) = delete;
0093 FrameModel(FrameModel&&) = default;
0094 FrameModel& operator=(FrameModel&&) = default;
0095
0096
0097
0098 const podio::CollectionBase* get(const std::string& name) const final;
0099
0100
0101
0102
0103 const podio::CollectionBase* put(std::unique_ptr<CollectionBase> coll, const std::string& name) final;
0104
0105
0106 podio::GenericParameters& parameters() override {
0107 return *m_parameters;
0108 }
0109
0110 const podio::GenericParameters& parameters() const override {
0111 return *m_parameters;
0112 }
0113
0114 bool get(uint32_t collectionID, podio::CollectionBase*& collection) const override;
0115
0116 podio::CollectionIDTable getIDTable() const override {
0117
0118 return {m_idTable.ids(), m_idTable.names()};
0119 }
0120
0121 std::vector<std::string> availableCollections() const override;
0122
0123 private:
0124 podio::CollectionBase* doGet(const std::string& name, bool setReferences = true) const;
0125
0126 using CollectionMapT = std::unordered_map<std::string, std::unique_ptr<podio::CollectionBase>>;
0127
0128 mutable CollectionMapT m_collections{};
0129 mutable std::unique_ptr<std::mutex> m_mapMtx{nullptr};
0130 std::unique_ptr<FrameDataT> m_data{nullptr};
0131 mutable std::unique_ptr<std::mutex> m_dataMtx{nullptr};
0132 podio::CollectionIDTable m_idTable{};
0133 std::unique_ptr<podio::GenericParameters> m_parameters{nullptr};
0134 mutable std::set<uint32_t> m_retrievedIDs{};
0135
0136 };
0137
0138 std::unique_ptr<FrameConcept> m_self;
0139
0140 public:
0141
0142 Frame();
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152 template <typename FrameDataT>
0153 Frame(std::unique_ptr<FrameDataT>);
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 template <RValueType FrameDataT>
0164 Frame(FrameDataT&&);
0165
0166
0167 Frame(const Frame&) = delete;
0168
0169 Frame& operator=(const Frame&) = delete;
0170
0171
0172 Frame(Frame&&) = default;
0173
0174
0175 Frame& operator=(Frame&&) = default;
0176
0177
0178
0179
0180
0181
0182 ~Frame() = default;
0183
0184
0185
0186
0187
0188
0189
0190
0191 template <CollectionType CollT>
0192 const CollT& get(const std::string& name) const;
0193
0194
0195
0196
0197
0198
0199
0200 const podio::CollectionBase* get(const std::string& name) const;
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216 template <CollectionRValueType CollT>
0217 const CollT& put(CollT&& coll, const std::string& name);
0218
0219
0220
0221
0222
0223
0224 void put(std::unique_ptr<podio::CollectionBase> coll, const std::string& name);
0225
0226
0227
0228
0229
0230
0231
0232 template <ValidGenericDataType T>
0233 inline void putParameter(const std::string& key, T value) {
0234 m_self->parameters().set(key, std::move(value));
0235 }
0236
0237
0238
0239
0240
0241
0242
0243
0244 inline void putParameter(const std::string& key, std::string value) {
0245 putParameter<std::string>(key, std::move(value));
0246 }
0247
0248
0249
0250
0251
0252
0253
0254
0255 inline void putParameter(const std::string& key, std::vector<std::string> values) {
0256 putParameter<std::vector<std::string>>(key, std::move(values));
0257 }
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 template <ValidGenericDataType T>
0270 inline void putParameter(const std::string& key, std::initializer_list<T>&& values) {
0271 putParameter<std::vector<T>>(key, std::move(values));
0272 }
0273
0274
0275
0276
0277
0278
0279
0280 template <ValidGenericDataType T>
0281 inline auto getParameter(const std::string& key) const {
0282 return m_self->parameters().get<T>(key);
0283 }
0284
0285
0286
0287
0288
0289
0290
0291 inline const podio::GenericParameters& getParameters() const {
0292 return m_self->parameters();
0293 }
0294
0295
0296
0297
0298
0299
0300 template <ValidGenericDataType T>
0301 inline std::vector<std::string> getParameterKeys() const {
0302 return m_self->parameters().getKeys<T>();
0303 }
0304
0305
0306
0307
0308
0309 std::vector<std::string> getAvailableCollections() const {
0310 return m_self->availableCollections();
0311 }
0312
0313
0314
0315
0316
0317
0318
0319 inline std::optional<std::string> getName(const podio::CollectionBase& coll) const {
0320 return getName(coll.getID());
0321 }
0322
0323
0324
0325
0326
0327
0328
0329 inline std::optional<std::string> getName(const uint32_t collectionID) const {
0330 return m_self->getIDTable().name(collectionID);
0331 }
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341 const podio::CollectionBase* getCollectionForWrite(const std::string& name) const {
0342 const auto* coll = m_self->get(name);
0343 if (coll) {
0344 coll->prepareForWrite();
0345 }
0346
0347 return coll;
0348 }
0349
0350
0351
0352
0353
0354
0355
0356 podio::CollectionIDTable getCollectionIDTableForWrite() const {
0357 return m_self->getIDTable();
0358 }
0359 };
0360
0361
0362
0363 inline Frame::Frame() : Frame(std::make_unique<detail::EmptyFrameData>()) {
0364 }
0365
0366 template <typename FrameDataT>
0367 Frame::Frame(std::unique_ptr<FrameDataT> data) : m_self(std::make_unique<FrameModel<FrameDataT>>(std::move(data))) {
0368 }
0369
0370 template <RValueType FrameDataT>
0371 Frame::Frame(FrameDataT&& data) : Frame(std::make_unique<FrameDataT>(std::move(data))) {
0372 }
0373
0374 template <CollectionType CollT>
0375 const CollT& Frame::get(const std::string& name) const {
0376 const auto* coll = dynamic_cast<const CollT*>(m_self->get(name));
0377 if (coll) {
0378 return *coll;
0379 }
0380
0381 static const auto emptyColl = CollT();
0382 return emptyColl;
0383 }
0384
0385 inline const podio::CollectionBase* Frame::get(const std::string& name) const {
0386 return m_self->get(name);
0387 }
0388
0389 inline void Frame::put(std::unique_ptr<podio::CollectionBase> coll, const std::string& name) {
0390 const auto* retColl = m_self->put(std::move(coll), name);
0391 if (!retColl) {
0392
0393 }
0394 }
0395
0396 template <CollectionRValueType CollT>
0397 const CollT& Frame::put(CollT&& coll, const std::string& name) {
0398 const auto* retColl = static_cast<const CollT*>(m_self->put(std::make_unique<CollT>(std::move(coll)), name));
0399 if (retColl) {
0400 return *retColl;
0401 }
0402
0403 static const auto emptyColl = CollT();
0404 return emptyColl;
0405 }
0406
0407 template <typename FrameDataT>
0408 Frame::FrameModel<FrameDataT>::FrameModel(std::unique_ptr<FrameDataT> data) :
0409 m_mapMtx(std::make_unique<std::mutex>()), m_dataMtx(std::make_unique<std::mutex>()) {
0410 if (!data) {
0411 throw std::invalid_argument(
0412 "FrameData is a nullptr. If you are reading from a file it may be corrupted or you may reading beyond the end "
0413 "of the file, please check the validity of the data before creating a Frame.");
0414 }
0415 m_data = std::move(data);
0416 m_idTable = std::move(m_data->getIDTable());
0417 m_parameters = std::move(m_data->getParameters());
0418 }
0419
0420 template <typename FrameDataT>
0421 const podio::CollectionBase* Frame::FrameModel<FrameDataT>::get(const std::string& name) const {
0422 return doGet(name);
0423 }
0424
0425 template <typename FrameDataT>
0426 podio::CollectionBase* Frame::FrameModel<FrameDataT>::doGet(const std::string& name, bool setReferences) const {
0427 {
0428
0429
0430
0431
0432 std::lock_guard lock{*m_mapMtx};
0433 if (const auto it = m_collections.find(name); it != m_collections.end()) {
0434 return it->second.get();
0435 }
0436 }
0437
0438 podio::CollectionBase* retColl = nullptr;
0439
0440
0441 if (m_data) {
0442
0443
0444 auto buffers = std::optional<podio::CollectionReadBuffers>{std::nullopt};
0445 {
0446 std::lock_guard lock{*m_dataMtx};
0447 buffers = unpack(m_data.get(), name);
0448 }
0449 if (buffers) {
0450 std::unique_ptr<podio::CollectionBase> coll{nullptr};
0451
0452 if (buffers->data == nullptr) {
0453 coll = buffers->createCollection(buffers.value(), true);
0454 } else {
0455 auto evolvedBuffers = podio::SchemaEvolution::instance().evolveBuffers(buffers.value(), buffers->schemaVersion,
0456 std::string(buffers->type));
0457 coll = evolvedBuffers.createCollection(evolvedBuffers, false);
0458 }
0459
0460 coll->prepareAfterRead();
0461 coll->setID(m_idTable.collectionID(name).value());
0462 {
0463 std::lock_guard mapLock{*m_mapMtx};
0464 auto [it, success] = m_collections.emplace(name, std::move(coll));
0465
0466
0467 retColl = it->second.get();
0468 }
0469
0470 if (setReferences) {
0471 retColl->setReferences(this);
0472 }
0473 }
0474 }
0475
0476 return retColl;
0477 }
0478
0479 template <typename FrameDataT>
0480 bool Frame::FrameModel<FrameDataT>::get(uint32_t collectionID, CollectionBase*& collection) const {
0481 const auto name = m_idTable.name(collectionID);
0482 if (!name) {
0483 return false;
0484 }
0485 const auto& [_, inserted] = m_retrievedIDs.insert(collectionID);
0486
0487 if (inserted) {
0488 auto coll = doGet(name.value());
0489 if (coll) {
0490 collection = coll;
0491 return true;
0492 }
0493 } else {
0494 auto coll = doGet(name.value(), false);
0495 if (coll) {
0496 collection = coll;
0497 return true;
0498 }
0499 }
0500
0501 return false;
0502 }
0503
0504 template <typename FrameDataT>
0505 const podio::CollectionBase* Frame::FrameModel<FrameDataT>::put(std::unique_ptr<podio::CollectionBase> coll,
0506 const std::string& name) {
0507 {
0508 std::lock_guard lock{*m_mapMtx};
0509 auto [it, success] = m_collections.try_emplace(name, std::move(coll));
0510 if (success) {
0511
0512
0513
0514
0515 it->second->setID(m_idTable.add(name));
0516 return it->second.get();
0517 } else {
0518 throw std::invalid_argument("An object with key " + name + " already exists in the frame");
0519 }
0520 }
0521
0522 return nullptr;
0523 }
0524
0525 template <typename FrameDataT>
0526 std::vector<std::string> Frame::FrameModel<FrameDataT>::availableCollections() const {
0527
0528
0529
0530
0531
0532
0533
0534 std::scoped_lock lock{*m_mapMtx, *m_dataMtx};
0535
0536 auto collections = m_data->getAvailableCollections();
0537 collections.reserve(collections.size() + m_collections.size());
0538
0539 for (const auto& [name, _] : m_collections) {
0540 collections.push_back(name);
0541 }
0542
0543 return collections;
0544 }
0545
0546 }
0547
0548 #endif