Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleProcessor.cxx
Go to the documentation of this file.
1/// \file RNTupleProcessor.cxx
2/// \ingroup NTuple
3/// \author Florine de Geus <florine.de.geus@cern.ch>
4/// \date 2024-03-26
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
17
18#include <ROOT/RFieldBase.hxx>
19#include <ROOT/RNTuple.hxx>
21#include <ROOT/StringUtils.hxx>
22
23#include <TDirectory.h>
24
25#include <iomanip>
26
27std::unique_ptr<ROOT::Internal::RPageSource> ROOT::Experimental::RNTupleOpenSpec::CreatePageSource() const
28{
29 if (const std::string *storagePath = std::get_if<std::string>(&fStorage))
31
32 auto dir = std::get<TDirectory *>(fStorage);
33 auto ntuple = std::unique_ptr<ROOT::RNTuple>(dir->Get<ROOT::RNTuple>(fNTupleName.c_str()));
35}
36
37std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
38ROOT::Experimental::RNTupleProcessor::Create(RNTupleOpenSpec ntuple, std::unique_ptr<ROOT::RNTupleModel> model,
39 std::string_view processorName)
40{
41 return std::unique_ptr<RNTupleSingleProcessor>(
42 new RNTupleSingleProcessor(std::move(ntuple), std::move(model), processorName));
43}
44
45std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
47 std::unique_ptr<ROOT::RNTupleModel> model,
48 std::string_view processorName)
49{
50 if (ntuples.empty())
51 throw RException(R__FAIL("at least one RNTuple must be provided"));
52
53 std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors;
54 innerProcessors.reserve(ntuples.size());
55
56 // If no model is provided, infer it from the first ntuple.
57 if (!model) {
58 auto firstPageSource = ntuples[0].CreatePageSource();
59 firstPageSource->Attach();
60 model = firstPageSource->GetSharedDescriptorGuard()->CreateModel();
61 }
62
63 for (auto &ntuple : ntuples) {
64 innerProcessors.emplace_back(Create(std::move(ntuple), model->Clone()));
65 }
66
67 return CreateChain(std::move(innerProcessors), std::move(model), processorName);
68}
69
70std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
71ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors,
72 std::unique_ptr<ROOT::RNTupleModel> model,
73 std::string_view processorName)
74{
75 if (innerProcessors.empty())
76 throw RException(R__FAIL("at least one inner processor must be provided"));
77
78 // If no model is provided, infer it from the first inner processor.
79 if (!model) {
80 model = innerProcessors[0]->GetModel().Clone();
81 }
82
83 return std::unique_ptr<RNTupleChainProcessor>(
84 new RNTupleChainProcessor(std::move(innerProcessors), std::move(model), processorName));
85}
86
87std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
89 const std::vector<std::string> &joinFields,
90 std::unique_ptr<ROOT::RNTupleModel> primaryModel,
91 std::unique_ptr<ROOT::RNTupleModel> auxModel,
92 std::string_view processorName)
93{
94 if (joinFields.size() > 4) {
95 throw RException(R__FAIL("a maximum of four join fields is allowed"));
96 }
97
98 if (std::unordered_set(joinFields.begin(), joinFields.end()).size() < joinFields.size()) {
99 throw RException(R__FAIL("join fields must be unique"));
100 }
101
102 std::unique_ptr<RNTupleProcessor> primaryProcessor;
103 if (primaryModel)
105 else
106 primaryProcessor = Create(primaryNTuple, nullptr, processorName);
107
108 std::unique_ptr<RNTupleProcessor> auxProcessor;
109 if (auxModel)
110 auxProcessor = Create(auxNTuple, auxModel->Clone());
111 else
112 auxProcessor = Create(auxNTuple);
113
114 return CreateJoin(std::move(primaryProcessor), std::move(auxProcessor), joinFields, std::move(primaryModel),
115 std::move(auxModel), processorName);
116}
117
118std::unique_ptr<ROOT::Experimental::RNTupleProcessor> ROOT::Experimental::RNTupleProcessor::CreateJoin(
119 std::unique_ptr<RNTupleProcessor> primaryProcessor, std::unique_ptr<RNTupleProcessor> auxProcessor,
120 const std::vector<std::string> &joinFields, std::unique_ptr<ROOT::RNTupleModel> primaryModel,
121 std::unique_ptr<ROOT::RNTupleModel> auxModel, std::string_view processorName)
122{
123 if (joinFields.size() > 4) {
124 throw RException(R__FAIL("a maximum of four join fields is allowed"));
125 }
126
127 if (std::unordered_set(joinFields.begin(), joinFields.end()).size() < joinFields.size()) {
128 throw RException(R__FAIL("join fields must be unique"));
129 }
130
131 return std::unique_ptr<RNTupleJoinProcessor>(
133 std::move(primaryModel), std::move(auxModel), processorName));
134}
135
136//------------------------------------------------------------------------------
137
139 std::unique_ptr<ROOT::RNTupleModel> model,
140 std::string_view processorName)
141 : RNTupleProcessor(processorName, std::move(model)), fNTupleSpec(std::move(ntuple))
142{
143 if (!fModel) {
145 fPageSource->Attach();
146 fModel = fPageSource->GetSharedDescriptorGuard()->CreateModel();
147 }
148
149 if (fProcessorName.empty()) {
151 }
152
153 fModel->Freeze();
154 fEntry = fModel->CreateEntry();
155
156 for (const auto &value : *fEntry) {
157 auto &field = value.GetField();
158 auto token = fEntry->GetToken(field.GetFieldName());
159
160 // If the model has a default entry, use the value pointers from the entry in the entry managed by the
161 // processor. This way, the pointers returned by RNTupleModel::MakeField can be used in the processor loop
162 // to access the corresponding field values.
163 if (!fModel->IsBare()) {
164 auto valuePtr = fModel->GetDefaultEntry().GetPtr<void>(token);
165 fEntry->BindValue(token, valuePtr);
166 }
167 }
168}
169
171{
172 Connect();
173
174 if (entryNumber >= fNEntries)
175 return kInvalidNTupleIndex;
176
177 fEntry->Read(entryNumber);
178
179 fNEntriesProcessed++;
180 fCurrentEntryNumber = entryNumber;
181 return entryNumber;
182}
183
185 std::string_view fieldNamePrefix)
186{
187 for (const auto &value : *fEntry) {
188 std::string fieldName = value.GetField().GetQualifiedFieldName();
189 auto valuePtr = fieldNamePrefix.empty() ? entry.GetPtr<void>(fieldName)
190 : entry.GetPtr<void>(std::string(fieldNamePrefix) + "." + fieldName);
191
192 fEntry->BindValue(fieldName, valuePtr);
193 }
194}
195
197{
198 // The processor has already been connected.
199 if (fNEntries != kInvalidNTupleIndex)
200 return;
201
202 if (!fPageSource)
203 fPageSource = fNTupleSpec.CreatePageSource();
204 fPageSource->Attach();
205 fNEntries = fPageSource->GetNEntries();
206
207 auto desc = fPageSource->GetSharedDescriptorGuard();
209 auto fieldZeroId = desc->GetFieldZeroId();
210 fieldZero.SetOnDiskId(fieldZeroId);
212
213 for (auto &field : fieldZero.GetMutableSubfields()) {
214 auto onDiskId = desc->FindFieldId(field->GetQualifiedFieldName(), fieldZeroId);
215 // The field we are trying to connect is not present in the ntuple
217 throw RException(R__FAIL("field \"" + field->GetQualifiedFieldName() + "\" not found in the current RNTuple"));
218 }
219
220 // The field will already have an on-disk ID when the model was inferred from the page source because the user
221 // didn't provide a model themselves.
222 if (field->GetOnDiskId() == kInvalidDescriptorId)
223 field->SetOnDiskId(onDiskId);
224
226 }
228}
229
236
238{
239 static constexpr int width = 32;
240
241 std::string ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 4);
242 if (ntupleNameTrunc.size() < fNTupleSpec.fNTupleName.size())
243 ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 6) + "..";
244
245 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
246 output << std::setfill(' ') << "| " << ntupleNameTrunc << std::setw(width - 2 - ntupleNameTrunc.size()) << " |\n";
247
248 if (const std::string *storage = std::get_if<std::string>(&fNTupleSpec.fStorage)) {
249 std::string storageTrunc = storage->substr(0, width - 5);
250 if (storageTrunc.size() < storage->size())
251 storageTrunc = storage->substr(0, width - 8) + "...";
252
253 output << std::setfill(' ') << "| " << storageTrunc << std::setw(width - 2 - storageTrunc.size()) << " |\n";
254 } else {
255 output << "| " << std::setw(width - 2) << " |\n";
256 }
257
258 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
259}
260
261//------------------------------------------------------------------------------
262
264 std::vector<std::unique_ptr<RNTupleProcessor>> processors, std::unique_ptr<ROOT::RNTupleModel> model,
265 std::string_view processorName)
266 : RNTupleProcessor(processorName, std::move(model)), fInnerProcessors(std::move(processors))
267{
268 if (fProcessorName.empty()) {
269 // `CreateChain` ensures there is at least one inner processor.
270 fProcessorName = fInnerProcessors[0]->GetProcessorName();
271 }
272
274
275 fModel->Freeze();
276 fEntry = fModel->CreateEntry();
277
278 for (const auto &value : *fEntry) {
279 auto &field = value.GetField();
280 auto token = fEntry->GetToken(field.GetQualifiedFieldName());
281
282 // If the model has a default entry, use the value pointers from the entry in the entry managed by the
283 // processor. This way, the pointers returned by RNTupleModel::MakeField can be used in the processor loop
284 // to access the corresponding field values.
285 if (!fModel->IsBare()) {
286 auto valuePtr = fModel->GetDefaultEntry().GetPtr<void>(token);
287 fEntry->BindValue(token, valuePtr);
288 }
289 }
290
291 for (auto &innerProc : fInnerProcessors) {
292 innerProc->SetEntryPointers(*fEntry);
293 }
294}
295
297{
298 if (fNEntries == kInvalidNTupleIndex) {
299 fNEntries = 0;
300
301 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
302 if (fInnerNEntries[i] == kInvalidNTupleIndex) {
303 fInnerNEntries[i] = fInnerProcessors[i]->GetNEntries();
304 }
305
306 fNEntries += fInnerNEntries[i];
307 }
308 }
309
310 return fNEntries;
311}
312
314 std::string_view fieldNamePrefix)
315{
316 for (const auto &value : *fEntry) {
317 std::string fieldName = value.GetField().GetQualifiedFieldName();
318 auto valuePtr = fieldNamePrefix.empty() ? entry.GetPtr<void>(fieldName)
319 : entry.GetPtr<void>(std::string(fieldNamePrefix) + "." + fieldName);
320
321 fEntry->BindValue(fieldName, valuePtr);
322 }
323
324 for (auto &innerProc : fInnerProcessors) {
325 innerProc->SetEntryPointers(entry, fieldNamePrefix);
326 }
327}
328
330{
332 size_t currProcessor = 0;
333
334 // As long as the entry fails to load from the current processor, we decrement the local entry number with the number
335 // of entries in this processor and try with the next processor until we find the correct local entry number.
336 while (fInnerProcessors[currProcessor]->LoadEntry(localEntryNumber) == kInvalidNTupleIndex) {
337 if (fInnerNEntries[currProcessor] == kInvalidNTupleIndex) {
338 fInnerNEntries[currProcessor] = fInnerProcessors[currProcessor]->GetNEntries();
339 }
340
341 localEntryNumber -= fInnerNEntries[currProcessor];
342
343 // The provided global entry number is larger than the number of available entries.
344 if (++currProcessor >= fInnerProcessors.size())
345 return kInvalidNTupleIndex;
346 }
347
348 if (currProcessor != fCurrentProcessorNumber)
349 fCurrentProcessorNumber = currProcessor;
350
351 fNEntriesProcessed++;
352 fCurrentEntryNumber = entryNumber;
353 return entryNumber;
354}
355
358{
359 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
360 const auto &innerProc = fInnerProcessors[i];
361 innerProc->AddEntriesToJoinTable(joinTable, entryOffset);
362 entryOffset += innerProc->GetNEntries();
363 }
364}
365
367{
368 for (const auto &innerProc : fInnerProcessors) {
369 innerProc->PrintStructure(output);
370 }
371}
372
373//------------------------------------------------------------------------------
374
377private:
380 {
381 throw RException(R__FAIL("RAuxiliaryProcessorField fields must only be used for reading"));
382 }
383
384public:
385 RAuxiliaryProcessorField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
386 : ROOT::RRecordField(fieldName, "RAuxiliaryProcessorField")
387 {
388 fOffsets.reserve(itemFields.size());
389 for (auto &item : itemFields) {
390 fOffsets.push_back(GetItemPadding(fSize, item->GetAlignment()));
391 }
392 AttachItemFields(std::move(itemFields));
393 }
394};
395} // namespace ROOT::Experimental::Internal
396
398 std::unique_ptr<RNTupleProcessor> auxProcessor,
399 const std::vector<std::string> &joinFields,
400 std::unique_ptr<ROOT::RNTupleModel> primaryModel,
401 std::unique_ptr<ROOT::RNTupleModel> auxModel,
402 std::string_view processorName)
404 fPrimaryProcessor(std::move(primaryProcessor)),
405 fAuxiliaryProcessor(std::move(auxProcessor))
406{
407 if (fProcessorName.empty()) {
408 fProcessorName = fPrimaryProcessor->GetProcessorName();
409 }
410
411 if (!primaryModel)
412 primaryModel = fPrimaryProcessor->GetModel().Clone();
413 if (!auxModel) {
414 auxModel = fAuxiliaryProcessor->GetModel().Clone();
415 }
416
417 // If the primaryProcessor has a field with the name of the auxProcessor (either as a "proper" field or because the
418 // primary processor itself is a join where its auxProcessor bears the same name as the current auxProcessor), there
419 // will be name conflicts, so error out.
420 if (primaryModel->GetFieldNames().find(fAuxiliaryProcessor->GetProcessorName()) !=
421 primaryModel->GetFieldNames().end()) {
422 throw RException(R__FAIL("a field or nested auxiliary processor named \"" +
423 fAuxiliaryProcessor->GetProcessorName() +
424 "\" is already present in the model of the primary processor; rename the auxiliary "
425 "processor to avoid conflicts"));
426 }
427
428 SetModel(std::move(primaryModel), std::move(auxModel));
429
430 fModel->Freeze();
431 fEntry = fModel->CreateEntry();
432
433 for (const auto &value : *fEntry) {
434 auto &field = value.GetField();
435 const auto &fieldName = field.GetQualifiedFieldName();
436
437 // If the model provided by the user has a default entry, use the value pointers from the default entry of the
438 // model that was passed to this constructor. This way, the pointers returned by RNTupleModel::MakeField can be
439 // used in the processor loop to access the corresponding field values.
440 if (!fModel->IsBare()) {
441 auto valuePtr = fModel->GetDefaultEntry().GetPtr<void>(fieldName);
442 fEntry->BindValue(fieldName, valuePtr);
443 }
444 }
445
446 fPrimaryProcessor->SetEntryPointers(*fEntry);
447 // FIXME(fdegeus): for nested auxiliary processors, simply passing the processor name is not sufficient because we
448 // also need the name(s) of the *inner* processor(s) (e.g., "ntuple0.ntuple1"). This means either (1) recursively
449 // infer this full name or (2) rethink the way fields in auxiliary processors together with how entries are
450 // currently set altogether.
451 fAuxiliaryProcessor->SetEntryPointers(*fEntry, fAuxiliaryProcessor->GetProcessorName());
452
453 if (!joinFields.empty()) {
454 for (const auto &joinField : joinFields) {
455 auto token = fEntry->GetToken(joinField);
456 fJoinFieldTokens.emplace_back(token);
457 }
458
460 }
461}
462
464 std::unique_ptr<RNTupleModel> auxModel)
465{
466 fModel = std::move(primaryModel);
467 fModel->Unfreeze();
468
469 // Create an anonymous record field for the auxiliary processor, containing its top-level fields. These original
470 // top-level fields are registered as subfields in the join model, such that they can be accessed as
471 // `auxNTupleName.fieldName`.
472 std::vector<std::unique_ptr<ROOT::RFieldBase>> auxFields;
473 auxFields.reserve(auxModel->GetFieldNames().size());
474
475 for (const auto &fieldName : auxModel->GetFieldNames()) {
476 auxFields.emplace_back(auxModel->GetConstField(fieldName).Clone(fieldName));
477 }
478
479 auto auxParentField = std::make_unique<Internal::RAuxiliaryProcessorField>(fAuxiliaryProcessor->GetProcessorName(),
480 std::move(auxFields));
481 const auto &subFields = auxParentField->GetConstSubfields();
482 fModel->AddField(std::move(auxParentField));
483
484 for (const auto &field : subFields) {
485 fModel->RegisterSubfield(field->GetQualifiedFieldName());
486
487 if (field->GetTypeName() == "RAuxiliaryProcessorField") {
488 for (const auto &auxSubField : field->GetConstSubfields()) {
489 fModel->RegisterSubfield(auxSubField->GetQualifiedFieldName());
490 }
491 }
492 }
493
494 // If the model has a default entry, adopt its value pointers. This way, the pointers returned by
495 // RNTupleModel::MakeField can be used in the processor loop to access the corresponding field values.
496 if (!fModel->IsBare() && !auxModel->IsBare()) {
497 const auto &auxDefaultEntry = auxModel->GetDefaultEntry();
498 auto &joinDefaultEntry = fModel->GetDefaultEntry();
499 for (const auto &fieldName : auxModel->GetFieldNames()) {
500 auto valuePtr = auxDefaultEntry.GetPtr<void>(fieldName);
501 joinDefaultEntry.BindValue(fAuxiliaryProcessor->GetProcessorName() + "." + fieldName, valuePtr);
502 }
503 }
504
505 fModel->Freeze();
506}
507
509 std::string_view fieldNamePrefix)
510{
511 for (const auto &value : *fEntry) {
512 std::string fieldName = value.GetField().GetQualifiedFieldName();
513 auto valuePtr = fieldNamePrefix.empty() ? entry.GetPtr<void>(fieldName)
514 : entry.GetPtr<void>(std::string(fieldNamePrefix) + "." + fieldName);
515
516 fEntry->BindValue(fieldName, valuePtr);
517 }
518
519 fPrimaryProcessor->SetEntryPointers(*fEntry);
520 fAuxiliaryProcessor->SetEntryPointers(*fEntry, fAuxiliaryProcessor->GetProcessorName());
521}
522
524{
525 if (fPrimaryProcessor->LoadEntry(entryNumber) == kInvalidNTupleIndex)
526 return kInvalidNTupleIndex;
527
528 fCurrentEntryNumber = entryNumber;
529 fNEntriesProcessed++;
530
531 if (!fJoinTable) {
532 if (fAuxiliaryProcessor->LoadEntry(entryNumber) == kInvalidNTupleIndex) {
533 throw RException(R__FAIL("entry " + std::to_string(entryNumber) +
534 " in the primary processor has no corresponding entry in auxiliary processor \"" +
535 fAuxiliaryProcessor->GetProcessorName() + "\""));
536 }
537
538 return entryNumber;
539 }
540
541 if (!fJoinTableIsBuilt) {
542 fAuxiliaryProcessor->AddEntriesToJoinTable(*fJoinTable);
543 fJoinTableIsBuilt = true;
544 }
545
546 // Collect the values of the join fields for this entry.
547 std::vector<void *> valPtrs;
548 valPtrs.reserve(fJoinFieldTokens.size());
549 for (const auto &token : fJoinFieldTokens) {
550 auto ptr = fEntry->GetPtr<void>(token);
551 valPtrs.push_back(ptr.get());
552 }
553
554 // Find the entry index corresponding to the join field values for each auxiliary processor and load the
555 // corresponding entry.
556 const auto entryIdx = fJoinTable->GetEntryIndex(valPtrs);
557
559 throw RException(R__FAIL("entry " + std::to_string(entryNumber) +
560 " in the primary processor has no corresponding entry in auxiliary processor \"" +
561 fAuxiliaryProcessor->GetProcessorName() + "\""));
562
563 fAuxiliaryProcessor->LoadEntry(entryIdx);
564
565 return entryNumber;
566}
567
569{
570 if (fNEntries == kInvalidNTupleIndex)
571 fNEntries = fPrimaryProcessor->GetNEntries();
572 return fNEntries;
573}
574
580
582{
583 std::ostringstream primaryStructureStr;
584 fPrimaryProcessor->PrintStructure(primaryStructureStr);
585 const auto primaryStructure = ROOT::Split(primaryStructureStr.str(), "\n", /*skipEmpty=*/true);
586 const auto primaryStructureWidth = primaryStructure.front().size();
587
588 std::ostringstream auxStructureStr;
589 fAuxiliaryProcessor->PrintStructure(auxStructureStr);
590 const auto auxStructure = ROOT::Split(auxStructureStr.str(), "\n", /*skipEmpty=*/true);
591
592 const auto maxLength = std::max(primaryStructure.size(), auxStructure.size());
593 for (unsigned i = 0; i < maxLength; i++) {
594 if (i < primaryStructure.size())
596 else
597 output << std::setw(primaryStructureWidth) << "";
598
599 if (i < auxStructure.size())
600 output << " " << auxStructure[i];
601
602 output << "\n";
603 }
604}
#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:300
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t width
RAuxiliaryProcessorField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields)
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
Builds a join table on one or several fields of an RNTuple so it can be joined onto other RNTuples.
static std::unique_ptr< RNTupleJoinTable > Create(const std::vector< std::string > &joinFieldNames)
Create an RNTupleJoinTable from an existing RNTuple.
static constexpr PartitionKey_t kDefaultPartitionKey
Processor specialization for vertically combined (chained) RNTupleProcessors.
void SetEntryPointers(const ROOT::REntry &, std::string_view fieldNamePrefix) final
void PrintStructureImpl(std::ostream &output) const final
Processor-specific implementation for printing its structure, called by PrintStructure().
void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset=0) final
Add the entry mappings for this processor to the provided join table.
ROOT::NTupleSize_t GetNEntries() final
Get the total number of entries in this processor.
std::vector< ROOT::NTupleSize_t > fInnerNEntries
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided (global) entry number (i.e., considering all RNTuples in th...
std::vector< std::unique_ptr< RNTupleProcessor > > fInnerProcessors
Processor specialization for horizontally combined (joined) RNTupleProcessors.
void SetModel(std::unique_ptr< ROOT::RNTupleModel > primaryModel, std::unique_ptr< ROOT::RNTupleModel > auxModel)
Set fModel by combining the primary and auxiliary models.
void SetEntryPointers(const ROOT::REntry &, std::string_view fieldNamePrefix) final
void PrintStructureImpl(std::ostream &output) const final
Processor-specific implementation for printing its structure, called by PrintStructure().
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided entry number of the primary processor.
void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset=0) final
Add the entry mappings for this processor to the provided join table.
ROOT::NTupleSize_t GetNEntries() final
Get the total number of entries in this processor.
std::unique_ptr< RNTupleProcessor > fPrimaryProcessor
std::unique_ptr< Internal::RNTupleJoinTable > fJoinTable
std::unique_ptr< RNTupleProcessor > fAuxiliaryProcessor
std::vector< ROOT::RFieldToken > fJoinFieldTokens
Tokens representing the join fields present in the primary processor.
Specification of the name and location of an RNTuple, used for creating a new RNTupleProcessor.
std::variant< std::string, TDirectory * > fStorage
std::unique_ptr< ROOT::Internal::RPageSource > CreatePageSource() const
Interface for iterating over entries of RNTuples and vertically concatenated RNTuples (chains).
static std::unique_ptr< RNTupleProcessor > CreateJoin(RNTupleOpenSpec primaryNTuple, RNTupleOpenSpec auxNTuple, const std::vector< std::string > &joinFields, std::unique_ptr< ROOT::RNTupleModel > primaryModel=nullptr, std::unique_ptr< ROOT::RNTupleModel > auxModel=nullptr, std::string_view processorName="")
Create an RNTupleProcessor for a join (i.e., a horizontal combination) of RNTuples.
std::unique_ptr< ROOT::REntry > fEntry
std::unique_ptr< ROOT::RNTupleModel > fModel
static std::unique_ptr< RNTupleProcessor > CreateChain(std::vector< RNTupleOpenSpec > ntuples, std::unique_ptr< ROOT::RNTupleModel > model=nullptr, std::string_view processorName="")
Create an RNTupleProcessor for a chain (i.e., a vertical combination) of RNTuples.
static std::unique_ptr< RNTupleProcessor > Create(RNTupleOpenSpec ntuple, std::unique_ptr< ROOT::RNTupleModel > model=nullptr, std::string_view processorName="")
Create an RNTupleProcessor for a single RNTuple.
Processor specialization for processing a single RNTuple.
void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset=0) final
Add the entry mappings for this processor to the provided join table.
void SetEntryPointers(const ROOT::REntry &entry, std::string_view fieldNamePrefix) final
void PrintStructureImpl(std::ostream &output) const final
Processor-specific implementation for printing its structure, called by PrintStructure().
std::unique_ptr< ROOT::Internal::RPageSource > fPageSource
void Connect()
Connect the page source of the underlying RNTuple.
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided (global) entry number (i.e., considering all RNTuples in th...
static std::unique_ptr< RPageSourceFile > CreateFromAnchor(const RNTuple &anchor, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Used from the RNTuple class to build a datasource if the anchor is already available.
static std::unique_ptr< RPageSource > Create(std::string_view ntupleName, std::string_view location, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Guess the concrete derived page source from the file name (location)
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:54
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
virtual void GenerateColumns()
Implementations in derived classes should create the backing columns corresponding to the field type ...
Representation of an RNTuple data set in a ROOT file.
Definition RNTuple.hxx:67
const_iterator begin() const
const_iterator end() const
The field for an untyped record.
void AttachItemFields(std::vector< std::unique_ptr< RFieldBase > > itemFields)
Definition RField.cxx:566
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:622
std::vector< std::size_t > fOffsets
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:34
ROOT::RFieldZero & GetFieldZeroOfModel(RNTupleModel &model)
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
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.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
constexpr DescriptorId_t kInvalidDescriptorId
static void output()