Skip to content

Commit 4808ccf

Browse files
committed
[ntuple] automatic evolution from T --> unique_ptr/optional<T>
1 parent 2c64ffe commit 4808ccf

File tree

3 files changed

+76
-14
lines changed

3 files changed

+76
-14
lines changed

tree/ntuple/inc/ROOT/RField/RFieldSTLMisc.hxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ class RNullableField : public RFieldBase {
195195
ROOT::Internal::RColumnIndex fNWritten{0};
196196

197197
protected:
198+
// For reading, indicates that we read type T as a nullable field of type T, i.e. the value is always present
199+
bool fIsEvolvedFromInnerType = false;
200+
198201
const RFieldBase::RColumnRepresentations &GetColumnRepresentations() const final;
199202
void GenerateColumns() final;
200203
void GenerateColumns(const ROOT::RNTupleDescriptor &) final;

tree/ntuple/src/RField.cxx

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ const ROOT::RFieldBase::RColumnRepresentations &ROOT::RNullableField::GetColumnR
797797
{ENTupleColumnType::kIndex64},
798798
{ENTupleColumnType::kSplitIndex32},
799799
{ENTupleColumnType::kIndex32}},
800-
{});
800+
{{}});
801801
return representations;
802802
}
803803

@@ -808,7 +808,8 @@ void ROOT::RNullableField::GenerateColumns()
808808

809809
void ROOT::RNullableField::GenerateColumns(const ROOT::RNTupleDescriptor &desc)
810810
{
811-
GenerateColumnsImpl<ROOT::Internal::RColumnIndex>(desc);
811+
if (!fIsEvolvedFromInnerType)
812+
GenerateColumnsImpl<ROOT::Internal::RColumnIndex>(desc);
812813
}
813814

814815
std::size_t ROOT::RNullableField::AppendNull()
@@ -830,8 +831,13 @@ void ROOT::RNullableField::ReconcileOnDiskField(const RNTupleDescriptor &desc)
830831
static const std::vector<std::string> prefixes = {"std::optional<", "std::unique_ptr<"};
831832

832833
const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
833-
EnsureMatchingOnDiskField(fieldDesc, kDiffTypeName);
834-
EnsureMatchingTypePrefix(fieldDesc, prefixes);
834+
try {
835+
EnsureMatchingOnDiskField(fieldDesc, kDiffTypeName);
836+
EnsureMatchingTypePrefix(fieldDesc, prefixes);
837+
} catch (const RException &) {
838+
fSubfields[0]->SetOnDiskId(GetOnDiskId());
839+
fIsEvolvedFromInnerType = true;
840+
}
835841
}
836842

837843
ROOT::RNTupleLocalIndex ROOT::RNullableField::GetItemIndex(ROOT::NTupleSize_t globalIndex)
@@ -900,16 +906,28 @@ void *ROOT::RUniquePtrField::PrepareRead(void *to, bool hasOnDiskValue)
900906

901907
void ROOT::RUniquePtrField::ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to)
902908
{
903-
auto itemIndex = GetItemIndex(globalIndex);
904-
const bool hasOnDiskValue = itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
909+
RNTupleLocalIndex itemIndex;
910+
if (!fIsEvolvedFromInnerType)
911+
itemIndex = GetItemIndex(globalIndex);
912+
const bool hasOnDiskValue = fIsEvolvedFromInnerType || itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
905913
auto valuePtr = PrepareRead(to, hasOnDiskValue);
906-
if (hasOnDiskValue)
907-
CallReadOn(*fSubfields[0], itemIndex, valuePtr);
914+
if (hasOnDiskValue) {
915+
if (fIsEvolvedFromInnerType) {
916+
CallReadOn(*fSubfields[0], globalIndex, valuePtr);
917+
} else {
918+
CallReadOn(*fSubfields[0], itemIndex, valuePtr);
919+
}
920+
}
908921
}
909922

