Skip to content

[ntuple] Remove GetView<void> with external address #18317

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions tree/ntuple/v7/inc/ROOT/RNTupleReader.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,22 @@ public:
return GetView<T>(RetrieveFieldId(fieldName), rawPtr);
}

/// Provides access to an individual (sub)field, reading its values into `rawPtr` as the type provided by `typeName`.
///
/// \sa GetView(std::string_view, std::shared_ptr<T>)
ROOT::RNTupleView<void> GetView(std::string_view fieldName, void *rawPtr, std::string_view typeName)
{
return GetView(RetrieveFieldId(fieldName), rawPtr, typeName);
}

/// Provides access to an individual (sub)field, reading its values into `rawPtr` as the type provided by `ti`.
///
/// \sa GetView(std::string_view, std::shared_ptr<T>)
ROOT::RNTupleView<void> GetView(std::string_view fieldName, void *rawPtr, const std::type_info &ti)
{
return GetView(RetrieveFieldId(fieldName), rawPtr, ROOT::Internal::GetRenormalizedDemangledTypeName(ti));
}

template <typename T>
ROOT::RNTupleView<T> GetView(ROOT::DescriptorId_t fieldId)
{
Expand All @@ -295,6 +311,7 @@ public:
template <typename T>
ROOT::RNTupleView<T> GetView(ROOT::DescriptorId_t fieldId, std::shared_ptr<T> objPtr)
{
static_assert(!std::is_void_v<T>, "invalid attempt to call GetView<void> without a type name");
auto field = ROOT::RNTupleView<T>::CreateField(fieldId, *fSource);
auto range = ROOT::Internal::GetFieldRange(*field, *fSource);
return ROOT::RNTupleView<T>(std::move(field), range, objPtr);
Expand All @@ -303,11 +320,32 @@ public:
template <typename T>
ROOT::RNTupleView<T> GetView(ROOT::DescriptorId_t fieldId, T *rawPtr)
{
static_assert(!std::is_void_v<T>, "invalid attempt to call GetView<void> without a type name");
auto field = ROOT::RNTupleView<T>::CreateField(fieldId, *fSource);
auto range = ROOT::Internal::GetFieldRange(*field, *fSource);
return ROOT::RNTupleView<T>(std::move(field), range, rawPtr);
}

/// Provides access to an individual (sub)field from its on-disk ID, reading its values into `rawPtr` as the type
/// provided by `typeName`.
///
/// \sa GetView(std::string_view, std::shared_ptr<T>)
ROOT::RNTupleView<void> GetView(ROOT::DescriptorId_t fieldId, void *rawPtr, std::string_view typeName)
{
auto field = RNTupleView<void>::CreateField(fieldId, *fSource, typeName);
auto range = ROOT::Internal::GetFieldRange(*field, *fSource);
return RNTupleView<void>(std::move(field), range, rawPtr);
}

/// Provides access to an individual (sub)field from its on-disk ID, reading its values into `objPtr` as the type
/// provided by `ti`.
///
/// \sa GetView(std::string_view, std::shared_ptr<T>)
ROOT::RNTupleView<void> GetView(ROOT::DescriptorId_t fieldId, void *rawPtr, const std::type_info &ti)
{
return GetView(fieldId, rawPtr, ROOT::Internal::GetRenormalizedDemangledTypeName(ti));
}

template <typename T>
ROOT::RNTupleDirectAccessView<T> GetDirectAccessView(std::string_view fieldName)
{
Expand Down
10 changes: 7 additions & 3 deletions tree/ntuple/v7/inc/ROOT/RNTupleView.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,19 @@ protected:
ROOT::RNTupleGlobalRange fFieldRange;
ROOT::RFieldBase::RValue fValue;

static std::unique_ptr<ROOT::RFieldBase>
CreateField(ROOT::DescriptorId_t fieldId, ROOT::Experimental::Internal::RPageSource &pageSource)
static std::unique_ptr<ROOT::RFieldBase> CreateField(ROOT::DescriptorId_t fieldId,
Experimental::Internal::RPageSource &pageSource,
std::string_view typeName = "")
{
std::unique_ptr<ROOT::RFieldBase> field;
{
const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
if constexpr (std::is_void_v<T>) {
field = fieldDesc.CreateField(desc);
if (typeName.empty())
field = fieldDesc.CreateField(desc);
else
field = ROOT::RFieldBase::Create(fieldDesc.GetFieldName(), std::string(typeName)).Unwrap();
} else {
field = std::make_unique<ROOT::RField<T>>(fieldDesc.GetFieldName());
}
Expand Down
94 changes: 84 additions & 10 deletions tree/ntuple/v7/test/ntuple_view.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,6 @@ TEST(RNTuple, ViewWithExternalAddress)
auto view_1 = reader->GetView("pt", data_1);
view_1(0);
EXPECT_FLOAT_EQ(42.0, *data_1);

// Void shared_ptr
std::shared_ptr<void> data_2{new float()};
auto view_2 = reader->GetView("pt", data_2);
view_2(0);
EXPECT_FLOAT_EQ(42.0, *static_cast<float *>(data_2.get()));
}

TEST(RNTuple, BindEmplaceTyped)
Expand Down Expand Up @@ -341,7 +335,7 @@ TEST(RNTuple, BindEmplaceVoid)

// bind to shared_ptr
std::shared_ptr<void> value1{new float()};
auto view = reader->GetView<void>("pt", nullptr);
auto view = reader->GetView<void>("pt");
view.Bind(value1);
view(0);
EXPECT_FLOAT_EQ(11.f, *reinterpret_cast<float *>(value1.get()));
Expand Down Expand Up @@ -433,23 +427,23 @@ TEST(RNTuple, ViewFrameworkUse)
for (auto i : reader->GetEntryRange()) {
if (i > 1) {
if (!viewPx) {
viewPx = reader->GetView<void>("px", &px);
viewPx = reader->GetView("px", &px, "float");
}
(*viewPx)(i);
EXPECT_FLOAT_EQ(i, px);
}

if (i > 3) {
if (!viewPy) {
viewPy = reader->GetView<void>("py", &py);
viewPy = reader->GetView("py", &py, "float");
}
(*viewPy)(i);
EXPECT_FLOAT_EQ(0.2 + i, py);
}

if (i > 7) {
if (!viewPz) {
viewPz = reader->GetView<void>("pz", &pz);
viewPz = reader->GetView("pz", &pz, "float");
}
(*viewPz)(i);
EXPECT_FLOAT_EQ(0.4 + i, pz);
Expand Down Expand Up @@ -533,3 +527,83 @@ TEST(RNTuple, ViewFieldIteration)
EXPECT_THAT(err.what(), testing::HasSubstr("field iteration over empty fields is unsupported"));
}
}

TEST(RNTuple, VoidWithExternalAddressAndTypeName)
{
FileRaii fileGuard("test_ntuple_voidwithexternaladdressandtypename.root");

{
auto model = RNTupleModel::Create();
auto fldFoo = model->MakeField<std::uint64_t>("foo");
auto fldBar = model->MakeField<std::uint64_t>("bar");
auto fldBaz = model->MakeField<std::vector<float>>("baz");

auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath());
*fldFoo = 42;
*fldBar = std::numeric_limits<std::uint64_t>::max();
*fldBaz = {1.f, 2.f, 3.f};
writer->Fill();
}

auto reader = RNTupleReader::Open("ntpl", fileGuard.GetPath());
ASSERT_EQ(1u, reader->GetNEntries());

// Read "foo" as std::int32_t (instead of its on-disk type std::uint64_t)
auto int32SharedPtr = std::make_shared<std::int32_t>();

// Raw pointer interface from type name string
{
auto viewFoo = reader->GetView("foo", int32SharedPtr.get(), "std::int32_t");
viewFoo(0);
EXPECT_EQ(42, *int32SharedPtr);
EXPECT_STREQ("std::int32_t", viewFoo.GetField().GetTypeName().c_str());
}

// Raw pointer interface from std::type_info
{
auto viewFoo = reader->GetView("foo", int32SharedPtr.get(), typeid(std::int32_t));
viewFoo(0);
EXPECT_EQ(42, *int32SharedPtr);
EXPECT_STREQ("std::int32_t", viewFoo.GetField().GetTypeName().c_str());
}

// Reading as a type when the on-disk value doesn't fit in this type is not possible
try {
auto viewBar = reader->GetView("bar", int32SharedPtr.get(), "std::int32_t");
viewBar(0);
} catch (const ROOT::RException &err) {
EXPECT_THAT(err.what(), testing::HasSubstr("value out of range: 18446744073709551615 for type i"));
}

// Read "baz" as std::vector<double> (instead of its on-disk type std::vector<float>)
std::vector<double> doubleVec;
void *doubleVecPtr = &doubleVec;
std::vector<double> expDoubleVec{1., 2., 3.};

// From type name string
{
auto viewBaz = reader->GetView("baz", doubleVecPtr, "std::vector<double>");
viewBaz(0);
EXPECT_EQ(expDoubleVec, viewBaz.GetValue().GetRef<std::vector<double>>());
EXPECT_STREQ("baz", viewBaz.GetField().GetFieldName().c_str());
EXPECT_STREQ("std::vector<double>", viewBaz.GetField().GetTypeName().c_str());
}

// From std::type_info
{
auto viewBaz = reader->GetView("baz", doubleVecPtr, typeid(std::vector<double>));
viewBaz(0);
EXPECT_EQ(expDoubleVec, viewBaz.GetValue().GetRef<std::vector<double>>());
EXPECT_STREQ("baz", viewBaz.GetField().GetFieldName().c_str());
EXPECT_STREQ("std::vector<double>", viewBaz.GetField().GetTypeName().c_str());
}

try {
std::vector<int> intVec;
void *bazAsIntsPtr = &intVec;
reader->GetView("baz", bazAsIntsPtr, "std::vector<int>");
} catch (const ROOT::RException &err) {
EXPECT_THAT(err.what(), testing::HasSubstr("On-disk column types {`SplitReal32`} for field `baz._0` cannot be "
"matched to its in-memory type `std::int32_t`"));
}
}
Loading