Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RNTupleAttrReading.cxx
Go to the documentation of this file.
1/// \file RNTupleAttrReading.cxx
2/// \author Giacomo Parolini <giacomo.parolini@cern.ch>
3/// \date 2026-04-01
4/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
5/// is welcome!
6
10#include <ROOT/RNTupleModel.hxx>
11#include <ROOT/RLogger.hxx>
12
13#include <algorithm>
14#include <cstddef>
15#include <utility>
16
18
20 std::uint16_t vSchemaMajor)
21 : fReader(std::move(reader))
22{
23 // Changes in major version imply forward incompatibility
24 if (vSchemaMajor != kSchemaVersionMajor)
25 throw ROOT::RException(R__FAIL("unsupported attribute schema version: " + std::to_string(vSchemaMajor)));
26
27 // Initialize user model
29
30 // Validate meta model format
31 const auto &metaDesc = fReader->GetDescriptor();
32 const auto &metaFieldIds = metaDesc.GetFieldZero().GetLinkIds();
33 if (metaFieldIds.size() != kMetaFieldIndex_Count) {
34 throw ROOT::RException(R__FAIL("invalid number of attribute meta-fields: expected " +
35 std::to_string(kMetaFieldIndex_Count) + ", got " +
36 std::to_string(metaFieldIds.size())));
37 }
38 for (std::size_t i = 0; i < kMetaFieldIndex_Count; ++i) {
39 const auto fieldId = metaFieldIds[i];
40 const auto &metaField = metaDesc.GetFieldDescriptor(fieldId);
41 if (metaField.GetFieldName() != kMetaFieldNames[i]) {
42 throw ROOT::RException(R__FAIL(std::string("invalid attribute meta-field name: expected '") +
43 kMetaFieldNames[i] + "', got '" + metaField.GetFieldName() + "'"));
44 }
45 }
46
47 const auto &userFieldRoot = metaDesc.GetFieldDescriptor(metaFieldIds[kMetaFieldIndex_UserData]);
48 for (const auto fieldId : userFieldRoot.GetLinkIds()) {
49 const auto &fdesc = metaDesc.GetFieldDescriptor(fieldId);
50 auto userField = RFieldBase::Create(fdesc.GetFieldName(), fdesc.GetTypeName()).Unwrap();
51 fUserModel->AddField(std::move(userField));
52 }
53 fUserModel->Freeze();
54
55 // Collect all entry ranges
56 auto entryRangeStartView = fReader->GetView<ROOT::NTupleSize_t>(kMetaFieldNames[kMetaFieldIndex_RangeStart]);
57 auto entryRangeLenView = fReader->GetView<ROOT::NTupleSize_t>(kMetaFieldNames[kMetaFieldIndex_RangeLen]);
58 fEntryRanges.reserve(fReader->GetNEntries());
59 for (auto i : fReader->GetEntryRange()) {
60 auto start = entryRangeStartView(i);
61 auto len = entryRangeLenView(i);
63 }
64
65 std::stable_sort(fEntryRanges.begin(), fEntryRanges.end(),
66 [](const auto &a, const auto &b) { return a.first.GetStart() < b.first.GetStart(); });
67
68 R__LOG_INFO(ROOT::Internal::NTupleLog()) << "Loaded " << fEntryRanges.size() << " attribute entries.";
69}
70
75
78{
79 // TODO(gparolini): find a way to avoid this const_cast
80 auto &metaModel = const_cast<ROOT::RNTupleModel &>(fReader->GetModel());
81 auto &metaEntry = metaModel.GetDefaultEntry();
82
83 if (R__unlikely(entry.GetModelId() != fUserModel->GetModelId()))
84 throw RException(R__FAIL("mismatch between entry and model"));
85
86 // Load the meta fields
87 metaEntry.fValues[kMetaFieldIndex_RangeStart].Read(index);
88 metaEntry.fValues[kMetaFieldIndex_RangeLen].Read(index);
89
90 // Load the user fields into `entry`
92 const auto userFields = userRootField->GetMutableSubfields();
93 assert(entry.fValues.size() == userFields.size());
94 for (std::size_t i = 0; i < userFields.size(); ++i) {
95 auto *field = userFields[i];
96 field->Read(index, entry.fValues[i].GetPtr<void>().get());
97 }
98
99 auto pStart = metaEntry.fValues[kMetaFieldIndex_RangeStart].GetPtr<NTupleSize_t>();
100 auto pLen = metaEntry.fValues[kMetaFieldIndex_RangeLen].GetPtr<NTupleSize_t>();
101
102 return RNTupleAttrRange::FromStartLength(*pStart, *pLen);
103}
104
106{
107 auto &entry = fUserModel->GetDefaultEntry();
108 return LoadEntry(index, entry);
109}
110
112{
113 return fUserModel->CreateEntry();
114}
115
118{
119 RNTupleAttrRange range;
120 if (endEntry <= startEntry) {
122 << "empty range given when getting attributes from Attribute Set '" << GetDescriptor().GetName()
123 << "' (range given: [" << startEntry << ", " << endEntry << ")).";
124 // Make sure we find 0 entries
125 range = RNTupleAttrRange::FromStartLength(startEntry, 0);
126 } else {
127 range = RNTupleAttrRange::FromStartEnd(startEntry, endEntry);
128 }
129 RNTupleAttrEntryIterable::RFilter filter{range, /*fIsContained=*/false};
130 return RNTupleAttrEntryIterable{*this, filter};
131}
132
135{
136 RNTupleAttrRange range;
137 if (endEntry <= startEntry) {
139 << "empty range given when getting attributes from Attribute Set '" << GetDescriptor().GetName()
140 << "' (range given: [" << startEntry << ", " << endEntry << ")).";
141 // Make sure we find 0 entries
142 range = RNTupleAttrRange::FromStartLength(startEntry, 0);
143 } else {
144 range = RNTupleAttrRange::FromStartEnd(startEntry, endEntry);
145 }
146 RNTupleAttrEntryIterable::RFilter filter{range, /*fIsContained=*/true};
147 return RNTupleAttrEntryIterable{*this, filter};
148}
149
152{
153 RNTupleAttrEntryIterable::RFilter filter{RNTupleAttrRange::FromStartEnd(entryIndex, entryIndex + 1),
154 /*fIsContained=*/false};
155 return RNTupleAttrEntryIterable{*this, filter};
156}
157
162
163//
164// RNTupleAttrEntryIterable
165//
167{
168 assert(fFilter);
169 if (fFilter->fIsContained) {
170 return fFilter->fRange.GetStart() <= range.GetStart() && range.GetEnd() <= fFilter->fRange.GetEnd();
171 } else {
172 return range.GetStart() <= fFilter->fRange.GetStart() && fFilter->fRange.GetEnd() <= range.GetEnd();
173 }
174}
175
178{
179 // If we have no filter, every entry is valid.
180 if (!fFilter)
181 return fCur;
182
183 // TODO: consider using binary search, since fEntryRanges is sorted
184 // (maybe it should be done only if the size of the list is bigger than a threshold).
185 for (auto it = fCur; it != fEnd; ++it) {
186 const auto &[range, index] = *it;
187 const auto &firstLast = range.GetFirstLast();
188 // If this is nullopt it means this is a zero-length entry: we always skip those except
189 // for the "catch-all" GetAttributes() (which is when fFilter is also nullopt).
190 if (!firstLast)
191 continue;
192
193 const auto &[first, last] = *firstLast;
194 if (first >= fFilter->fRange.GetEnd()) {
195 // Since fEntryRanges is sorted we know we are at the end of the iteration
196 // TODO: tweak fEnd to directly pass the last entry?
197 return fEnd;
198 }
199
201 return it;
202 }
203 return fEnd;
204}
#define R__unlikely(expr)
Definition RConfig.hxx:586
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:299
#define R__LOG_WARNING(...)
Definition RLogger.hxx:357
#define R__LOG_INFO(...)
Definition RLogger.hxx:358
#define b(i)
Definition RSha256.hxx:100
#define a(i)
Definition RSha256.hxx:99
start
Definition Rotated.cxx:223
decltype(std::declval< RNTupleAttrSetReader >().fEntryRanges.begin()) Iter_t
Iterable class used to loop over attribute entries.
A range of main entries referred to by an attribute entry.
static RNTupleAttrRange FromStartLength(ROOT::NTupleSize_t start, ROOT::NTupleSize_t length)
static RNTupleAttrRange FromStartEnd(ROOT::NTupleSize_t start, ROOT::NTupleSize_t end)
Creates an AttributeRange from [start, end), where end is one past the last valid entry of the range ...
ROOT::NTupleSize_t GetStart() const
Returns the beginning of the range.
ROOT::NTupleSize_t GetEnd() const
Returns one past the last valid index of the range, equal to GetStart() + GetLength().
RNTupleAttrEntryIterable GetAttributesInRange(NTupleSize_t startEntry, NTupleSize_t endEntry)
Returns all the attributes whose range is fully contained in [startEntry, endEntry).
std::unique_ptr< ROOT::RNTupleModel > fUserModel
The reconstructed user model.
const ROOT::RNTupleDescriptor & GetDescriptor() const
Returns the read-only descriptor of this attribute set.
std::unique_ptr< RNTupleReader > fReader
The internal Reader used to read the AttributeSet RNTuple.
RNTupleAttrSetReader(std::unique_ptr< RNTupleReader > reader, std::uint16_t vSchemaMajor)
RNTupleAttrEntryIterable GetAttributes()
Returns all the attributes in this Set. The returned attributes are sorted by entry range start.
std::vector< std::pair< RNTupleAttrRange, NTupleSize_t > > fEntryRanges
List containing pairs { entryRange, entryIndex }, used to quickly find out which entries in the Attri...
std::unique_ptr< REntry > CreateEntry()
Creates an entry suitable for use with LoadEntry.
RNTupleAttrEntryIterable GetAttributesContainingRange(NTupleSize_t startEntry, NTupleSize_t endEntry)
Returns all the attributes whose range fully contains [startEntry, endEntry).
RNTupleAttrRange LoadEntry(NTupleSize_t index)
Loads the attribute entry at position index into the default entry.
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:54
std::vector< ROOT::RFieldBase::RValue > fValues
Corresponds to the fields of the linked model.
Definition REntry.hxx:67
std::uint64_t GetModelId() const
Definition REntry.hxx:254
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
std::vector< RFieldBase * > GetMutableSubfields()
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
Factory method to resurrect a field from the stored on-disk type information.
The on-storage metadata of an RNTuple.
The RNTupleModel encapulates the schema of an RNTuple.
REntry & GetDefaultEntry()
Retrieves the default entry of this model.
static std::unique_ptr< RNTupleModel > Create()
ROOT::RFieldZero & GetFieldZeroOfModel(RNTupleModel &model)
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.