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>
39{
40 return std::unique_ptr<RNTupleSingleProcessor>(new RNTupleSingleProcessor(std::move(ntuple), processorName));
41}
42
43std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
44ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<RNTupleOpenSpec> ntuples, std::string_view processorName)
45{
46 if (ntuples.empty())
47 throw RException(R__FAIL("at least one RNTuple must be provided"));
48
49 std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors;
50 innerProcessors.reserve(ntuples.size());
51
52 for (auto &ntuple : ntuples) {
53 innerProcessors.emplace_back(Create(std::move(ntuple)));
54 }
55
56 return CreateChain(std::move(innerProcessors), processorName);
57}
58
59std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
60ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors,
61 std::string_view processorName)
62{
63 if (innerProcessors.empty())
64 throw RException(R__FAIL("at least one inner processor must be provided"));
65
66 return std::unique_ptr<RNTupleChainProcessor>(new RNTupleChainProcessor(std::move(innerProcessors), processorName));
67}
68
69std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
71 const std::vector<std::string> &joinFields,
72 std::string_view processorName)
73{
74 if (joinFields.size() > 4) {
75 throw RException(R__FAIL("a maximum of four join fields is allowed"));
76 }
77
78 if (std::unordered_set(joinFields.begin(), joinFields.end()).size() < joinFields.size()) {
79 throw RException(R__FAIL("join fields must be unique"));
80 }
81
82 std::unique_ptr<RNTupleProcessor> primaryProcessor = Create(primaryNTuple, processorName);
83
84 std::unique_ptr<RNTupleProcessor> auxProcessor = Create(auxNTuple);
85
86 return CreateJoin(std::move(primaryProcessor), std::move(auxProcessor), joinFields, processorName);
87}
88
89std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
91 std::unique_ptr<RNTupleProcessor> auxProcessor,
92 const std::vector<std::string> &joinFields,
93 std::string_view processorName)
94{
95 if (joinFields.size() > 4) {
96 throw RException(R__FAIL("a maximum of four join fields is allowed"));
97 }
98
99 if (std::unordered_set(joinFields.begin(), joinFields.end()).size() < joinFields.size()) {
100 throw RException(R__FAIL("join fields must be unique"));
101 }
102
103 return std::unique_ptr<RNTupleJoinProcessor>(
105}
106
107//------------------------------------------------------------------------------
108
117
119 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
120{
121 // The processor has already been initialized.
122 if (IsInitialized())
123 return;
124
125 if (!entry)
126 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
127 else
128 fEntry = entry;
129
130 fPageSource = fNTupleSpec.CreatePageSource();
131 fPageSource->Attach();
133 opts.SetCreateBare(true);
134 fProtoModel = fPageSource->GetSharedDescriptorGuard()->CreateModel(opts);
135 fProtoModel->Unfreeze();
136}
137
139{
140 Initialize();
141 auto desc = fPageSource->GetSharedDescriptorGuard();
142 auto fieldZeroId = desc->GetFieldZeroId();
143
144 // TODO handle subfields
145 return desc->FindFieldId(fieldName, fieldZeroId) != ROOT::kInvalidDescriptorId;
146}
147
151{
152 auto fieldIdx = fEntry->FindFieldIndex(fieldName);
153 if (!fieldIdx) {
154 try {
155 std::string onDiskFieldName = std::string(fieldName);
156 if (provenance.IsPresentInFieldName(onDiskFieldName)) {
157 onDiskFieldName = onDiskFieldName.substr(provenance.Get().size() + 1);
158 }
159 auto &field = fProtoModel->GetMutableField(onDiskFieldName);
160 fieldIdx = fEntry->AddField(fieldName, field, valuePtr, provenance);
161 return *fieldIdx;
162 } catch (const ROOT::RException &) {
163 return R__FAIL("cannot register field with name \"" + std::string(fieldName) +
164 "\" because it is not present in the on-disk information of the RNTuple(s) this "
165 "processor is created from");
166 }
167 } else {
168 return *fieldIdx;
169 }
170}
171
173{
174 if (entryNumber >= fNEntries || !fEntry)
175 return kInvalidNTupleIndex;
176
177 for (auto fieldIdx : fFieldIdxs) {
178 fEntry->ReadValue(fieldIdx, entryNumber);
179 }
180
181 fNEntriesProcessed++;
182 fCurrentEntryNumber = entryNumber;
183 return entryNumber;
184}
185
187 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
188 const Internal::RNTupleProcessorProvenance & /* provenance */, bool updateFields)
189{
190 Initialize();
191
192 // The processor has already been connected.
193 if (fNEntries != kInvalidNTupleIndex && !updateFields)
194 return;
195
196 fFieldIdxs = fieldIdxs;
197 fNEntries = fPageSource->GetNEntries();
198
199 auto desc = fPageSource->GetSharedDescriptorGuard();
201 auto fieldZeroId = desc->GetFieldZeroId();
202 fieldZero.SetOnDiskId(fieldZeroId);
204
205 for (const auto &fieldIdx : fieldIdxs) {
206 const auto &entryField = fEntry->GetField(fieldIdx);
207
208 // TODO handle subfields
209 auto onDiskId = desc->FindFieldId(entryField.GetQualifiedFieldName(), fieldZeroId);
210 // The field we are trying to connect is not present in the ntuple
212 fEntry->SetFieldValidity(fieldIdx, false);
213 continue;
214 }
215
216 auto &modelField = fProtoModel->GetMutableField(entryField.GetQualifiedFieldName());
217
219 fEntry->UpdateField(fieldIdx, modelField);
220 }
221
223 modelField.SetOnDiskId(onDiskId);
225 }
226
227 fEntry->SetFieldValidity(fieldIdx, true);
228 }
230}
231
238
240{
241 static constexpr int width = 32;
242
243 std::string ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 4);
244 if (ntupleNameTrunc.size() < fNTupleSpec.fNTupleName.size())
245 ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 6) + "..";
246
247 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
248 output << std::setfill(' ') << "| " << ntupleNameTrunc << std::setw(width - 2 - ntupleNameTrunc.size()) << " |\n";
249
250 if (const std::string *storage = std::get_if<std::string>(&fNTupleSpec.fStorage)) {
251 std::string storageTrunc = storage->substr(0, width - 5);
252 if (storageTrunc.size() < storage->size())
253 storageTrunc = storage->substr(0, width - 8) + "...";
254
255 output << std::setfill(' ') << "| " << storageTrunc << std::setw(width - 2 - storageTrunc.size()) << " |\n";
256 } else {
257 output << "| " << std::setw(width - 2) << " |\n";
258 }
259
260 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
261}
262
263//------------------------------------------------------------------------------
264
266 std::vector<std::unique_ptr<RNTupleProcessor>> processors, std::string_view processorName)
267 : RNTupleProcessor(processorName), fInnerProcessors(std::move(processors))
268{
269 if (fProcessorName.empty()) {
270 // `CreateChain` ensures there is at least one inner processor.
271 fProcessorName = fInnerProcessors[0]->GetProcessorName();
272 }
273
275}
276
278 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
279{
280 if (IsInitialized())
281 return;
282
283 if (!entry)
284 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
285 else
286 fEntry = entry;
287
288 fInnerProcessors[0]->Initialize(fEntry);
289 fProtoModel = fInnerProcessors[0]->GetProtoModel().Clone();
290}
291
293{
294 if (fNEntries == kInvalidNTupleIndex) {
295 fNEntries = 0;
296
297 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
298 if (fInnerNEntries[i] == kInvalidNTupleIndex) {
299 fInnerNEntries[i] = fInnerProcessors[i]->GetNEntries();
300 }
301
302 fNEntries += fInnerNEntries[i];
303 }
304 }
305
306 return fNEntries;
307}
308
310 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
311 const Internal::RNTupleProcessorProvenance &provenance, bool /* updateFields */)
312{
313 Initialize();
314 fFieldIdxs = fieldIdxs;
315 fProvenance = provenance;
316 ConnectInnerProcessor(fCurrentProcessorNumber);
317}
318
320{
321 auto &innerProc = fInnerProcessors[processorNumber];
322 innerProc->Initialize(fEntry);
323 innerProc->Connect(fFieldIdxs, fProvenance, /*updateFields=*/true);
324}
325
329{
330 return R__FORWARD_RESULT(
331 fInnerProcessors[fCurrentProcessorNumber]->AddFieldToEntry(fieldName, valuePtr, provenance));
332}
333
335{
337 std::size_t currProcessorNumber = 0;
338 if (entryNumber < fCurrentEntryNumber) {
339 fCurrentProcessorNumber = 0;
340 ConnectInnerProcessor(fCurrentProcessorNumber);
341 }
342
343 // As long as the entry fails to load from the current processor, we decrement the local entry number with the number
344 // of entries in this processor and try with the next processor until we find the correct local entry number.
345 while (fInnerProcessors[currProcessorNumber]->LoadEntry(localEntryNumber) == kInvalidNTupleIndex) {
346 if (fInnerNEntries[currProcessorNumber] == kInvalidNTupleIndex) {
347 fInnerNEntries[currProcessorNumber] = fInnerProcessors[currProcessorNumber]->GetNEntries();
348 }
349
350 localEntryNumber -= fInnerNEntries[currProcessorNumber];
351
352 // The provided global entry number is larger than the number of available entries.
353 if (++currProcessorNumber >= fInnerProcessors.size())
354 return kInvalidNTupleIndex;
355
356 ConnectInnerProcessor(currProcessorNumber);
357 }
358
359 fCurrentProcessorNumber = currProcessorNumber;
360 fNEntriesProcessed++;
361 fCurrentEntryNumber = entryNumber;
362 return entryNumber;
363}
364
367{
368 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
369 const auto &innerProc = fInnerProcessors[i];
370 // TODO can this be done (more) lazily? I.e. only when a match cannot be found in the current inner proc?
371 // At this stage, we don't want to fully initialize (i.e. set the entry of) the inner processor yet
372 innerProc->Initialize(nullptr);
373 innerProc->AddEntriesToJoinTable(joinTable, entryOffset);
374 entryOffset += innerProc->GetNEntries();
375 }
376}
377
379{
380 for (const auto &innerProc : fInnerProcessors) {
381 innerProc->PrintStructure(output);
382 }
383}
384
385//------------------------------------------------------------------------------
386
389private:
392 {
393 throw RException(R__FAIL("RAuxiliaryProcessorField fields must only be used for reading"));
394 }
395
396public:
397 RAuxiliaryProcessorField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
398 : ROOT::RRecordField(fieldName, "RAuxiliaryProcessorField")
399 {
400 fOffsets.reserve(itemFields.size());
401 for (auto &item : itemFields) {
402 fOffsets.push_back(GetItemPadding(fSize, item->GetAlignment()));
403 }
404 AttachItemFields(std::move(itemFields));
405 }
406};
407} // namespace ROOT::Experimental::Internal
408
410 std::unique_ptr<RNTupleProcessor> auxProcessor,
411 const std::vector<std::string> &joinFields,
412 std::string_view processorName)
414 fPrimaryProcessor(std::move(primaryProcessor)),
415 fAuxiliaryProcessor(std::move(auxProcessor)),
416 fJoinFieldNames(joinFields)
417{
418 if (fProcessorName.empty()) {
419 fProcessorName = fPrimaryProcessor->GetProcessorName();
420 }
421}
422
424 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
425{
426 if (IsInitialized())
427 return;
428
429 if (!entry)
430 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
431 else
432 fEntry = entry;
433
434 fPrimaryProcessor->Initialize(fEntry);
435 fAuxiliaryProcessor->Initialize(fEntry);
436
437 // If the primaryProcessor has a field with the name of the auxProcessor (either as a "proper" field or because the
438 // primary processor itself is a join where its auxProcessor bears the same name as the current auxProcessor), there
439 // will be name conflicts, so error out.
440 if (auto &primaryModel = fPrimaryProcessor->GetProtoModel();
441 primaryModel.GetFieldNames().find(fAuxiliaryProcessor->GetProcessorName()) !=
442 primaryModel.GetFieldNames().end()) {
443 throw RException(R__FAIL("a field or nested auxiliary processor named \"" +
444 fAuxiliaryProcessor->GetProcessorName() +
445 "\" is already present as a field in the primary processor; rename the auxiliary "
446 "processor to avoid conflicts"));
447 }
448
449 SetProtoModel(fPrimaryProcessor->GetProtoModel().Clone(), fAuxiliaryProcessor->GetProtoModel().Clone());
450
451 if (!fJoinFieldNames.empty()) {
452 for (const auto &joinField : fJoinFieldNames) {
453 if (!fAuxiliaryProcessor->CanReadFieldFromDisk(joinField)) {
454 throw RException(R__FAIL("could not find join field \"" + joinField + "\" in auxiliary processor \"" +
455 fAuxiliaryProcessor->GetProcessorName() + "\""));
456 }
457 // We prepend the name of the primary processor in this case to prevent reading from the wrong join field in
458 // composed join operations.
459 auto fieldIdx = AddFieldToEntry(fProcessorName + "." + joinField, nullptr,
461 if (!fieldIdx)
462 throw RException(R__FAIL("could not find join field \"" + joinField + "\" in primary processor \"" +
463 fPrimaryProcessor->GetProcessorName() + "\""));
464 fJoinFieldIdxs.insert(fieldIdx.Unwrap());
465 }
466
467 fJoinTable = Internal::RNTupleJoinTable::Create(fJoinFieldNames);
468 }
469}
470
472 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
474{
475 Initialize();
476
477 auto auxProvenance = provenance.Evolve(fAuxiliaryProcessor->GetProcessorName());
478 for (const auto &fieldIdx : fieldIdxs) {
479 auto fieldProvenance = fEntry->GetFieldProvenance(fieldIdx);
480 if (fieldProvenance.Contains(auxProvenance))
481 fAuxiliaryFieldIdxs.insert(fieldIdx);
482 else
483 fFieldIdxs.insert(fieldIdx);
484 }
485
486 fPrimaryProcessor->Connect(fFieldIdxs, provenance, updateFields);
487 fAuxiliaryProcessor->Connect(fAuxiliaryFieldIdxs, auxProvenance, updateFields);
488}
489
491 std::unique_ptr<RNTupleModel> auxModel)
492{
493 fProtoModel = std::move(primaryModel);
494 fProtoModel->Unfreeze();
495
496 // Create an anonymous record field for the auxiliary processor, containing its top-level fields. These original
497 // top-level fields are registered as subfields in this processor's proto-model, such that they can be accessed as
498 // `auxNTupleName.fieldName`.
499 std::vector<std::unique_ptr<ROOT::RFieldBase>> auxFields;
500 auxFields.reserve(auxModel->GetFieldNames().size());
501
502 for (const auto &fieldName : auxModel->GetFieldNames()) {
503 auxFields.emplace_back(auxModel->GetConstField(fieldName).Clone(fieldName));
504 }
505
506 auto auxParentField = std::make_unique<Internal::RAuxiliaryProcessorField>(fAuxiliaryProcessor->GetProcessorName(),
507 std::move(auxFields));
508 const auto &subFields = auxParentField->GetConstSubfields();
509 fProtoModel->AddField(std::move(auxParentField));
510
511 for (const auto &field : subFields) {
512 fProtoModel->RegisterSubfield(field->GetQualifiedFieldName());
513
514 if (field->GetTypeName() == "RAuxiliaryProcessorField") {
515 for (const auto &auxSubField : field->GetConstSubfields()) {
516 fProtoModel->RegisterSubfield(auxSubField->GetQualifiedFieldName());
517 }
518 }
519 }
520}
521
525{
526 auto auxProvenance = provenance.Evolve(fAuxiliaryProcessor->GetProcessorName());
527 if (auxProvenance.IsPresentInFieldName(fieldName)) {
528 auto fieldIdx = fAuxiliaryProcessor->AddFieldToEntry(fieldName, valuePtr, auxProvenance);
529 if (fieldIdx)
530 fAuxiliaryFieldIdxs.insert(fieldIdx.Unwrap());
532 } else {
533 auto fieldIdx = fPrimaryProcessor->AddFieldToEntry(fieldName, valuePtr, provenance);
534 if (fieldIdx)
535 fFieldIdxs.insert(fieldIdx.Unwrap());
537 }
538}
539
541{
542 for (const auto &fieldIdx : fAuxiliaryFieldIdxs) {
543 fEntry->SetFieldValidity(fieldIdx, isValid);
544 }
545}
546
548{
549 if (fPrimaryProcessor->LoadEntry(entryNumber) == kInvalidNTupleIndex) {
550 for (auto fieldIdx : fFieldIdxs) {
551 fEntry->SetFieldValidity(fieldIdx, false);
552 }
553 SetAuxiliaryFieldValidity(false);
554 return kInvalidNTupleIndex;
555 }
556
557 fCurrentEntryNumber = entryNumber;
558 fNEntriesProcessed++;
559
560 if (!fJoinTable) {
561 // The auxiliary processor's fields are valid if the entry could be loaded.
562 fAuxiliaryProcessor->LoadEntry(entryNumber);
563 return entryNumber;
564 }
565
566 if (!fJoinTableIsBuilt) {
567 fAuxiliaryProcessor->AddEntriesToJoinTable(*fJoinTable);
568 fJoinTableIsBuilt = true;
569 }
570
571 // Collect the values of the join fields for this entry.
572 std::vector<void *> valPtrs;
573 valPtrs.reserve(fJoinFieldIdxs.size());
574 for (const auto &fieldIdx : fJoinFieldIdxs) {
575 auto ptr = fEntry->GetPtr<void>(fieldIdx);
576 valPtrs.push_back(ptr.get());
577 }
578
579 // Find the entry index corresponding to the join field values for each auxiliary processor and load the
580 // corresponding entry.
581 const auto entryIdx = fJoinTable->GetEntryIndex(valPtrs);
582
584 SetAuxiliaryFieldValidity(false);
585 } else {
586 SetAuxiliaryFieldValidity(true);
587 for (const auto &fieldIdx : fAuxiliaryFieldIdxs) {
588 fEntry->ReadValue(fieldIdx, entryIdx);
589 }
590 }
591
592 return entryNumber;
593}
594
596{
597 if (fNEntries == kInvalidNTupleIndex)
598 fNEntries = fPrimaryProcessor->GetNEntries();
599 return fNEntries;
600}
601
607
609{
610 std::ostringstream primaryStructureStr;
611 fPrimaryProcessor->PrintStructure(primaryStructureStr);
612 const auto primaryStructure = ROOT::Split(primaryStructureStr.str(), "\n", /*skipEmpty=*/true);
613 const auto primaryStructureWidth = primaryStructure.front().size();
614
615 std::ostringstream auxStructureStr;
616 fAuxiliaryProcessor->PrintStructure(auxStructureStr);
617 const auto auxStructure = ROOT::Split(auxStructureStr.str(), "\n", /*skipEmpty=*/true);
618
619 const auto maxLength = std::max(primaryStructure.size(), auxStructure.size());
620 for (unsigned i = 0; i < maxLength; i++) {
621 if (i < primaryStructure.size())
623 else
624 output << std::setw(primaryStructureWidth) << "";
625
626 if (i < auxStructure.size())
627 output << " " << auxStructure[i];
628
629 output << "\n";
630 }
631}
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:302
#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 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 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.
void ConnectInnerProcessor(std::size_t processorNumber)
Update the entry to reflect any missing fields in the current inner processor.
ROOT::NTupleSize_t GetNEntries() final
Get the total number of entries in this processor.
void Initialize(std::shared_ptr< Internal::RNTupleProcessorEntry > entry=nullptr) final
Initialize the processor, by setting fProtoModel and creating an (initially empty) fEntry,...
std::vector< ROOT::NTupleSize_t > fInnerNEntries
void Connect(const std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > &fieldIdxs, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance(), bool updateFields=false) final
Connect the provided fields indices in the entry to their on-disk fields.
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...
ROOT::RResult< Internal::RNTupleProcessorEntry::FieldIndex_t > AddFieldToEntry(std::string_view fieldName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
std::vector< std::unique_ptr< RNTupleProcessor > > fInnerProcessors
Processor specialization for horizontally combined (joined) RNTupleProcessors.
void PrintStructureImpl(std::ostream &output) const final
Processor-specific implementation for printing its structure, called by PrintStructure().
ROOT::RResult< Internal::RNTupleProcessorEntry::FieldIndex_t > AddFieldToEntry(std::string_view fieldName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
void SetProtoModel(std::unique_ptr< ROOT::RNTupleModel > primaryModel, std::unique_ptr< ROOT::RNTupleModel > auxModel)
Set the processor's proto model by combining the primary and auxiliary models.
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.
void SetAuxiliaryFieldValidity(bool validity)
Set the validity for all fields in the auxiliary processor at once.
void Connect(const std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > &fieldIdxs, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance(), bool updateFields=false) final
Connect the provided fields indices in the entry to their on-disk fields.
std::unique_ptr< RNTupleProcessor > fPrimaryProcessor
void Initialize(std::shared_ptr< Internal::RNTupleProcessorEntry > entry=nullptr) final
Initialize the processor, by setting fProtoModel and creating an (initially empty) fEntry,...
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 vertically ("chained") and/or horizontally ("joined") combine...
static std::unique_ptr< RNTupleProcessor > CreateJoin(RNTupleOpenSpec primaryNTuple, RNTupleOpenSpec auxNTuple, const std::vector< std::string > &joinFields, std::string_view processorName="")
Create an RNTupleProcessor for a join (i.e., a horizontal combination) of RNTuples.
static std::unique_ptr< RNTupleProcessor > CreateChain(std::vector< RNTupleOpenSpec > ntuples, 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::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.
ROOT::RResult< Internal::RNTupleProcessorEntry::FieldIndex_t > AddFieldToEntry(std::string_view fieldName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
void Connect(const std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > &fieldIdxs, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance(), bool updateFields=false) final
Connect the provided fields indices in the entry to their on-disk fields.
void Initialize(std::shared_ptr< Internal::RNTupleProcessorEntry > entry=nullptr) final
Initialize the processor, by setting fProtoModel and creating an (initially empty) fEntry,...
void PrintStructureImpl(std::ostream &output) const final
Processor-specific implementation for printing its structure, called by PrintStructure().
bool CanReadFieldFromDisk(std::string_view fieldName) final
Check if a field exists on-disk and can be read by the processor.
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)
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:568
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:624
std::vector< std::size_t > fOffsets
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:198
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:36
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()