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
19ROOT::RNTupleAttrSetReader::RNTupleAttrSetReader(std::unique_ptr<RNTupleReader> reader, std::uint16_t vSchemaMajor)
20 : fReader(std::move(reader))
21{
22 // Changes in major version imply forward incompatibility
23 if (vSchemaMajor != kSchemaVersionMajor)
24 throw ROOT::RException(R__FAIL("unsupported attribute schema version: " + std::to_string(vSchemaMajor)));
25
26 // Initialize user model
28
29 // Validate meta model format
30 const auto &metaDesc = fReader->GetDescriptor();
31 const auto &metaFieldIds = metaDesc.GetFieldZero().GetLinkIds();
32 if (metaFieldIds.size() != kMetaFieldIndex_Count) {
33 throw ROOT::RException(R__FAIL("invalid number of attribute meta-fields: expected " +
34 std::to_string(kMetaFieldIndex_Count) + ", got " +
35 std::to_string(metaFieldIds.size())));
36 }
37 for (std::size_t i = 0; i < kMetaFieldIndex_Count; ++i) {
38 const auto fieldId = metaFieldIds[i];
39 const auto &metaField = metaDesc.GetFieldDescriptor(fieldId);
40 if (metaField.GetFieldName() != kMetaFieldNames[i]) {
41 throw ROOT::RException(R__FAIL(std::string("invalid attribute meta-field name: expected '") +
42 kMetaFieldNames[i] + "', got '" + metaField.GetFieldName() + "'"));
43 }
44 }
45
46 const auto &userFieldRoot = metaDesc.GetFieldDescriptor(metaFieldIds[kMetaFieldIndex_UserData]);
47 for (const auto fieldId : userFieldRoot.GetLinkIds()) {
48 const auto &fdesc = metaDesc.GetFieldDescriptor(fieldId);
49 auto userField = RFieldBase::Create(fdesc.GetFieldName(), fdesc.GetTypeName()).Unwrap();
50 fUserModel->AddField(std::move(userField));
51 }
52 fUserModel->Freeze();
53
54 // Collect all entry ranges
55 auto entryRangeStartView = fReader->GetView<ROOT::NTupleSize_t>(kMetaFieldNames[kMetaFieldIndex_RangeStart]);
56 auto entryRangeLenView = fReader->GetView<ROOT::NTupleSize_t>(kMetaFieldNames[kMetaFieldIndex_RangeLen]);
57 fEntryRanges.reserve(fReader->GetNEntries());
58 for (auto i : fReader->GetEntryRange()) {
59 auto start = entryRangeStartView(i);
60 auto len = entryRangeLenView(i);
62 }
63
64 std::stable_sort(fEntryRanges.begin(), fEntryRanges.end(),
65 [](const auto &a, const auto &b) { return a.first.GetStart() < b.first.GetStart(); });
66
67 R__LOG_INFO(ROOT::Internal::NTupleLog()) << "Loaded " << fEntryRanges.size() << " attribute entries.";
68}
69
71{
72 return fReader->GetDescriptor();
73}
74
76{
77 // TODO(gparolini): find a way to avoid this const_cast
78 auto &metaModel = const_cast<ROOT::RNTupleModel &>(fReader->GetModel());
79 auto &metaEntry = metaModel.GetDefaultEntry();
80
81 if (R__unlikely(entry.GetModelId() != fUserModel->GetModelId()))
82 throw RException(R__FAIL("mismatch between entry and model"));
83
84 // Load the meta fields
85 metaEntry.fValues[kMetaFieldIndex_RangeStart].Read(index);
86 metaEntry.fValues[kMetaFieldIndex_RangeLen].Read(index);
87
88 // Load the user fields into `entry`
90 const auto userFields = userRootField->GetMutableSubfields();
91 assert(entry.fValues.size() == userFields.size());
92 for (std::size_t i = 0; i < userFields.size(); ++i) {
93 auto *field = userFields[i];
94 field->Read(index, entry.fValues[i].GetPtr<void>().get());
95 }
96
97 auto pStart = metaEntry.fValues[kMetaFieldIndex_RangeStart].GetPtr<NTupleSize_t>();
98 auto pLen = metaEntry.fValues[kMetaFieldIndex_RangeLen].GetPtr<NTupleSize_t>();
99
100 return RNTupleAttrRange::FromStartLength(*pStart, *pLen);
101}
102
104{
105 auto &entry = fUserModel->GetDefaultEntry();
106 return LoadEntry(index, entry);
107}
108
109std::unique_ptr<ROOT::REntry> ROOT::RNTupleAttrSetReader::CreateEntry()
110{
111 return fUserModel->CreateEntry();
112}
113
116{
117 RNTupleAttrRange range;
118 if (endEntry <= startEntry) {
120 << "empty range given when getting attributes from Attribute Set '" << GetDescriptor().GetName()
121 << "' (range given: [" << startEntry << ", " << endEntry << ")).";
122 // Make sure we find 0 entries
123 range = RNTupleAttrRange::FromStartLength(startEntry, 0);
124 } else {
125 range = RNTupleAttrRange::FromStartEnd(startEntry, endEntry);
126 }
127 RNTupleAttrEntryIterable::RFilter filter{range, /*fIsContained=*/false};
128 return RNTupleAttrEntryIterable{*this, filter};
129}
130
133{
134 RNTupleAttrRange range;
135 if (endEntry <= startEntry) {
137 << "empty range given when getting attributes from Attribute Set '" << GetDescriptor().GetName()
138 << "' (range given: [" << startEntry << ", " << endEntry << ")).";
139 // Make sure we find 0 entries
140 range = RNTupleAttrRange::FromStartLength(startEntry, 0);
141 } else {
142 range = RNTupleAttrRange::FromStartEnd(startEntry, endEntry);
143 }
144 RNTupleAttrEntryIterable::RFilter filter{range, /*fIsContained=*/true};
145 return RNTupleAttrEntryIterable{*this, filter};
146}
147
149{
150 RNTupleAttrEntryIterable::RFilter filter{RNTupleAttrRange::FromStartEnd(entryIndex, entryIndex + 1),
151 /*fIsContained=*/false};
152 return RNTupleAttrEntryIterable{*this, filter};
153}
154
159
160//
161// RNTupleAttrEntryIterable
162//
164{
165 assert(fFilter);
166 if (fFilter->fIsContained) {
167 return fFilter->fRange.GetStart() <= range.GetStart() && range.GetEnd() <= fFilter->fRange.GetEnd();
168 } else {
169 return range.GetStart() <= fFilter->fRange.GetStart() && fFilter->fRange.GetEnd() <= range.GetEnd();
170 }
171}
172
174{
175 // If we have no filter, every entry is valid.
176 if (!fFilter)
177 return fCur;
178
179 // TODO: consider using binary search, since fEntryRanges is sorted
180 // (maybe it should be done only if the size of the list is bigger than a threshold).
181 for (auto it = fCur; it != fEnd; ++it) {
182 const auto &[range, index] = *it;
183 const auto &firstLast = range.GetFirstLast();
184 // If this is nullopt it means this is a zero-length entry: we always skip those except
185 // for the "catch-all" GetAttributes() (which is when fFilter is also nullopt).
186 if (!firstLast)
187 continue;
188
189 const auto &[first, last] = *firstLast;
190 if (first >= fFilter->fRange.GetEnd()) {
191 // Since fEntryRanges is sorted we know we are at the end of the iteration
192 // TODO: tweak fEnd to directly pass the last entry?
193 return fEnd;
194 }
195
196 if (FullyContained(RNTupleAttrRange::FromStartEnd(first, last + 1)))
197 return it;
198 }
199 return fEnd;
200}
#define R__unlikely(expr)
Definition RConfig.hxx:568
#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:322
#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
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:55
std::vector< ROOT::RFieldBase::RValue > fValues
Corresponds to the fields of the linked model.
Definition REntry.hxx:69
std::uint64_t GetModelId() const
Definition REntry.hxx:256
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.
bool FullyContained(RNTupleAttrRange range) const
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.
ROOT::NTupleSize_t GetEnd() const
Returns one past the last valid index of the range, equal to GetStart() + GetLength().
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 ...
static RNTupleAttrRange FromStartLength(ROOT::NTupleSize_t start, ROOT::NTupleSize_t length)
ROOT::NTupleSize_t GetStart() const
Returns the beginning of the range.
const ROOT::RNTupleDescriptor & GetDescriptor() const
Returns the read-only descriptor of this attribute set.
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 GetAttributesInRange(NTupleSize_t startEntry, NTupleSize_t endEntry)
Returns all the attributes whose range is fully contained in [startEntry, endEntry)
std::unique_ptr< RNTupleReader > fReader
The internal Reader used to read the AttributeSet RNTuple.
std::unique_ptr< ROOT::RNTupleModel > fUserModel
The reconstructed user model.
RNTupleAttrSetReader(std::unique_ptr< RNTupleReader > reader, std::uint16_t vSchemaMajor)
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.
RNTupleAttrEntryIterable GetAttributes()
Returns all the attributes in this Set. The returned attributes are sorted by entry range start.
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()
constexpr const char * kMetaFieldNames[]
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.