Skip to content

Commit be32af3

Browse files
committed
[ntuple] fix type names with [U]Long64_t template args
Custom classes with [U]Long64_t template arguments need to use their meta-normalized name as type alias. Otherwise, during reconstruction with the RNTuple normalized name, the streamer info for the `std::[u]int64_t` argument will be requested (typically `long` instead of `long long`).
1 parent 26df1c6 commit be32af3

File tree

4 files changed

+38
-19
lines changed

4 files changed

+38
-19
lines changed

tree/ntuple/src/RFieldMeta.cxx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ ROOT::RClassField::RClassField(std::string_view fieldName, TClass *classp)
158158
if (!(fClass->ClassProperty() & kClassHasExplicitDtor))
159159
fTraits |= kTraitTriviallyDestructible;
160160

161+
std::string renormalizedAlias;
162+
if (Internal::NeedsMetaNameAsAlias(classp->GetName(), renormalizedAlias))
163+
fTypeAlias = renormalizedAlias;
164+
161165
int i = 0;
162166
const auto *bases = fClass->GetListOfBases();
163167
assert(bases);

tree/ntuple/test/CustomStruct.hxx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,19 @@ struct alignas(std::uint64_t) TestEBO : public EmptyStruct {
100100
template <typename T>
101101
class EdmWrapper {
102102
public:
103+
struct Inner {
104+
T fX;
105+
};
106+
103107
bool fIsPresent = true;
104108
T fMember;
105109
};
106110

107111
class EdmContainer {
108112
public:
113+
using EdmWrapperLong64_t = EdmWrapper<long long>;
109114
// Used to test that the streamer info for fWrapper will use long long
110-
EdmWrapper<long long> fWrapper;
115+
EdmWrapperLong64_t fWrapper;
111116
};
112117

113118
template <typename T>

tree/ntuple/test/CustomStructLinkDef.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#pragma link C++ class EdmWrapper<CustomStruct> +;
3434
#pragma link C++ class EdmHash < 1> + ;
3535
#pragma link C++ class EdmWrapper<long long>+;
36-
#pragma link C++ class EdmContainer;
36+
#pragma link C++ class EdmContainer+;
3737

3838
#pragma link C++ class DataVector < int, double> + ;
3939
#pragma link C++ class DataVector < int, float> + ;

tree/ntuple/test/rfield_class.cxx

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -395,37 +395,40 @@ TEST(RNTuple, TClassMetaName)
395395

396396
TEST(RNTuple, StreamerInfoRecords)
397397
{
398-
// Every testee consists of the type stored on disk and the expected streamer info records
399-
std::vector<std::pair<std::string, std::vector<std::string>>> testees{
400-
{"float", {}},
401-
{"std::vector<float>", {}},
402-
{"std::pair<float, float>", {}},
403-
{"std::map<int, float>", {}},
404-
{"CustomStruct", {"CustomStruct"}},
405-
{"std::vector<CustomStruct>", {"CustomStruct"}},
406-
{"std::map<int, CustomStruct>", {"CustomStruct"}},
407-
{"DerivedA", {"DerivedA", "CustomStruct"}},
408-
{"std::pair<CustomStruct, DerivedA>", {"DerivedA", "CustomStruct"}},
409-
{"EdmWrapper<long long>", {"EdmWrapper<Long64_t>"}},
410-
{"TRotation", {"TRotation"}}};
398+
// Every testee consists of the type stored on disk, the expected streamer info records, and the expected type alias
399+
std::vector<std::tuple<std::string, std::vector<std::string>, std::string>> testees{
400+
{"float", {}, ""},
401+
{"std::vector<float>", {}, ""},
402+
{"std::pair<float, float>", {}, ""},
403+
{"std::map<int, float>", {}, ""},
404+
{"CustomStruct", {"CustomStruct"}, ""},
405+
{"std::vector<CustomStruct>", {"CustomStruct"}, ""},
406+
{"std::map<int, CustomStruct>", {"CustomStruct"}, ""},
407+
{"DerivedA", {"DerivedA", "CustomStruct"}, ""},
408+
{"std::pair<CustomStruct, DerivedA>", {"DerivedA", "CustomStruct"}, ""},
409+
{"EdmWrapper<long long>", {"EdmWrapper<Long64_t>"}, "EdmWrapper<Long64_t>"},
410+
{"EdmContainer", {"EdmContainer", "EdmWrapper<Long64_t>"}, ""},
411+
{"EdmWrapper<long long>::Inner", {"EdmWrapper<Long64_t>::Inner"}, "EdmWrapper<Long64_t>::Inner"},
412+
{"EdmContainer::EdmWrapperLong64_t", {"EdmWrapper<Long64_t>"}, "EdmContainer::EdmWrapperLong64_t"},
413+
{"TRotation", {"TRotation"}, ""}};
411414

412415
for (const auto &t : testees) {
413416
FileRaii fileGuard("test_ntuple_streamer_info_records.root");
414417

415418
{
416419
auto model = ROOT::RNTupleModel::Create();
417-
if (t.first == "TRotation") {
418-
model->AddField(std::make_unique<ROOT::RStreamerField>("f", t.first));
420+
if (std::get<0>(t) == "TRotation") {
421+
model->AddField(std::make_unique<ROOT::RStreamerField>("f", std::get<0>(t)));
419422
} else {
420-
model->AddField(ROOT::RFieldBase::Create("f", t.first).Unwrap());
423+
model->AddField(ROOT::RFieldBase::Create("f", std::get<0>(t)).Unwrap());
421424
}
422425
auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath());
423426
}
424427

425428
auto f = std::unique_ptr<TFile>(TFile::Open(fileGuard.GetPath().c_str()));
426429
ASSERT_TRUE(f && !f->IsZombie());
427430

428-
std::unordered_set<std::string> expectedInfos{t.second.begin(), t.second.end()};
431+
std::unordered_set<std::string> expectedInfos{std::get<1>(t).begin(), std::get<1>(t).end()};
429432
expectedInfos.insert("ROOT::RNTuple");
430433
for (const auto info : TRangeDynCast<TVirtualStreamerInfo>(*f->GetStreamerInfoList())) {
431434
auto itr = expectedInfos.find(info->GetName());
@@ -436,5 +439,12 @@ TEST(RNTuple, StreamerInfoRecords)
436439
expectedInfos.erase(itr);
437440
}
438441
EXPECT_TRUE(expectedInfos.empty());
442+
443+
// Make sure we can reconstruct the fields
444+
auto reader = RNTupleReader::Open("ntpl", fileGuard.GetPath());
445+
EXPECT_EQ(std::get<2>(t), reader->GetModel().GetConstField("f").GetTypeAlias());
446+
if (auto field = dynamic_cast<const ROOT::RClassField *>(&reader->GetModel().GetConstField("f"))) {
447+
EXPECT_EQ(std::get<1>(t)[0], field->GetClass()->GetName());
448+
}
439449
}
440450
}

0 commit comments

Comments
 (0)