Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleProcessorDS.cxx
Go to the documentation of this file.
1/// \file RNTupleProcessorDS.cxx
2/// \author Florine de Geus <florine.de.geus@cern.ch>
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \author Enrico Guiraud <enrico.guiraud@cern.ch>
5/// \date 2026-06-18
6/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
7/// is welcome!
8
10#include <ROOT/RDataFrame.hxx>
11#include <ROOT/RDF/Utils.hxx>
12#include <ROOT/RField.hxx>
13#include <ROOT/RFieldUtils.hxx>
17#include <ROOT/RPageStorage.hxx>
18
19#include "RNTupleDSFields.hxx"
20
21#include <TError.h>
22#include <TSystem.h>
23
24#include <cassert>
25#include <memory>
26#include <string>
27#include <string_view>
28
30/// Every RDF column is represented by exactly one RNTuple field
32 RNTupleProcessorValuePtr<void> fValuePtr; ///< Container for the value of the column
34
35public:
37 ~RNTupleProcessorColumnReader() override = default;
38
39 void *GetImpl(Long64_t entry [[maybe_unused]]) final
40 {
41 assert(entry == fLastLoadedEntry);
42 return fValuePtr.GetPtr().get();
43 }
44
45 void SetEntryLoaded(Long64_t entry) { fLastLoadedEntry = entry; }
46};
47
49
50// TODO: see if common parts of this and RNTupleDS::AddField can be factored out.
51void RNTupleProcessorDS::AddField(const ROOT::RFieldBase &field, std::string_view colName,
53 std::deque<RNTupleProcessorDS::RFieldInfo> &fieldInfos, bool convertToRVec)
54{
55 // As an example for the mapping of RNTuple fields to RDF columns, let's consider an RNTuple
56 // using the following types and with a top-level field named "event" of type Event:
57 //
58 // struct Event {
59 // int id;
60 // std::vector<Track> tracks;
61 // };
62 // struct Track {
63 // std::vector<Hit> hits;
64 // };
65 // struct Hit {
66 // float x;
67 // float y;
68 // };
69 //
70 // AddField() will be called from the constructor with the RNTuple root field (ENTupleStructure::kRecord).
71 // From there, we recurse into the "event" sub field (also ENTupleStructure::kRecord) and further down the
72 // tree of sub fields and expose the following RDF columns:
73 //
74 // "event" [Event]
75 // "event.id" [int]
76 // "event.tracks" [RVec<Track>]
77 // "R_rdf_sizeof_event.tracks" [unsigned int]
78 // "event.tracks.hits" [RVec<RVec<Hit>>]
79 // "R_rdf_sizeof_event.tracks.hits" [RVec<unsigned int>]
80 // "event.tracks.hits.x" [RVec<RVec<float>>]
81 // "R_rdf_sizeof_event.tracks.hits.x" [RVec<unsigned int>]
82 // "event.tracks.hits.y" [RVec<RVec<float>>]
83 // "R_rdf_sizeof_event.tracks.hits.y" [RVec<unsigned int>]
84
85 std::uint16_t nFieldInfosAdded = 0;
86
87 const auto &nRepetitions = field.GetNRepetitions();
88 if ((field.GetStructure() == ROOT::ENTupleStructure::kCollection) || (nRepetitions > 0)) {
89 // The field is a collection or a fixed-size array.
90 // We open a new collection scope with fieldID being the inner most collection. E.g. for "event.tracks.hits",
91 // fieldInfos would already contain the fieldID of "event.tracks"
92 const std::string name = (procProvenance.Empty() ? "" : procProvenance.Get() + ".") + std::string(colName);
93 fieldInfos.emplace_back(field.GetOnDiskId(), field.GetFieldName(), field.GetTypeName(), nRepetitions,
94 *fProcessor->GetEntry().FindFieldIndex(name));
95 nFieldInfosAdded++;
96 }
97
99 // Inner fields of collections are provided as projected collections of only that inner field,
100 // E.g. we provide a projected collection RVec<RVec<float>> for "event.tracks.hits.x" in the example
101 // above.
102 bool representableAsRVec =
103 convertToRVec && (field.GetTypeName().substr(0, 19) == "ROOT::VecOps::RVec<" ||
104 field.GetTypeName().substr(0, 12) == "std::vector<" || field.GetTypeName() == "");
105 const auto *f = field.GetConstSubfields()[0];
106 AddField(*f, colName, procProvenance, fieldInfos, representableAsRVec);
107
108 // Note that at the end of the recursion, we handled the inner sub collections as well as the
109 // collection as whole, so we are done.
110 return;
111
112 } else if (nRepetitions > 0) {
113 // Fixed-size array, same logic as ROOT::RVec.
114 const auto *f = field.GetConstSubfields()[0];
115 AddField(*f, colName, procProvenance, fieldInfos);
116 return;
117 } else if (field.GetStructure() == ROOT::ENTupleStructure::kRecord) {
118 // Inner fields of records are provided as individual RDF columns, e.g. "event.id"
119 for (const auto &f : field.GetConstSubfields()) {
120 auto innerName = colName.empty() ? f->GetFieldName() : (std::string(colName) + "." + f->GetFieldName());
121 // Inner fields of collections of records are always exposed as ROOT::RVec
122 AddField(*f, innerName, procProvenance, fieldInfos);
123 }
124
125 // Do not add untyped record fields
126 if (field.GetTypeName() == "")
127 return;
128 }
129
130 // The fieldID could be the root field or the class of fieldId might not be loaded.
131 // In these cases, only the inner fields are exposed as RDF columns.
132 std::string fieldName = field.GetFieldName();
133 auto fieldInfoIt = fieldInfos.begin();
134 while (fieldName == "_0") {
135 assert(fieldInfoIt != fieldInfos.end());
136 fieldName = fieldInfoIt->fFieldName;
137 fieldInfoIt++;
138 }
139 auto fieldOrException = ROOT::RFieldBase::Create(fieldName, field.GetTypeName());
140 if (!fieldOrException)
141 return;
142 auto valueField = fieldOrException.Unwrap();
143 if (const auto cardinalityField = dynamic_cast<const ROOT::RCardinalityField *>(valueField.get())) {
144 // Cardinality fields in RDataFrame are presented as integers
145 if (cardinalityField->As32Bit()) {
146 valueField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint32_t>>(field.GetFieldName());
147 } else if (cardinalityField->As64Bit()) {
148 valueField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint64_t>>(field.GetFieldName());
149 } else {
150 R__ASSERT(false && "cardinality field stored with an unexpected integer type");
151 }
152 }
153
154 valueField->SetOnDiskId(field.GetOnDiskId());
155 auto valueSubfields = valueField->GetMutableSubfields();
156 const auto fieldSubfields = field.GetConstSubfields();
157 for (unsigned i = 0; i < valueSubfields.size(); ++i) {
158 valueSubfields[i]->SetOnDiskId(fieldSubfields[i]->GetOnDiskId());
159 }
160
161 std::unique_ptr<ROOT::RFieldBase> cardinalityField;
162 // Collections get the additional "number of" RDF column (e.g. "R_rdf_sizeof_tracks")
163 if (!fieldInfos.empty()) {
164 const auto &info = fieldInfos.back();
165 const std::string name =
166 (procProvenance.Empty() ? "R_rdf_sizeof_" : procProvenance.Get() + "_R_rdf_sizeof_") + info.fFieldName;
167 if (info.fNRepetitions > 0) {
168 cardinalityField = std::make_unique<ROOT::Internal::RDF::RArraySizeField>(name, info.fNRepetitions);
169 } else {
170 cardinalityField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::size_t>>(name);
171 }
172 cardinalityField->SetOnDiskId(info.fOnDiskId);
173 }
174
175 for (auto i = fieldInfos.rbegin(); i != fieldInfos.rend(); ++i) {
176 const auto &fieldInfo = *i;
177
178 const auto valueFieldName = valueField->GetFieldName();
179
180 if (fieldInfo.fNRepetitions > 0) {
181 // Fixed-size array, read it as ROOT::RVec in memory
182 valueField =
183 std::make_unique<ROOT::RArrayAsRVecField>(valueFieldName, valueField->Clone("_0"), fieldInfo.fNRepetitions);
184 } else {
185 // Actual collection. A std::vector or ROOT::RVec gets added as a ROOT::RVec. All other collection types keep
186 // their original type.
187 if (convertToRVec) {
188 valueField = std::make_unique<ROOT::RRVecField>(valueFieldName, valueField->Clone("_0"));
189 } else {
190 auto outerFieldType = fieldInfo.fTypeName;
191 valueField = ROOT::RFieldBase::Create(valueFieldName, outerFieldType).Unwrap();
192 }
193 }
194
195 valueField->SetOnDiskId(fieldInfo.fOnDiskId);
196
197 // Skip the inner-most collection level to construct the cardinality column
198 // It's taken care of by the `if (!fieldInfos.empty())` scope above
199 if (i != fieldInfos.rbegin()) {
200 const auto cardinalityFieldName = cardinalityField->GetFieldName();
201 if (fieldInfo.fNRepetitions > 0) {
202 // This collection level refers to a fixed-size array
203 cardinalityField = std::make_unique<ROOT::RArrayAsRVecField>(
204 cardinalityFieldName, cardinalityField->Clone("_0"), fieldInfo.fNRepetitions);
205 } else {
206 // This collection level refers to an RVec
207 cardinalityField = std::make_unique<ROOT::RRVecField>(cardinalityFieldName, cardinalityField->Clone("_0"));
208 }
209
210 cardinalityField->SetOnDiskId(fieldInfo.fOnDiskId);
211 }
212 }
213
214 std::string canonicalName = (procProvenance.Empty() ? "" : procProvenance.Get() + ".") + std::string(colName);
215 fColumnNames.emplace_back(canonicalName);
216 fColumnTypes.emplace_back(valueField->GetTypeName());
217
219 if (auto optFieldIdx = fProcessor->GetEntry().FindFieldIndex(canonicalName);
220 optFieldIdx && fProcessor->GetEntry().GetField(*optFieldIdx).GetTypeName() == field.GetTypeName()) {
221 fieldIdx = *optFieldIdx;
222 } else {
223 fieldIdx = fProcessor->AddFieldToEntry(std::move(valueField), canonicalName, nullptr,
225 }
226
227 if (cardinalityField) {
228 // FIXME(fdegeus): Make cardinality field name work properly with "#colname"
229 std::string cardinalityFieldName =
230 (procProvenance.Empty() ? "R_rdf_sizeof_" : procProvenance.Get() + ".R_rdf_sizeof_") + std::string(colName);
231 fColumnNames.emplace_back(cardinalityFieldName);
232 fColumnTypes.emplace_back(cardinalityField->GetTypeName());
233 auto cardinalityFieldIdx = fProcessor->AddFieldToEntry(std::move(cardinalityField), cardinalityFieldName, nullptr,
235 if (!fieldInfos.empty()) {
236 const auto &fieldInfo = fieldInfos.back();
237 fieldIdx = fieldInfo.fEntryFieldIdx;
238 }
239 fProcessor->GetEntry().SetFieldOriginIdx(cardinalityFieldIdx, fieldIdx);
240 }
241
242 for (std::uint16_t i = 0; i < nFieldInfosAdded; i++) {
243 fieldInfos.pop_back();
244 }
245}
246
247RNTupleProcessorDS::RNTupleProcessorDS(std::unique_ptr<ROOT::RNTupleProcessor> processor)
248 : fProcessor(std::move(processor))
249{
250 // Do not add the subfields now, this is handled by AddField.
251 fProcessor->AddAllFieldsToEntry(ROOT::Internal::RNTupleProcessorProvenance(), /*includeSubfields=*/false);
252 const auto &entry = fProcessor->GetEntry();
253 for (auto fieldIdx : entry.GetFieldIndices()) {
254 const auto &field = entry.GetValue(fieldIdx).GetField();
255 std::deque<RNTupleProcessorDS::RFieldInfo> fieldInfos{};
256 AddField(field, entry.GetQualifiedFieldName(fieldIdx), entry.GetFieldProvenance(fieldIdx), fieldInfos);
257 }
258}
259
261RNTupleProcessorDS::GetColumnReadersImpl(std::string_view /* name */, const std::type_info & /* ti */)
262{
263 // This datasource uses the newer GetColumnReaders() API
264 return {};
265}
266
267std::unique_ptr<ROOT::Detail::RDF::RColumnReaderBase>
268RNTupleProcessorDS::GetColumnReaders(unsigned int /* slot */, std::string_view name, const std::type_info &tid)
269{
270 // At this point we can assume that `name` will be found in fColumnNames
272
273 // First check if a field with the requested type already exists. If that is the case, we can immediately create a
274 // column reader for it.
275 if (fProcessor->GetEntry().FindFieldIndex(name, requestedType)) {
276 auto valuePtr = fProcessor->RequestField(std::string(name), requestedType);
277 auto reader = std::make_unique<Internal::RDF::RNTupleProcessorColumnReader>(valuePtr);
278 fColumnReaders.emplace_back(reader.get());
279
280 return reader;
281 }
282
283 // Secondly, check whether a field with the same name, but a different on-disk type exists. If this is not the case,
284 // first try to add the field. If the field cannot be added, throw an exception.
285 // Otherwise, we create a new field with the requested type and add it to the processor entry
286 // before creating a column reader for it.
287 auto fieldIdx = fProcessor->GetEntry().FindFieldIndex(name);
288 if (!fieldIdx) {
289 std::unique_ptr<Internal::RDF::RNTupleProcessorColumnReader> reader;
290 try {
291 auto valuePtr = fProcessor->RequestField(std::string(name), requestedType);
292 reader = std::make_unique<Internal::RDF::RNTupleProcessorColumnReader>(valuePtr);
293 fColumnReaders.emplace_back(reader.get());
294 } catch (const ROOT::RException &) {
295 throw std::runtime_error("RNTupleProcessorDS: Column \"" + std::string(name) + "\" does not exist");
296 }
297 return reader;
298 }
299
300 const auto &field = fProcessor->GetEntry().GetField(*fieldIdx);
301 const std::string strName = std::string(name);
302 std::unique_ptr<ROOT::RFieldBase> newField;
303 if (dynamic_cast<const ROOT::RCardinalityField *>(&field)) {
304 if (requestedType == "bool") {
305 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<bool>>(strName);
306 } else if (requestedType == "char") {
307 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<char>>(strName);
308 } else if (requestedType == "std::int8_t") {
309 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::int8_t>>(strName);
310 } else if (requestedType == "std::uint8_t") {
311 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint8_t>>(strName);
312 } else if (requestedType == "std::int16_t") {
313 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::int16_t>>(strName);
314 } else if (requestedType == "std::uint16_t") {
315 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint16_t>>(strName);
316 } else if (requestedType == "std::int32_t") {
317 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::int32_t>>(strName);
318 } else if (requestedType == "std::uint32_t") {
319 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint32_t>>(strName);
320 } else if (requestedType == "std::int64_t") {
321 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::int64_t>>(strName);
322 } else if (requestedType == "std::uint64_t") {
323 newField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint64_t>>(strName);
324 } else {
325 throw std::runtime_error("RNTupleProcessorDS: Could not create field with type \"" + requestedType +
326 "\" for column \"" + strName + "\"");
327 }
328 } else {
329 auto baseName = ROOT::Split(strName, ".").back();
330 auto newAltProtoFieldOrException = ROOT::RFieldBase::Create(baseName, requestedType);
331 if (!newAltProtoFieldOrException) {
332 throw std::runtime_error("RNTupleProcessorDS: Could not create field with type \"" + requestedType +
333 "\" for column \"" + strName + "\"");
334 }
335 newField = newAltProtoFieldOrException.Unwrap();
336 }
337 newField->SetOnDiskId(field.GetOnDiskId());
338
339 try {
340 fProcessor->AddFieldToEntry(std::move(newField), strName, nullptr, ROOT::Internal::RNTupleProcessorProvenance());
341 } catch (const ROOT::RException &) {
342 std::string msg = "RNTupleProcessorDS: invalid type \"" + requestedType + "\" for column \"" + strName +
343 "\" with on-disk type \"" + field.GetTypeName() + "\"";
344 throw std::runtime_error(msg);
345 }
346
347 auto valuePtr = fProcessor->RequestField(std::string(name), requestedType);
348 auto reader = std::make_unique<Internal::RDF::RNTupleProcessorColumnReader>(valuePtr);
349 fColumnReaders.emplace_back(reader.get());
350
351 return reader;
352}
353
354std::vector<std::pair<ULong64_t, ULong64_t>> RNTupleProcessorDS::GetEntryRanges()
355{
356 if (fCurrentRanges.empty()) {
357 fCurrentRanges.emplace_back(0, fProcessor->GetNEntries());
358 return fCurrentRanges;
359 }
360 return {};
361}
362
363void RNTupleProcessorDS::InitSlot(unsigned int /* slot */, ULong64_t /* firstEntry */)
364{
365 assert(fNSlots == 1);
366}
367
368void RNTupleProcessorDS::FinalizeSlot(unsigned int /* slot */)
369{
370 assert(fNSlots == 1);
371}
372
373std::string RNTupleProcessorDS::GetTypeName(std::string_view colName) const
374{
375 auto colNamePos = std::find(fColumnNames.begin(), fColumnNames.end(), colName);
376
377 if (colNamePos == fColumnNames.end()) {
378 auto msg = std::string("RNTupleProcessorDS: There is no column with name \"") + std::string(colName) + "\"";
379 throw std::runtime_error(msg);
380 }
381
382 const auto index = std::distance(fColumnNames.begin(), colNamePos);
383 return fColumnTypes[index];
384}
385
386bool RNTupleProcessorDS::HasColumn(std::string_view colName) const
387{
388 return std::find(fColumnNames.begin(), fColumnNames.end(), colName) != fColumnNames.end();
389}
390
392{
393 fCurrentRanges.clear();
394 fProcessor->Connect(fProcessor->GetEntry().GetFieldIndices(), ROOT::Internal::RNTupleProcessorProvenance(),
395 /*updateFields=*/false);
396}
397
399{
400 // noop
401}
402
403void RNTupleProcessorDS::SetNSlots(unsigned int nSlots)
404{
405 assert(fNSlots == 0);
406 // FIXME(fdegeus): Set to actual nSlots once MT support lands
407 if (nSlots > 1)
408 Warning("RNTupleProcessorDS", "MT is not yet supported. Using single-threaded processing instead.");
409 fNSlots = 1;
410}
411
412bool RNTupleProcessorDS::SetEntry(unsigned int /* slot */, ULong64_t entry)
413{
414 fProcessor->SetEntryMapping(entry, fEntryMapping);
416 return false;
417
418 fProcessor->LoadEntry(fEntryMapping);
419
420 for (auto colReader : fColumnReaders) {
421 colReader->SetEntryLoaded(entry);
422 }
423
424 return true;
425}
426
428 unsigned int /* slot */, const std::unordered_map<std::string, ROOT::RDF::Experimental::RSample *> &sampleMap) const
429{
430 const auto &ntupleID = fProcessor->GetOptions().GetProcessorName();
431
432 // TODO: There is no support for RNTuple in RDatasetSpec, thus the sample map
433 // is always empty at the moment.
434 if (sampleMap.empty())
435 return ROOT::RDF::RSampleInfo(ntupleID, std::make_pair(0, fProcessor->GetNEntries()));
436
437 if (sampleMap.find(ntupleID) == sampleMap.end())
438 throw std::runtime_error("Full sample identifier '" + ntupleID + "' cannot be found in the available samples.");
439
440 return ROOT::RDF::RSampleInfo(ntupleID, std::make_pair(0, fProcessor->GetNEntries()), sampleMap.at(ntupleID));
441}
442} // namespace ROOT::Experimental::Internal::RDF
443
444ROOT::RDataFrame ROOT::Experimental::RDF::FromRNTupleProcessor(std::unique_ptr<ROOT::RNTupleProcessor> processor)
445{
446 return ROOT::RDataFrame(
447 std::make_unique<ROOT::Experimental::Internal::RDF::RNTupleProcessorDS>(std::move(processor)));
448}
#define f(i)
Definition RSha256.hxx:104
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:85
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:139
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:252
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
char name[80]
Definition TGX11.cxx:142
Every RDF column is represented by exactly one RNTuple field.
RNTupleProcessorValuePtr< void > fValuePtr
Container for the value of the column.
RNTupleProcessorColumnReader(RNTupleProcessorValuePtr< void > &valuePtr)
std::string GetTypeName(std::string_view colName) const final
Type of a column as a string, e.g.
void Finalize() final
Convenience method called after concluding an event-loop.
bool HasColumn(std::string_view colName) const final
Checks if the dataset has a certain column.
std::vector< std::pair< ULong64_t, ULong64_t > > GetEntryRanges() final
Return ranges of entries to distribute to tasks.
void FinalizeSlot(unsigned int slot) final
Convenience method called at the end of the data processing associated to a slot.
Record_t GetColumnReadersImpl(std::string_view name, const std::type_info &) final
type-erased vector of pointers to pointers to column values - one per slot
RNTupleProcessorDS(std::unique_ptr< ROOT::RNTupleProcessor > processor)
void Initialize() final
Convenience method called before starting an event-loop.
std::vector< ROOT::Experimental::Internal::RDF::RNTupleProcessorColumnReader * > fColumnReaders
std::unique_ptr< ROOT::Detail::RDF::RColumnReaderBase > GetColumnReaders(unsigned int slot, std::string_view name, const std::type_info &) final
If the other GetColumnReaders overload returns an empty vector, this overload will be called instead.
std::vector< std::pair< ULong64_t, ULong64_t > > fCurrentRanges
void InitSlot(unsigned int slot, ULong64_t firstEntry) final
Convenience method called at the start of the data processing associated to a slot.
void AddField(const ROOT::RFieldBase &field, std::string_view colName, ROOT::Internal::RNTupleProcessorProvenance procProvenance, std::deque< RFieldInfo > &fieldInfos, bool convertToRVec=true)
Provides the RDF column "colName" given the field.
bool SetEntry(unsigned int, ULong64_t) final
Advance the "cursors" returned by GetColumnReaders to the selected entry for a particular slot.
void SetNSlots(unsigned int nSlots) final
Inform RDataSource of the number of processing slots (i.e.
std::string Get() const
Get the full processor provenance, in the form of "x.y.z".
An artificial field that transforms an RNTuple column that contains the offset of collections into co...
Definition RField.hxx:369
friend ROOT::RDF::RSampleInfo ROOT::Internal::RDF::CreateSampleInfo(const ROOT::RDF::RDataSource &, unsigned int, const std::unordered_map< std::string, ROOT::RDF::Experimental::RSample * > &)
std::vector< void * > Record_t
This type represents a sample identifier, to be used in conjunction with RDataFrame features such as ...
ROOT's RDataFrame offers a modern, high-level interface for analysis of data stored in TTree ,...
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
A field translates read and write calls from/to underlying columns to/from tree values.
ROOT::ENTupleStructure GetStructure() const
std::vector< const RFieldBase * > GetConstSubfields() const
const std::string & GetFieldName() const
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.
std::size_t GetNRepetitions() const
const std::string & GetTypeName() const
ROOT::DescriptorId_t GetOnDiskId() const
std::shared_ptr< void > GetPtr() const
Get the pointer to the field value managed by the processor's entry.
ROOT::NTupleSize_t GetEntryNumber() const
RDataFrame FromRNTupleProcessor(std::unique_ptr< ROOT::RNTupleProcessor > processor)
std::string TypeID2TypeName(const std::type_info &id)
Returns the name of a type starting from its type_info An empty string is returned in case of failure...
Definition RDFUtils.cxx:212
std::string GetRenormalizedTypeName(const std::string &metaNormalizedName)
Given a type name normalized by ROOT meta, renormalize it for RNTuple. E.g., insert std::prefix.
constexpr NTupleSize_t kInvalidNTupleIndex
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.