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