diff --git a/include/podio/RNTupleReader.h b/include/podio/RNTupleReader.h index 4a056f4f6..c56caceb4 100644 --- a/include/podio/RNTupleReader.h +++ b/include/podio/RNTupleReader.h @@ -5,6 +5,7 @@ #include "podio/SchemaEvolution.h" #include "podio/podioVersion.h" #include "podio/utilities/DatamodelRegistryIOHelpers.h" +#include "podio/utilities/RootHelpers.h" #include #include @@ -161,15 +162,8 @@ class RNTupleReader { std::unordered_map> m_readerEntries{}; std::unordered_map m_totalEntries{}; - struct CollectionInfo { - std::vector id{}; - std::vector name{}; - std::vector type{}; - std::vector isSubsetCollection{}; - std::vector schemaVersion{}; - }; - - std::unordered_map m_collectionInfo{}; + /// Map each category to the collections that have been written and are available + std::unordered_map> m_collectionInfo{}; std::vector m_availableCategories{}; diff --git a/include/podio/RNTupleWriter.h b/include/podio/RNTupleWriter.h index 49a1a128e..6529517b5 100644 --- a/include/podio/RNTupleWriter.h +++ b/include/podio/RNTupleWriter.h @@ -105,12 +105,9 @@ class RNTupleWriter { struct CategoryInfo { std::unique_ptr writer{nullptr}; ///< The RNTupleWriter for this category - // The following are assumed to run in parallel! - std::vector ids{}; ///< The ids of all collections - std::vector names{}; ///< The names of all collections - std::vector types{}; ///< The types of all collections - std::vector subsetCollections{}; ///< The flags identifying the subcollections - std::vector schemaVersions{}; ///< The schema versions of all collections + /// Collection info for this category + std::vector collInfo{}; + std::vector names{}; ///< The names of all collections to write // Storage for the keys & values of all the parameters of this category // (resp. at least the current entry) diff --git a/include/podio/ROOTLegacyReader.h b/include/podio/ROOTLegacyReader.h index 9693bfdb0..c98d52713 100644 --- a/include/podio/ROOTLegacyReader.h +++ b/include/podio/ROOTLegacyReader.h @@ -116,7 +116,7 @@ class ROOTLegacyReader { private: std::pair getLocalTreeAndEntry(const std::string& treename); - void createCollectionBranches(const std::vector& collInfo); + void createCollectionBranches(const std::vector& collInfo); podio::GenericParameters readEventMetaData(); diff --git a/include/podio/ROOTWriter.h b/include/podio/ROOTWriter.h index 5ee23835f..d3cb3e7c8 100644 --- a/include/podio/ROOTWriter.h +++ b/include/podio/ROOTWriter.h @@ -103,11 +103,10 @@ class ROOTWriter { /// Helper struct to group together all necessary state to write / process a /// given category. Created during the first writing of a category struct CategoryInfo { - TTree* tree{nullptr}; ///< The TTree to which this category is written - std::vector branches{}; ///< The branches for this category - std::vector collInfo{}; ///< Collection info for this category - podio::CollectionIDTable idTable{}; ///< The collection id table for this category - std::vector collsToWrite{}; ///< The collections to write for this category + TTree* tree{nullptr}; ///< The TTree to which this category is written + std::vector branches{}; ///< The branches for this category + std::vector collInfo{}; ///< Collection info for this category + std::vector collsToWrite{}; ///< The collections to write for this category // Storage for the keys & values of all the parameters of this category // (resp. at least the current entry) diff --git a/include/podio/utilities/RootHelpers.h b/include/podio/utilities/RootHelpers.h index 360ef6674..41d17f927 100644 --- a/include/podio/utilities/RootHelpers.h +++ b/include/podio/utilities/RootHelpers.h @@ -18,7 +18,17 @@ namespace root_utils { // A collection of additional information that describes the collection: the // collectionID, the collection (data) type, whether it is a subset // collection, and its schema version + struct CollectionWriteInfo { + uint32_t collectionID{static_cast(-1)}; ///< collection id + std::string dataType{}; ///< The fully qualified data type of the collection + bool isSubset{false}; ///< Whether this collection is a subset collection or not + unsigned int schemaVersion{0}; ///< The schema version of the collection type + std::string name{}; ///< The name of the collection + std::string storageType{}; ///< The type in which the data is actually stored + }; + // The format used until version 1.2 using CollectionWriteInfoT = std::tuple; + // for backwards compatibility using CollectionInfoWithoutSchemaT = std::tuple; diff --git a/src/RNTupleReader.cc b/src/RNTupleReader.cc index 5e935b053..579e4014f 100644 --- a/src/RNTupleReader.cc +++ b/src/RNTupleReader.cc @@ -4,11 +4,13 @@ #include "podio/CollectionIDTable.h" #include "podio/DatamodelRegistry.h" #include "podio/GenericParameters.h" +#include "podio/utilities/RootHelpers.h" #include "rootUtils.h" #include #include +#include #include // Adjust for the move of this out of ROOT v7 in @@ -48,27 +50,11 @@ bool RNTupleReader::initCategory(const std::string& category) { // Assume that the metadata is the same in all files auto filename = m_filenames[0]; - auto& collInfo = m_collectionInfo[category]; + auto collInfo = m_metadata_readers[filename]->GetView>( + {root_utils::collInfoName(category)}); - auto id = m_metadata_readers[filename]->GetView>(root_utils::idTableName(category)); - collInfo.id = id(0); - - auto collectionName = - m_metadata_readers[filename]->GetView>(root_utils::collectionName(category)); - collInfo.name = collectionName(0); - - auto collectionType = - m_metadata_readers[filename]->GetView>(root_utils::collInfoName(category)); - collInfo.type = collectionType(0); - - auto subsetCollection = - m_metadata_readers[filename]->GetView>(root_utils::subsetCollection(category)); - collInfo.isSubsetCollection = subsetCollection(0); - - auto schemaVersion = m_metadata_readers[filename]->GetView>("schemaVersion_" + category); - collInfo.schemaVersion = schemaVersion(0); - - m_idTables[category] = std::make_shared(collInfo.id, collInfo.name); + m_collectionInfo[category] = collInfo(0); + m_idTables[category] = root_utils::makeCollIdTable(collInfo(0)); return true; } @@ -162,7 +148,7 @@ std::unique_ptr RNTupleReader::readEntry(const std::string& categ // Make sure to not silently ignore non-existant but requested collections if (!collsToRead.empty()) { for (const auto& name : collsToRead) { - if (std::ranges::find(collInfo.name, name) == collInfo.name.end()) { + if (std::ranges::find(collInfo, name, &root_utils::CollectionWriteInfo::name) == collInfo.end()) { throw std::invalid_argument(name + " is not available from Frame"); } } @@ -184,47 +170,46 @@ std::unique_ptr RNTupleReader::readEntry(const std::string& categ // we set all the fields there in any case. auto dentry = m_readers[category][readerIndex]->GetModel().CreateEntry(); - for (size_t i = 0; i < collInfo.id.size(); ++i) { - if (!collsToRead.empty() && std::ranges::find(collsToRead, collInfo.name[i]) == collsToRead.end()) { + for (const auto& coll : collInfo) { + if (!collsToRead.empty() && std::ranges::find(collsToRead, coll.name) == collsToRead.end()) { continue; } - const auto& collType = collInfo.type[i]; + const auto& collType = coll.dataType; const auto& bufferFactory = podio::CollectionBufferFactory::instance(); - auto maybeBuffers = - bufferFactory.createBuffers(collType, collInfo.schemaVersion[i], collInfo.isSubsetCollection[i]); + auto maybeBuffers = bufferFactory.createBuffers(collType, coll.schemaVersion, coll.isSubset); auto collBuffers = maybeBuffers.value_or(podio::CollectionReadBuffers{}); if (!maybeBuffers) { - std::cout << "WARNING: Buffers couldn't be created for collection " << collInfo.name[i] << " of type " - << collInfo.type[i] << " and schema version " << collInfo.schemaVersion[i] << std::endl; + std::cout << "WARNING: Buffers couldn't be created for collection " << coll.name << " of type " << coll.dataType + << " and schema version " << coll.schemaVersion << std::endl; return nullptr; } - if (collInfo.isSubsetCollection[i]) { - auto brName = root_utils::subsetBranch(collInfo.name[i]); + if (coll.isSubset) { + auto brName = root_utils::subsetBranch(coll.name); auto vec = new std::vector; dentry->BindRawPtr(brName, vec); collBuffers.references->at(0) = std::unique_ptr>(vec); } else { - dentry->BindRawPtr(collInfo.name[i], collBuffers.data); + dentry->BindRawPtr(coll.name, collBuffers.data); const auto relVecNames = podio::DatamodelRegistry::instance().getRelationNames(collType); for (size_t j = 0; j < relVecNames.relations.size(); ++j) { const auto relName = relVecNames.relations[j]; auto vec = new std::vector; - const auto brName = root_utils::refBranch(collInfo.name[i], relName); + const auto brName = root_utils::refBranch(coll.name, relName); dentry->BindRawPtr(brName, vec); collBuffers.references->at(j) = std::unique_ptr>(vec); } for (size_t j = 0; j < relVecNames.vectorMembers.size(); ++j) { const auto vecName = relVecNames.vectorMembers[j]; - const auto brName = root_utils::vecBranch(collInfo.name[i], vecName); + const auto brName = root_utils::vecBranch(coll.name, vecName); dentry->BindRawPtr(brName, collBuffers.vectorMembers->at(j).second); } } - buffers.emplace(collInfo.name[i], std::move(collBuffers)); + buffers.emplace(coll.name, std::move(collBuffers)); } m_readers[category][readerIndex]->LoadEntry(localEntry, *dentry); diff --git a/src/RNTupleWriter.cc b/src/RNTupleWriter.cc index b34e21446..cb97888cc 100644 --- a/src/RNTupleWriter.cc +++ b/src/RNTupleWriter.cc @@ -2,6 +2,7 @@ #include "podio/DatamodelRegistry.h" #include "podio/SchemaEvolution.h" #include "podio/podioVersion.h" +#include "podio/utilities/RootHelpers.h" #include "rootUtils.h" #include "TFile.h" @@ -81,14 +82,13 @@ void RNTupleWriter::writeFrame(const podio::Frame& frame, const std::string& cat auto model = createModels(collections); catInfo.writer = ROOT::Experimental::RNTupleWriter::Append(std::move(model), category, *m_file.get(), {}); + catInfo.collInfo.reserve(collections.size()); for (const auto& [name, coll] : collections) { - catInfo.ids.emplace_back(coll->getID()); - catInfo.types.emplace_back(coll->getTypeName()); - catInfo.subsetCollections.emplace_back(coll->isSubsetCollection()); - catInfo.schemaVersions.emplace_back(coll->getSchemaVersion()); + catInfo.collInfo.emplace_back(coll->getID(), std::string(coll->getTypeName()), coll->isSubsetCollection(), + coll->getSchemaVersion(), name, root_utils::getStorageTypeName(coll)); } } else { - if (!root_utils::checkConsistentColls(catInfo.names, collsToWrite)) { + if (!root_utils::checkConsistentColls(catInfo.collInfo, collsToWrite)) { throw std::runtime_error("Trying to write category '" + category + "' with inconsistent collection content. " + root_utils::getInconsistentCollsMsg(catInfo.names, collsToWrite)); } @@ -251,16 +251,9 @@ void RNTupleWriter::finish() { } for (auto& [category, collInfo] : m_categories) { - auto idField = metadata->MakeField>({root_utils::idTableName(category)}); - *idField = collInfo.ids; - auto collectionNameField = metadata->MakeField>({root_utils::collectionName(category)}); - *collectionNameField = collInfo.names; - auto collectionTypeField = metadata->MakeField>({root_utils::collInfoName(category)}); - *collectionTypeField = collInfo.types; - auto subsetCollectionField = metadata->MakeField>({root_utils::subsetCollection(category)}); - *subsetCollectionField = collInfo.subsetCollections; - auto schemaVersionField = metadata->MakeField>({"schemaVersion_" + category}); - *schemaVersionField = collInfo.schemaVersions; + auto collInfoField = + metadata->MakeField>({root_utils::collInfoName(category)}); + *collInfoField = collInfo.collInfo; } metadata->Freeze(); diff --git a/src/ROOTLegacyReader.cc b/src/ROOTLegacyReader.cc index d94303aa8..d8329c7f2 100644 --- a/src/ROOTLegacyReader.cc +++ b/src/ROOTLegacyReader.cc @@ -152,7 +152,12 @@ void ROOTLegacyReader::openFiles(const std::vector& filenames) { collInfoBranch->SetAddress(&collectionInfo); collInfoBranch->GetEntry(0); } - createCollectionBranches(*collectionInfo); + std::vector collInfo; + collInfo.reserve(collectionInfo->size()); + for (auto& [id, typeName, isSubsetColl, schemaVersion] : *collectionInfo) { + collInfo.emplace_back(id, std::move(typeName), isSubsetColl, schemaVersion); + } + createCollectionBranches(collInfo); delete collectionInfo; } else { std::cout << "PODIO: Reconstructing CollectionTypeInfo branch from other sources in file: \'" @@ -170,10 +175,10 @@ unsigned ROOTLegacyReader::getEntries(const std::string& name) const { return m_chain->GetEntries(); } -void ROOTLegacyReader::createCollectionBranches(const std::vector& collInfo) { +void ROOTLegacyReader::createCollectionBranches(const std::vector& collInfo) { size_t collectionIndex{0}; - for (const auto& [collID, collType, isSubsetColl, collSchemaVersion] : collInfo) { + for (const auto& [collID, collType, isSubsetColl, collSchemaVersion, _, __] : collInfo) { // We only write collections that are in the collectionIDTable, so no need // to check here const auto name = m_table->name(collID).value(); diff --git a/src/ROOTReader.cc b/src/ROOTReader.cc index 1164321b0..184c4806b 100644 --- a/src/ROOTReader.cc +++ b/src/ROOTReader.cc @@ -5,6 +5,7 @@ #include "podio/CollectionIDTable.h" #include "podio/DatamodelRegistry.h" #include "podio/GenericParameters.h" +#include "podio/podioVersion.h" #include "podio/utilities/RootHelpers.h" #include "rootUtils.h" @@ -13,6 +14,7 @@ #include "TClass.h" #include +#include #include #include @@ -20,11 +22,11 @@ namespace podio { std::tuple, std::vector> createCollectionBranches(TChain* chain, const podio::CollectionIDTable& idTable, - const std::vector& collInfo); + const std::vector& collInfo); std::tuple, std::vector> createCollectionBranchesIndexBased(TChain* chain, const podio::CollectionIDTable& idTable, - const std::vector& collInfo); + const std::vector& collInfo); template void ROOTReader::readParams(ROOTReader::CategoryInfo& catInfo, podio::GenericParameters& params, bool reloadBranches, @@ -163,7 +165,7 @@ ROOTReader::CategoryInfo& ROOTReader::getCategoryInfo(const std::string& categor if (auto it = m_categories.find(category); it != m_categories.end()) { // Use the id table as proxy to check whether this category has been // initialized already - if (it->second.table == nullptr) { + if (it->second.branches.empty()) { initCategory(it->second, category); } return it->second; @@ -177,28 +179,47 @@ ROOTReader::CategoryInfo& ROOTReader::getCategoryInfo(const std::string& categor } void ROOTReader::initCategory(CategoryInfo& catInfo, const std::string& category) { - catInfo.table = std::make_shared(); - auto* table = catInfo.table.get(); - auto* tableBranch = root_utils::getBranch(m_metaChain.get(), root_utils::idTableName(category)); - tableBranch->SetAddress(&table); - tableBranch->GetEntry(0); auto* collInfoBranch = root_utils::getBranch(m_metaChain.get(), root_utils::collInfoName(category)); - auto collInfo = new std::vector(); - if (m_fileVersion < podio::version::Version{0, 16, 4}) { - auto oldCollInfo = new std::vector(); - collInfoBranch->SetAddress(&oldCollInfo); + auto collInfo = new std::vector(); + if (m_fileVersion >= podio::version::Version{1, 2, 99}) { + collInfoBranch->SetAddress(&collInfo); collInfoBranch->GetEntry(0); - collInfo->reserve(oldCollInfo->size()); - for (auto&& [collID, collType, isSubsetColl] : *oldCollInfo) { - // Manually set the schema version to 1 - collInfo->emplace_back(collID, std::move(collType), isSubsetColl, 1u); + } else { + auto collInfoOld = new std::vector(); + if (m_fileVersion < podio::version::Version{0, 16, 4}) { + auto collInfoReallyOld = new std::vector(); + collInfoBranch->SetAddress(&collInfoReallyOld); + collInfoBranch->GetEntry(0); + collInfoOld->reserve(collInfoReallyOld->size()); + for (auto& [collID, collType, isSubsetColl] : *collInfoReallyOld) { + // Manually set the schema version to 1 + collInfo->emplace_back(collID, std::move(collType), isSubsetColl, 1u); + } + delete collInfoReallyOld; + } else { + collInfoBranch->SetAddress(&collInfoOld); + collInfoBranch->GetEntry(0); + } + // "Convert" to new style + collInfo->reserve(collInfoOld->size()); + for (auto& [id, typeName, isSubsetColl, schemaVersion] : *collInfoOld) { + collInfo->emplace_back(id, std::move(typeName), isSubsetColl, schemaVersion); } - delete oldCollInfo; + delete collInfoOld; + } + + // Recreate the idTable form the collection info if necessary, otherwise read + // it directly + if (m_fileVersion >= podio::version::Version{1, 2, 99}) { + catInfo.table = root_utils::makeCollIdTable(*collInfo); } else { - collInfoBranch->SetAddress(&collInfo); - collInfoBranch->GetEntry(0); + catInfo.table = std::make_shared(); + auto* table = catInfo.table.get(); + auto* tableBranch = root_utils::getBranch(m_metaChain.get(), root_utils::idTableName(category)); + tableBranch->SetAddress(&table); + tableBranch->GetEntry(0); } // For backwards compatibility make it possible to read the index based files @@ -238,7 +259,7 @@ std::vector getAvailableCategories(TChain* metaChain) { for (int i = 0; i < branches->GetEntries(); ++i) { const std::string name = branches->At(i)->GetName(); - const auto fUnder = name.find(root_utils::idTableName("")); + const auto fUnder = name.find(root_utils::collInfoName("")); if (fUnder != std::string::npos) { brNames.emplace_back(name.substr(0, fUnder)); } @@ -325,7 +346,7 @@ std::vector ROOTReader::getAvailableCategories() const { std::tuple, std::vector> createCollectionBranchesIndexBased(TChain* chain, const podio::CollectionIDTable& idTable, - const std::vector& collInfo) { + const std::vector& collInfo) { size_t collectionIndex{0}; std::vector collBranches; @@ -333,7 +354,7 @@ createCollectionBranchesIndexBased(TChain* chain, const podio::CollectionIDTable std::vector storedClasses; storedClasses.reserve(collInfo.size()); - for (const auto& [collID, collType, isSubsetColl, collSchemaVersion] : collInfo) { + for (const auto& [collID, collType, isSubsetColl, collSchemaVersion, _, __] : collInfo) { // We only write collections that are in the collectionIDTable, so no need // to check here const auto name = idTable.name(collID).value(); @@ -377,7 +398,7 @@ createCollectionBranchesIndexBased(TChain* chain, const podio::CollectionIDTable std::tuple, std::vector> createCollectionBranches(TChain* chain, const podio::CollectionIDTable& idTable, - const std::vector& collInfo) { + const std::vector& collInfo) { size_t collectionIndex{0}; std::vector collBranches; @@ -385,7 +406,7 @@ createCollectionBranches(TChain* chain, const podio::CollectionIDTable& idTable, std::vector storedClasses; storedClasses.reserve(collInfo.size()); - for (const auto& [collID, collType, isSubsetColl, collSchemaVersion] : collInfo) { + for (const auto& [collID, collType, isSubsetColl, collSchemaVersion, _, __] : collInfo) { // We only write collections that are in the collectionIDTable, so no need // to check here const auto name = idTable.name(collID).value(); diff --git a/src/ROOTWriter.cc b/src/ROOTWriter.cc index c4a3bc30f..42d4042ff 100644 --- a/src/ROOTWriter.cc +++ b/src/ROOTWriter.cc @@ -32,7 +32,6 @@ void ROOTWriter::writeFrame(const podio::Frame& frame, const std::string& catego // Use the TTree as proxy here to decide whether this category has already // been initialized if (catInfo.tree == nullptr) { - catInfo.idTable = frame.getCollectionIDTableForWrite(); catInfo.collsToWrite = podio::utils::sortAlphabeticaly(collsToWrite); catInfo.tree = new TTree(category.c_str(), (category + " data tree").c_str()); catInfo.tree->SetDirectory(m_file.get()); @@ -54,11 +53,10 @@ void ROOTWriter::writeFrame(const podio::Frame& frame, const std::string& catego // collections if (catInfo.branches.empty()) { initBranches(catInfo, collections, const_cast(frame.getParameters())); - } else { // Make sure that the category contents are consistent with the initial // frame in the category - if (!root_utils::checkConsistentColls(catInfo.collsToWrite, collsToWrite)) { + if (!root_utils::checkConsistentColls(catInfo.collInfo, collsToWrite)) { throw std::runtime_error("Trying to write category '" + category + "' with inconsistent collection content. " + root_utils::getInconsistentCollsMsg(catInfo.collsToWrite, collsToWrite)); } @@ -120,8 +118,8 @@ void ROOTWriter::initBranches(CategoryInfo& catInfo, const std::vectorgetTypeName()), - coll->isSubsetCollection(), coll->getSchemaVersion()); + catInfo.collInfo.emplace_back(coll->getID(), std::string(coll->getTypeName()), coll->isSubsetCollection(), + coll->getSchemaVersion(), name, root_utils::getStorageTypeName(coll)); } fillParams(catInfo, parameters); @@ -175,7 +173,6 @@ void ROOTWriter::finish() { // Store the collection id table and collection info for reading in the meta tree for (/*const*/ auto& [category, info] : m_categories) { - metaTree->Branch(root_utils::idTableName(category).c_str(), &info.idTable); metaTree->Branch(root_utils::collInfoName(category).c_str(), &info.collInfo); } diff --git a/src/rootUtils.h b/src/rootUtils.h index b58fc6aea..fdb6b0c96 100644 --- a/src/rootUtils.h +++ b/src/rootUtils.h @@ -1,6 +1,7 @@ #ifndef PODIO_ROOT_UTILS_H // NOLINT(llvm-header-guard): internal headers confuse clang-tidy #define PODIO_ROOT_UTILS_H // NOLINT(llvm-header-guard): internal headers confuse clang-tidy +#include "podio/CollectionBase.h" #include "podio/CollectionIDTable.h" #include "podio/utilities/MiscHelpers.h" #include "podio/utilities/RootHelpers.h" @@ -199,6 +200,10 @@ inline std::string subsetBranch(const std::string& name) { return name + "_objIdx"; } +inline std::string getStorageTypeName(const podio::CollectionBase* coll) { + return "std::vector<" + std::string(coll->getDataTypeName()) + ">"; +} + /** * Reset all the branches that by getting them from the TTree again */ @@ -259,7 +264,7 @@ inline void readBranchesData(const CollectionBranches& branches, Long64_t entry) * collections */ inline auto reconstructCollectionInfo(TTree* eventTree, podio::CollectionIDTable const& idTable) { - std::vector collInfo; + std::vector collInfo; for (size_t iColl = 0; iColl < idTable.names().size(); ++iColl) { const auto collID = idTable.ids()[iColl]; @@ -287,26 +292,22 @@ inline auto reconstructCollectionInfo(TTree* eventTree, podio::CollectionIDTable * can have random order wrt each other, but the assumption is that each vector * only contains unique names. */ -inline bool checkConsistentColls(const std::vector& existingColls, +inline bool checkConsistentColls(const std::vector& collInfo, const std::vector& candidateColls) { - if (existingColls.size() != candidateColls.size()) { + if (collInfo.size() != candidateColls.size()) { return false; } - // Since we are guaranteed to have unique names here, we can just look for - // collisions brute force, which seems to be quickest approach for vector - // sizes we typically have (few hundred). We can take advantage of the fact - // that the existingColls are ordered (alphabetically and case-insensitive), - // so we can do a binary_search for (const auto& id : candidateColls) { - if (!std::binary_search(existingColls.begin(), existingColls.end(), id, [](const auto& lhs, const auto& rhs) { + std::ranges::binary_search( + collInfo, id, + [](const auto& lhs, const auto& rhs) { return lhs.size() == rhs.size() && std::lexicographical_compare( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](const auto cl, const auto cr) { return std::tolower(cl) < std::tolower(cr); }); - })) { - return false; - } + }, + &root_utils::CollectionWriteInfo::name); } return true; @@ -362,6 +363,21 @@ inline std::string getInconsistentCollsMsg(const std::vector& exist return sstr.str(); } +/// Create a collection id table from the information in the +/// CollectionWriteInfos +inline std::shared_ptr makeCollIdTable(const std::vector& collInfo) { + std::vector ids{}; + ids.reserve(collInfo.size()); + std::vector names{}; + names.reserve(collInfo.size()); + for (const auto& [id, _1, _2, _3, name, _5] : collInfo) { + ids.emplace_back(id); + names.emplace_back(name); + } + + return std::make_shared(std::move(ids), std::move(names)); +} + } // namespace podio::root_utils #endif diff --git a/src/root_selection.xml b/src/root_selection.xml index 38db949c0..dc4dbb9db 100644 --- a/src/root_selection.xml +++ b/src/root_selection.xml @@ -5,5 +5,8 @@ + + +