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);
211
212 for (auto &field : fieldZero.GetMutableSubfields()) {
213 auto onDiskId = desc->FindFieldId(field->GetQualifiedFieldName(), fieldZeroId);
214 // The field we are trying to connect is not present in the ntuple
216 throw RException(R__FAIL("field \"" + field->GetQualifiedFieldName() + "\" not found in the current RNTuple"));
217 }
218
219 // The field will already have an on-disk ID when the model was inferred from the page source because the user
220 // didn't provide a model themselves.
221 if (field->GetOnDiskId() == kInvalidDescriptorId)
222 field->SetOnDiskId(onDiskId);
223
225 }
226}
227
234
236{
237 static constexpr int width = 32;
238
239 std::string ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 4);
240 if (ntupleNameTrunc.size() < fNTupleSpec.fNTupleName.size())
241 ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 6) + "..";
242
243 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
244 output << std::setfill(' ') << "| " << ntupleNameTrunc << std::setw(width - 2 - ntupleNameTrunc.size()) << " |\n";
245
246 if (const std::string *storage = std::get_if<std::string>(&fNTupleSpec.fStorage)) {
247 std::string storageTrunc = storage->substr(0, width - 5);
248 if (storageTrunc.size() < storage->size())
249 storageTrunc = storage->substr(0, width - 8) + "...";
250
251 output << std::setfill(' ') << "| " << storageTrunc << std::setw(width - 2 - storageTrunc.size()) << " |\n";
252 } else {
253 output << "| " << std::setw(width - 2) << " |\n";
254 }
255
256 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
257}
258
259//------------------------------------------------------------------------------
260
262 std::vector<std::unique_ptr<RNTupleProcessor>> processors, std::unique_ptr<ROOT::RNTupleModel> model,
263 std::string_view processorName)
264 : RNTupleProcessor(processorName, std::move(model)), fInnerProcessors(std::move(processors))
265{
266 if (fProcessorName.empty()) {
267 // `CreateChain` ensures there is at least one inner processor.
268 fProcessorName = fInnerProcessors[0]->GetProcessorName();
269 }
270
272
273 fModel->Freeze();
274 fEntry = fModel->CreateEntry();
275
276 for (const auto &value : *fEntry) {
277 auto &field = value.GetField();
278 auto token = fEntry->GetToken(field.GetQualifiedFieldName());
279
280 // If the model has a default entry, use the value pointers from the entry in the entry managed by the
281 // processor. This way, the pointers returned by RNTupleModel::MakeField can be used in the processor loop
282 // to access the corresponding field values.
283 if (!fModel->IsBare()) {
284 auto valuePtr = fModel->GetDefaultEntry().GetPtr<void>(token);
285 fEntry->BindValue(token, valuePtr);
286 }
287 }
288
289 for (auto &innerProc : fInnerProcessors) {
290 innerProc->SetEntryPointers(*fEntry);
291 }
292}
293
295{
296 if (fNEntries == kInvalidNTupleIndex) {
297 fNEntries = 0;
298
299 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
300 if (fInnerNEntries[i] == kInvalidNTupleIndex) {
301 fInnerNEntries[i] = fInnerProcessors[i]->GetNEntries();
302 }
303
304 fNEntries += fInnerNEntries[i];
305 }
306 }
307
308 return fNEntries;
309}
310
312 std::string_view fieldNamePrefix)
313{
314 for (const auto &value : *fEntry) {
315 std::string fieldName = value.GetField().GetQualifiedFieldName();
316 auto valuePtr = fieldNamePrefix.empty() ? entry.GetPtr<void>(fieldName)
317 : entry.GetPtr<void>(std::string(fieldNamePrefix) + "." + fieldName);
318
319 fEntry->BindValue(fieldName, valuePtr);
320 }
321
322 for (auto &innerProc : fInnerProcessors) {
323 innerProc->SetEntryPointers(entry, fieldNamePrefix);
324 }
325}
326
328{
330 size_t currProcessor = 0;
331
332 // As long as the entry fails to load from the current processor, we decrement the local entry number with the number
333 // of entries in this processor and try with the next processor until we find the correct local entry number.
334 while (fInnerProcessors[currProcessor]->LoadEntry(localEntryNumber) == kInvalidNTupleIndex) {
335 if (fInnerNEntries[currProcessor] == kInvalidNTupleIndex) {
336 fInnerNEntries[currProcessor] = fInnerProcessors[currProcessor]->GetNEntries();
337 }
338
339 localEntryNumber -= fInnerNEntries[currProcessor];
340
341 // The provided global entry number is larger than the number of available entries.
342 if (++currProcessor >= fInnerProcessors.size())
343 return kInvalidNTupleIndex;
344 }
345
346 if (currProcessor != fCurrentProcessorNumber)
347 fCurrentProcessorNumber = currProcessor;
348
349 fNEntriesProcessed++;
350 fCurrentEntryNumber = entryNumber;
351 return entryNumber;
352}
353
356{
357 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
358 const auto &innerProc = fInnerProcessors[i];
359 innerProc->AddEntriesToJoinTable(joinTable, entryOffset);
360 entryOffset += innerProc->GetNEntries();
361 }
362}
363
365{
366 for (const auto &innerProc : fInnerProcessors) {
367 innerProc->PrintStructure(output);
368 }
369}
370
371//------------------------------------------------------------------------------
372
375private:
378 {
379 throw RException(R__FAIL("RAuxiliaryProcessorField fields must only be used for reading"));
380 }
381
382public:
383 RAuxiliaryProcessorField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
384 : ROOT::RRecordField(fieldName, "RAuxiliaryProcessorField")
385 {
386 fOffsets.reserve(itemFields.size());
387 for (auto &item : itemFields) {
388 fOffsets.push_back(GetItemPadding(fSize, item->GetAlignment()));
389 }
390 AttachItemFields(std::move(itemFields));
391 }
392};
393} // namespace ROOT::Experimental::Internal
394
396 std::unique_ptr<RNTupleProcessor> auxProcessor,
397 const std::vector<std::string> &joinFields,
398 std::unique_ptr<ROOT::RNTupleModel> primaryModel,
399 std::unique_ptr<ROOT::RNTupleModel> auxModel,
400 std::string_view processorName)
402 fPrimaryProcessor(std::move(primaryProcessor)),
403 fAuxiliaryProcessor(std::move(auxProcessor))
404{
405 if (fProcessorName.empty()) {
406 fProcessorName = fPrimaryProcessor->GetProcessorName();
407 }
408
409 if (!primaryModel)
410 primaryModel = fPrimaryProcessor->GetModel().Clone();
411 if (!auxModel) {
412 auxModel = fAuxiliaryProcessor->GetModel().Clone();
413 }
414
415 // If the primaryProcessor has a field with the name of the auxProcessor (either as a "proper" field or because the
416 // primary processor itself is a join where its auxProcessor bears the same name as the current auxProcessor), there
417 // will be name conflicts, so error out.
418 if (primaryModel->GetFieldNames().find(fAuxiliaryProcessor->GetProcessorName()) !=
419 primaryModel->GetFieldNames().end()) {
420 throw RException(R__FAIL("a field or nested auxiliary processor named \"" +
421 fAuxiliaryProcessor->GetProcessorName() +
422 "\" is already present in the model of the primary processor; rename the auxiliary "
423 "processor to avoid conflicts"));
424 }
425
426 SetModel(std::move(primaryModel), std::move(auxModel));
427
428 fModel->Freeze();
429 fEntry = fModel->CreateEntry();
430
431 for (const auto &value : *fEntry) {
432 auto &field = value.GetField();
433 const auto &fieldName = field.GetQualifiedFieldName();
434
435 // If the model provided by the user has a default entry, use the value pointers from the default entry of the
436 // model that was passed to this constructor. This way, the pointers returned by RNTupleModel::MakeField can be
437 // used in the processor loop to access the corresponding field values.
438 if (!fModel->IsBare()) {
439 auto valuePtr = fModel->GetDefaultEntry().GetPtr<void>(fieldName);
440 fEntry->BindValue(fieldName, valuePtr);
441 }
442 }
443
444 fPrimaryProcessor->SetEntryPointers(*fEntry);
445 // FIXME(fdegeus): for nested auxiliary processors, simply passing the processor name is not sufficient because we
446 // also need the name(s) of the *inner* processor(s) (e.g., "ntuple0.ntuple1"). This means either (1) recursively
447 // infer this full name or (2) rethink the way fields in auxiliary processors together with how entries are
448 // currently set altogether.
449 fAuxiliaryProcessor->SetEntryPointers(*fEntry, fAuxiliaryProcessor->GetProcessorName());
450
451 if (!joinFields.empty()) {
452 for (const auto &joinField : joinFields) {
453 auto token = fEntry->GetToken(joinField);
454 fJoinFieldTokens.emplace_back(token);
455 }
456
458 }
459}
460
462 std::unique_ptr<RNTupleModel> auxModel)
463{
464 fModel = std::move(primaryModel);
465 fModel->Unfreeze();
466
467 // Create an anonymous record field for the auxiliary processor, containing its top-level fields. These original
468 // top-level fields are registered as subfields in the join model, such that they can be accessed as
469 // `auxNTupleName.fieldName`.
470 std::vector<std::unique_ptr<ROOT::RFieldBase>> auxFields;
471 auxFields.reserve(auxModel->GetFieldNames().size());
472
473 for (const auto &fieldName : auxModel->GetFieldNames()) {
474 auxFields.emplace_back(auxModel->GetConstField(fieldName).Clone(fieldName));
475 }
476
477 auto auxParentField = std::make_unique<Internal::RAuxiliaryProcessorField>(fAuxiliaryProcessor->GetProcessorName(),
478 std::move(auxFields));
479 const auto &subFields = auxParentField->GetConstSubfields();
480 fModel->AddField(std::move(auxParentField));
481
482 for (const auto &field : subFields) {
483 fModel->RegisterSubfield(field->GetQualifiedFieldName());
484
485 if (field->GetTypeName() == "RAuxiliaryProcessorField") {
486 for (const auto &auxSubField : field->GetConstSubfields()) {
487 fModel->RegisterSubfield(auxSubField->GetQualifiedFieldName());
488 }
489 }
490 }
491
492 // If the model has a default entry, adopt its value pointers. This way, the pointers returned by
493 // RNTupleModel::MakeField can be used in the processor loop to access the corresponding field values.
494 if (!fModel->IsBare() && !auxModel->IsBare()) {
495 const auto &auxDefaultEntry = auxModel->GetDefaultEntry();
496 auto &joinDefaultEntry = fModel->GetDefaultEntry();
497 for (const auto &fieldName : auxModel->GetFieldNames()) {
498 auto valuePtr = auxDefaultEntry.GetPtr<void>(fieldName);
499 joinDefaultEntry.BindValue(fAuxiliaryProcessor->GetProcessorName() + "." + fieldName, valuePtr);
500 }
501 }
502
503 fModel->Freeze();
504}
505
507 std::string_view fieldNamePrefix)
508{
509 for (const auto &value : *fEntry) {
510 std::string fieldName = value.GetField().GetQualifiedFieldName();
511 auto valuePtr = fieldNamePrefix.empty() ? entry.GetPtr<void>(fieldName)
512 : entry.GetPtr<void>(std::string(fieldNamePrefix) + "." + fieldName);
513
514 fEntry->BindValue(fieldName, valuePtr);
515 }
516
517 fPrimaryProcessor->SetEntryPointers(*fEntry);
518 fAuxiliaryProcessor->SetEntryPointers(*fEntry, fAuxiliaryProcessor->GetProcessorName());
519}
520
522{
523 if (fPrimaryProcessor->LoadEntry(entryNumber) == kInvalidNTupleIndex)
524 return kInvalidNTupleIndex;
525
526 fCurrentEntryNumber = entryNumber;
527 fNEntriesProcessed++;
528
529 if (!fJoinTable) {
530 if (fAuxiliaryProcessor->LoadEntry(entryNumber) == kInvalidNTupleIndex) {
531 throw RException(R__FAIL("entry " + std::to_string(entryNumber) +
532 " in the primary processor has no corresponding entry in auxiliary processor \"" +
533 fAuxiliaryProcessor->GetProcessorName() + "\""));
534 }
535
536 return entryNumber;
537 }
538
539 if (!fJoinTableIsBuilt) {
540 fAuxiliaryProcessor->AddEntriesToJoinTable(*fJoinTable);
541 fJoinTableIsBuilt = true;
542 }
543
544 // Collect the values of the join fields for this entry.
545 std::vector<void *> valPtrs;
546 valPtrs.reserve(fJoinFieldTokens.size());
547 for (const auto &token : fJoinFieldTokens) {
548 auto ptr = fEntry->GetPtr<void>(token);
549 valPtrs.push_back(ptr.get());
550 }
551
552 // Find the entry index corresponding to the join field values for each auxiliary processor and load the
553 // corresponding entry.
554 const auto entryIdx = fJoinTable->GetEntryIndex(valPtrs);
555
557 throw RException(R__FAIL("entry " + std::to_string(entryNumber) +
558 " in the primary processor has no corresponding entry in auxiliary processor \"" +
559 fAuxiliaryProcessor->GetProcessorName() + "\""));
560
561 fAuxiliaryProcessor->LoadEntry(entryIdx);
562
563 return entryNumber;
564}
565
567{
568 if (fNEntries == kInvalidNTupleIndex)
569 fNEntries = fPrimaryProcessor->GetNEntries();
570 return fNEntries;
571}
572
578
580{
581 std::ostringstream primaryStructureStr;
582 fPrimaryProcessor->PrintStructure(primaryStructureStr);
583 const auto primaryStructure = ROOT::Split(primaryStructureStr.str(), "\n", /*skipEmpty=*/true);
584 const auto primaryStructureWidth = primaryStructure.front().size();
585
586 std::ostringstream auxStructureStr;
587 fAuxiliaryProcessor->PrintStructure(auxStructureStr);
588 const auto auxStructure = ROOT::Split(auxStructureStr.str(), "\n", /*skipEmpty=*/true);
589
590 const auto maxLength = std::max(primaryStructure.size(), auxStructure.size());
591 for (unsigned i = 0; i < maxLength; i++) {
592 if (i < primaryStructure.size())
594 else
595 output << std::setw(primaryStructureWidth) << "";
596
597 if (i < auxStructure.size())
598 output << " " << auxStructure[i];
599
600 output << "\n";
601 }
602}
#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
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
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
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
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:498
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:544
std::vector< std::size_t > fOffsets
ROOT::RFieldZero & GetFieldZeroOfModel(RNTupleModel &model)
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
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()