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