Skip to content

Commit 22ad2f2

Browse files
committed
[roottest] Provide reproducer for #19022
1 parent 7da0d20 commit 22ad2f2

File tree

5 files changed

+170
-0
lines changed

5 files changed

+170
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#ifndef ATLASLIKEDATAVECTOR
2+
#define ATLASLIKEDATAVECTOR
3+
4+
// Mimicks the DataVector hierarchy as found in athena
5+
6+
#include <RootMetaSelection.h>
7+
8+
#include <cstdint>
9+
#include <string>
10+
#include <vector>
11+
12+
// https://gitlab.cern.ch/atlas/athena/-/blob/26885cbcf82f069cddff6cd30c123572e362d8fa/Control/AthContainers/AthContainers/tools/DVLNoBase.h#L32
13+
namespace DataModel_detail {
14+
struct NoBase {};
15+
} // namespace DataModel_detail
16+
17+
// https://gitlab.cern.ch/atlas/athena/-/blob/26885cbcf82f069cddff6cd30c123572e362d8fa/Control/AthContainers/AthContainers/DataVector.h#L632
18+
template <class T>
19+
struct DataVectorBase {
20+
typedef DataModel_detail::NoBase Base;
21+
};
22+
23+
// https://gitlab.cern.ch/atlas/athena/-/blob/26885cbcf82f069cddff6cd30c123572e362d8fa/Control/AthContainers/AthContainers/DataVector.h#L792
24+
template <class T, class BASE = typename DataVectorBase<T>::Base>
25+
class AtlasLikeDataVector : public BASE {};
26+
27+
namespace SG {
28+
// https://gitlab.cern.ch/atlas/athena/-/blob/26885cbcf82f069cddff6cd30c123572e362d8fa/Control/AthContainers/AthContainers/AuxVectorData.h#L164
29+
class AuxVectorData {
30+
public:
31+
AuxVectorData() = default;
32+
};
33+
// https://gitlab.cern.ch/atlas/athena/-/blob/26885cbcf82f069cddff6cd30c123572e362d8fa/Control/AthContainers/AthContainers/AuxVectorBase.h#L96
34+
class AuxVectorBase : public AuxVectorData {
35+
public:
36+
AuxVectorBase() = default;
37+
};
38+
} // namespace SG
39+
40+
// https://gitlab.cern.ch/atlas/athena/-/blob/26885cbcf82f069cddff6cd30c123572e362d8fa/Control/AthContainers/AthContainers/DataVector.h#L2058
41+
template <class T>
42+
class AtlasLikeDataVector<T, DataModel_detail::NoBase> : public SG::AuxVectorBase {};
43+
44+
namespace ROOT::Meta::Selection {
45+
// https://gitlab.cern.ch/atlas/athena/-/blob/26885cbcf82f069cddff6cd30c123572e362d8fa/Control/AthContainers/AthContainers/DataVector.h#L3422
46+
template <class T, class BASE>
47+
class AtlasLikeDataVector : KeepFirstTemplateArguments<1>, SelectNoInstance {};
48+
} // namespace ROOT::Meta::Selection
49+
50+
struct CustomStruct {
51+
float a = 0.0;
52+
std::vector<float> v1;
53+
std::vector<std::vector<float>> v2;
54+
std::string s;
55+
std::byte b{};
56+
};
57+
58+
namespace {
59+
// https://gitlab.cern.ch/atlas/athena/-/blob/26885cbcf82f069cddff6cd30c123572e362d8fa/Control/AthContainers/AthContainers/AthContainersDict.h#L29
60+
struct DUMMY_INSTANTIATION {
61+
AtlasLikeDataVector<CustomStruct, DataModel_detail::NoBase> dummy1;
62+
ROOT::Meta::Selection::AtlasLikeDataVector<CustomStruct, DataModel_detail::NoBase> dummy2;
63+
};
64+
} // namespace
65+
66+
#endif // ATLASLIKEDATAVECTOR
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Reproducer of https://github.com/root-project/root/issues/19022
2+
3+
# Generate the dictionary for the ATLAS-like container class
4+
# Note that we use a selection.xml file, not a LinkDef, as this is what
5+
# is done in Athena as well. Also note that in the selection we have a rule
6+
# that uses a pattern AtlasLikeDataVector<CustomStruct,*> so we don't rely
7+
# on an explicit declaration of the full class template with 2 arguments.
8+
ROOTTEST_GENERATE_DICTIONARY(
9+
AtlasLikeDataVectorDict
10+
${CMAKE_CURRENT_SOURCE_DIR}/AtlasLikeDataVector.hxx
11+
LINKDEF ${CMAKE_CURRENT_SOURCE_DIR}/selection.xml
12+
FIXTURES_SETUP atlas_datavector_dict_setup
13+
)
14+
15+
# Generate a shared library from the dictionary sources
16+
add_library(AtlasLikeDataVector SHARED AtlasLikeDataVectorDict.cxx)
17+
target_link_libraries(AtlasLikeDataVector Core RIO ROOTNTuple)
18+
add_dependencies(AtlasLikeDataVector AtlasLikeDataVectorDict)
19+
20+
# Generate an executable to write an RNTuple with a field of type
21+
# AtlasLikeDataVector<CustomStruct>. Note that we don't link explicitly
22+
# the executable against the shared library, but the information of the
23+
# dictionary should be autoloaded, thus the rule to drop the second template
24+
# argument should kick in when writing the class to disk.
25+
ROOTTEST_GENERATE_EXECUTABLE(
26+
write
27+
write.cxx
28+
LIBRARIES Core RIO ROOTNTuple
29+
FIXTURES_REQUIRED atlas_datavector_dict_setup
30+
FIXTURES_SETUP atlas_datavector_write_setup)
31+
32+
# Generate an executable to read back the RNTuple with a field of type
33+
# AtlasLikeDataVector<CustomStruct>. Note that we don't link explicitly
34+
# the executable against the shared library, but the information of the
35+
# dictionary should be autoloaded, thus the rule to drop the second template
36+
# argument should kick in when reading the field.
37+
ROOTTEST_GENERATE_EXECUTABLE(
38+
read
39+
read.cxx
40+
LIBRARIES Core RIO ROOTNTuple gtest gtest_main
41+
FIXTURES_REQUIRED atlas_datavector_dict_setup
42+
FIXTURES_SETUP atlas_datavector_read_setup)
43+
44+
ROOTTEST_ADD_TEST(write
45+
EXEC ${CMAKE_CURRENT_BINARY_DIR}/write
46+
FIXTURES_REQUIRED atlas_datavector_write_setup
47+
FIXTURES_SETUP atlas_datavector_write_done)
48+
49+
# In the reading test we rely on the templated call that uses the shortened
50+
# class type AtlasLikeDataVector<CustomStruct>, so we need to include the header
51+
ROOTTEST_ADD_TEST(read
52+
EXEC ${CMAKE_CURRENT_BINARY_DIR}/read
53+
COPY_TO_BUILDDIR ${CMAKE_CURRENT_SOURCE_DIR}/AtlasLikeDataVector.hxx
54+
FIXTURES_REQUIRED "atlas_datavector_read_setup;atlas_datavector_write_done")
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <string>
2+
3+
#include <ROOT/RField.hxx>
4+
#include <ROOT/RNTupleModel.hxx>
5+
#include <ROOT/RNTupleReader.hxx>
6+
7+
#include <gtest/gtest.h>
8+
9+
#include "AtlasLikeDataVector.hxx"
10+
11+
TEST(RNTupleAtlasDataVector, Read)
12+
{
13+
const auto typeNameBefore = ROOT::RField<AtlasLikeDataVector<CustomStruct>>::TypeName();
14+
const std::string expectedBefore{"AtlasLikeDataVector<CustomStruct,DataModel_detail::NoBase>"};
15+
// Make sure no autoloading happened yet
16+
ASSERT_EQ(typeNameBefore, expectedBefore);
17+
18+
auto reader = ROOT::RNTupleReader::Open("ntpl", "test_ntuple_datavector.root");
19+
const auto &entry = reader->GetModel().GetDefaultEntry();
20+
// The following call should not throw an exception
21+
ASSERT_NO_THROW(entry.GetPtr<AtlasLikeDataVector<CustomStruct>>("my_field"));
22+
23+
const auto typeNameAfter = ROOT::RField<AtlasLikeDataVector<CustomStruct>>::TypeName();
24+
const std::string expectedAfter{"AtlasLikeDataVector<CustomStruct>"};
25+
// Make sure autoloading happened and the rule to suppress the second template argument kicked in
26+
ASSERT_EQ(typeNameAfter, expectedAfter);
27+
}
28+
29+
int main(int argc, char **argv)
30+
{
31+
::testing::InitGoogleTest(&argc, argv);
32+
return RUN_ALL_TESTS();
33+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<lcgdict>
2+
<class name="CustomStruct" />
3+
<class name="SG::AuxVectorData" />
4+
<class name="SG::AuxVectorBase" />
5+
<class pattern="AtlasLikeDataVector<CustomStruct,*>" />
6+
</lcgdict>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <ROOT/RField.hxx>
2+
#include <ROOT/RNTupleModel.hxx>
3+
#include <ROOT/RNTupleWriter.hxx>
4+
5+
int main()
6+
{
7+
auto model = ROOT::RNTupleModel::Create();
8+
model->AddField(ROOT::RFieldBase::Create("my_field", "AtlasLikeDataVector<CustomStruct>").Unwrap());
9+
auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "ntpl", "test_ntuple_datavector.root");
10+
writer->Fill();
11+
}

0 commit comments

Comments
 (0)