Skip to content

Commit ef0feec

Browse files
committed
[ntuple] automatic evolution in and out std::atomic
Allow for std::atomic<T> --> T (or compatible) automatic conversion and vice versa.
1 parent 4731fd5 commit ef0feec

File tree

5 files changed

+52
-5
lines changed

5 files changed

+52
-5
lines changed

tree/ntuple/inc/ROOT/RNTupleDescriptor.hxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ public:
153153
/// The dictionary does not need to be available for this method.
154154
/// Needs the full descriptor to look up sub fields.
155155
bool IsCustomEnum(const RNTupleDescriptor &desc) const;
156+
bool IsStdAtomic() const;
156157
};
157158

158159
// clang-format off

tree/ntuple/src/RField.cxx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,11 +1096,12 @@ std::unique_ptr<ROOT::RFieldBase> ROOT::RAtomicField::CloneImpl(std::string_view
10961096

10971097
void ROOT::RAtomicField::ReconcileOnDiskField(const RNTupleDescriptor &desc)
10981098
{
1099-
static const std::vector<std::string> prefixes = {"std::atomic<"};
1100-
11011099
const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1102-
EnsureMatchingOnDiskField(fieldDesc, kDiffTypeName).ThrowOnError();
1103-
EnsureMatchingTypePrefix(fieldDesc, prefixes).ThrowOnError();
1100+
if (fieldDesc.GetTypeName().rfind("std::atomic<", 0) == 0) {
1101+
EnsureMatchingOnDiskField(fieldDesc, kDiffTypeName).ThrowOnError();
1102+
} else {
1103+
fSubfields[0]->SetOnDiskId(GetOnDiskId());
1104+
}
11041105
}
11051106

11061107
std::vector<ROOT::RFieldBase::RValue> ROOT::RAtomicField::SplitValue(const RValue &value) const

tree/ntuple/src/RFieldBase.cxx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,13 @@ void ROOT::RFieldBase::ConnectPageSource(ROOT::Internal::RPageSource &pageSource
975975

976976
if (!fIsArtificial) {
977977
R__ASSERT(fOnDiskId != kInvalidDescriptorId);
978-
ReconcileOnDiskField(pageSource.GetSharedDescriptorGuard().GetRef());
978+
// Handle moving from on-disk std::atomic<T> to (compatible of) T in memory centrally because otherwise
979+
// we would need to handle it in each and every ReconcileOnDiskField()
980+
const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
981+
if (!dynamic_cast<RAtomicField *>(this) && desc.GetFieldDescriptor(GetOnDiskId()).IsStdAtomic()) {
982+
SetOnDiskId(desc.GetFieldDescriptor(GetOnDiskId()).GetLinkIds()[0]);
983+
}
984+
ReconcileOnDiskField(desc);
979985
}
980986

981987
for (auto &f : fSubfields) {

tree/ntuple/src/RNTupleDescriptor.cxx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ bool ROOT::RFieldDescriptor::IsCustomEnum(const RNTupleDescriptor &desc) const
187187
desc.GetFieldDescriptor(subFieldId).GetTypeName()) != std::end(gIntTypeNames);
188188
}
189189

190+
bool ROOT::RFieldDescriptor::IsStdAtomic() const
191+
{
192+
if (fStructure != ROOT::ENTupleStructure::kPlain)
193+
return false;
194+
return (fTypeName.rfind("std::atomic<", 0) == 0);
195+
}
196+
190197
////////////////////////////////////////////////////////////////////////////////
191198

192199
bool ROOT::RColumnDescriptor::operator==(const RColumnDescriptor &other) const

tree/ntuple/test/ntuple_evolution_type.cxx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,35 @@ TEST(RNTupleEvolution, ArrayAsRVec)
253253
EXPECT_EQ(1, a(0)[0]);
254254
EXPECT_EQ(2, a(0)[1]);
255255
}
256+
257+
TEST(RNTupleEvolution, CheckAtomic)
258+
{
259+
FileRaii fileGuard("test_ntuple_evolution_check_atomic.root");
260+
{
261+
auto model = ROOT::RNTupleModel::Create();
262+
auto a = model->MakeField<std::atomic<std::int32_t>>("a");
263+
auto i = model->MakeField<std::int32_t>("i");
264+
auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath());
265+
266+
*a = 7;
267+
*i = 13;
268+
writer->Fill();
269+
}
270+
271+
auto reader = RNTupleReader::Open("ntpl", fileGuard.GetPath());
272+
273+
auto v1 = reader->GetView<std::atomic<std::int64_t>>("a");
274+
auto v2 = reader->GetView<std::atomic<std::int64_t>>("i");
275+
auto v3 = reader->GetView<std::int64_t>("a");
276+
277+
try {
278+
reader->GetView<std::atomic<std::byte>>("a");
279+
FAIL() << "automatic evolution into an invalid atomic inner type should fail";
280+
} catch (const ROOT::RException &err) {
281+
EXPECT_THAT(err.what(), testing::HasSubstr("incompatible with on-disk field"));
282+
}
283+
284+
EXPECT_EQ(7, v1(0));
285+
EXPECT_EQ(13, v2(0));
286+
EXPECT_EQ(7, v3(0));
287+
}

0 commit comments

Comments
 (0)