910923
void ROOT::RUniquePtrField::ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to)
911924
{
912-
auto itemIndex = GetItemIndex(localIndex);
925+
RNTupleLocalIndex itemIndex;
926+
if (!fIsEvolvedFromInnerType) {
927+
itemIndex = GetItemIndex(localIndex);
928+
} else {
929+
itemIndex = localIndex;
930+
}
913931
const bool hasOnDiskValue = itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
914932
auto valuePtr = PrepareRead(to, hasOnDiskValue);
915933
if (hasOnDiskValue)
@@ -992,16 +1010,28 @@ void ROOT::ROptionalField::PrepareRead(void *to, bool hasOnDiskValue)
9921010

9931011
void ROOT::ROptionalField::ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to)
9941012
{
995-
auto itemIndex = GetItemIndex(globalIndex);
996-
const bool hasOnDiskValue = itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
1013+
RNTupleLocalIndex itemIndex;
1014+
if (!fIsEvolvedFromInnerType)
1015+
itemIndex = GetItemIndex(globalIndex);
1016+
const bool hasOnDiskValue = fIsEvolvedFromInnerType || itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
9971017
PrepareRead(to, hasOnDiskValue);
998-
if (hasOnDiskValue)
999-
CallReadOn(*fSubfields[0], itemIndex, to);
1018+
if (hasOnDiskValue) {
1019+
if (fIsEvolvedFromInnerType) {
1020+
CallReadOn(*fSubfields[0], globalIndex, to);
1021+
} else {
1022+
CallReadOn(*fSubfields[0], itemIndex, to);
1023+
}
1024+
}
10001025
}
10011026

10021027
void ROOT::ROptionalField::ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to)
10031028
{
1004-
auto itemIndex = GetItemIndex(localIndex);
1029+
RNTupleLocalIndex itemIndex;
1030+
if (!fIsEvolvedFromInnerType) {
1031+
itemIndex = GetItemIndex(localIndex);
1032+
} else {
1033+
itemIndex = localIndex;
1034+
}
10051035
const bool hasOnDiskValue = itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
10061036
PrepareRead(to, hasOnDiskValue);
10071037
if (hasOnDiskValue)

tree/ntuple/test/ntuple_evolution_type.cxx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,32 @@ TEST(RNTupleEvolution, CheckPairTuple)
207207
EXPECT_EQ(1, std::get<0>(p(0)));
208208
EXPECT_DOUBLE_EQ(2.0, std::get<1>(p(0)));
209209
}
210+
211+
TEST(RNTupleEvolution, CheckNullable)
212+
{
213+
FileRaii fileGuard("test_ntuple_evolution_check_nullable.root");
214+
{
215+
auto model = ROOT::RNTupleModel::Create();
216+
auto o = model->MakeField<std::optional<std::int32_t>>("o");
217+
auto u = model->MakeField<std::unique_ptr<std::int32_t>>("u");
218+
auto i = model->MakeField<std::int32_t>("i");
219+
auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath());
220+
221+
*o = 7;
222+
*u = std::make_unique<std::int32_t>(11);
223+
*i = 13;
224+
writer->Fill();
225+
}
226+
227+
auto reader = RNTupleReader::Open("ntpl", fileGuard.GetPath());
228+
229+
auto v1 = reader->GetView<std::unique_ptr<std::int64_t>>("o");
230+
auto v2 = reader->GetView<std::optional<std::int64_t>>("u");
231+
auto v3 = reader->GetView<std::unique_ptr<std::int64_t>>("i");
232+
auto v4 = reader->GetView<std::optional<std::int64_t>>("i");
233+
234+
EXPECT_EQ(7, *v1(0));
235+
EXPECT_EQ(11, *v2(0));
236+
EXPECT_EQ(13, *v3(0));
237+
EXPECT_EQ(13, *v4(0));
238+
}

0 commit comments

Comments
 (0)