Skip to content

Commit d4e54bd

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 ca5a24e commit d4e54bd

File tree

4 files changed

+206
-7
lines changed

4 files changed

+206
-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: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ std::string GetTypeList(std::span<std::unique_ptr<ROOT::RFieldBase>> itemFields,
9292
return result;
9393
}
9494

95-
std::string BuildSetTypeName(ROOT::RSetField::ESetType setType, const ROOT::RFieldBase &innerField)
95+
std::string BuildSetTypeName(ROOT::RSetField::ESetType setType, const ROOT::RFieldBase &innerField, bool useTypeAlias)
9696
{
9797
std::string typePrefix;
9898
switch (setType) {
@@ -102,10 +102,13 @@ std::string BuildSetTypeName(ROOT::RSetField::ESetType setType, const ROOT::RFie
102102
case ROOT::RSetField::ESetType::kUnorderedMultiSet: typePrefix = "std::unordered_multiset<"; break;
103103
default: R__ASSERT(false);
104104
}
105-
return typePrefix + innerField.GetTypeName() + ">";
105+
return typePrefix +
106+
((useTypeAlias && !innerField.GetTypeAlias().empty()) ? innerField.GetTypeAlias()
107+
: innerField.GetTypeName()) +
108+
">";
106109
}
107110

108-
std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFieldBase *innerField)
111+
std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFieldBase *innerField, bool useTypeAliases)
109112
{
110113
if (const auto pairField = dynamic_cast<const ROOT::RPairField *>(innerField)) {
111114
std::string typePrefix;
@@ -116,8 +119,18 @@ std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFie
116119
case ROOT::RMapField::EMapType::kUnorderedMultiMap: typePrefix = "std::unordered_multimap<"; break;
117120
default: R__ASSERT(false);
118121
}
119-
auto subFields = pairField->GetConstSubfields();
120-
return typePrefix + subFields[0]->GetTypeName() + "," + subFields[1]->GetTypeName() + ">";
122+
const auto &items = pairField->GetConstSubfields();
123+
std::string type = typePrefix;
124+
for (int i : {0, 1}) {
125+
if (useTypeAliases && !items[i]->GetTypeAlias().empty()) {
126+
type += items[i]->GetTypeAlias();
127+
} else {
128+
type += items[i]->GetTypeName();
129+
}
130+
if (i == 0)
131+
type.push_back(',');
132+
}
133+
return type + ">";
121134
}
122135

123136
throw ROOT::RException(R__FAIL("RMapField inner field type must be of RPairField"));
@@ -692,6 +705,10 @@ ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_
692705
const std::array<std::size_t, 2> &offsets)
693706
: ROOT::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
694707
{
708+
const std::string typeAlias = "std::pair<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
709+
if (typeAlias != GetTypeName())
710+
fTypeAlias = typeAlias;
711+
695712
AttachItemFields(std::move(itemFields));
696713
fOffsets.push_back(offsets[0]);
697714
fOffsets.push_back(offsets[1]);
@@ -700,6 +717,10 @@ ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_
700717
ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields)
701718
: ROOT::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
702719
{
720+
const std::string typeAlias = "std::pair<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
721+
if (typeAlias != GetTypeName())
722+
fTypeAlias = typeAlias;
723+
703724
AttachItemFields(std::move(itemFields));
704725

705726
// ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
@@ -945,8 +966,13 @@ void ROOT::RProxiedCollectionField::AcceptVisitor(ROOT::Detail::RFieldVisitor &v
945966
//------------------------------------------------------------------------------
946967

947968
ROOT::RMapField::RMapField(std::string_view fieldName, EMapType mapType, std::unique_ptr<RFieldBase> itemField)
948-
: RProxiedCollectionField(fieldName, EnsureValidClass(BuildMapTypeName(mapType, itemField.get()))), fMapType(mapType)
969+
: RProxiedCollectionField(fieldName,
970+
EnsureValidClass(BuildMapTypeName(mapType, itemField.get(), false /* useTypeAliases */))),
971+
fMapType(mapType)
949972
{
973+
if (!itemField->GetTypeAlias().empty())
974+
fTypeAlias = BuildMapTypeName(mapType, itemField.get(), true /* useTypeAliases */);
975+
950976
auto *itemClass = fProxy->GetValueClass();
951977
fItemSize = itemClass->GetClassSize();
952978

@@ -976,10 +1002,15 @@ void ROOT::RMapField::ReconcileOnDiskField(const RNTupleDescriptor &desc)
9761002
//------------------------------------------------------------------------------
9771003

9781004
ROOT::RSetField::RSetField(std::string_view fieldName, ESetType setType, std::unique_ptr<RFieldBase> itemField)
979-
: ROOT::RProxiedCollectionField(fieldName, EnsureValidClass(BuildSetTypeName(setType, *itemField))),
1005+
: ROOT::RProxiedCollectionField(fieldName,
1006+
EnsureValidClass(BuildSetTypeName(setType, *itemField, false /* useTypeAlias */))),
9801007
fSetType(setType)
9811008
{
1009+
if (!itemField->GetTypeAlias().empty())
1010+
fTypeAlias = BuildSetTypeName(setType, *itemField, true /* useTypeAlias */);
1011+
9821012
fItemSize = itemField->GetValueSize();
1013+
9831014
Attach(std::move(itemField));
9841015
}
9851016

@@ -1288,13 +1319,21 @@ ROOT::RTupleField::RTupleField(std::string_view fieldName, std::vector<std::uniq
12881319
const std::vector<std::size_t> &offsets)
12891320
: ROOT::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
12901321
{
1322+
const std::string typeAlias = "std::tuple<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1323+
if (typeAlias != GetTypeName())
1324+
fTypeAlias = typeAlias;
1325+
12911326
AttachItemFields(std::move(itemFields));
12921327
fOffsets = offsets;
12931328
}
12941329

12951330
ROOT::RTupleField::RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
12961331
: ROOT::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
12971332
{
1333+
const std::string typeAlias = "std::tuple<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1334+
if (typeAlias != GetTypeName())
1335+
fTypeAlias = typeAlias;
1336+
12981337
AttachItemFields(std::move(itemFields));
12991338

13001339
auto *c = TClass::GetClass(GetTypeName().c_str());
@@ -1386,6 +1425,10 @@ ROOT::RVariantField::RVariantField(std::string_view fieldName, std::vector<std::
13861425
// The variant needs to initialize its own tag member
13871426
fTraits |= kTraitTriviallyDestructible & ~kTraitTriviallyConstructible;
13881427

1428+
const std::string typeAlias = "std::variant<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1429+
if (typeAlias != GetTypeName())
1430+
fTypeAlias = typeAlias;
1431+
13891432
auto nFields = itemFields.size();
13901433
if (nFields == 0 || nFields > kMaxVariants) {
13911434
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)