Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RNTupleProcessor.cxx
Go to the documentation of this file.
1/// \file RNTupleProcessor.cxx
2/// \author Florine de Geus <florine.de.geus@cern.ch>
3/// \date 2024-03-26
4/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
5/// is welcome!
6
7/*************************************************************************
8 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
9 * All rights reserved. *
10 * *
11 * For the licensing terms see $ROOTSYS/LICENSE. *
12 * For the list of contributors see $ROOTSYS/README/CREDITS. *
13 *************************************************************************/
14
16
17#include <ROOT/RFieldBase.hxx>
18#include <ROOT/RNTuple.hxx>
20#include <ROOT/StringUtils.hxx>
21
22#include <TDirectory.h>
23
24#include <iomanip>
25
26std::unique_ptr<ROOT::Internal::RPageSource> ROOT::Experimental::RNTupleOpenSpec::CreatePageSource() const
27{
28 if (const std::string *storagePath = std::get_if<std::string>(&fStorage))
30
31 auto dir = std::get<TDirectory *>(fStorage);
32 auto ntuple = std::unique_ptr<ROOT::RNTuple>(dir->Get<ROOT::RNTuple>(fNTupleName.c_str()));
34}
35
36std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
38{
39 return std::unique_ptr<RNTupleSingleProcessor>(new RNTupleSingleProcessor(std::move(ntuple), processorName));
40}
41
42std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
43ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<RNTupleOpenSpec> ntuples, std::string_view processorName)
44{
45 if (ntuples.empty())
46 throw RException(R__FAIL("at least one RNTuple must be provided"));
47
48 std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors;
49 innerProcessors.reserve(ntuples.size());
50
51 for (auto &ntuple : ntuples) {
52 innerProcessors.emplace_back(Create(std::move(ntuple)));
53 }
54
55 return CreateChain(std::move(innerProcessors), processorName);
56}
57
58std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
59ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors,
60 std::string_view processorName)
61{
62 if (innerProcessors.empty())
63 throw RException(R__FAIL("at least one inner processor must be provided"));
64
65 return std::unique_ptr<RNTupleChainProcessor>(new RNTupleChainProcessor(std::move(innerProcessors), processorName));
66}
67
68std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
70 const std::vector<std::string> &joinFields,
71 std::string_view processorName)
72{
73 if (joinFields.size() > 4) {
74 throw RException(R__FAIL("a maximum of four join fields is allowed"));
75 }
76
77 if (std::unordered_set(joinFields.begin(), joinFields.end()).size() < joinFields.size()) {
78 throw RException(R__FAIL("join fields must be unique"));
79 }
80
81 std::unique_ptr<RNTupleProcessor> primaryProcessor = Create(primaryNTuple, processorName);
82
83 std::unique_ptr<RNTupleProcessor> auxProcessor = Create(auxNTuple);
84
85 return CreateJoin(std::move(primaryProcessor), std::move(auxProcessor), joinFields, processorName);
86}
87
88std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
89ROOT::Experimental::RNTupleProcessor::CreateJoin(std::unique_ptr<RNTupleProcessor> primaryProcessor,
90 std::unique_ptr<RNTupleProcessor> auxProcessor,
91 const std::vector<std::string> &joinFields,
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 return std::unique_ptr<RNTupleJoinProcessor>(
103 new RNTupleJoinProcessor(std::move(primaryProcessor), std::move(auxProcessor), joinFields, processorName));
104}
105
106//------------------------------------------------------------------------------
107
109 std::string_view processorName)
110 : RNTupleProcessor(processorName), fNTupleSpec(std::move(ntuple))
111{
112 if (fProcessorName.empty()) {
113 fProcessorName = fNTupleSpec.fNTupleName;
114 }
115}
116
118 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
119{
120 // The processor has already been initialized.
121 if (IsInitialized())
122 return;
123
124 if (!entry)
125 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
126 else
127 fEntry = entry;
128
129 fPageSource = fNTupleSpec.CreatePageSource();
130 fPageSource->Attach();
132 opts.SetCreateBare(true);
133 fProtoModel = fPageSource->GetSharedDescriptorGuard()->CreateModel(opts);
134 fProtoModel->Unfreeze();
135}
136
138{
139 Initialize();
140 auto desc = fPageSource->GetSharedDescriptorGuard();
141 auto fieldZeroId = desc->GetFieldZeroId();
142
143 // TODO handle subfields
144 return desc->FindFieldId(fieldName, fieldZeroId) != ROOT::kInvalidDescriptorId;
145}
146
148ROOT::Experimental::RNTupleSingleProcessor::AddFieldToEntry(std::string_view fieldName, void *valuePtr,
149 const Internal::RNTupleProcessorProvenance &provenance)
150{
151 auto fieldIdx = fEntry->FindFieldIndex(fieldName);
152 if (!fieldIdx) {
153 try {
154 std::string onDiskFieldName = std::string(fieldName);
155 if (provenance.IsPresentInFieldName(onDiskFieldName)) {
156 onDiskFieldName = onDiskFieldName.substr(provenance.Get().size() + 1);
157 }
158 auto &field = fProtoModel->GetMutableField(onDiskFieldName);
159 fieldIdx = fEntry->AddField(fieldName, field, valuePtr, provenance);
160 return *fieldIdx;
161 } catch (const ROOT::RException &) {
162 return R__FAIL("cannot register field with name \"" + std::string(fieldName) +
163 "\" because it is not present in the on-disk information of the RNTuple(s) this "
164 "processor is created from");
165 }
166 } else {
167 return *fieldIdx;
168 }
169}
170
172{
173 if (entryNumber >= fNEntries || !fEntry)
174 return kInvalidNTupleIndex;
175
176 for (auto fieldIdx : fFieldIdxs) {
177 fEntry->ReadValue(fieldIdx, entryNumber);
178 }
179
181 fCurrentEntryNumber = entryNumber;
182 return entryNumber;
183}
184
186 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
187 const Internal::RNTupleProcessorProvenance & /* provenance */, bool updateFields)
188{
189 Initialize();
190
191 // The processor has already been connected.
192 if (fNEntries != kInvalidNTupleIndex && !updateFields)
193 return;
194
195 fFieldIdxs = fieldIdxs;
196 fNEntries = fPageSource->GetNEntries();
197
198 auto desc = fPageSource->GetSharedDescriptorGuard();
200 auto fieldZeroId = desc->GetFieldZeroId();
201 fieldZero.SetOnDiskId(fieldZeroId);
203
204 for (const auto &fieldIdx : fieldIdxs) {
205 const auto &entryField = fEntry->GetField(fieldIdx);
206
207 // TODO handle subfields
208 auto onDiskId = desc->FindFieldId(entryField.GetQualifiedFieldName(), fieldZeroId);
209 // The field we are trying to connect is not present in the ntuple
210 if (onDiskId == kInvalidDescriptorId) {
211 fEntry->SetFieldValidity(fieldIdx, false);
212 continue;
213 }
214
215 auto &modelField = fProtoModel->GetMutableField(entryField.GetQualifiedFieldName());
216
217 if (entryField.GetState() == RFieldBase::EState::kConnectedToSource && &entryField != &modelField) {
218 fEntry->UpdateField(fieldIdx, modelField);
219 }
220
221 if (modelField.GetState() == RFieldBase::EState::kUnconnected) {
222 modelField.SetOnDiskId(onDiskId);
224 }
225
226 fEntry->SetFieldValidity(fieldIdx, true);
227 }
229}
230
237
239{
240 static constexpr int width = 32;
241
242 std::string ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 4);
243 if (ntupleNameTrunc.size() < fNTupleSpec.fNTupleName.size())
244 ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 6) + "..";
245
246 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
247 output << std::setfill(' ') << "| " << ntupleNameTrunc << std::setw(width - 2 - ntupleNameTrunc.size()) << " |\n";
248
249 if (const std::string *storage = std::get_if<std::string>(&fNTupleSpec.fStorage)) {
250 std::string storageTrunc = storage->substr(0, width - 5);
251 if (storageTrunc.size() < storage->size())
252 storageTrunc = storage->substr(0, width - 8) + "...";
253
254 output << std::setfill(' ') << "| " << storageTrunc << std::setw(width - 2 - storageTrunc.size()) << " |\n";
255 } else {
256 output << "| " << std::setw(width - 2) << " |\n";
257 }
258
259 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
260}
261
262//------------------------------------------------------------------------------
263
265 std::vector<std::unique_ptr<RNTupleProcessor>> processors, std::string_view processorName)
266 : RNTupleProcessor(processorName), 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
277 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
278{
279 if (IsInitialized())
280 return;
281
282 if (!entry)
283 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
284 else
285 fEntry = entry;
286
287 fInnerProcessors[0]->Initialize(fEntry);
288 fProtoModel = fInnerProcessors[0]->GetProtoModel().Clone();
289}
290
292{
294 fNEntries = 0;
295
296 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
298 fInnerNEntries[i] = fInnerProcessors[i]->GetNEntries();
299 }
300
302 }
303 }
304
305 return fNEntries;
306}
307
309 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
310 const Internal::RNTupleProcessorProvenance &provenance, bool /* updateFields */)
311{
312 Initialize();
313 fFieldIdxs = fieldIdxs;
314 fProvenance = provenance;
316}
317
319{
320 auto &innerProc = fInnerProcessors[processorNumber];
321 innerProc->Initialize(fEntry);
322 innerProc->Connect(fFieldIdxs, fProvenance, /*updateFields=*/true);
323}
324
326ROOT::Experimental::RNTupleChainProcessor::AddFieldToEntry(std::string_view fieldName, void *valuePtr,
327 const Internal::RNTupleProcessorProvenance &provenance)
328{
329 return R__FORWARD_RESULT(
330 fInnerProcessors[fCurrentProcessorNumber]->AddFieldToEntry(fieldName, valuePtr, provenance));
331}
332
334{
335 ROOT::NTupleSize_t localEntryNumber = entryNumber;
336 std::size_t currProcessorNumber = 0;
337 if (entryNumber < fCurrentEntryNumber) {
340 }
341
342 // As long as the entry fails to load from the current processor, we decrement the local entry number with the number
343 // of entries in this processor and try with the next processor until we find the correct local entry number.
344 while (fInnerProcessors[currProcessorNumber]->LoadEntry(localEntryNumber) == kInvalidNTupleIndex) {
345 if (fInnerNEntries[currProcessorNumber] == kInvalidNTupleIndex) {
346 fInnerNEntries[currProcessorNumber] = fInnerProcessors[currProcessorNumber]->GetNEntries();
347 }
348
349 localEntryNumber -= fInnerNEntries[currProcessorNumber];
350
351 // The provided global entry number is larger than the number of available entries.
352 if (++currProcessorNumber >= fInnerProcessors.size())
353 return kInvalidNTupleIndex;
354
355 ConnectInnerProcessor(currProcessorNumber);
356 }
357
358 fCurrentProcessorNumber = currProcessorNumber;
360 fCurrentEntryNumber = entryNumber;
361 return entryNumber;
362}
363
365 ROOT::NTupleSize_t entryOffset)
366{
367 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
368 const auto &innerProc = fInnerProcessors[i];
369 // TODO can this be done (more) lazily? I.e. only when a match cannot be found in the current inner proc?
370 // At this stage, we don't want to fully initialize (i.e. set the entry of) the inner processor yet
371 innerProc->Initialize(nullptr);
372 innerProc->AddEntriesToJoinTable(joinTable, entryOffset);
373 entryOffset += innerProc->GetNEntries();
374 }
375}
376
378{
379 for (const auto &innerProc : fInnerProcessors) {
380 innerProc->PrintStructure(output);
381 }
382}
383
384//------------------------------------------------------------------------------
385
388private:
390 void GenerateColumns() final
391 {
392 throw RException(R__FAIL("RAuxiliaryProcessorField fields must only be used for reading"));
393 }
394
395public:
396 RAuxiliaryProcessorField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
397 : ROOT::RRecordField(fieldName, "RAuxiliaryProcessorField")
398 {
399 AttachItemFields(std::move(itemFields));
400 }
401};
402} // namespace ROOT::Experimental::Internal
403
404ROOT::Experimental::RNTupleJoinProcessor::RNTupleJoinProcessor(std::unique_ptr<RNTupleProcessor> primaryProcessor,
405 std::unique_ptr<RNTupleProcessor> auxProcessor,
406 const std::vector<std::string> &joinFields,
407 std::string_view processorName)
408 : RNTupleProcessor(processorName),
409 fPrimaryProcessor(std::move(primaryProcessor)),
410 fAuxiliaryProcessor(std::move(auxProcessor)),
411 fJoinFieldNames(joinFields)
412{
413 if (fProcessorName.empty()) {
414 fProcessorName = fPrimaryProcessor->GetProcessorName();
415 }
416}
417
419 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
420{
421 if (IsInitialized())
422 return;
423
424 if (!entry)
425 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
426 else
427 fEntry = entry;
428
429 fPrimaryProcessor->Initialize(fEntry);
430 fAuxiliaryProcessor->Initialize(fEntry);
431
432 // If the primaryProcessor has a field with the name of the auxProcessor (either as a "proper" field or because the
433 // primary processor itself is a join where its auxProcessor bears the same name as the current auxProcessor), there
434 // will be name conflicts, so error out.
435 if (auto &primaryModel = fPrimaryProcessor->GetProtoModel();
436 primaryModel.GetFieldNames().find(fAuxiliaryProcessor->GetProcessorName()) !=
437 primaryModel.GetFieldNames().end()) {
438 throw RException(R__FAIL("a field or nested auxiliary processor named \"" +
439 fAuxiliaryProcessor->GetProcessorName() +
440 "\" is already present as a field in the primary processor; rename the auxiliary "
441 "processor to avoid conflicts"));
442 }
443
444 SetProtoModel(fPrimaryProcessor->GetProtoModel().Clone(), fAuxiliaryProcessor->GetProtoModel().Clone());
445
446 if (!fJoinFieldNames.empty()) {
447 for (const auto &joinField : fJoinFieldNames) {
448 if (!fAuxiliaryProcessor->CanReadFieldFromDisk(joinField)) {
449 throw RException(R__FAIL("could not find join field \"" + joinField + "\" in auxiliary processor \"" +
450 fAuxiliaryProcessor->GetProcessorName() + "\""));
451 }
452 // We prepend the name of the primary processor in this case to prevent reading from the wrong join field in
453 // composed join operations.
454 auto fieldIdx = AddFieldToEntry(fProcessorName + "." + joinField, nullptr,
456 if (!fieldIdx)
457 throw RException(R__FAIL("could not find join field \"" + joinField + "\" in primary processor \"" +
458 fPrimaryProcessor->GetProcessorName() + "\""));
459 fJoinFieldIdxs.insert(fieldIdx.Unwrap());
460 }
461
463 }
464}
465
467 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
468 const Internal::RNTupleProcessorProvenance &provenance, bool updateFields)
469{
470 Initialize();
471
472 auto auxProvenance = provenance.Evolve(fAuxiliaryProcessor->GetProcessorName());
473 for (const auto &fieldIdx : fieldIdxs) {
474 auto fieldProvenance = fEntry->GetFieldProvenance(fieldIdx);
475 if (fieldProvenance.Contains(auxProvenance))
476 fAuxiliaryFieldIdxs.insert(fieldIdx);
477 else
478 fFieldIdxs.insert(fieldIdx);
479 }
480
481 fPrimaryProcessor->Connect(fFieldIdxs, provenance, updateFields);
482 fAuxiliaryProcessor->Connect(fAuxiliaryFieldIdxs, auxProvenance, updateFields);
483}
484
485void ROOT::Experimental::RNTupleJoinProcessor::SetProtoModel(std::unique_ptr<ROOT::RNTupleModel> primaryModel,
486 std::unique_ptr<RNTupleModel> auxModel)
487{
488 fProtoModel = std::move(primaryModel);
489 fProtoModel->Unfreeze();
490
491 // Create an anonymous record field for the auxiliary processor, containing its top-level fields. These original
492 // top-level fields are registered as subfields in this processor's proto-model, such that they can be accessed as
493 // `auxNTupleName.fieldName`.
494 std::vector<std::unique_ptr<ROOT::RFieldBase>> auxFields;
495 auxFields.reserve(auxModel->GetFieldNames().size());
496
497 for (const auto &fieldName : auxModel->GetFieldNames()) {
498 auxFields.emplace_back(auxModel->GetConstField(fieldName).Clone(fieldName));
499 }
500
501 auto auxParentField = std::make_unique<Internal::RAuxiliaryProcessorField>(fAuxiliaryProcessor->GetProcessorName(),
502 std::move(auxFields));
503 const auto &subFields = auxParentField->GetConstSubfields();
504 fProtoModel->AddField(std::move(auxParentField));
505
506 for (const auto &field : subFields) {
507 fProtoModel->RegisterSubfield(field->GetQualifiedFieldName());
508
509 if (field->GetTypeName() == "RAuxiliaryProcessorField") {
510 for (const auto &auxSubfield : field->GetConstSubfields()) {
511 fProtoModel->RegisterSubfield(auxSubfield->GetQualifiedFieldName());
512 }
513 }
514 }
515}
516
518ROOT::Experimental::RNTupleJoinProcessor::AddFieldToEntry(std::string_view fieldName, void *valuePtr,
519 const Internal::RNTupleProcessorProvenance &provenance)
520{
521 auto auxProvenance = provenance.Evolve(fAuxiliaryProcessor->GetProcessorName());
522 if (auxProvenance.IsPresentInFieldName(fieldName)) {
523 auto fieldIdx = fAuxiliaryProcessor->AddFieldToEntry(fieldName, valuePtr, auxProvenance);
524 if (fieldIdx)
525 fAuxiliaryFieldIdxs.insert(fieldIdx.Unwrap());
526 return R__FORWARD_RESULT(fieldIdx);
527 } else {
528 auto fieldIdx = fPrimaryProcessor->AddFieldToEntry(fieldName, valuePtr, provenance);
529 if (fieldIdx)
530 fFieldIdxs.insert(fieldIdx.Unwrap());
531 return R__FORWARD_RESULT(fieldIdx);
532 }
533}
534
536{
537 for (const auto &fieldIdx : fAuxiliaryFieldIdxs) {
538 fEntry->SetFieldValidity(fieldIdx, isValid);
539 }
540}
541
543{
544 if (fPrimaryProcessor->LoadEntry(entryNumber) == kInvalidNTupleIndex) {
545 for (auto fieldIdx : fFieldIdxs) {
546 fEntry->SetFieldValidity(fieldIdx, false);
547 }
549 return kInvalidNTupleIndex;
550 }
551
552 fCurrentEntryNumber = entryNumber;
554
555 if (!fJoinTable) {
556 // The auxiliary processor's fields are valid if the entry could be loaded.
557 fAuxiliaryProcessor->LoadEntry(entryNumber);
558 return entryNumber;
559 }
560
561 if (!fJoinTableIsBuilt) {
562 fAuxiliaryProcessor->AddEntriesToJoinTable(*fJoinTable);
563 fJoinTableIsBuilt = true;
564 }
565
566 // Collect the values of the join fields for this entry.
567 std::vector<void *> valPtrs;
568 valPtrs.reserve(fJoinFieldIdxs.size());
569 for (const auto &fieldIdx : fJoinFieldIdxs) {
570 auto ptr = fEntry->GetPtr<void>(fieldIdx);
571 valPtrs.push_back(ptr.get());
572 }
573
574 // Find the entry index corresponding to the join field values for each auxiliary processor and load the
575 // corresponding entry.
576 const auto entryIdx = fJoinTable->GetEntryIndex(valPtrs);
577
578 if (entryIdx == kInvalidNTupleIndex) {
580 } else {
582 for (const auto &fieldIdx : fAuxiliaryFieldIdxs) {
583 fEntry->ReadValue(fieldIdx, entryIdx);
584 }
585 }
586
587 return entryNumber;
588}
589
596
598 ROOT::NTupleSize_t entryOffset)
599{
600 fPrimaryProcessor->AddEntriesToJoinTable(joinTable, entryOffset);
601}
602
604{
605 std::ostringstream primaryStructureStr;
606 fPrimaryProcessor->PrintStructure(primaryStructureStr);
607 const auto primaryStructure = ROOT::Split(primaryStructureStr.str(), "\n", /*skipEmpty=*/true);
608 const auto primaryStructureWidth = primaryStructure.front().size();
609
610 std::ostringstream auxStructureStr;
611 fAuxiliaryProcessor->PrintStructure(auxStructureStr);
612 const auto auxStructure = ROOT::Split(auxStructureStr.str(), "\n", /*skipEmpty=*/true);
613
614 const auto maxLength = std::max(primaryStructure.size(), auxStructure.size());
615 for (unsigned i = 0; i < maxLength; i++) {
616 if (i < primaryStructure.size())
617 output << primaryStructure[i];
618 else
619 output << std::setw(primaryStructureWidth) << "";
620
621 if (i < auxStructure.size())
622 output << " " << auxStructure[i];
623
624 output << "\n";
625 }
626}
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:301
#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
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.
RNTupleJoinTable & Add(ROOT::Internal::RPageSource &pageSource, PartitionKey_t partitionKey=kDefaultPartitionKey, ROOT::NTupleSize_t entryOffset=0)
Add an entry mapping to the join table.
static constexpr PartitionKey_t kDefaultPartitionKey
std::string Get() const
Get the full processor provenance, in the form of "x.y.z".
bool IsPresentInFieldName(std::string_view fieldName) const
Check whether the provided field name contains this provenance.
RNTupleProcessorProvenance Evolve(const std::string &processorName) const
Add a new processor to the provenance.
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.
Internal::RNTupleProcessorProvenance fProvenance
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
std::set< Internal::RNTupleProcessorEntry::FieldIndex_t > fJoinFieldIdxs
std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > fAuxiliaryFieldIdxs
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,...
std::unique_ptr< Internal::RNTupleJoinTable > fJoinTable
std::unique_ptr< RNTupleProcessor > fAuxiliaryProcessor
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
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.
ROOT::NTupleSize_t fNEntries
Total number of entries.
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.
std::shared_ptr< Internal::RNTupleProcessorEntry > fEntry
std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > fFieldIdxs
bool IsInitialized() const
Check if the processor already has been initialized.
std::unique_ptr< ROOT::RNTupleModel > fProtoModel
static std::unique_ptr< RNTupleProcessor > Create(RNTupleOpenSpec ntuple, std::string_view processorName="")
Create an RNTupleProcessor for 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().
std::unique_ptr< ROOT::Internal::RPageSource > fPageSource
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:78
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
The field for an untyped record.
RRecordField(std::string_view name, const RRecordField &source)
Definition RField.cxx:572
void AttachItemFields(ContainerT &&itemFields)
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:197
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:35
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