Skip to content

Commit 3ec064d

Browse files
committed
[ntuple] Propagate type aliases from item fields
When constructing compound types from item fields, propagate alias types from the item fields to the parent field. This is already done globally in RFieldBase::Create() because the entire type name is compared to the unresolved type name. However, the type alias propagation was missing when a field is directly constructed with an item field.
1 parent 1017bf5 commit 3ec064d

File tree

4 files changed

+205
-7
lines changed

4 files changed

+205
-7
lines changed

tree/ntuple/src/RField.cxx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,9 @@ ROOT::RNullableField::RNullableField(std::string_view fieldName, const std::stri
842842
: ROOT::RFieldBase(fieldName, typePrefix + "<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kCollection,
843843
false /* isSimple */)
844844
{
845+
if (!itemField->GetTypeAlias().empty())
846+
fTypeAlias = typePrefix + "<" + itemField->GetTypeAlias() + ">";
847+
845848
Attach(std::move(itemField));
846849
}
847850

@@ -1183,6 +1186,10 @@ ROOT::RAtomicField::RAtomicField(std::string_view fieldName, std::unique_ptr<RFi
11831186
fTraits |= kTraitTriviallyConstructible;
11841187
if (itemField->GetTraits() & kTraitTriviallyDestructible)
11851188
fTraits |= kTraitTriviallyDestructible;
1189+
1190+
if (!itemField->GetTypeAlias().empty())
1191+
fTypeAlias = "std::atomic<" + itemField->GetTypeAlias() + ">";
1192+
11861193
Attach(std::move(itemField));
11871194
}
11881195

tree/ntuple/src/RFieldMeta.cxx

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ std::string GetTypeList(std::span<std::unique_ptr<ROOT::RFieldBase>> itemFields,
8989
return result;
9090
}
9191

92-
std::string BuildSetTypeName(ROOT::RSetField::ESetType setType, const ROOT::RFieldBase &innerField)
92+
std::string BuildSetTypeName(ROOT::RSetField::ESetType setType, const ROOT::RFieldBase &innerField, bool useTypeAlias)
9393
{
9494
std::string typePrefix;
9595
switch (setType) {
@@ -99,10 +99,12 @@ std::string BuildSetTypeName(ROOT::RSetField::ESetType setType, const ROOT::RFie
9999
case ROOT::RSetField::ESetType::kUnorderedMultiSet: typePrefix = "std::unordered_multiset<"; break;
100100
default: R__ASSERT(false);
101101
}
102-
return typePrefix + innerField.GetTypeName() + ">";
102+
return typePrefix +
103+
((useTypeAlias && !innerField.GetTypeAlias().empty()) ? innerField.GetTypeAlias() : innerField.GetTypeName())
104+
+ ">";
103105
}
104106

105-
std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFieldBase *innerField)
107+
std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFieldBase *innerField, bool useTypeAliases)
106108
{
107109
if (const auto pairField = dynamic_cast<const ROOT::RPairField *>(innerField)) {
108110
std::string typePrefix;
@@ -113,8 +115,18 @@ std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFie
113115
case ROOT::RMapField::EMapType::kUnorderedMultiMap: typePrefix = "std::unordered_multimap<"; break;
114116
default: R__ASSERT(false);
115117
}
116-
auto subFields = pairField->GetConstSubfields();
117-
return typePrefix + subFields[0]->GetTypeName() + "," + subFields[1]->GetTypeName() + ">";
118+
const auto &items = pairField->GetConstSubfields();
119+
std::string type = typePrefix;
120+
for (int i : {0, 1}) {
121+
if (useTypeAliases && !items[i]->GetTypeAlias().empty()) {
122+
type += items[i]->GetTypeAlias();
123+
} else {
124+
type += items[i]->GetTypeName();
125+
}
126+
if (i == 0)
127+
type.push_back(',');
128+
}
129+
return type + ">";
118130
}
119131

