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>
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>(
104}
105
106//------------------------------------------------------------------------------
107
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();
131
132 fNEntries = fPageSource->GetNEntries();
133}
134
136{
137 Initialize();
138 auto desc = fPageSource->GetSharedDescriptorGuard();
139 auto fieldZeroId = desc->GetFieldZeroId();
140
141 // TODO handle subfields
142 return desc->FindFieldId(fieldName, fieldZeroId) != ROOT::kInvalidDescriptorId;
143}
144
145std::unique_ptr<ROOT::RFieldBase>
147 const std::string &typeName)
148{
149 assert(fPageSource);
150
152
153 // Strip the "_join" prefix (for join fields) from the field name, if present.
154 if (onDiskFieldName.find("_join.") == 0) {
156 }
157
158 const auto &desc = fPageSource->GetSharedDescriptorGuard().GetRef();
161
162 const auto onDiskFieldId = desc.FindFieldId(onDiskFieldName);
163
165 return nullptr;
166 }
167
168 std::unique_ptr<ROOT::RFieldBase> field;
169 if (typeName.empty()) {
170 const auto &fieldDesc = desc.GetFieldDescriptor(onDiskFieldId);
171 field = fieldDesc.CreateField(desc);
172 } else {
173 // Strip the parent field name prefix(es), if present.
174 std::string subfieldName = onDiskFieldName;
175 auto posDot = onDiskFieldName.find_last_of('.');
176 if (posDot != std::string::npos)
177 subfieldName = onDiskFieldName.substr(posDot + 1);
178
179 field = ROOT::RFieldBase::Create(subfieldName, typeName).Unwrap();
180 }
181
182 field->SetOnDiskId(onDiskFieldId);
183 fieldZero.Attach(std::move(field));
185 return std::move(fieldZero.ReleaseSubfields()[0]);
186}
187
189ROOT::Experimental::RNTupleSingleProcessor::AddFieldToEntry(const std::string &fieldName, const std::string &typeName,
190 void *valuePtr,
192{
193 auto fieldIdx = fEntry->FindFieldIndex(fieldName, typeName);
194 if (!fieldIdx) {
195 // Strip the processor name prefix(es), if present.
196 std::string qualifiedFieldName = fieldName;
197 if (provenance.IsPresentInFieldName(qualifiedFieldName)) {
198 qualifiedFieldName = qualifiedFieldName.substr(provenance.Get().size() + 1);
199 }
200
201 auto field = CreateAndConnectField(qualifiedFieldName, typeName);
202
203 if (!field) {
204 throw RException(R__FAIL("cannot register field with name \"" + qualifiedFieldName +
205 "\" because it is not present in the on-disk information of the RNTuple(s) this "
206 "processor is created from"));
207 }
208
209 fieldIdx = fEntry->AddField(qualifiedFieldName, std::move(field), valuePtr, provenance);
210 }
211
212 return *fieldIdx;
213}
214
216{
217 if (entryNumber >= fNEntries || !fEntry)
218 return kInvalidNTupleIndex;
219
220 for (auto fieldIdx : fFieldIdxs) {
221 fEntry->ReadValue(fieldIdx, entryNumber);
222 }
223
224 fNEntriesProcessed++;
225 fCurrentEntryNumber = entryNumber;
226 return entryNumber;
227}
228
230 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
231 const Internal::RNTupleProcessorProvenance & /* provenance */, bool updateFields)
232{
233 Initialize();
234
235 fFieldIdxs = fieldIdxs;
236
237 if (updateFields) {
238 for (const auto &fieldIdx : fFieldIdxs) {
239 const auto &currField = fEntry->GetValue(fieldIdx).GetField();
240 auto newField = CreateAndConnectField(fEntry->GetQualifiedFieldName(fieldIdx), currField.GetTypeName());
241
242 fEntry->UpdateField(fieldIdx, std::move(newField));
243 }
244 }
245}
246
253
255{
256 static constexpr int width = 32;
257
258 std::string ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 4);
259 if (ntupleNameTrunc.size() < fNTupleSpec.fNTupleName.size())
260 ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 6) + "..";
261
262 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
263 output << std::setfill(' ') << "| " << ntupleNameTrunc << std::setw(width - 2 - ntupleNameTrunc.size()) << " |\n";
264
265 if (const std::string *storage = std::get_if<std::string>(&fNTupleSpec.fStorage)) {
266 std::string storageTrunc = storage->substr(0, width - 5);
267 if (storageTrunc.size() < storage->size())
268 storageTrunc = storage->substr(0, width - 8) + "...";
269
270 output << std::setfill(' ') << "| " << storageTrunc << std::setw(width - 2 - storageTrunc.size()) << " |\n";
271 } else {
272 output << "| " << std::setw(width - 2) << " |\n";
273 }
274
275 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
276}
277
278//------------------------------------------------------------------------------
279
281 std::vector<std::unique_ptr<RNTupleProcessor>> processors, std::string_view processorName)
282 : RNTupleProcessor(processorName), fInnerProcessors(std::move(processors))
283{
284 if (fProcessorName.empty()) {
285 // `CreateChain` ensures there is at least one inner processor.
286 fProcessorName = fInnerProcessors[0]->GetProcessorName();
287 }
288
290}
291
293 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
294{
295 if (IsInitialized())
296 return;
297
298 if (!entry)
299 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
300 else
301 fEntry = entry;
302
303 fInnerProcessors[0]->Initialize(fEntry);
304}
305
307{
308 if (fNEntries == kInvalidNTupleIndex) {
309 fNEntries = 0;
310
311 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
312 if (fInnerNEntries[i] == kInvalidNTupleIndex) {
313 fInnerNEntries[i] = fInnerProcessors[i]->GetNEntries();
314 }
315
316 fNEntries += fInnerNEntries[i];
317 }
318 }
319
320 return fNEntries;
321}
322
324 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
325 const Internal::RNTupleProcessorProvenance &provenance, bool /* updateFields */)
326{
327 Initialize();
328 fFieldIdxs = fieldIdxs;
329 fProvenance = provenance;
330 ConnectInnerProcessor(fCurrentProcessorNumber);
331}
332
334{
335 auto &innerProc = fInnerProcessors[processorNumber];
336 innerProc->Initialize(fEntry);
337 innerProc->Connect(fFieldIdxs, fProvenance, /*updateFields=*/true);
338}
339
341ROOT::Experimental::RNTupleChainProcessor::AddFieldToEntry(const std::string &fieldName, const std::string &typeName,
342 void *valuePtr,
344{
345 return fInnerProcessors[fCurrentProcessorNumber]->AddFieldToEntry(fieldName, typeName, valuePtr, provenance);
346}
347
349{
351 std::size_t currProcessorNumber = 0;
352 if (entryNumber < fCurrentEntryNumber) {
353 fCurrentProcessorNumber = 0;
354 ConnectInnerProcessor(fCurrentProcessorNumber);
355 }
356
357 // As long as the entry fails to load from the current processor, we decrement the local entry number with the number
358 // of entries in this processor and try with the next processor until we find the correct local entry number.
359 while (fInnerProcessors[currProcessorNumber]->LoadEntry(localEntryNumber) == kInvalidNTupleIndex) {
360 if (fInnerNEntries[currProcessorNumber] == kInvalidNTupleIndex) {
361 fInnerNEntries[currProcessorNumber] = fInnerProcessors[currProcessorNumber]->GetNEntries();
362 }
363
364 localEntryNumber -= fInnerNEntries[currProcessorNumber];
365
366 // The provided global entry number is larger than the number of available entries.
367 if (++currProcessorNumber >= fInnerProcessors.size())
368 return kInvalidNTupleIndex;
369
370 ConnectInnerProcessor(currProcessorNumber);
371 }
372
373 fCurrentProcessorNumber = currProcessorNumber;
374 fNEntriesProcessed++;
375 fCurrentEntryNumber = entryNumber;
376 return entryNumber;
377}
378
381{
382 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
383 const auto &innerProc = fInnerProcessors[i];
384 // TODO can this be done (more) lazily? I.e. only when a match cannot be found in the current inner proc?
385 // At this stage, we don't want to fully initialize (i.e. set the entry of) the inner processor yet
386 innerProc->Initialize(nullptr);
387 innerProc->AddEntriesToJoinTable(joinTable, entryOffset);
388 entryOffset += innerProc->GetNEntries();
389 }
390}
391
393{
394 for (const auto &innerProc : fInnerProcessors) {
395 innerProc->PrintStructure(output);
396 }
397}
398
399//------------------------------------------------------------------------------
400
403private:
406 {
407 throw RException(R__FAIL("RAuxiliaryProcessorField fields must only be used for reading"));
408 }
409
410public:
411 RAuxiliaryProcessorField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
412 : ROOT::RRecordField(fieldName, "RAuxiliaryProcessorField")
413 {
414 AttachItemFields(std::move(itemFields));
415 }
416};
417} // namespace ROOT::Experimental::Internal
418
420 std::unique_ptr<RNTupleProcessor> auxProcessor,
421 const std::vector<std::string> &joinFields,
422 std::string_view processorName)
424 fPrimaryProcessor(std::move(primaryProcessor)),
425 fAuxiliaryProcessor(std::move(auxProcessor)),
426 fJoinFieldNames(joinFields)
427{
428 if (fProcessorName.empty()) {
429 fProcessorName = fPrimaryProcessor->GetProcessorName();
430 }
431}
432
434 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
435{
436 if (IsInitialized())
437 return;
438
439 if (!entry)
440 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
441 else
442 fEntry = entry;
443
444 fPrimaryProcessor->Initialize(fEntry);
445 fAuxiliaryProcessor->Initialize(fEntry);
446
447 if (!fJoinFieldNames.empty()) {
448 for (const auto &joinField : fJoinFieldNames) {
449 if (!fPrimaryProcessor->CanReadFieldFromDisk(joinField)) {
450 throw RException(R__FAIL("could not find join field \"" + joinField + "\" in primary processor \"" +
451 fPrimaryProcessor->GetProcessorName() + "\""));
452 }
453 if (!fAuxiliaryProcessor->CanReadFieldFromDisk(joinField)) {
454 throw RException(R__FAIL("could not find join field \"" + joinField + "\" in auxiliary processor \"" +
455 fAuxiliaryProcessor->GetProcessorName() + "\""));
456 }
457
458 // We prepend the name of the primary processor in this case to prevent reading from the wrong join field in
459 // composed join operations.
460 auto fieldIdx = AddFieldToEntry(fProcessorName + "._join." + joinField, "std::uint64_t", nullptr,
462 fJoinFieldIdxs.insert(fieldIdx);
463 }
464
465 fJoinTable = Internal::RNTupleJoinTable::Create(fJoinFieldNames);
466 }
467}
468
470 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
472{
473 Initialize();
474
475 auto auxProvenance = provenance.Evolve(fAuxiliaryProcessor->GetProcessorName());
476 for (const auto &fieldIdx : fieldIdxs) {
477 const auto &fieldProvenance = fEntry->GetFieldProvenance(fieldIdx);
478 if (fieldProvenance.Contains(auxProvenance))
479 fAuxiliaryFieldIdxs.insert(fieldIdx);
480 else
481 fFieldIdxs.insert(fieldIdx);
482 }
483
484 fPrimaryProcessor->Connect(fFieldIdxs, provenance, updateFields);
485 fAuxiliaryProcessor->Connect(fAuxiliaryFieldIdxs, auxProvenance, updateFields);
486}
487
489ROOT::Experimental::RNTupleJoinProcessor::AddFieldToEntry(const std::string &fieldName, const std::string &typeName,
490 void *valuePtr,
492{
493 auto auxProvenance = provenance.Evolve(fAuxiliaryProcessor->GetProcessorName());
494 if (auxProvenance.IsPresentInFieldName(fieldName)) {
495 // If the primaryProcessor has a field with the name of the auxProcessor (either as a "proper" field or because
496 // the primary processor itself is a join where its auxProcessor bears the same name as the current auxProcessor),
497 // there will be name conflicts, so error out.
498 if (fPrimaryProcessor->CanReadFieldFromDisk(fieldName)) {
499 throw RException(R__FAIL("ambiguous field name: \"" + fieldName +
500 "\" is present in the primary RNTupleProcessor \"" +
501 fPrimaryProcessor->GetProcessorName() +
502 "\", but may also refer to a field in the auxiliary RNTupleProcessor named \"" +
503 fAuxiliaryProcessor->GetProcessorName() +
504 "\". To avoid this ambiguity, rename the auxiliary RNTupleProcessor."));
505 }
506
507 auto fieldIdx = fAuxiliaryProcessor->AddFieldToEntry(fieldName, typeName, valuePtr, auxProvenance);
508 if (fieldIdx)
509 fAuxiliaryFieldIdxs.insert(fieldIdx);
510 return fieldIdx;
511 } else {
512 auto fieldIdx = fPrimaryProcessor->AddFieldToEntry(fieldName, typeName, valuePtr, provenance);
513 if (fieldIdx)
514 fFieldIdxs.insert(fieldIdx);
515 return fieldIdx;
516 }
517}
518
520{
521 for (const auto &fieldIdx : fAuxiliaryFieldIdxs) {
522 fEntry->SetFieldValidity(fieldIdx, isValid);
523 }
524}
525
527{
528 if (fPrimaryProcessor->LoadEntry(entryNumber) == kInvalidNTupleIndex) {
529 for (auto fieldIdx : fFieldIdxs) {
530 fEntry->SetFieldValidity(fieldIdx, false);
531 }
532 SetAuxiliaryFieldValidity(false);
533 return kInvalidNTupleIndex;
534 }
535
536 fCurrentEntryNumber = entryNumber;
537 fNEntriesProcessed++;
538
539 if (!fJoinTable) {
540 // The auxiliary processor's fields are valid if the entry could be loaded.
541 fAuxiliaryProcessor->LoadEntry(entryNumber);
542 return entryNumber;
543 }
544
545 if (!fJoinTableIsBuilt) {
546 fAuxiliaryProcessor->AddEntriesToJoinTable(*fJoinTable);
547 fJoinTableIsBuilt = true;
548 }
549
550 // Collect the values of the join fields for this entry.
551 std::vector<ROOT::Experimental::Internal::RNTupleJoinTable::JoinValue_t> values;
552 values.reserve(fJoinFieldIdxs.size());
553 for (const auto &fieldIdx : fJoinFieldIdxs) {
554 auto val = fEntry->GetValue(fieldIdx).GetRef<ROOT::Experimental::Internal::RNTupleJoinTable::JoinValue_t>();
555 values.push_back(val);
556 }
557
558 // Find the entry index corresponding to the join field values for each auxiliary processor and load the
559 // corresponding entry.
560 const auto entryIdx = fJoinTable->GetEntryIndex(values);
561
563 SetAuxiliaryFieldValidity(false);
564 } else {
565 SetAuxiliaryFieldValidity(true);
566 for (const auto &fieldIdx : fAuxiliaryFieldIdxs) {
567 fEntry->ReadValue(fieldIdx, entryIdx);
568 }
569 }
570
571 return entryNumber;
572}
573
575{
576 if (fNEntries == kInvalidNTupleIndex)
577 fNEntries = fPrimaryProcessor->GetNEntries();
578 return fNEntries;
579}
580
586
588{
589 std::ostringstream primaryStructureStr;
590 fPrimaryProcessor->PrintStructure(primaryStructureStr);
591 const auto primaryStructure = ROOT::Split(primaryStructureStr.str(), "\n", /*skipEmpty=*/true);
592 const auto primaryStructureWidth = primaryStructure.front().size();
593
594 std::ostringstream auxStructureStr;
595 fAuxiliaryProcessor->PrintStructure(auxStructureStr);
596 const auto auxStructure = ROOT::Split(auxStructureStr.str(), "\n", /*skipEmpty=*/true);
597
598 const auto maxLength = std::max(primaryStructure.size(), auxStructure.size());
599 for (unsigned i = 0; i < maxLength; i++) {
600 if (i < primaryStructure.size())
601 output << primaryStructure[i];
602 else
603 output << std::setw(primaryStructureWidth) << "";
604
605 if (i < auxStructure.size())
606 output << " " << auxStructure[i];
607
608 output << "\n";
609 }
610}
#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 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.
Internal::RNTupleProcessorEntry::FieldIndex_t AddFieldToEntry(const std::string &fieldName, const std::string &typeName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
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 creating an (initially empty) fEntry, or setting an existing one.
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...
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::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 creating an (initially empty) fEntry, or setting an existing one.
Internal::RNTupleProcessorEntry::FieldIndex_t AddFieldToEntry(const std::string &fieldName, const std::string &typeName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
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.
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 creating an (initially empty) fEntry, or setting an existing one.
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...
Internal::RNTupleProcessorEntry::FieldIndex_t AddFieldToEntry(const std::string &fieldName, const std::string &typeName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
std::unique_ptr< ROOT::RFieldBase > CreateAndConnectField(const std::string &qualifiedFieldName, const std::string &typeName)
Create a new field and connect it to the processor's page source.
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 ...
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
Factory method to resurrect a field from the stored on-disk type information.
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:58
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(ContainerT &&itemFields)
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:35
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