Skip to content

Commit 48b72ff

Browse files
committed
[ntuple] Add de/serialization of RNTupleAttributes
1 parent a4b2bda commit 48b72ff

File tree

6 files changed

+480
-20
lines changed

6 files changed

+480
-20
lines changed

tree/ntuple/inc/ROOT/RNTupleDescriptor.hxx

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,53 @@ struct RNTupleClusterBoundaries {
6767
std::vector<ROOT::Internal::RNTupleClusterBoundaries> GetClusterBoundaries(const RNTupleDescriptor &desc);
6868
} // namespace Internal
6969

70+
namespace Experimental {
71+
namespace Internal {
72+
class RNTupleAttrSetDescriptorBuilder;
73+
}
74+
75+
// clang-format off
76+
/**
77+
\class ROOT::Experimental::RNTupleAttrSetDescriptor
78+
\ingroup NTuple
79+
\brief Metadata stored for every Attribute Set linked to an RNTuple.
80+
*/
81+
// clang-format on
82+
class RNTupleAttrSetDescriptor final {
83+
friend class Experimental::Internal::RNTupleAttrSetDescriptorBuilder;
84+
85+
std::uint16_t fSchemaVersionMajor = 0;
86+
std::uint16_t fSchemaVersionMinor = 0;
87+
std::uint32_t fAnchorLength = 0; ///< uncompressed size of the linked anchor
88+
// The locator of the AttributeSet anchor.
89+
// In case of kTypeFile, it points to the beginning of the Anchor's payload.
90+
// NOTE: Only kTypeFile is supported at the moment.
91+
RNTupleLocator fAnchorLocator;
92+
std::string fName;
93+
94+
public:
95+
RNTupleAttrSetDescriptor() = default;
96+
RNTupleAttrSetDescriptor(const RNTupleAttrSetDescriptor &other) = delete;
97+
RNTupleAttrSetDescriptor &operator=(const RNTupleAttrSetDescriptor &other) = delete;
98+
RNTupleAttrSetDescriptor(RNTupleAttrSetDescriptor &&other) = default;
99+
RNTupleAttrSetDescriptor &operator=(RNTupleAttrSetDescriptor &&other) = default;
100+
101+
bool operator==(const RNTupleAttrSetDescriptor &other) const;
102+
bool operator!=(const RNTupleAttrSetDescriptor &other) const { return !(*this == other); }
103+
104+
const std::string &GetName() const { return fName; }
105+
std::uint16_t GetSchemaVersionMajor() const { return fSchemaVersionMajor; }
106+
std::uint16_t GetSchemaVersionMinor() const { return fSchemaVersionMinor; }
107+
std::uint32_t GetAnchorLength() const { return fAnchorLength; }
108+
const RNTupleLocator &GetAnchorLocator() const { return fAnchorLocator; }
109+
110+
RNTupleAttrSetDescriptor Clone() const;
111+
};
112+
113+
class RNTupleAttrSetDescriptorIterable;
114+
115+
} // namespace Experimental
116+
70117
// clang-format off
71118
/**
72119
\class ROOT::RFieldDescriptor
@@ -697,6 +744,8 @@ private:
697744
std::vector<ROOT::DescriptorId_t> fSortedClusterGroupIds;
698745
/// Potentially a subset of all the available clusters
699746
std::unordered_map<ROOT::DescriptorId_t, RClusterDescriptor> fClusterDescriptors;
747+
/// List of AttributeSets linked to this RNTuple
748+
std::vector<Experimental::RNTupleAttrSetDescriptor> fAttributeSets;
700749

701750
// We don't expose this publicly because when we add sharded clusters, this interface does not make sense anymore
702751
ROOT::DescriptorId_t FindClusterId(ROOT::NTupleSize_t entryIdx) const;
@@ -714,6 +763,7 @@ public:
714763
class RClusterGroupDescriptorIterable;
715764
class RClusterDescriptorIterable;
716765
class RExtraTypeInfoDescriptorIterable;
766+
friend class Experimental::RNTupleAttrSetDescriptorIterable;
717767

718768
/// Modifiers passed to CreateModel()
719769
struct RCreateModelOptions {
@@ -802,6 +852,8 @@ public:
802852

803853
RExtraTypeInfoDescriptorIterable GetExtraTypeInfoIterable() const;
804854

855+
ROOT::Experimental::RNTupleAttrSetDescriptorIterable GetAttrSetIterable() const;
856+
805857
const std::string &GetName() const { return fName; }
806858
const std::string &GetDescription() const { return fDescription; }
807859

@@ -812,6 +864,7 @@ public:
812864
std::size_t GetNClusters() const { return fNClusters; }
813865
std::size_t GetNActiveClusters() const { return fClusterDescriptors.size(); }
814866
std::size_t GetNExtraTypeInfos() const { return fExtraTypeInfoDescriptors.size(); }
867+
std::size_t GetNAttributeSets() const { return fAttributeSets.size(); }
815868

816869
/// We know the number of entries from adding the cluster summaries
817870
ROOT::NTupleSize_t GetNEntries() const { return fNEntries; }
@@ -1141,6 +1194,59 @@ public:
11411194
RIterator end() { return RIterator(fNTuple.fExtraTypeInfoDescriptors.cend()); }
11421195
};
11431196

1197+
namespace Experimental {
1198+
// clang-format off
1199+
/**
1200+
\class ROOT::Experimental::RNTupleAttrSetDescriptorIterable
1201+
\ingroup NTuple
1202+
\brief Used to loop over all the Attribute Sets linked to an RNTuple
1203+
*/
1204+
// clang-format on
1205+
// TODO: move this to RNTupleDescriptor::RNTupleAttrSetDescriptorIterable when it moves out of Experimental.
1206+
class RNTupleAttrSetDescriptorIterable final {
1207+
private:
1208+
/// The associated RNTuple for this range.
1209+
const RNTupleDescriptor &fNTuple;
1210+
1211+
public:
1212+
class RIterator final {
1213+
private:
1214+
using Iter_t = std::vector<RNTupleAttrSetDescriptor>::const_iterator;
1215+
/// The wrapped map iterator
1216+
Iter_t fIter;
1217+
1218+
public:
1219+
using iterator_category = std::bidirectional_iterator_tag;
1220+
using iterator = RIterator;
1221+
using value_type = RNTupleAttrSetDescriptor;
1222+
using difference_type = std::ptrdiff_t;
1223+
using pointer = const value_type *;
1224+
using reference = const value_type &;
1225+
1226+
RIterator(Iter_t iter) : fIter(iter) {}
1227+
iterator &operator++() /* prefix */
1228+
{
1229+
++fIter;
1230+
return *this;
1231+
}
1232+
iterator operator++(int) /* postfix */
1233+
{
1234+
auto old = *this;
1235+
operator++();
1236+
return old;
1237+
}
1238+
reference operator*() const { return *fIter; }
1239+
pointer operator->() const { return &*fIter; }
1240+
bool operator!=(const iterator &rh) const { return fIter != rh.fIter; }
1241+
bool operator==(const iterator &rh) const { return fIter == rh.fIter; }
1242+
};
1243+
1244+
RNTupleAttrSetDescriptorIterable(const RNTupleDescriptor &ntuple) : fNTuple(ntuple) {}
1245+
RIterator begin() { return RIterator(fNTuple.fAttributeSets.cbegin()); }
1246+
RIterator end() { return RIterator(fNTuple.fAttributeSets.cend()); }
1247+
};
1248+
} // namespace Experimental
1249+
11441250
// clang-format off
11451251
/**
11461252
\class ROOT::RNTupleDescriptor::RHeaderExtension
@@ -1214,6 +1320,39 @@ public:
12141320
}
12151321
};
12161322

1323+
namespace Experimental::Internal {
1324+
class RNTupleAttrSetDescriptorBuilder final {
1325+
ROOT::Experimental::RNTupleAttrSetDescriptor fDesc;
1326+
1327+
public:
1328+
RNTupleAttrSetDescriptorBuilder &Name(std::string_view name)
1329+
{
1330+
fDesc.fName = name;
1331+
return *this;
1332+
}
1333+
RNTupleAttrSetDescriptorBuilder &SchemaVersion(std::uint16_t major, std::uint16_t minor)
1334+
{
1335+
fDesc.fSchemaVersionMajor = major;
1336+
fDesc.fSchemaVersionMinor = minor;
1337+
return *this;
1338+
}
1339+
RNTupleAttrSetDescriptorBuilder &AnchorLocator(const RNTupleLocator &loc)
1340+
{
1341+
fDesc.fAnchorLocator = loc;
1342+
return *this;
1343+
}
1344+
RNTupleAttrSetDescriptorBuilder &AnchorLength(std::uint32_t length)
1345+
{
1346+
fDesc.fAnchorLength = length;
1347+
return *this;
1348+
}
1349+
1350+
/// Attempt to make an AttributeSet descriptor. This may fail if the builder
1351+
/// was not given enough information to make a proper descriptor.
1352+
RResult<ROOT::Experimental::RNTupleAttrSetDescriptor> MoveDescriptor();
1353+
};
1354+
} // namespace Experimental::Internal
1355+
12171356
namespace Internal {
12181357

12191358
// clang-format off
@@ -1597,6 +1736,8 @@ public:
15971736
RResult<void> AddExtraTypeInfo(RExtraTypeInfoDescriptor &&extraTypeInfoDesc);
15981737
void ReplaceExtraTypeInfo(RExtraTypeInfoDescriptor &&extraTypeInfoDesc);
15991738

1739+
RResult<void> AddAttributeSet(Experimental::RNTupleAttrSetDescriptor &&attrSetDesc);
1740+
16001741
/// Mark the beginning of the header extension; any fields and columns added after a call to this function are
16011742
/// annotated as begin part of the header extension.
16021743
void BeginHeaderExtension();
@@ -1630,6 +1771,7 @@ inline RNTupleDescriptor CloneDescriptorSchema(const RNTupleDescriptor &desc)
16301771
}
16311772

16321773
} // namespace Internal
1774+
16331775
} // namespace ROOT
16341776

16351777
#endif // ROOT_RNTupleDescriptor

tree/ntuple/inc/ROOT/RNTupleSerialize.hxx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ class RNTupleDescriptor;
3636
class RClusterDescriptor;
3737
enum class EExtraTypeInfoIds;
3838

39+
namespace Experimental {
40+
class RNTupleAttrSetDescriptor;
41+
namespace Internal {
42+
class RNTupleAttrSetDescriptorBuilder;
43+
}
44+
} // namespace Experimental
45+
3946
namespace Internal {
4047

4148
class RClusterDescriptorBuilder;
@@ -271,6 +278,12 @@ public:
271278
static RResult<std::uint32_t> DeserializeSchemaDescription(const void *buffer, std::uint64_t bufSize,
272279
ROOT::Internal::RNTupleDescriptorBuilder &descBuilder);
273280

281+
static RResult<std::uint32_t>
282+
SerializeAttributeSet(const Experimental::RNTupleAttrSetDescriptor &attrSetDesc, void *buffer);
283+
static RResult<std::uint32_t>
284+
DeserializeAttributeSet(const void *buffer, std::uint64_t bufSize,
285+
Experimental::Internal::RNTupleAttrSetDescriptorBuilder &attrSetDescBld);
286+
274287
static RResult<RContext> SerializeHeader(void *buffer, const RNTupleDescriptor &desc);
275288
static RResult<std::uint32_t> SerializePageList(void *buffer, const RNTupleDescriptor &desc,
276289
std::span<ROOT::DescriptorId_t> physClusterIDs,

tree/ntuple/src/RNTupleDescriptor.cxx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,8 @@ ROOT::RNTupleDescriptor ROOT::RNTupleDescriptor::Clone() const
785785
clone.fSortedClusterGroupIds = fSortedClusterGroupIds;
786786
for (const auto &d : fClusterDescriptors)
787787
clone.fClusterDescriptors.emplace(d.first, d.second.Clone());
788+
for (const auto &d : fAttributeSets)
789+
clone.fAttributeSets.emplace_back(d.Clone());
788790
return clone;
789791
}
790792

@@ -1105,6 +1107,19 @@ void ROOT::Internal::RNTupleDescriptorBuilder::SetFeature(unsigned int flag)
11051107
fDescriptor.fFeatureFlags.insert(flag);
11061108
}
11071109

1110+
ROOT::RResult<ROOT::Experimental::RNTupleAttrSetDescriptor>
1111+
ROOT::Experimental::Internal::RNTupleAttrSetDescriptorBuilder::MoveDescriptor()
1112+
{
1113+
if (fDesc.fName.empty())
1114+
return R__FAIL("AttributeSet name cannot be empty");
1115+
if (fDesc.fAnchorLength == 0)
1116+
return R__FAIL("invalid anchor length");
1117+
if (fDesc.fAnchorLocator.GetType() == RNTupleLocator::kTypeUnknown)
1118+
return R__FAIL("invalid locator type");
1119+
1120+
return std::move(fDesc);
1121+
}
1122+
11081123
ROOT::RResult<ROOT::RColumnDescriptor> ROOT::Internal::RColumnDescriptorBuilder::MakeDescriptor() const
11091124
{
11101125
if (fColumn.GetLogicalId() == ROOT::kInvalidDescriptorId)
@@ -1359,6 +1374,19 @@ void ROOT::Internal::RNTupleDescriptorBuilder::ReplaceExtraTypeInfo(RExtraTypeIn
13591374
fDescriptor.fExtraTypeInfoDescriptors.emplace_back(std::move(extraTypeInfoDesc));
13601375
}
13611376

1377+
ROOT::RResult<void>
1378+
ROOT::Internal::RNTupleDescriptorBuilder::AddAttributeSet(Experimental::RNTupleAttrSetDescriptor &&attrSetDesc)
1379+
{
1380+
auto &attrSets = fDescriptor.fAttributeSets;
1381+
if (std::find_if(attrSets.begin(), attrSets.end(), [&name = attrSetDesc.GetName()](const auto &desc) {
1382+
return desc.GetName() == name;
1383+
}) != attrSets.end()) {
1384+
return R__FAIL("attribute sets with duplicate names");
1385+
}
1386+
attrSets.push_back(std::move(attrSetDesc));
1387+
return RResult<void>::Success();
1388+
}
1389+
13621390
RNTupleSerializer::StreamerInfoMap_t ROOT::Internal::RNTupleDescriptorBuilder::BuildStreamerInfos() const
13631391
{
13641392
RNTupleSerializer::StreamerInfoMap_t streamerInfoMap;
@@ -1474,3 +1502,25 @@ ROOT::RNTupleDescriptor::RExtraTypeInfoDescriptorIterable ROOT::RNTupleDescripto
14741502
{
14751503
return RExtraTypeInfoDescriptorIterable(*this);
14761504
}
1505+
1506+
ROOT::Experimental::RNTupleAttrSetDescriptorIterable ROOT::RNTupleDescriptor::GetAttrSetIterable() const
1507+
{
1508+
return Experimental::RNTupleAttrSetDescriptorIterable(*this);
1509+
}
1510+
1511+
bool ROOT::Experimental::RNTupleAttrSetDescriptor::operator==(const RNTupleAttrSetDescriptor &other) const
1512+
{
1513+
return fAnchorLength == other.fAnchorLength && fSchemaVersionMajor == other.fSchemaVersionMajor &&
1514+
fSchemaVersionMinor == other.fSchemaVersionMinor && fAnchorLocator == other.fAnchorLocator &&
1515+
fName == other.fName;
1516+
};
1517+
1518+
ROOT::Experimental::RNTupleAttrSetDescriptor ROOT::Experimental::RNTupleAttrSetDescriptor::Clone() const
1519+
{
1520+
RNTupleAttrSetDescriptor desc;
1521+
desc.fAnchorLength = fAnchorLength;
1522+
desc.fSchemaVersionMajor = fSchemaVersionMajor;
1523+
desc.fSchemaVersionMinor = fSchemaVersionMinor;
1524+
desc.fName = fName;
1525+
return desc;
1526+
}

0 commit comments

Comments
 (0)