diff --git a/tree/dataframe/test/datasource_ntuple.cxx b/tree/dataframe/test/datasource_ntuple.cxx index b5a64fb4820c7..9e25a83f1a060 100644 --- a/tree/dataframe/test/datasource_ntuple.cxx +++ b/tree/dataframe/test/datasource_ntuple.cxx @@ -455,7 +455,7 @@ TEST_F(RNTupleDSTest, AlternativeColumnTypes) auto multipleAlternativeTypes = df.Define("nJets", [](const std::vector &jets) { return jets.size(); }, {"jets"}) - .Define("smallestJet", [](const std::set &jets) { return *(jets.begin()); }, {"jets"}) + .Define("smallestJet", [](const std::multiset &jets) { return *(jets.begin()); }, {"jets"}) .Min("smallestJet") .GetValue(); EXPECT_FLOAT_EQ(1.f, multipleAlternativeTypes); diff --git a/tree/ntuple/inc/ROOT/RField/RFieldProxiedCollection.hxx b/tree/ntuple/inc/ROOT/RField/RFieldProxiedCollection.hxx index 9a1ed6cba5b58..fe0d63b11364c 100644 --- a/tree/ntuple/inc/ROOT/RField/RFieldProxiedCollection.hxx +++ b/tree/ntuple/inc/ROOT/RField/RFieldProxiedCollection.hxx @@ -154,7 +154,7 @@ protected: /// (Attach() and setting fItemSize) RProxiedCollectionField(std::string_view fieldName, TClass *classp); - std::unique_ptr CloneImpl(std::string_view newName) const final; + std::unique_ptr CloneImpl(std::string_view newName) const override; const RColumnRepresentations &GetColumnRepresentations() const final; void GenerateColumns() final; void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final; @@ -165,7 +165,7 @@ protected: std::size_t AppendImpl(const void *from) final; void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final; - void ReconcileOnDiskField(const RNTupleDescriptor &desc) final; + void ReconcileOnDiskField(const RNTupleDescriptor &desc) override; void CommitClusterImpl() final { fNWritten = 0; } @@ -277,6 +277,15 @@ public: kMultiMap, kUnorderedMultiMap }; + +private: + EMapType fMapType; + +protected: + std::unique_ptr CloneImpl(std::string_view newName) const final; + void ReconcileOnDiskField(const RNTupleDescriptor &desc) final; + +public: RMapField(std::string_view fieldName, EMapType mapType, std::unique_ptr itemField); RMapField(RMapField &&other) = default; RMapField &operator=(RMapField &&other) = default; @@ -364,6 +373,15 @@ public: kMultiSet, kUnorderedMultiSet }; + +private: + ESetType fSetType; + +protected: + std::unique_ptr CloneImpl(std::string_view newName) const final; + void ReconcileOnDiskField(const RNTupleDescriptor &desc) final; + +public: RSetField(std::string_view fieldName, ESetType setType, std::unique_ptr itemField); RSetField(RSetField &&other) = default; RSetField &operator=(RSetField &&other) = default; diff --git a/tree/ntuple/src/RFieldMeta.cxx b/tree/ntuple/src/RFieldMeta.cxx index aeeade9d72892..1bccf8b34cb31 100644 --- a/tree/ntuple/src/RFieldMeta.cxx +++ b/tree/ntuple/src/RFieldMeta.cxx @@ -880,7 +880,7 @@ void ROOT::RProxiedCollectionField::AcceptVisitor(ROOT::Detail::RFieldVisitor &v //------------------------------------------------------------------------------ ROOT::RMapField::RMapField(std::string_view fieldName, EMapType mapType, std::unique_ptr itemField) - : RProxiedCollectionField(fieldName, EnsureValidClass(BuildMapTypeName(mapType, itemField.get()))) + : RProxiedCollectionField(fieldName, EnsureValidClass(BuildMapTypeName(mapType, itemField.get()))), fMapType(mapType) { auto *itemClass = fProxy->GetValueClass(); fItemSize = itemClass->GetClassSize(); @@ -888,15 +888,58 @@ ROOT::RMapField::RMapField(std::string_view fieldName, EMapType mapType, std::un Attach(std::move(itemField)); } +std::unique_ptr ROOT::RMapField::CloneImpl(std::string_view newName) const +{ + return std::make_unique(newName, fMapType, fSubfields[0]->Clone(fSubfields[0]->GetFieldName())); +} + +void ROOT::RMapField::ReconcileOnDiskField(const RNTupleDescriptor &desc) +{ + static const std::vector prefixesRegular = {"std::map<", "std::unordered_map<", "std::set<", + "std::unordered_set<"}; + + EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError(); + + switch (fMapType) { + case EMapType::kMap: + case EMapType::kUnorderedMap: EnsureMatchingTypePrefix(desc, prefixesRegular).ThrowOnError(); break; + default: + break; + // no restrictions for multimaps + } +} + //------------------------------------------------------------------------------ ROOT::RSetField::RSetField(std::string_view fieldName, ESetType setType, std::unique_ptr itemField) - : ROOT::RProxiedCollectionField(fieldName, EnsureValidClass(BuildSetTypeName(setType, *itemField))) + : ROOT::RProxiedCollectionField(fieldName, EnsureValidClass(BuildSetTypeName(setType, *itemField))), + fSetType(setType) { fItemSize = itemField->GetValueSize(); Attach(std::move(itemField)); } +std::unique_ptr ROOT::RSetField::CloneImpl(std::string_view newName) const +{ + return std::make_unique(newName, fSetType, fSubfields[0]->Clone(fSubfields[0]->GetFieldName())); +} + +void ROOT::RSetField::ReconcileOnDiskField(const RNTupleDescriptor &desc) +{ + static const std::vector prefixesRegular = {"std::set<", "std::unordered_set<", "std::map<", + "std::unordered_map<"}; + + EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError(); + + switch (fSetType) { + case ESetType::kSet: + case ESetType::kUnorderedSet: EnsureMatchingTypePrefix(desc, prefixesRegular).ThrowOnError(); break; + default: + break; + // no restrictions for multisets + } +} + //------------------------------------------------------------------------------ namespace { diff --git a/tree/ntuple/src/RFieldSequenceContainer.cxx b/tree/ntuple/src/RFieldSequenceContainer.cxx index cd5e1cd133563..0f526a0a1b8a0 100644 --- a/tree/ntuple/src/RFieldSequenceContainer.cxx +++ b/tree/ntuple/src/RFieldSequenceContainer.cxx @@ -547,7 +547,7 @@ ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr ROOT::RVectorField::CreateUntyped(std::string_view fieldName, std::unique_ptr itemField) { - return std::unique_ptr(new RVectorField(fieldName, std::move(itemField), "")); + return std::unique_ptr(new RVectorField(fieldName, itemField->Clone("_0"), "")); } std::unique_ptr ROOT::RVectorField::CloneImpl(std::string_view newName) const diff --git a/tree/ntuple/test/CMakeLists.txt b/tree/ntuple/test/CMakeLists.txt index 9d090c68a1059..a31206aea57fa 100644 --- a/tree/ntuple/test/CMakeLists.txt +++ b/tree/ntuple/test/CMakeLists.txt @@ -38,6 +38,11 @@ ROOT_GENERATE_DICTIONARY(RNTupleDescriptorDict ${CMAKE_CURRENT_SOURCE_DIR}/RNTup ROOT_ADD_GTEST(ntuple_endian ntuple_endian.cxx LIBRARIES ROOTNTuple) ROOT_ADD_GTEST(ntuple_evolution_type ntuple_evolution_type.cxx LIBRARIES ROOTNTuple) +ROOT_GENERATE_DICTIONARY(STLContainerEvolutionDict ${CMAKE_CURRENT_SOURCE_DIR}/STLContainerEvolution.hxx + MODULE ntuple_evolution_type + LINKDEF STLContainerEvolutionLinkDef.h + OPTIONS -inlineInputHeader + DEPENDENCIES CustomStruct) if(NOT MSVC) # These unit tests rely on fork(), which is not available on Windows. ROOT_ADD_GTEST(ntuple_evolution_shape ntuple_evolution_shape.cxx LIBRARIES ROOTNTuple) diff --git a/tree/ntuple/test/STLContainerEvolution.hxx b/tree/ntuple/test/STLContainerEvolution.hxx new file mode 100644 index 0000000000000..65fc69403589a --- /dev/null +++ b/tree/ntuple/test/STLContainerEvolution.hxx @@ -0,0 +1,39 @@ +#ifndef ROOT_RNTuple_Test_STLContainerEvolution +#define ROOT_RNTuple_Test_STLContainerEvolution + +#include +#include +#include +#include +#include +#include + +// The following std::hash specializations allow for creating unordered sets of pairs in the Collections test. +// It is a quick but bad hash but for this test though it should be ok. +template <> +struct std::hash> { + std::size_t operator()(const std::pair &p) const noexcept + { + std::size_t h1 = std::hash{}(p.first); + std::size_t h2 = std::hash{}(p.second); + return h1 ^ (h2 << 1); + } +}; + +template <> +struct std::hash> { + std::size_t operator()(const std::pair &p) const noexcept + { + std::size_t h1 = std::hash{}(p.first); + std::size_t h2 = std::hash{}(p.second); + return h1 ^ (h2 << 1); + } +}; + +template +struct CollectionProxy { + using ValueType = T; + std::vector v; //! +}; + +#endif diff --git a/tree/ntuple/test/STLContainerEvolutionLinkDef.h b/tree/ntuple/test/STLContainerEvolutionLinkDef.h new file mode 100644 index 0000000000000..36fde4f9cd9da --- /dev/null +++ b/tree/ntuple/test/STLContainerEvolutionLinkDef.h @@ -0,0 +1,40 @@ +#ifdef __CLING__ + +#pragma link C++ class std::set+; +#pragma link C++ class std::set+; +#pragma link C++ class std::set>+; +#pragma link C++ class std::set>+; + +#pragma link C++ class std::unordered_set+; +#pragma link C++ class std::unordered_set+; +#pragma link C++ class std::unordered_set>+; +#pragma link C++ class std::unordered_set>+; + +#pragma link C++ class std::multiset+; +#pragma link C++ class std::multiset+; +#pragma link C++ class std::multiset>+; +#pragma link C++ class std::multiset>+; + +#pragma link C++ class std::unordered_multiset+; +#pragma link C++ class std::unordered_multiset+; +#pragma link C++ class std::unordered_multiset>+; +#pragma link C++ class std::unordered_multiset>+; + +#pragma link C++ class std::map+; +#pragma link C++ class std::map+; + +#pragma link C++ class std::unordered_map+; +#pragma link C++ class std::unordered_map+; + +#pragma link C++ class std::multimap+; +#pragma link C++ class std::multimap+; + +#pragma link C++ class std::unordered_multimap+; +#pragma link C++ class std::unordered_multimap+; + +#pragma link C++ class CollectionProxy+; +#pragma link C++ class CollectionProxy+; +#pragma link C++ class CollectionProxy>+; +#pragma link C++ class CollectionProxy>+; + +#endif diff --git a/tree/ntuple/test/ntuple_evolution_type.cxx b/tree/ntuple/test/ntuple_evolution_type.cxx index 8fcf9df075384..75ef884464ccb 100644 --- a/tree/ntuple/test/ntuple_evolution_type.cxx +++ b/tree/ntuple/test/ntuple_evolution_type.cxx @@ -1,4 +1,6 @@ #include "ntuple_test.hxx" +#include "SimpleCollectionProxy.hxx" +#include "STLContainerEvolution.hxx" #include #include @@ -253,3 +255,319 @@ TEST(RNTupleEvolution, ArrayAsRVec) EXPECT_EQ(1, a(0)[0]); EXPECT_EQ(2, a(0)[1]); } + +TEST(RNTupleEvolution, NullableToVector) +{ + FileRaii fileGuard("test_ntuple_evolution_nullable_to_vector.root"); + { + auto model = ROOT::RNTupleModel::Create(); + auto o = model->MakeField>("o"); + auto u = model->MakeField>("u"); + auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); + + *o = 137; + *u = std::make_unique(42); + writer->Fill(); + o->reset(); + u->reset(); + writer->Fill(); + } + + auto reader = RNTupleReader::Open("ntpl", fileGuard.GetPath()); + auto v1 = reader->GetView>("o"); + auto v2 = reader->GetView>("o"); + auto v3 = reader->GetView>("u"); + auto v4 = reader->GetView>("u"); + EXPECT_EQ(137, v1(0)[0]); + EXPECT_EQ(137, v2(0)[0]); + EXPECT_EQ(42, v3(0)[0]); + EXPECT_EQ(42, v4(0)[0]); + EXPECT_TRUE(v1(1).empty()); + EXPECT_TRUE(v2(1).empty()); + EXPECT_TRUE(v3(1).empty()); + EXPECT_TRUE(v4(1).empty()); +} + +namespace { +template +void WriteCollection(std::string_view ntplName, TFile &f) +{ + auto model = RNTupleModel::Create(); + auto ptrCollection = model->MakeField("f"); + auto writer = ROOT::RNTupleWriter::Append(std::move(model), ntplName, f); + if constexpr (OfPairsT) { + *ptrCollection = {{1, 2}, {3, 4}, {5, 6}}; + } else { + *ptrCollection = {1, 2, 3}; + } + writer->Fill(); + ptrCollection->clear(); + writer->Fill(); + if constexpr (OfPairsT) { + *ptrCollection = {{7, 8}}; + } else { + *ptrCollection = {4}; + } + writer->Fill(); +} + +template +void ReadCollection(std::string_view ntplName, std::string_view path) +{ + auto reader = RNTupleReader::Open(ntplName, path); + ASSERT_EQ(3u, reader->GetNEntries()); + + auto view = reader->GetView("f"); + CollectionT exp0; + CollectionT exp2; + if constexpr (OfPairsT) { + exp0 = {{1, 2}, {3, 4}, {5, 6}}; + exp2 = {{7, 8}}; + } else { + exp0 = {1, 2, 3}; + exp2 = {4}; + } + EXPECT_EQ(exp0.size(), view(0).size()); + for (const auto &elem : exp0) { + const auto &ref = view(0); + EXPECT_TRUE(std::find(ref.begin(), ref.end(), elem) != ref.end()); + } + EXPECT_TRUE(view(1).empty()); + EXPECT_EQ(exp2.size(), view(2).size()); + for (std::size_t i = 0; i < exp2.size(); ++i) + EXPECT_EQ(*exp2.begin(), *view(2).begin()); +} + +template +void ReadCollectionFail(std::string_view ntplName, std::string_view path) +{ + auto reader = RNTupleReader::Open(ntplName, path); + ASSERT_EQ(3u, reader->GetNEntries()); + + try { + reader->GetView("f"); + FAIL() << "this case of automatic collection schema evolution should have failed"; + } catch (const ROOT::RException &err) { + EXPECT_THAT(err.what(), testing::HasSubstr("incompatible type")); + } +} +} // anonymous namespace + +namespace ROOT { +template <> +struct IsCollectionProxy> : std::true_type {}; +template <> +struct IsCollectionProxy> : std::true_type {}; +template <> +struct IsCollectionProxy>> : std::true_type {}; +template <> +struct IsCollectionProxy>> : std::true_type {}; +} // namespace ROOT + +TEST(RNTupleEvolution, Collections) +{ + FileRaii fileGuard("test_ntuple_evolution_collections.root"); + auto f = std::unique_ptr(TFile::Open(fileGuard.GetPath().c_str(), "UPDATE")); + + TClass::GetClass("CollectionProxy")->CopyCollectionProxy(SimpleCollectionProxy>()); + TClass::GetClass("CollectionProxy") + ->CopyCollectionProxy(SimpleCollectionProxy>()); + TClass::GetClass("CollectionProxy>") + ->CopyCollectionProxy(SimpleCollectionProxy>>()); + TClass::GetClass("CollectionProxy>") + ->CopyCollectionProxy(SimpleCollectionProxy>>()); + + { + auto model = RNTupleModel::Create(); + model->AddField(ROOT::RVectorField::CreateUntyped("f", std::make_unique>("x"))); + model->Freeze(); + auto v = std::static_pointer_cast>(model->GetDefaultEntry().GetPtr("f")); + auto writer = ROOT::RNTupleWriter::Append(std::move(model), "untyped", *f); + *v = {1, 2, 3}; + writer->Fill(); + v->clear(); + writer->Fill(); + *v = {4}; + writer->Fill(); + } + { + auto model = RNTupleModel::Create(); + model->AddField(ROOT::RVectorField::CreateUntyped("f", std::make_unique>>("x"))); + model->Freeze(); + auto v = std::static_pointer_cast>>(model->GetDefaultEntry().GetPtr("f")); + auto writer = ROOT::RNTupleWriter::Append(std::move(model), "untypedOfPairs", *f); + *v = {{1, 2}, {3, 4}, {5, 6}}; + writer->Fill(); + v->clear(); + writer->Fill(); + *v = {{7, 8}}; + writer->Fill(); + } + { + auto model = RNTupleModel::Create(); + auto proxy = model->MakeField>("f"); + auto writer = RNTupleWriter::Append(std::move(model), "proxy", *f); + proxy->v = {1, 2, 3}; + writer->Fill(); + proxy->v.clear(); + writer->Fill(); + proxy->v = {4}; + writer->Fill(); + } + { + auto model = RNTupleModel::Create(); + auto proxy = model->MakeField>>("f"); + auto writer = RNTupleWriter::Append(std::move(model), "proxyOfPairs", *f); + proxy->v = {{1, 2}, {3, 4}, {5, 6}}; + writer->Fill(); + proxy->v.clear(); + writer->Fill(); + proxy->v = {{7, 8}}; + writer->Fill(); + } + + WriteCollection, false>("vector", *f); + WriteCollection, false>("rvec", *f); + WriteCollection, false>("set", *f); + WriteCollection, false>("unordered_set", *f); + WriteCollection, false>("multiset", *f); + WriteCollection, false>("unordered_multiset", *f); + WriteCollection, true>("map", *f); + WriteCollection, true>("unordered_map", *f); + WriteCollection, true>("multimap", *f); + WriteCollection, true>("unordered_multimap", *f); + + WriteCollection>, true>("vectorOfPairs", *f); + WriteCollection>, true>("rvecOfPairs", *f); + WriteCollection>, true>("setOfPairs", *f); + WriteCollection>, true>("unordered_setOfPairs", *f); + WriteCollection>, true>("multisetOfPairs", *f); + WriteCollection>, true>("unordered_multisetOfPairs", *f); + + // All variations written out. Now test the collection matrix. + + ReadCollection, false>("untyped", fileGuard.GetPath()); + ReadCollection, false>("proxy", fileGuard.GetPath()); + ReadCollection, false>("rvec", fileGuard.GetPath()); + ReadCollection, false>("set", fileGuard.GetPath()); + ReadCollection, false>("unordered_set", fileGuard.GetPath()); + ReadCollection, false>("multiset", fileGuard.GetPath()); + ReadCollection, false>("unordered_multiset", fileGuard.GetPath()); + ReadCollection>, true>("map", fileGuard.GetPath()); + ReadCollection>, true>("unordered_map", fileGuard.GetPath()); + ReadCollection>, true>("multimap", fileGuard.GetPath()); + ReadCollection>, true>("unordered_multimap", fileGuard.GetPath()); + + ReadCollection, false>("untyped", fileGuard.GetPath()); + ReadCollection, false>("proxy", fileGuard.GetPath()); + ReadCollection, false>("vector", fileGuard.GetPath()); + ReadCollection, false>("set", fileGuard.GetPath()); + ReadCollection, false>("unordered_set", fileGuard.GetPath()); + ReadCollection, false>("multiset", fileGuard.GetPath()); + ReadCollection, false>("unordered_multiset", fileGuard.GetPath()); + ReadCollection>, true>("map", fileGuard.GetPath()); + ReadCollection>, true>("unordered_map", fileGuard.GetPath()); + ReadCollection>, true>("multimap", fileGuard.GetPath()); + ReadCollection>, true>("unordered_multimap", fileGuard.GetPath()); + + ReadCollectionFail, false>("untyped", fileGuard.GetPath()); + ReadCollectionFail, false>("proxy", fileGuard.GetPath()); + ReadCollectionFail, false>("vector", fileGuard.GetPath()); + ReadCollectionFail, false>("rvec", fileGuard.GetPath()); + ReadCollection, false>("unordered_set", fileGuard.GetPath()); + ReadCollectionFail, false>("multiset", fileGuard.GetPath()); + ReadCollectionFail, false>("unordered_multiset", fileGuard.GetPath()); + ReadCollection>, true>("map", fileGuard.GetPath()); + ReadCollection>, true>("unordered_map", fileGuard.GetPath()); + ReadCollectionFail>, true>("multimap", fileGuard.GetPath()); + ReadCollectionFail>, true>("unordered_multimap", fileGuard.GetPath()); + + ReadCollectionFail, false>("untyped", fileGuard.GetPath()); + ReadCollectionFail, false>("proxy", fileGuard.GetPath()); + ReadCollectionFail, false>("vector", fileGuard.GetPath()); + ReadCollectionFail, false>("rvec", fileGuard.GetPath()); + ReadCollection, false>("set", fileGuard.GetPath()); + ReadCollectionFail, false>("multiset", fileGuard.GetPath()); + ReadCollectionFail, false>("unordered_multiset", fileGuard.GetPath()); + ReadCollection>, true>("map", fileGuard.GetPath()); + ReadCollection>, true>("unordered_map", fileGuard.GetPath()); + ReadCollectionFail>, true>("multimap", fileGuard.GetPath()); + ReadCollectionFail>, true>("unordered_multimap", + fileGuard.GetPath()); + + ReadCollection, false>("untyped", fileGuard.GetPath()); + ReadCollection, false>("proxy", fileGuard.GetPath()); + ReadCollection, false>("vector", fileGuard.GetPath()); + ReadCollection, false>("rvec", fileGuard.GetPath()); + ReadCollection, false>("unordered_set", fileGuard.GetPath()); + ReadCollection, false>("set", fileGuard.GetPath()); + ReadCollection, false>("unordered_multiset", fileGuard.GetPath()); + ReadCollection>, true>("map", fileGuard.GetPath()); + ReadCollection>, true>("unordered_map", fileGuard.GetPath()); + ReadCollection>, true>("multimap", fileGuard.GetPath()); + ReadCollection>, true>("unordered_multimap", fileGuard.GetPath()); + + ReadCollection, false>("untyped", fileGuard.GetPath()); + ReadCollection, false>("proxy", fileGuard.GetPath()); + ReadCollection, false>("vector", fileGuard.GetPath()); + ReadCollection, false>("rvec", fileGuard.GetPath()); + ReadCollection, false>("unordered_set", fileGuard.GetPath()); + ReadCollection, false>("set", fileGuard.GetPath()); + ReadCollection, false>("multiset", fileGuard.GetPath()); + ReadCollection>, true>("map", fileGuard.GetPath()); + ReadCollection>, true>("unordered_map", fileGuard.GetPath()); + ReadCollection>, true>("multimap", fileGuard.GetPath()); + ReadCollection>, true>("unordered_multimap", + fileGuard.GetPath()); + + ReadCollectionFail, true>("untypedOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("proxyOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("vectorOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("rvecOfPairs", fileGuard.GetPath()); + ReadCollection, true>("setOfPairs", fileGuard.GetPath()); + ReadCollection, true>("unordered_setOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("multisetOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("unordered_multisetOfPairs", fileGuard.GetPath()); + ReadCollection, true>("unordered_map", fileGuard.GetPath()); + ReadCollectionFail, true>("multimap", fileGuard.GetPath()); + ReadCollectionFail, true>("unordered_multimap", fileGuard.GetPath()); + + ReadCollectionFail, true>("untypedOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("proxyOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("vectorOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("rvecOfPairs", fileGuard.GetPath()); + ReadCollection, true>("setOfPairs", fileGuard.GetPath()); + ReadCollection, true>("unordered_setOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("multisetOfPairs", fileGuard.GetPath()); + ReadCollectionFail, true>("unordered_multisetOfPairs", fileGuard.GetPath()); + ReadCollection, true>("map", fileGuard.GetPath()); + ReadCollectionFail, true>("multimap", fileGuard.GetPath()); + ReadCollectionFail, true>("unordered_multimap", fileGuard.GetPath()); + + ReadCollection, true>("untypedOfPairs", fileGuard.GetPath()); + ReadCollection, true>("proxyOfPairs", fileGuard.GetPath()); + ReadCollection, true>("vectorOfPairs", fileGuard.GetPath()); + ReadCollection, true>("rvecOfPairs", fileGuard.GetPath()); + ReadCollection, true>("setOfPairs", fileGuard.GetPath()); + ReadCollection, true>("unordered_setOfPairs", fileGuard.GetPath()); + ReadCollection, true>("multisetOfPairs", fileGuard.GetPath()); + ReadCollection, true>("unordered_multisetOfPairs", fileGuard.GetPath()); + ReadCollection, true>("map", fileGuard.GetPath()); + ReadCollection, true>("unordered_map", fileGuard.GetPath()); + ReadCollection, true>("multimap", fileGuard.GetPath()); + ReadCollection, true>("unordered_multimap", fileGuard.GetPath()); + + ReadCollection, true>("untypedOfPairs", fileGuard.GetPath()); + ReadCollection, true>("proxyOfPairs", fileGuard.GetPath()); + ReadCollection, true>("vectorOfPairs", fileGuard.GetPath()); + ReadCollection, true>("rvecOfPairs", fileGuard.GetPath()); + ReadCollection, true>("setOfPairs", fileGuard.GetPath()); + ReadCollection, true>("unordered_setOfPairs", fileGuard.GetPath()); + ReadCollection, true>("multisetOfPairs", fileGuard.GetPath()); + ReadCollection, true>("unordered_multisetOfPairs", + fileGuard.GetPath()); + ReadCollection, true>("map", fileGuard.GetPath()); + ReadCollection, true>("unordered_map", fileGuard.GetPath()); + ReadCollection, true>("multimap", fileGuard.GetPath()); + ReadCollection, true>("unordered_multimap", fileGuard.GetPath()); +} diff --git a/tree/ntupleutil/src/RNTupleImporter.cxx b/tree/ntupleutil/src/RNTupleImporter.cxx index bc64a15ce42e0..3184a0959084b 100644 --- a/tree/ntupleutil/src/RNTupleImporter.cxx +++ b/tree/ntupleutil/src/RNTupleImporter.cxx @@ -318,8 +318,8 @@ ROOT::RResult ROOT::Experimental::RNTupleImporter::PrepareSchema() c.fFieldName = "_collection" + std::to_string(iLeafCountCollection); auto recordField = std::make_unique("_0", std::move(c.fLeafFields)); - c.fRecordField = recordField.get(); auto collectionField = ROOT::RVectorField::CreateUntyped(c.fFieldName, std::move(recordField)); + c.fRecordField = static_cast(collectionField->GetMutableSubfields()[0]); fModel->AddField(std::move(collectionField)); // Add projected fields for all leaf count arrays