120132
throw ROOT::RException(R__FAIL("RMapField inner field type must be of RPairField"));
@@ -689,6 +701,10 @@ ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_
689701
const std::array<std::size_t, 2> &offsets)
690702
: ROOT::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
691703
{
704+
const std::string typeAlias = "std::pair<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
705+
if (typeAlias != GetTypeName())
706+
fTypeAlias = typeAlias;
707+
692708
AttachItemFields(std::move(itemFields));
693709
fOffsets.push_back(offsets[0]);
694710
fOffsets.push_back(offsets[1]);
@@ -697,6 +713,10 @@ ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_
697713
ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields)
698714
: ROOT::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
699715
{
716+
const std::string typeAlias = "std::pair<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
717+
if (typeAlias != GetTypeName())
718+
fTypeAlias = typeAlias;
719+
700720
AttachItemFields(std::move(itemFields));
701721

702722
// ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
@@ -942,8 +962,13 @@ void ROOT::RProxiedCollectionField::AcceptVisitor(ROOT::Detail::RFieldVisitor &v
942962
//------------------------------------------------------------------------------
943963

944964
ROOT::RMapField::RMapField(std::string_view fieldName, EMapType mapType, std::unique_ptr<RFieldBase> itemField)
945-
: RProxiedCollectionField(fieldName, EnsureValidClass(BuildMapTypeName(mapType, itemField.get()))), fMapType(mapType)
965+
: RProxiedCollectionField(fieldName,
966+
EnsureValidClass(BuildMapTypeName(mapType, itemField.get(), false /* useTypeAliases */))),
967+
fMapType(mapType)
946968
{
969+
if (!itemField->GetTypeAlias().empty())
970+
fTypeAlias = BuildMapTypeName(mapType, itemField.get(), true /* useTypeAliases */);
971+
947972
auto *itemClass = fProxy->GetValueClass();
948973
fItemSize = itemClass->GetClassSize();
949974

@@ -973,10 +998,15 @@ void ROOT::RMapField::ReconcileOnDiskField(const RNTupleDescriptor &desc)
973998
//------------------------------------------------------------------------------
974999

9751000
ROOT::RSetField::RSetField(std::string_view fieldName, ESetType setType, std::unique_ptr<RFieldBase> itemField)
976-
: ROOT::RProxiedCollectionField(fieldName, EnsureValidClass(BuildSetTypeName(setType, *itemField))),
1001+
: ROOT::RProxiedCollectionField(fieldName,
1002+
EnsureValidClass(BuildSetTypeName(setType, *itemField, false /* useTypeAlias */))),
9771003
fSetType(setType)
9781004
{
1005+
if (!itemField->GetTypeAlias().empty())
1006+
fTypeAlias = BuildSetTypeName(setType, *itemField, true /* useTypeAlias */);
1007+
9791008
fItemSize = itemField->GetValueSize();
1009+
9801010
Attach(std::move(itemField));
9811011
}
9821012

@@ -1285,13 +1315,21 @@ ROOT::RTupleField::RTupleField(std::string_view fieldName, std::vector<std::uniq
12851315
const std::vector<std::size_t> &offsets)
12861316
: ROOT::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
12871317
{
1318+
const std::string typeAlias = "std::tuple<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1319+
if (typeAlias != GetTypeName())
1320+
fTypeAlias = typeAlias;
1321+
12881322
AttachItemFields(std::move(itemFields));
12891323
fOffsets = offsets;
12901324
}
12911325

12921326
ROOT::RTupleField::RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
12931327
: ROOT::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
12941328
{
1329+
const std::string typeAlias = "std::tuple<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1330+
if (typeAlias != GetTypeName())
1331+
fTypeAlias = typeAlias;
1332+
12951333
AttachItemFields(std::move(itemFields));
12961334

12971335
auto *c = TClass::GetClass(GetTypeName().c_str());
@@ -1383,6 +1421,10 @@ ROOT::RVariantField::RVariantField(std::string_view fieldName, std::vector<std::
13831421
// The variant needs to initialize its own tag member
13841422
fTraits |= kTraitTriviallyDestructible & ~kTraitTriviallyConstructible;
13851423

1424+
const std::string typeAlias = "std::variant<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1425+
if (typeAlias != GetTypeName())
1426+
fTypeAlias = typeAlias;
1427+
13861428
auto nFields = itemFields.size();
13871429
if (nFields == 0 || nFields > kMaxVariants) {
13881430
throw RException(R__FAIL("invalid number of variant fields (outside [1.." + std::to_string(kMaxVariants) + ")"));

tree/ntuple/src/RFieldSequenceContainer.cxx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ ROOT::RArrayField::RArrayField(std::string_view fieldName, std::unique_ptr<RFiel
124124
fArrayLength(arrayLength)
125125
{
126126
fTraits |= itemField->GetTraits() & ~kTraitMappable;
127+
if (!itemField->GetTypeAlias().empty()) {
128+
fTypeAlias = "std::array<" + itemField->GetTypeAlias() + "," +
129+
Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">";
130+
}
127131
Attach(std::move(itemField));
128132
}
129133

@@ -245,6 +249,8 @@ ROOT::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<RFieldB
245249
{
246250
if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
247251
fItemDeleter = GetDeleterOf(*itemField);
252+
if (!itemField->GetTypeAlias().empty())
253+
fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
248254
Attach(std::move(itemField));
249255
fValueSize = EvalRVecValueSize(fSubfields[0]->GetAlignment(), fSubfields[0]->GetValueSize(), GetAlignment());
250256

@@ -549,6 +555,9 @@ ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFi
549555
if (emulatedFromType && !emulatedFromType->empty())
550556
fTraits |= kTraitEmulatedField;
551557

558+
if (!itemField->GetTypeAlias().empty())
559+
fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
560+
552561
if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
553562
fItemDeleter = GetDeleterOf(*itemField);
554563
Attach(std::move(itemField));
@@ -859,6 +868,8 @@ ROOT::RArrayAsRVecField::RArrayAsRVecField(std::string_view fieldName, std::uniq
859868
fItemSize(itemField->GetValueSize()),
860869
fArrayLength(arrayLength)
861870
{
871+
if (!itemField->GetTypeAlias().empty())
872+
fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
862873
Attach(std::move(itemField));
863874
fValueSize = EvalRVecValueSize(fSubfields[0]->GetAlignment(), fSubfields[0]->GetValueSize(), GetAlignment());
864875
if (!(fSubfields[0]->GetTraits() & kTraitTriviallyDestructible))
@@ -961,6 +972,8 @@ ROOT::RArrayAsVectorField::RArrayAsVectorField(std::string_view fieldName, std::
961972
fItemSize(itemField->GetValueSize()),
962973
fArrayLength(arrayLength)
963974
{
975+
if (!itemField->GetTypeAlias().empty())
976+
fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
964977
Attach(std::move(itemField));
965978
if (!(fSubfields[0]->GetTraits() & kTraitTriviallyDestructible))
966979
fItemDeleter = GetDeleterOf(*fSubfields[0]);

tree/ntuple/test/ntuple_type_name.cxx

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,3 +411,139 @@ TEST(RNTuple, NeedsMetaNameAsAlias)
411411
EXPECT_TRUE(NeedsMetaNameAsAlias("MyClass<std::map<Long64_t, ULong64_t>>", renormalizedAlias));
412412
EXPECT_EQ("MyClass<std::map<Long64_t,ULong64_t>>", renormalizedAlias);
413413
}
414+
415+
TEST(RNTuple, PropagateTypeAlias)
416+
{
417+
{
418+
auto f = ROOT::RFieldBase::Create("f", "std::vector<Double32_t>").Unwrap();
419+
EXPECT_EQ("std::vector<double>", f->GetTypeName());
420+
EXPECT_EQ("std::vector<Double32_t>", f->GetTypeAlias());
421+
}
422+
423+
{
424+
auto f = ROOT::RFieldBase::Create("f", "ROOT::RVec<Double32_t>").Unwrap();
425+
EXPECT_EQ("ROOT::VecOps::RVec<double>", f->GetTypeName());
426+
EXPECT_EQ("ROOT::VecOps::RVec<Double32_t>", f->GetTypeAlias());
427+
}
428+
429+
{
430+
auto f = ROOT::RFieldBase::Create("f", "std::array<Double32_t, 2>").Unwrap();
431+
EXPECT_EQ("std::array<double,2>", f->GetTypeName());
432+
EXPECT_EQ("std::array<Double32_t,2>", f->GetTypeAlias());
433+
}
434+
435+
{
436+
auto f = ROOT::RFieldBase::Create("f", "std::variant<Double32_t, int>").Unwrap();
437+
EXPECT_EQ("std::variant<double,std::int32_t>", f->GetTypeName());
438+
EXPECT_EQ("std::variant<Double32_t,std::int32_t>", f->GetTypeAlias());
439+
}
440+
441+
{
442+
auto f = ROOT::RFieldBase::Create("f", "std::pair<Double32_t, int>").Unwrap();
443+
EXPECT_EQ("std::pair<double,std::int32_t>", f->GetTypeName());
444+
EXPECT_EQ("std::pair<Double32_t,std::int32_t>", f->GetTypeAlias());
445+
}
446+
447+
{
448+
auto f = ROOT::RFieldBase::Create("f", "std::tuple<Double32_t, int>").Unwrap();
449+
EXPECT_EQ("std::tuple<double,std::int32_t>", f->GetTypeName());
450+
EXPECT_EQ("std::tuple<Double32_t,std::int32_t>", f->GetTypeAlias());
451+
}
452+
453+
{
454+
auto f = ROOT::RFieldBase::Create("f", "std::optional<Double32_t>").Unwrap();
455+
EXPECT_EQ("std::optional<double>", f->GetTypeName());
456+
EXPECT_EQ("std::optional<Double32_t>", f->GetTypeAlias());
457+
}
458+
459+
{
460+
auto f = ROOT::RFieldBase::Create("f", "std::multiset<Double32_t>").Unwrap();
461+
EXPECT_EQ("std::multiset<double>", f->GetTypeName());
462+
EXPECT_EQ("std::multiset<Double32_t>", f->GetTypeAlias());
463+
}
464+
465+
{
466+
auto f = ROOT::RFieldBase::Create("f", "std::multimap<Double32_t, int>").Unwrap();
467+
EXPECT_EQ("std::multimap<double,std::int32_t>", f->GetTypeName());
468+
EXPECT_EQ("std::multimap<Double32_t,std::int32_t>", f->GetTypeAlias());
469+
}
470+
471+
{
472+
auto f = ROOT::RFieldBase::Create("f", "std::atomic<Double32_t>").Unwrap();
473+
EXPECT_EQ("std::atomic<double>", f->GetTypeName());
474+
EXPECT_EQ("std::atomic<Double32_t>", f->GetTypeAlias());
475+
}
476+
477+
auto GetDouble32Item = []() {
478+
auto item = std::make_unique<ROOT::RField<double>>("_0");
479+
item->SetDouble32();
480+
return item;
481+
};
482+
483+
{
484+
auto f = std::make_unique<ROOT::RVectorField>("f", GetDouble32Item());
485+
EXPECT_EQ("std::vector<double>", f->GetTypeName());
486+
EXPECT_EQ("std::vector<Double32_t>", f->GetTypeAlias());
487+
}
488+
489+
{
490+
auto f = std::make_unique<ROOT::RRVecField>("f", GetDouble32Item());
491+
EXPECT_EQ("ROOT::VecOps::RVec<double>", f->GetTypeName());
492+
EXPECT_EQ("ROOT::VecOps::RVec<Double32_t>", f->GetTypeAlias());
493+
}
494+
495+
{
496+
auto f = std::make_unique<ROOT::RArrayField>("f", GetDouble32Item(), 2);
497+
EXPECT_EQ("std::array<double,2>", f->GetTypeName());
498+
EXPECT_EQ("std::array<Double32_t,2>", f->GetTypeAlias());
499+
}
500+
501+
{
502+
std::vector<std::unique_ptr<RFieldBase>> items;
503+
items.emplace_back(GetDouble32Item());
504+
items.emplace_back(std::make_unique<RField<int>>("f"));
505+
auto f = std::make_unique<ROOT::RVariantField>("f", std::move(items));
506+
EXPECT_EQ("std::variant<double,std::int32_t>", f->GetTypeName());
507+
EXPECT_EQ("std::variant<Double32_t,std::int32_t>", f->GetTypeAlias());
508+
}
509+
510+
{
511+
std::array<std::unique_ptr<RFieldBase>, 2> items;
512+
items[0] = GetDouble32Item();
513+
items[1] = std::make_unique<RField<int>>("f");
514+
auto f = std::make_unique<ROOT::RPairField>("f", std::move(items));
515+
EXPECT_EQ("std::pair<double,std::int32_t>", f->GetTypeName());
516+
EXPECT_EQ("std::pair<Double32_t,std::int32_t>", f->GetTypeAlias());
517+
}
518+
519+
{
520+
std::vector<std::unique_ptr<RFieldBase>> items;
521+
items.emplace_back(GetDouble32Item());
522+
items.emplace_back(std::make_unique<RField<int>>("f"));
523+
auto f = std::make_unique<ROOT::RTupleField>("f", std::move(items));
524+
EXPECT_EQ("std::tuple<double,std::int32_t>", f->GetTypeName());
525+
EXPECT_EQ("std::tuple<Double32_t,std::int32_t>", f->GetTypeAlias());
526+
}
527+
528+
{
529+
auto f = std::make_unique<ROOT::ROptionalField>("f", GetDouble32Item());
530+
EXPECT_EQ("std::optional<double>", f->GetTypeName());
531+
EXPECT_EQ("std::optional<Double32_t>", f->GetTypeAlias());
532+
}
533+
534+
{
535+
std::array<std::unique_ptr<RFieldBase>, 2> items;
536+
items[0] = GetDouble32Item();
537+
items[1] = std::make_unique<RField<int>>("f");
538+
auto f = std::make_unique<ROOT::RMapField>("f", ROOT::RMapField::EMapType::kMultiMap,
539+
std::make_unique<ROOT::RPairField>("f", std::move(items)));
540+
EXPECT_EQ("std::multimap<double,std::int32_t>", f->GetTypeName());
541+
EXPECT_EQ("std::multimap<Double32_t,std::int32_t>", f->GetTypeAlias());
542+
}
543+
544+
{
545+
auto f = std::make_unique<ROOT::RAtomicField>("f", GetDouble32Item());
546+
EXPECT_EQ("std::atomic<double>", f->GetTypeName());
547+
EXPECT_EQ("std::atomic<Double32_t>", f->GetTypeAlias());
548+
}
549+
}

0 commit comments

Comments
 (0)