Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleProcessor.hxx
Go to the documentation of this file.
1/// \file ROOT/RNTupleProcessor.hxx
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
15#ifndef ROOT_RNTupleProcessor
16#define ROOT_RNTupleProcessor
17
18#include <ROOT/REntry.hxx>
19#include <ROOT/RError.hxx>
22#include <ROOT/RNTupleModel.hxx>
23#include <ROOT/RNTupleTypes.hxx>
25#include <ROOT/RPageStorage.hxx>
26
27#include <memory>
28#include <string>
29#include <string_view>
30#include <vector>
31
32namespace ROOT {
33namespace Experimental {
34class RNTupleProcessor;
35
36namespace Internal {
37struct RNTupleProcessorEntryLoader; // for unit tests
38const RNTupleProcessorEntry *
39LoadFullRNTupleProcessorEntry(ROOT::Experimental::RNTupleProcessor &processor, bool includeSubfields); // for unit tests
40
41namespace RDF {
42class RNTupleProcessorColumnReader;
44} // namespace RDF
45} // namespace Internal
46
47// clang-format off
48/**
49\class ROOT::Experimental::RNTupleOpenSpec
50\ingroup NTuple
51\brief Specification of the name and location of an RNTuple, used for creating a new RNTupleProcessor.
52
53An RNTupleOpenSpec can be created by providing either a string with a path to the ROOT file or a pointer to the
54TDirectory (or any of its subclasses) that contains the RNTuple.
55
56Note that the RNTupleOpenSpec is *write-only*, to prevent usability issues with Python.
57*/
58// clang-format on
60 friend class RNTupleProcessor;
63
64private:
65 std::string fNTupleName;
66 std::variant<std::string, TDirectory *> fStorage;
67
68public:
69 RNTupleOpenSpec(std::string_view n, TDirectory *s) : fNTupleName(n), fStorage(s) {}
70 RNTupleOpenSpec(std::string_view n, const std::string &s) : fNTupleName(n), fStorage(s) {}
71
72 std::unique_ptr<ROOT::Internal::RPageSource> CreatePageSource() const;
73};
74
76private:
77 /// By default, the processor name is the name of the underlying RNTuple for RNTupleSingleProcessor, the name of the
78 /// first processor for RNTupleChainProcessor, or the name of the primary RNTuple for RNTupleJoinProcessor.
79 std::string fProcessorName = "";
80
81public:
82 const std::string &GetProcessorName() const { return fProcessorName; }
83
84 void SetProcessorName(std::string_view name) { fProcessorName = name; }
85};
86
87// clang-format off
88/**
89\class ROOT::Experimental::RNTupleProcessorOptionalPtr<T>
90\ingroup NTuple
91\brief The RNTupleProcessorOptionalPtr provides access to values from fields present in an RNTupleProcessor, with support
92and checks for missing values.
93*/
94// clang-format on
95template <typename T>
97 friend class RNTupleProcessor;
98
99private:
102
108
109 /////////////////////////////////////////////////////////////////////////////
110 /// \brief Get a non-owning pointer to the field value managed by the processor's entry.
111 ///
112 /// \return A `T*` if the field is valid in the current entry, or a `nullptr` otherwise.
113 T *GetRawPtr() const { return GetPtr().get(); }
114
115 /////////////////////////////////////////////////////////////////////////////
116 /// \brief Bind the value to `valuePtr`.
117 ///
118 /// \param[in] valuePtr Pointer to bind the value to.
119 ///
120 /// \warning Use this function with care! Values may not always be valid for every entry during processing, for
121 /// example when a field is not present in one of the chained processors or when during a join operation, no matching
122 /// entry in the auxiliary processor can be found. Reading `valuePtr` as-is therefore comes with the risk of reading
123 /// invalid data. After binding a pointer to an `RNTupleProcessorOptionalPtr`, we *strongly* recommend only accessing
124 /// its data through this interface, to ensure that only valid data can be read.
125 void BindRawPtr(T *valuePtr) { fProcessorEntry->BindRawPtr(fFieldIndex, valuePtr); }
126
127public:
128 /////////////////////////////////////////////////////////////////////////////
129 /// \brief Check if the pointer currently holds a valid value.
131
132 /////////////////////////////////////////////////////////////////////////////
133 /// \brief Get a shared pointer to the field value managed by the processor's entry.
134 ///
135 /// \return A `std::shared_ptr<T>` if the field is valid in the current entry, or a `nullptr` otherwise.
136 std::shared_ptr<T> GetPtr() const
137 {
140 return value.template GetPtr<T>();
141 }
142
143 return nullptr;
144 }
145
146 /////////////////////////////////////////////////////////////////////////////
147 /// \brief Bind the value to `valuePtr`.
148 ///
149 /// \param[in] valuePtr Pointer to bind the value to.
150 ///
151 /// \warning Use this function with care! Values may not always be valid for every entry during processing, for
152 /// example when a field is not present in one of the chained processors or when during a join operation, no matching
153 /// entry in the auxiliary processor can be found. Reading `valuePtr` as-is therefore comes with the risk of reading
154 /// invalid data. After binding a pointer to an `RNTupleProcessorOptionalPtr`, we *strongly* recommend only accessing
155 /// its data through this interface, to ensure that only valid data can be read.
156 void Bind(std::shared_ptr<T> valuePtr) { fProcessorEntry->Bind(fFieldIndex, std::move(valuePtr)); }
157
158 /////////////////////////////////////////////////////////////////////////////
159 /// \brief Get a reference to the field value managed by the processor's entry.
160 ///
161 /// Throws an exception if the field is invalid in the processor's current entry.
162 const T &operator*() const
163 {
164 if (auto ptr = GetPtr())
165 return *ptr;
166 else
167 throw RException(R__FAIL("cannot read \"" + fProcessorEntry->FindFieldName(fFieldIndex) +
168 "\" because it has no value for the current entry"));
169 }
170
171 /////////////////////////////////////////////////////////////////////////////
172 /// \brief Access the field value managed by the processor's entry.
173 ///
174 /// Throws an exception if the field is invalid in the processor's current entry.
175 const T *operator->() const
176 {
177 if (auto ptr = GetPtr())
178 return ptr.get();
179 else
180 throw RException(R__FAIL("cannot read \"" + fProcessorEntry->FindFieldName(fFieldIndex) +
181 "\" because it has no value for the current entry"));
182 }
183
185 {
186 return lhs.fProcessorEntry == rhs.fProcessorEntry && lhs.fFieldIndex == rhs.fFieldIndex;
187 }
188};
189
190// clang-format off
191/**
192\class ROOT::Experimental::RNTupleProcessorOptionalPtr<void>
193\ingroup NTuple
194\brief Specialization of RNTupleProcessorOptionalPtr<T> for `void`-type pointers.
195*/
196// clang-format on
197template <>
199 friend class RNTupleProcessor;
200
201private:
204
210
211 /////////////////////////////////////////////////////////////////////////////
212 /// \brief Get a non-owning pointer to the field value managed by the processor's entry.
213 ///
214 /// \return A `void*` if the field is valid in the current entry, or a `nullptr` otherwise.
215 void *GetRawPtr() const { return GetPtr().get(); }
216
217 /////////////////////////////////////////////////////////////////////////////
218 /// \brief Bind the value to `valuePtr`.
219 ///
220 /// \param[in] valuePtr Pointer to bind the value to.
221 ///
222 /// \warning Use this function with care! Values may not always be valid for every entry during processing, for
223 /// example when a field is not present in one of the chained processors or when during a join operation, no matching
224 /// entry in the auxiliary processor can be found. Reading `valuePtr` as-is therefore comes with the risk of reading
225 /// invalid data. After binding a pointer to an `RNTupleProcessorOptionalPtr`, we *strongly* recommend only accessing
226 /// its data through this interface, to ensure that only valid data can be read.
227 void BindRawPtr(void *valuePtr) { fProcessorEntry->BindRawPtr(fFieldIndex, valuePtr); }
228
229public:
230 /////////////////////////////////////////////////////////////////////////////
231 /// \brief Check if the pointer currently holds a valid value.
233
234 /////////////////////////////////////////////////////////////////////////////
235 /// \brief Get the pointer to the field value managed by the processor's entry.
236 ///
237 /// \return A `std::shared_ptr<void>` if the field is valid in the current entry, or a `nullptr` otherwise.
238 std::shared_ptr<void> GetPtr() const
239 {
242 return value.template GetPtr<void>();
243 }
244
245 return nullptr;
246 }
247
248 /////////////////////////////////////////////////////////////////////////////
249 /// \brief Bind the value to `valuePtr`.
250 ///
251 /// \param[in] valuePtr Pointer to bind the value to.
252 ///
253 /// \warning Use this function with care! Values may not always be valid for every entry during processing, for
254 /// example when a field is not present in one of the chained processors or when during a join operation, no matching
255 /// entry in the auxiliary processor can be found. Reading `valuePtr` as-is therefore comes with the risk of reading
256 /// invalid data. After binding a pointer to an `RNTupleProcessorOptionalPtr`, we *strongly* recommend only accessing
257 /// its data through this interface, to ensure that only valid data can be read.
258 void Bind(std::shared_ptr<void> valuePtr) { fProcessorEntry->Bind(fFieldIndex, std::move(valuePtr)); }
259
261 {
262 return lhs.fProcessorEntry == rhs.fProcessorEntry && lhs.fFieldIndex == rhs.fFieldIndex;
263 }
264};
265
266/////////////////////////////////////////////////////////////////////////////
267/// \brief Create an RNTupleProcessor for a *join* (i.e., a horizontal combination) of RNTuples.
268///
269/// \param[in] primaryNTuple The name and location of the primary RNTuple. Its entries are processed in sequential
270/// order.
271/// \param[in] auxNTuple The name and location of the RNTuple to join the primary RNTuple with. The order in which
272/// its entries are processed is determined by the primary RNTuple and doesn't necessarily have to be sequential.
273/// \param[in] joinFields The names of the fields on which to join, in case the specified RNTuples are unaligned.
274/// The join is made based on the combined join field values, and therefore each field has to be present in each
275/// specified RNTuple. If an empty list is provided, it is assumed that the specified ntuple are fully aligned.
276/// \param[in] opts Options for the processor.
277///
278/// \return A pointer to the newly created RNTupleProcessor.
279// TODO(fdegeus) Move back to RNTupleProcessor::CreateJoin once RNTupleProcessor moves out of Experimental.
280std::unique_ptr<RNTupleProcessor>
281CreateRNTupleJoinProcessor(RNTupleOpenSpec primaryNTuple, RNTupleOpenSpec auxNTuple,
282 const std::vector<std::string> &joinFields,
283 const RNTupleProcessorOptions &opts = RNTupleProcessorOptions());
284
285/////////////////////////////////////////////////////////////////////////////
286/// \brief Create an RNTupleProcessor for a *join* (i.e., a horizontal combination) of RNTuples.
287///
288/// \param[in] primaryProcessor The primary processor. Its entries are processed in sequential order.
289/// \param[in] auxProcessor The processor to join the primary processor with. The order in which its entries are
290/// processed is determined by the primary processor and doesn't necessarily have to be sequential.
291/// \param[in] joinFields The names of the fields on which to join, in case the specified processors are unaligned.
292/// The join is made based on the combined join field values, and therefore each field has to be present in each
293/// specified processors. If an empty list is provided, it is assumed that the specified processors are fully
294/// aligned.
295/// \param[in] opts Options for the processor.
296///
297/// \return A pointer to the newly created RNTupleProcessor.
298// TODO(fdegeus) Move back to RNTupleProcessor::CreateJoin once RNTupleProcessor moves out of Experimental.
299std::unique_ptr<RNTupleProcessor>
300CreateRNTupleJoinProcessor(std::unique_ptr<RNTupleProcessor> primaryProcessor,
301 std::unique_ptr<RNTupleProcessor> auxProcessor, const std::vector<std::string> &joinFields,
302 const RNTupleProcessorOptions &opts = RNTupleProcessorOptions());
303
304// clang-format off
305/**
306\class ROOT::Experimental::RNTupleProcessor
307\ingroup NTuple
308\brief Interface for iterating over entries of vertically ("chained") and/or horizontally ("joined") combined RNTuples.
309
310Example usage (see ntpl012_processor_chain.C and ntpl015_processor_join.C for bigger examples):
311
312~~~{.cpp}
313#include <ROOT/RNTupleProcessor.hxx>
314using ROOT::Experimental::RNTupleProcessor;
315using ROOT::Experimental::RNTupleOpenSpec;
316
317std::vector<RNTupleOpenSpec> ntuples = {{"ntuple1", "ntuple1.root"}, {"ntuple2", "ntuple2.root"}};
318auto processor = RNTupleProcessor::CreateChain(ntuples);
319
320auto pt = processor->RequestField<float>("pt");
321
322for (const auto &idx : *processor) {
323 processor->LoadEntry(idx);
324 std::cout << "event = " << idx.GetEntryNumber() << ", pt = " << *pt << std::endl;
325}
326~~~
327
328An RNTupleProcessor is created either:
3291. By providing one or more RNTupleOpenSpecs, each of which contains the name and storage location of a single RNTuple;
3302. By providing a previously created RNTupleProcessor.
331
332The RNTupleProcessor provides an iterator which gives access to the index of the current *global* entry of the
333processor, i.e. taking into account previously processed RNTuples.
334
335Because the schemas of each RNTuple that are part of an RNTupleProcessor may not necessarily be identical, or because
336it can occur that entries are only partially complete in a join-based processor, field values may be marked as
337"invalid", at which point their data should not be read. This is handled by the RNTupleProcessorOptionalPtr
338that is returned by RequestField().
339*/
340// clang-format on
345 bool includeSubfields); // For unit tests
350
351protected:
352 /////////////////////////////////////////////////////////////////////////////
353 /// \brief Maps a processor's global (outer) entry index to its inner ones
358
359 private:
361
362 // Used by chain processors
363 std::size_t fInnerProcessorIdx = 0;
364 std::unique_ptr<REntryMapping> fInnerMapping = nullptr;
365
366 // Used by join processors
367 std::unique_ptr<REntryMapping> fPrimaryMapping = nullptr;
368 std::unique_ptr<REntryMapping> fAuxiliaryMapping = nullptr;
369
370 void SetEntryNumber(ROOT::NTupleSize_t entryNumber) { fEntryNumber = entryNumber; }
371
372 std::size_t GetInnerProcessorIdx() const { return fInnerProcessorIdx; }
373 void SetInnerProcessorIdx(std::size_t idx) { fInnerProcessorIdx = idx; }
374
376 {
377 if (!fInnerMapping)
378 fInnerMapping = std::make_unique<REntryMapping>();
379 return *fInnerMapping;
380 }
381
383 {
384 assert(fInnerMapping);
385 return *fInnerMapping;
386 }
387
389 {
390 if (!fPrimaryMapping)
391 fPrimaryMapping = std::make_unique<REntryMapping>();
392 return *fPrimaryMapping;
393 }
394
396 {
397 assert(fPrimaryMapping);
398 return *fPrimaryMapping;
399 }
400
402 {
404 fAuxiliaryMapping = std::make_unique<REntryMapping>();
405 return *fAuxiliaryMapping;
406 }
407
409 {
410 assert(fAuxiliaryMapping);
411 return *fAuxiliaryMapping;
412 }
413
414 friend bool operator==(const REntryMapping &lhs, const REntryMapping &rhs)
415 {
416 return lhs.fEntryNumber == rhs.fEntryNumber && lhs.fInnerProcessorIdx == rhs.fInnerProcessorIdx &&
417 ((lhs.fInnerMapping == nullptr && rhs.fInnerMapping == nullptr) ||
418 *lhs.fInnerMapping == *rhs.fInnerMapping) &&
419 ((lhs.fPrimaryMapping == nullptr && rhs.fPrimaryMapping == nullptr) ||
420 *lhs.fPrimaryMapping == *rhs.fPrimaryMapping) &&
421 ((lhs.fAuxiliaryMapping == nullptr && rhs.fAuxiliaryMapping == nullptr) ||
423 }
424
425 friend bool operator!=(const REntryMapping &lhs, const REntryMapping &rhs) { return !(lhs == rhs); }
426
427 public:
429
431 };
432
434
435 std::shared_ptr<Internal::RNTupleProcessorEntry> fEntry = nullptr;
436 std::unordered_set<Internal::RNTupleProcessorEntry::FieldIndex_t> fFieldIdxs;
437
438 /// Total number of entries. Only to be used internally by the processor, not meant to be exposed in the public
439 /// interface.
441
442 ROOT::NTupleSize_t fNEntriesProcessed = 0; //< Total number of entries processed so far
443
444 /////////////////////////////////////////////////////////////////////////////
445 /// \brief Initialize the processor by creating an (initially empty) `fEntry`, or setting an existing one.
446 virtual void Initialize(std::shared_ptr<Internal::RNTupleProcessorEntry> entry) = 0;
447
448 /////////////////////////////////////////////////////////////////////////////
449 /// \brief Check if the processor already has been initialized.
450 bool IsInitialized() const { return fEntry != nullptr; }
451
452 /////////////////////////////////////////////////////////////////////////////
453 /// \brief Connect fields to the page source of the processor's underlying RNTuple(s).
454 ///
455 /// \param[in] fieldIdxs Indices of the fields to connect.
456 /// \param[in] provenance Provenance of the processor.
457 /// \param[in] updateFields Whether the fields in the entry need to be updated, because the current underlying
458 /// RNTuple source changed.
459 virtual void Connect(const std::unordered_set<Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
460 const Internal::RNTupleProcessorProvenance &provenance, bool updateFields) = 0;
461
462 /////////////////////////////////////////////////////////////////////////////
463 /// \brief Disconnect the processor from associated physical storage.
464 virtual void Disconnect() = 0;
465
466 /////////////////////////////////////////////////////////////////////////////
467 /// \brief Set the local entry mapping (for nested processors), according to a global entry number.
468 ///
469 /// \param[in] entryNumber Global entry number to map to
470 /// \param[in] mapping Entry mapping to update
471 virtual void SetEntryMapping(ROOT::NTupleSize_t globalEntryNumber, REntryMapping &mapping) = 0;
472
473 /////////////////////////////////////////////////////////////////////////////
474 /// \brief Increment the local entry mapping by one.
475 ///
476 /// \param[in] mapping Entry mapping to increment
477 void IncrementEntryMapping(REntryMapping &mapping) { SetEntryMapping(mapping.GetEntryNumber() + 1, mapping); }
478
479 /////////////////////////////////////////////////////////////////////////////
480 /// \brief Load the entry identified by the entry mapping.
481 ///
482 /// \param[in] mapping Mapping to the entry to load
483 virtual void LoadEntryImpl(const REntryMapping &mapping) = 0;
484
485 /////////////////////////////////////////////////////////////////////////////
486 /// \brief Get a reference to the processor's internal entry.
488
489 /////////////////////////////////////////////////////////////////////////////
490 /// \brief Get a reference to the processor's internal entry.
492
493 /////////////////////////////////////////////////////////////////////////////
494 /// \brief Get the total number of entries in this processor
496
497 /////////////////////////////////////////////////////////////////////////////
498 /// \brief Check if a field exists on-disk and can be read by the processor.
499 ///
500 /// \param[in] fieldName Name of the field to check.
501 virtual bool CanReadFieldFromDisk(std::string_view fieldName) = 0;
502
503 /////////////////////////////////////////////////////////////////////////////
504 /// \brief Add a field to the entry.
505 ///
506 ///
507 /// \param[in] canonicalFieldName Canonical name of the field to add. This includes the prefix of any parent fields,
508 /// as well as the auxiliary processor name prefix, if present.
509 /// \param[in] typeName Type of the field to add.
510 /// \param[in] valuePtr Pointer to bind to the field's value in the entry. If this is a `nullptr`, a pointer will be
511 /// created.
512 /// \param[in] provenance Provenance of the processor.
513 ///
514 /// \return The index of the newly added field in the entry.
515 ///
516 /// In case the field was already present in the entry, the index of the existing field is returned.
518 AddFieldToEntry(const std::string &canonicalFieldName, const std::string &typeName, void *valuePtr,
519 const Internal::RNTupleProcessorProvenance &provenance) = 0;
520
521 /////////////////////////////////////////////////////////////////////////////
522 /// \brief Add a field to the entry.
523 ///
524 ///
525 /// \param[in] field The field to add.
526 /// \param[in] canonicalFieldName Canonical name of the field to add. This includes the prefix of any parent fields,
527 /// as well as the auxiliary processor name prefix, if present. This is different from the field name stored in
528 /// `field`.
529 /// \param[in] valuePtr Pointer to bind to the field's value in the entry. If this is a `nullptr`, a pointer will be
530 /// created.
531 /// \param[in] provenance Provenance of the processor.
532 ///
533 /// \return The index of the newly added field in the entry.
534 ///
535 /// In case the field was already present in the entry, the index of the existing field is returned.
537 AddFieldToEntry(std::unique_ptr<ROOT::RFieldBase> field, const std::string &canonicalFieldName, void *valuePtr,
538 const Internal::RNTupleProcessorProvenance &provenance) = 0;
539
540 /////////////////////////////////////////////////////////////////////////////
541 /// \brief Add all known fields (from on-disk information) to the entry.
542 ///
543 /// \param[in] provenance Provenance of the processor.
544 /// \param[in] addFieldMode Bitfield indicating how the fields should be added.
545 virtual void AddAllFieldsToEntry(const Internal::RNTupleProcessorProvenance &provenance, bool includeSubfields) = 0;
546
547 /////////////////////////////////////////////////////////////////////////////
548 /// \brief Add the entry mappings for this processor to the provided join table.
549 ///
550 /// \param[in] joinTable the join table to map the entries to.
551 /// \param[in] entryOffset In case the entry mapping is added from a chain, the offset of the entry indexes to use
552 /// with respect to the processor's position in the chain.
553 virtual void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset = 0) = 0;
554
555 /////////////////////////////////////////////////////////////////////////////
556 /// \brief Processor-specific implementation for printing its structure, called by PrintStructure().
557 ///
558 /// \param[in,out] output Output stream to print to.
559 virtual void PrintStructureImpl(std::ostream &output) const = 0;
560
561 /////////////////////////////////////////////////////////////////////////////
562 /// \brief Create a new base RNTupleProcessor.
563 ///
564 /// \param[in] processorName Name of the processor. By default, this is the name of the underlying RNTuple for
565 /// RNTupleSingleProcessor, the name of the first processor for RNTupleChainProcessor, or the name of the primary
566 /// RNTuple for RNTupleJoinProcessor.
568
569public:
574 virtual ~RNTupleProcessor() = default;
575
576 /////////////////////////////////////////////////////////////////////////////
577 /// \brief Get the options used for this processor.
578 const RNTupleProcessorOptions &GetOptions() const { return fOptions; }
579
580 /////////////////////////////////////////////////////////////////////////////
581 /// \brief Get the total number of entries processed so far.
583
584 /////////////////////////////////////////////////////////////////////////////
585 /// \brief Request access to a field for reading during processing.
586 ///
587 /// \tparam T Type of the requested field.
588 ///
589 /// \param[in] fieldName Name of the requested field.
590 /// \param[in] valuePtr Pointer to bind to the field's value in the entry. If this is a `nullptr`, a pointer will be
591 /// created.
592 ///
593 /// \return An RNTupleProcessorOptionalPtr of type `T`, which provides access to the field's value.
594 ///
595 /// \warning Provide a `valuePtr` with care! Values may not always be valid for every entry during processing, for
596 /// example when a field is not present in one of the chained processors or when during a join operation, no matching
597 /// entry in the auxiliary processor can be found. Reading `valuePtr` as-is therefore comes with the risk of reading
598 /// invalid data. After passing a pointer to `RequestField`, we *strongly* recommend only accessing its data through
599 /// the interface of the returned `RNTupleProcessorOptionalPtr`, to ensure that only valid data can be read.
600 template <typename T>
601 RNTupleProcessorOptionalPtr<T> RequestField(const std::string &fieldName, void *valuePtr = nullptr)
602 {
604 std::string typeName{};
605 if constexpr (!std::is_void_v<T>) {
606 typeName = ROOT::Internal::GetRenormalizedTypeName(typeid(T));
607 }
608
609 // The field already exists, so return the existing one.
610 if (auto fieldIdx = fEntry->FindFieldIndex(fieldName, typeName)) {
611 auto value = fEntry->GetValue(*fieldIdx);
612 // Need to check that the provided pointer is not conflicting with the existing one
613
614 if (valuePtr != nullptr && valuePtr != value.GetPtr<void>().get()) {
615 throw RException(R__FAIL("attempted to request a field with user-provided value pointer to field \"" +
616 fieldName +
617 "\", which already exists in the entry. To change the underlying value pointer, "
618 "use RNTupleProcessorOptionalPtr::Bind instead."));
619 }
620 return RNTupleProcessorOptionalPtr<T>(fEntry.get(), *fieldIdx);
621 }
622
623 auto fieldIdx = AddFieldToEntry(fieldName, typeName, valuePtr, Internal::RNTupleProcessorProvenance());
624 return RNTupleProcessorOptionalPtr<T>(fEntry.get(), fieldIdx);
625 }
626
627 /////////////////////////////////////////////////////////////////////////////
628 /// \brief Request access to a field for reading during processing.
629 ///
630 /// \param[in] fieldName Name of the requested field.
631 /// \param[in] typeName Type of the requested field.
632 /// \param[in] valuePtr Pointer to bind to the field's value in the entry. If this is a `nullptr`, a pointer will be
633 /// created.
634 ///
635 /// \return An void-type RNTupleProcessorOptionalPtr, which provides access to the field's value.
636 ///
637 /// \warning Provide a `valuePtr` with care! Values may not always be valid for every entry during processing, for
638 /// example when a field is not present in one of the chained processors or when during a join operation, no matching
639 /// entry in the auxiliary processor can be found. Reading `valuePtr` as-is therefore comes with the risk of reading
640 /// invalid data. After passing a pointer to `RequestField`, we *strongly* recommend only accessing its data through
641 /// the interface of the returned `RNTupleProcessorOptionalPtr`, to ensure that only valid data can be read.
643 RequestField(const std::string &fieldName, const std::string &typeName, void *valuePtr = nullptr)
644 {
646 auto fieldIdx = AddFieldToEntry(fieldName, typeName, valuePtr, Internal::RNTupleProcessorProvenance());
647 return RNTupleProcessorOptionalPtr<void>(fEntry.get(), fieldIdx);
648 }
649
650 /////////////////////////////////////////////////////////////////////////////
651 /// \brief Load the entry identified by the entry mapping.
652 ///
653 /// \param[in] mapping Mapping to the entry to load
654 void LoadEntry(const REntryMapping &mapping) { LoadEntryImpl(mapping); }
655
656 /////////////////////////////////////////////////////////////////////////////
657 /// \brief Print a graphical representation of the processor composition.
658 ///
659 /// \param[in,out] output Stream to print to (default is stdout).
660 ///
661 /// ### Example:
662 /// The structure of a processor representing a join between a single primary RNTuple and a chain of two auxiliary
663 /// RNTuples will be printed as follows:
664 /// ~~~
665 /// +-----------------------------+ +-----------------------------+
666 /// | ntuple | | ntuple_aux |
667 /// | ntuple.root | | ntuple_aux1.root |
668 /// +-----------------------------+ +-----------------------------+
669 /// +-----------------------------+
670 /// | ntuple_aux |
671 /// | ntuple_aux2.root |
672 /// +-----------------------------+
673 /// ~~~
674 void PrintStructure(std::ostream &output = std::cout) { PrintStructureImpl(output); }
675
676 // clang-format off
677 /**
678 \class ROOT::Experimental::RNTupleProcessor::RIterator
679 \ingroup NTuple
680 \brief Iterator over the entries of an RNTuple, or vertical concatenation thereof.
681 */
682 // clang-format on
683 class RIterator {
684 private:
687
688 public:
689 using iterator_category = std::forward_iterator_tag;
693
694 RIterator(RNTupleProcessor &processor, ROOT::NTupleSize_t firstEntryIdx) : fProcessor(processor)
695 {
696 if (fProcessor.fEntry && firstEntryIdx != ROOT::kInvalidNTupleIndex) {
698 /*updateFields=*/false);
700 }
701 }
702
704 {
706
707 return *this;
708 }
709
711 {
712 auto &obj = *this;
713 ++(*this);
714 return obj;
715 }
716
718
719 const value_type *operator->() const { return &fEntryMapping; }
720
721 friend bool operator!=(const iterator &lh, const iterator &rh)
722 {
724 }
725 friend bool operator==(const iterator &lh, const iterator &rh)
726 {
728 }
729 };
730
731 RIterator begin() { return RIterator(*this, 0); }
733
734 /////////////////////////////////////////////////////////////////////////////
735 /// \brief Create an RNTupleProcessor for a single RNTuple.
736 ///
737 /// \param[in] ntuple The name and storage location of the RNTuple to process.
738 /// \param[in] opts Options for the processor.
739 ///
740 /// \return A pointer to the newly created RNTupleProcessor.
741 static std::unique_ptr<RNTupleProcessor>
743
744 /////////////////////////////////////////////////////////////////////////////
745 /// \brief Create an RNTupleProcessor for a *chain* (i.e., a vertical combination) of RNTuples.
746 ///
747 /// \param[in] ntuples A list specifying the names and locations of the RNTuples to process.
748 /// \param[in] opts Options for the processor.
749 ///
750 /// \return A pointer to the newly created RNTupleProcessor.
751 static std::unique_ptr<RNTupleProcessor>
752 CreateChain(std::vector<RNTupleOpenSpec> ntuples, const RNTupleProcessorOptions &opts = RNTupleProcessorOptions());
753
754 /////////////////////////////////////////////////////////////////////////////
755 /// \brief Create an RNTupleProcessor for a *chain* (i.e., a vertical combination) of other RNTupleProcessors.
756 ///
757 /// \param[in] innerProcessors A list with the processors to chain.
758 /// \param[in] opts Options for the processor.
759 ///
760 /// \return A pointer to the newly created RNTupleProcessor.
761 static std::unique_ptr<RNTupleProcessor>
762 CreateChain(std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors,
764};
765
766// clang-format off
767/**
768\class ROOT::Experimental::RNTupleSingleProcessor
769\ingroup NTuple
770\brief Processor specialization for processing a single RNTuple.
771*/
772// clang-format on
774 friend class RNTupleProcessor;
775
776private:
778 std::unique_ptr<ROOT::Internal::RPageSource> fPageSource;
779
780 /////////////////////////////////////////////////////////////////////////////
781 /// \brief Create a new field and connect it to the processor's page source.
782 ///
783 /// \param[in] qualifiedFieldName Name of the field to add, prefixed with its parent fields, if applicable.
784 /// \param[in] typeName Type of the field to add.
785 ///
786 /// \return The newly created field.
787 /// \throws ROOT::RException In case the requested field cannot be found on disk.
788 std::unique_ptr<ROOT::RFieldBase>
789 CreateAndConnectField(const std::string &qualifiedFieldName, const std::string &typeName);
790
791 /////////////////////////////////////////////////////////////////////////////
792 /// \brief Connect an existing field to the processor's page source.
793 ///
794 /// \param[in] field Pointer to the field to add
795 ///
796 /// \return The same field, but wrapped in a new unique pointer. This is needed, because in order to add the field to
797 /// the page source it first needs to be attached to its zero field, in order to correctly handle field
798 /// substitutions. Afterwards, we release the field again from the zero field.
799 std::unique_ptr<ROOT::RFieldBase> ConnectField(std::unique_ptr<ROOT::RFieldBase> field);
800
801 /////////////////////////////////////////////////////////////////////////////
802 /// \brief Initialize the processor by creating an (initially empty) `fEntry`, or setting an existing one.
803 ///
804 /// At this point, the page source for the underlying RNTuple of the processor will be created and opened.
805 void Initialize(std::shared_ptr<Internal::RNTupleProcessorEntry> entry = nullptr) final;
806
807 /////////////////////////////////////////////////////////////////////////////
808 /// \brief Connect the provided fields indices in the entry to their on-disk fields.
809 void Connect(const std::unordered_set<Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
810 const Internal::RNTupleProcessorProvenance &provenance = Internal::RNTupleProcessorProvenance(),
811 bool updateFields = false) final;
812
813 /////////////////////////////////////////////////////////////////////////////
814 /// \brief Disconnect the processor from associated physical storage.
815 void Disconnect() final;
816
817 /////////////////////////////////////////////////////////////////////////////
818 /// \brief Set the local entry mapping (for nested processors), according to a global entry number.
819 ///
820 /// \sa ROOT::Experimental::RNTupleProcessor::SetEntryMapping
821 void SetEntryMapping(ROOT::NTupleSize_t globalEntryNumber, REntryMapping &mapping) final;
822
823 /////////////////////////////////////////////////////////////////////////////
824 /// \brief Load the entry identified by the entry mapping.
825 ///
826 /// \sa ROOT::Experimental::RNTupleProcessor::LoadEntryImpl
827 void LoadEntryImpl(const REntryMapping &mapping) final;
828
829 /////////////////////////////////////////////////////////////////////////////
830 /// \brief Get the total number of entries in this processor.
832 {
834 Initialize();
835 return fNEntries;
836 }
837
838 /////////////////////////////////////////////////////////////////////////////
839 /// \brief Check if a field exists on-disk and can be read by the processor.
840 ///
841 /// \sa RNTupleProcessor::CanReadFieldFromDisk()
842 bool CanReadFieldFromDisk(std::string_view fieldName) final;
843
844 /////////////////////////////////////////////////////////////////////////////
845 /// \brief Add a field to the entry.
846 ///
847 /// \sa RNTupleProcessor::AddFieldToEntry()
849 const std::string &fieldName, const std::string &typeName, void *valuePtr = nullptr,
851
852 /////////////////////////////////////////////////////////////////////////////
853 /// \brief Add a field to the entry.
854 ///
855 /// \sa RNTupleProcessor::AddFieldToEntry()
856 Internal::RNTupleProcessorEntry::FieldIndex_t
857 AddFieldToEntry(std::unique_ptr<ROOT::RFieldBase> field, const std::string &fieldName, void *valuePtr,
858 const Internal::RNTupleProcessorProvenance &provenance) final;
859
860 /////////////////////////////////////////////////////////////////////////////
861 /// \brief Add all known fields (from on-disk information) to the entry.
862 ///
863 /// \sa RNTupleProcessor::AddAllFieldsToEntry()
864 void AddAllFieldsToEntry(const Internal::RNTupleProcessorProvenance &provenance, bool includeSubfields) final;
865
866 /////////////////////////////////////////////////////////////////////////////
867 /// \brief Add the entry mappings for this processor to the provided join table.
868 ///
869 /// \sa ROOT::Experimental::RNTupleProcessor::AddEntriesToJoinTable
870 void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset = 0) final;
871
872 /////////////////////////////////////////////////////////////////////////////
873 /// \brief Processor-specific implementation for printing its structure, called by PrintStructure().
874 ///
875 /// \sa ROOT::Experimental::RNTupleProcessor::PrintStructureImpl
876 void PrintStructureImpl(std::ostream &output) const final;
877
878 /////////////////////////////////////////////////////////////////////////////
879 /// \brief Construct a new RNTupleProcessor for processing a single RNTuple.
880 ///
881 /// \param[in] ntuple The source specification (name and storage location) for the RNTuple to process.
882 /// \param[in] opts Options for the processor.
884
885public:
888 RNTupleSingleProcessor &operator=(const RNTupleSingleProcessor &) = delete;
891 {
892 // The entry's fields need to be deleted before fPageSource.
893 if (fEntry)
894 fEntry->Clear();
895 };
896};
897
898// clang-format off
899/**
900\class ROOT::Experimental::RNTupleChainProcessor
901\ingroup NTuple
902\brief Processor specialization for vertically combined (*chained*) RNTupleProcessors.
903*/
904// clang-format on
906 friend class RNTupleProcessor;
907
908private:
909 std::vector<std::unique_ptr<RNTupleProcessor>> fInnerProcessors;
910 std::vector<ROOT::NTupleSize_t> fInnerNEntries;
911
912 ROOT::NTupleSize_t fLastLoadedEntry = 0; //< Last (global) entry number that was loaded
913 std::size_t fCurrentProcessorNumber = 0; //< Number of the currently open inner processor
914
916
917 /////////////////////////////////////////////////////////////////////////////
918 /// \brief Initialize the processor by creating an (initially empty) `fEntry`, or setting an existing one.
919 void Initialize(std::shared_ptr<Internal::RNTupleProcessorEntry> entry = nullptr) final;
920
921 /////////////////////////////////////////////////////////////////////////////
922 /// \brief Connect the provided fields indices in the entry to their on-disk fields.
923 ///
924 /// \sa RNTupleProcessor::Connect()
925 void Connect(const std::unordered_set<Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
926 const Internal::RNTupleProcessorProvenance &provenance = Internal::RNTupleProcessorProvenance(),
927 bool updateFields = false) final;
928
929 /////////////////////////////////////////////////////////////////////////////
930 /// \brief Update the entry to reflect any missing fields in the current inner processor.
931 void ConnectInnerProcessor(std::size_t processorNumber);
932
933 /////////////////////////////////////////////////////////////////////////////
934 /// \brief Disconnect the processor from associated physical storage.
935 void Disconnect() final;
936
937 /////////////////////////////////////////////////////////////////////////////
938 /// \brief Set the local entry mapping (for nested processors), according to a global entry number.
939 ///
940 /// \sa ROOT::Experimental::RNTupleProcessor::SetEntryMapping
941 void SetEntryMapping(ROOT::NTupleSize_t globalEntryNumber, REntryMapping &mapping) final;
942
943 /////////////////////////////////////////////////////////////////////////////
944 /// \brief Load the entry identified by the entry mapping.
945 ///
946 /// \sa ROOT::Experimental::RNTupleProcessor::LoadEntryImpl
947 void LoadEntryImpl(const REntryMapping &mapping) final;
948
949 /////////////////////////////////////////////////////////////////////////////
950 /// \brief Get the total number of entries in this processor.
951 ///
952 /// \note This requires opening all underlying RNTuples being processed in the chain, and could become costly!
954
955 /////////////////////////////////////////////////////////////////////////////
956 /// \brief Check if a field exists on-disk and can be read by the processor.
957 ///
958 /// \sa RNTupleProcessor::CanReadFieldFromDisk()
959 bool CanReadFieldFromDisk(std::string_view fieldName) final
960 {
961 return fInnerProcessors[fCurrentProcessorNumber]->CanReadFieldFromDisk(fieldName);
962 }
963
964 /////////////////////////////////////////////////////////////////////////////
965 /// \brief Add a field to the entry.
966 ///
967 /// \sa RNTupleProcessor::AddFieldToEntry()
969 const std::string &fieldName, const std::string &typeName, void *valuePtr = nullptr,
971
972 /////////////////////////////////////////////////////////////////////////////
973 /// \brief Add a field to the entry.
974 ///
975 /// \sa RNTupleProcessor::AddFieldToEntry()
976 Internal::RNTupleProcessorEntry::FieldIndex_t
977 AddFieldToEntry(std::unique_ptr<ROOT::RFieldBase> field, const std::string &fieldName, void *valuePtr,
978 const Internal::RNTupleProcessorProvenance &provenance) final;
979
980 /////////////////////////////////////////////////////////////////////////////
981 /// \brief Add all known fields (from on-disk information) to the entry.
982 ///
983 /// \sa RNTupleProcessor::AddAllFieldsToEntry()
984 void AddAllFieldsToEntry(const Internal::RNTupleProcessorProvenance &provenance, bool includeSubfields) final;
985
986 /////////////////////////////////////////////////////////////////////////////
987 /// \brief Add the entry mappings for this processor to the provided join table.
988 ///
989 /// \sa ROOT::Experimental::RNTupleProcessor::AddEntriesToJoinTable
990 void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset = 0) final;
991
992 /////////////////////////////////////////////////////////////////////////////
993 /// \brief Processor-specific implementation for printing its structure, called by PrintStructure().
994 ///
995 /// \sa ROOT::Experimental::RNTupleProcessor::PrintStructureImpl
996 void PrintStructureImpl(std::ostream &output) const final;
997
998 /////////////////////////////////////////////////////////////////////////////
999 /// \brief Construct a new RNTupleChainProcessor.
1000 ///
1001 /// \param[in] ntuples The source specification (name and storage location) for each RNTuple to process.
1002 /// \param[in] opts Options for the processor.
1003 ///
1004 /// RNTuples are processed in the order in which they are specified.
1005 RNTupleChainProcessor(std::vector<std::unique_ptr<RNTupleProcessor>> processors,
1006 const RNTupleProcessorOptions &opts);
1007
1008public:
1011 RNTupleChainProcessor &operator=(const RNTupleChainProcessor &) = delete;
1013 ~RNTupleChainProcessor() override = default;
1014};
1015
1016// clang-format off
1017/**
1018\class ROOT::Experimental::RNTupleJoinProcessor
1019\ingroup NTuple
1020\brief Processor specialization for horizontally combined (*joined*) RNTupleProcessors.
1021*/
1022// clang-format on
1024 friend class RNTupleProcessor;
1025 friend std::unique_ptr<RNTupleProcessor>
1026 CreateRNTupleJoinProcessor(std::unique_ptr<RNTupleProcessor> primaryProcessor,
1027 std::unique_ptr<RNTupleProcessor> auxProcessor,
1028 const std::vector<std::string> &joinFields, const RNTupleProcessorOptions &opts);
1029
1030private:
1031 std::unique_ptr<RNTupleProcessor> fPrimaryProcessor;
1032 std::unique_ptr<RNTupleProcessor> fAuxiliaryProcessor;
1033
1034 std::vector<std::string> fJoinFieldNames;
1035 std::set<Internal::RNTupleProcessorEntry::FieldIndex_t> fJoinFieldIdxs;
1036
1037 std::unique_ptr<Internal::RNTupleJoinTable> fJoinTable;
1038 bool fJoinTableIsBuilt = false;
1039
1040 std::unordered_set<Internal::RNTupleProcessorEntry::FieldIndex_t> fAuxiliaryFieldIdxs;
1041
1042 /// \brief Initialize the processor by creating an (initially empty) `fEntry`, or setting an existing one.
1043 void Initialize(std::shared_ptr<Internal::RNTupleProcessorEntry> entry = nullptr) final;
1044
1045 /////////////////////////////////////////////////////////////////////////////
1046 /// \brief Connect the provided fields indices in the entry to their on-disk fields.
1047 ///
1048 /// \sa RNTupleProcessor::Connect()
1049 void Connect(const std::unordered_set<Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
1050 const Internal::RNTupleProcessorProvenance &provenance = Internal::RNTupleProcessorProvenance(),
1051 bool updateFields = false) final;
1052
1053 /////////////////////////////////////////////////////////////////////////////
1054 /// \brief Disconnect the processor from associated physical storage.
1055 void Disconnect() final;
1056
1057 /////////////////////////////////////////////////////////////////////////////
1058 /// \brief Set the local entry mapping (for nested processors), according to a global entry number.
1059 ///
1060 /// \sa ROOT::Experimental::RNTupleProcessor::SetEntryMapping
1061 void SetEntryMapping(ROOT::NTupleSize_t globalEntryNumber, REntryMapping &mapping) final;
1062
1063 /////////////////////////////////////////////////////////////////////////////
1064 /// \brief Load the entry identified by the entry mapping.
1065 ///
1066 /// \sa ROOT::Experimental::RNTupleProcessor::LoadEntryImpl
1067 void LoadEntryImpl(const REntryMapping &mapping) final;
1068
1069 /////////////////////////////////////////////////////////////////////////////
1070 /// \brief Get the total number of entries in this processor.
1071 ROOT::NTupleSize_t GetNEntries() final;
1072
1073 /////////////////////////////////////////////////////////////////////////////
1074 /// \brief Set the validity for all fields in the auxiliary processor at once.
1075 void SetAuxiliaryFieldValidity(bool validity);
1076
1077 /////////////////////////////////////////////////////////////////////////////
1078 /// \brief Check if a field exists on-disk and can be read by the processor.
1079 ///
1080 /// \sa RNTupleProcessor::CanReadFieldFromDisk()
1081 bool CanReadFieldFromDisk(std::string_view fieldName) final
1082 {
1083 if (!fPrimaryProcessor->CanReadFieldFromDisk(fieldName)) {
1084 if (fieldName.find(fAuxiliaryProcessor->fOptions.GetProcessorName()) == 0)
1085 fieldName = fieldName.substr(fAuxiliaryProcessor->fOptions.GetProcessorName().size() + 1);
1086 return fAuxiliaryProcessor->CanReadFieldFromDisk(fieldName);
1087 }
1088
1089 return true;
1090 }
1091
1092 /////////////////////////////////////////////////////////////////////////////
1093 /// \brief Add a field to the entry.
1094 ///
1095 /// \sa RNTupleProcessor::AddFieldToEntry()
1097 const std::string &fieldName, const std::string &typeName, void *valuePtr = nullptr,
1099
1100 /////////////////////////////////////////////////////////////////////////////
1101 /// \brief Add a field to the entry.
1102 ///
1103 /// \sa RNTupleProcessor::AddFieldToEntry()
1104 Internal::RNTupleProcessorEntry::FieldIndex_t
1105 AddFieldToEntry(std::unique_ptr<ROOT::RFieldBase> field, const std::string &fieldName, void *valuePtr,
1106 const Internal::RNTupleProcessorProvenance &provenance) final;
1107
1108 /////////////////////////////////////////////////////////////////////////////
1109 /// \brief Add all known fields (from on-disk information) to the entry.
1110 ///
1111 /// \sa RNTupleProcessor::AddAllFieldsToEntry()
1112 void AddAllFieldsToEntry(const Internal::RNTupleProcessorProvenance &provenance, bool includeSubfields) final;
1113
1114 /////////////////////////////////////////////////////////////////////////////
1115 /// \brief Add the entry mappings for this processor to the provided join table.
1116 ///
1117 /// \sa ROOT::Experimental::RNTupleProcessor::AddEntriesToJoinTable
1118 void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset = 0) final;
1119
1120 /////////////////////////////////////////////////////////////////////////////
1121 /// \brief Processor-specific implementation for printing its structure, called by PrintStructure().
1122 ///
1123 /// \sa ROOT::Experimental::RNTupleProcessor::PrintStructureImpl
1124 void PrintStructureImpl(std::ostream &output) const final;
1125
1126 /////////////////////////////////////////////////////////////////////////////
1127 /// \brief Construct a new RNTupleJoinProcessor.
1128 /// \param[in] primaryProcessor The primary processor. Its entries are processed in sequential order.
1129 /// \param[in] auxProcessor The processor to join the primary processor with. The order in which its entries are
1130 /// processed is determined by the primary processor and doesn't necessarily have to be sequential.
1131 /// \param[in] joinFields The names of the fields on which to join, in case the specified processors are unaligned.
1132 /// The join is made based on the combined join field values, and therefore each field has to be present in each
1133 /// specified processor. If an empty list is provided, it is assumed that the processors are fully aligned.
1134 /// \param[in] opts Options for the processor.
1135 RNTupleJoinProcessor(std::unique_ptr<RNTupleProcessor> primaryProcessor,
1136 std::unique_ptr<RNTupleProcessor> auxProcessor, const std::vector<std::string> &joinFields,
1137 const RNTupleProcessorOptions &opts);
1138
1139public:
1141 RNTupleJoinProcessor operator=(const RNTupleJoinProcessor &) = delete;
1144 ~RNTupleJoinProcessor() override = default;
1145};
1146
1147} // namespace Experimental
1148} // namespace ROOT
1149
1150#endif // ROOT_RNTupleProcessor
#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:322
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:142
Builds a join table on one or several fields of an RNTuple so it can be joined onto other RNTuples.
Collection of values in an RNTupleProcessor, analogous to REntry, with checks and support for missing...
void Bind(FieldIndex_t fieldIdx, std::shared_ptr< void > valuePtr)
Bind a new value pointer to a field in the entry.
void BindRawPtr(FieldIndex_t fieldIdx, void *valuePtr)
Bind a new value pointer to a field in the entry.
const ROOT::RFieldBase::RValue & GetValue(FieldIndex_t fieldIdx) const
bool IsValidField(FieldIndex_t fieldIdx) const
Check whether a field is valid for reading.
const std::string & FindFieldName(FieldIndex_t fieldIdx) const
Find the name of a field from its field index.
The RDataSource implementation for the RNTupleProcessor.
Processor specialization for vertically combined (chained) RNTupleProcessors.
bool CanReadFieldFromDisk(std::string_view fieldName) final
Check if a field exists on-disk and can be read by the processor.
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.
Internal::RNTupleProcessorProvenance fProvenance
void AddAllFieldsToEntry(const Internal::RNTupleProcessorProvenance &provenance, bool includeSubfields) final
Add all known fields (from on-disk information) 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 LoadEntryImpl(const REntryMapping &mapping) final
Load the entry identified by the entry mapping.
void SetEntryMapping(ROOT::NTupleSize_t globalEntryNumber, REntryMapping &mapping) final
Set the local entry mapping (for nested processors), according to a global entry number.
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 Disconnect() final
Disconnect the processor from associated physical storage.
std::vector< std::unique_ptr< RNTupleProcessor > > fInnerProcessors
Processor specialization for horizontally combined (joined) RNTupleProcessors.
std::set< Internal::RNTupleProcessorEntry::FieldIndex_t > fJoinFieldIdxs
std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > fAuxiliaryFieldIdxs
std::unique_ptr< RNTupleProcessor > fPrimaryProcessor
std::unique_ptr< Internal::RNTupleJoinTable > fJoinTable
friend std::unique_ptr< RNTupleProcessor > CreateRNTupleJoinProcessor(std::unique_ptr< RNTupleProcessor > primaryProcessor, std::unique_ptr< RNTupleProcessor > auxProcessor, const std::vector< std::string > &joinFields, const RNTupleProcessorOptions &opts)
Create an RNTupleProcessor for a join (i.e., a horizontal combination) of RNTuples.
std::unique_ptr< RNTupleProcessor > fAuxiliaryProcessor
Specification of the name and location of an RNTuple, used for creating a new RNTupleProcessor.
RNTupleOpenSpec(std::string_view n, const std::string &s)
std::variant< std::string, TDirectory * > fStorage
RNTupleOpenSpec(std::string_view n, TDirectory *s)
std::unique_ptr< ROOT::Internal::RPageSource > CreatePageSource() const
RNTupleProcessorOptionalPtr(Internal::RNTupleProcessorEntry *processorEntry, Internal::RNTupleProcessorEntry::FieldIndex_t fieldIdx)
void BindRawPtr(void *valuePtr)
Bind the value to valuePtr.
void * GetRawPtr() const
Get a non-owning pointer to the field value managed by the processor's entry.
Internal::RNTupleProcessorEntry::FieldIndex_t fFieldIndex
friend bool operator==(const RNTupleProcessorOptionalPtr< void > &lhs, const RNTupleProcessorOptionalPtr< void > &rhs)
std::shared_ptr< void > GetPtr() const
Get the pointer to the field value managed by the processor's entry.
bool HasValue() const
Check if the pointer currently holds a valid value.
void Bind(std::shared_ptr< void > valuePtr)
Bind the value to valuePtr.
std::shared_ptr< T > GetPtr() const
Get a shared pointer to the field value managed by the processor's entry.
void Bind(std::shared_ptr< T > valuePtr)
Bind the value to valuePtr.
const T & operator*() const
Get a reference to the field value managed by the processor's entry.
Internal::RNTupleProcessorEntry::FieldIndex_t fFieldIndex
friend bool operator==(const RNTupleProcessorOptionalPtr< T > &lhs, const RNTupleProcessorOptionalPtr< T > &rhs)
const T * operator->() const
Access the field value managed by the processor's entry.
void BindRawPtr(T *valuePtr)
Bind the value to valuePtr.
bool HasValue() const
Check if the pointer currently holds a valid value.
T * GetRawPtr() const
Get a non-owning pointer to the field value managed by the processor's entry.
Internal::RNTupleProcessorEntry * fProcessorEntry
RNTupleProcessorOptionalPtr(Internal::RNTupleProcessorEntry *processorEntry, Internal::RNTupleProcessorEntry::FieldIndex_t fieldIdx)
std::string fProcessorName
By default, the processor name is the name of the underlying RNTuple for RNTupleSingleProcessor,...
Identifies how a processor is composed.
Maps a processor's global (outer) entry index to its inner ones.
friend bool operator==(const REntryMapping &lhs, const REntryMapping &rhs)
void SetEntryNumber(ROOT::NTupleSize_t entryNumber)
friend bool operator!=(const REntryMapping &lhs, const REntryMapping &rhs)
Iterator over the entries of an RNTuple, or vertical concatenation thereof.
RIterator(RNTupleProcessor &processor, ROOT::NTupleSize_t firstEntryIdx)
friend bool operator==(const iterator &lh, const iterator &rh)
friend bool operator!=(const iterator &lh, const iterator &rh)
Interface for iterating over entries of vertically ("chained") and/or horizontally ("joined") combine...
Internal::RNTupleProcessorEntry & GetEntry()
Get a reference to the processor's internal entry.
virtual bool CanReadFieldFromDisk(std::string_view fieldName)=0
Check if a field exists on-disk and can be read by the processor.
virtual Internal::RNTupleProcessorEntry::FieldIndex_t AddFieldToEntry(std::unique_ptr< ROOT::RFieldBase > field, const std::string &canonicalFieldName, void *valuePtr, const Internal::RNTupleProcessorProvenance &provenance)=0
Add a field to the entry.
static std::unique_ptr< RNTupleProcessor > CreateChain(std::vector< RNTupleOpenSpec > ntuples, const RNTupleProcessorOptions &opts=RNTupleProcessorOptions())
Create an RNTupleProcessor for a chain (i.e., a vertical combination) of RNTuples.
RNTupleProcessorOptionalPtr< T > RequestField(const std::string &fieldName, void *valuePtr=nullptr)
Request access to a field for reading during processing.
virtual ROOT::NTupleSize_t GetNEntries()=0
Get the total number of entries in this processor.
ROOT::NTupleSize_t fNEntries
Total number of entries.
RNTupleProcessorOptionalPtr< void > RequestField(const std::string &fieldName, const std::string &typeName, void *valuePtr=nullptr)
Request access to a field for reading during processing.
friend struct ROOT::Experimental::Internal::RNTupleProcessorEntryLoader
virtual void AddAllFieldsToEntry(const Internal::RNTupleProcessorProvenance &provenance, bool includeSubfields)=0
Add all known fields (from on-disk information) to the entry.
const RNTupleProcessorOptions & GetOptions() const
Get the options used for this processor.
RNTupleProcessor(RNTupleProcessor &&)=delete
std::shared_ptr< Internal::RNTupleProcessorEntry > fEntry
virtual void PrintStructureImpl(std::ostream &output) const =0
Processor-specific implementation for printing its structure, called by PrintStructure().
virtual void Connect(const std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > &fieldIdxs, const Internal::RNTupleProcessorProvenance &provenance, bool updateFields)=0
Connect fields to the page source of the processor's underlying RNTuple(s).
virtual Internal::RNTupleProcessorEntry::FieldIndex_t AddFieldToEntry(const std::string &canonicalFieldName, const std::string &typeName, void *valuePtr, const Internal::RNTupleProcessorProvenance &provenance)=0
Add a field to the entry.
virtual void Disconnect()=0
Disconnect the processor from associated physical storage.
std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > fFieldIdxs
virtual void Initialize(std::shared_ptr< Internal::RNTupleProcessorEntry > entry)=0
Initialize the processor by creating an (initially empty) fEntry, or setting an existing one.
bool IsInitialized() const
Check if the processor already has been initialized.
virtual void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset=0)=0
Add the entry mappings for this processor to the provided join table.
const Internal::RNTupleProcessorEntry & GetEntry() const
Get a reference to the processor's internal entry.
void IncrementEntryMapping(REntryMapping &mapping)
Increment the local entry mapping by one.
void PrintStructure(std::ostream &output=std::cout)
Print a graphical representation of the processor composition.
void LoadEntry(const REntryMapping &mapping)
Load the entry identified by the entry mapping.
ROOT::NTupleSize_t GetNEntriesProcessed() const
Get the total number of entries processed so far.
RNTupleProcessor(const RNTupleProcessorOptions &options)
Create a new base RNTupleProcessor.
RNTupleProcessor(const RNTupleProcessor &)=delete
RNTupleProcessor & operator=(RNTupleProcessor &&)=delete
virtual void SetEntryMapping(ROOT::NTupleSize_t globalEntryNumber, REntryMapping &mapping)=0
Set the local entry mapping (for nested processors), according to a global entry number.
virtual void LoadEntryImpl(const REntryMapping &mapping)=0
Load the entry identified by the entry mapping.
static std::unique_ptr< RNTupleProcessor > Create(RNTupleOpenSpec ntuple, const RNTupleProcessorOptions &opts=RNTupleProcessorOptions())
Create an RNTupleProcessor for a single RNTuple.
RNTupleProcessor & operator=(const RNTupleProcessor &)=delete
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.
std::unique_ptr< ROOT::RFieldBase > ConnectField(std::unique_ptr< ROOT::RFieldBase > field)
Connect an existing field to the processor's page source.
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().
void Disconnect() final
Disconnect the processor from associated physical storage.
std::unique_ptr< ROOT::Internal::RPageSource > fPageSource
void LoadEntryImpl(const REntryMapping &mapping) final
Load the entry identified by the entry mapping.
bool CanReadFieldFromDisk(std::string_view fieldName) final
Check if a field exists on-disk and can be read by the processor.
void SetEntryMapping(ROOT::NTupleSize_t globalEntryNumber, REntryMapping &mapping) final
Set the local entry mapping (for nested processors), according to a global entry number.
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 AddAllFieldsToEntry(const Internal::RNTupleProcessorProvenance &provenance, bool includeSubfields) final
Add all known fields (from on-disk information) 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.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
A field translates read and write calls from/to underlying columns to/from tree values.
Describe directory structure in memory.
Definition TDirectory.h:45
const Int_t n
Definition legend1.C:16
const RNTupleProcessorEntry * LoadFullRNTupleProcessorEntry(ROOT::Experimental::RNTupleProcessor &processor, bool includeSubfields)
std::unique_ptr< RNTupleProcessor > CreateRNTupleJoinProcessor(RNTupleOpenSpec primaryNTuple, RNTupleOpenSpec auxNTuple, const std::vector< std::string > &joinFields, const RNTupleProcessorOptions &opts=RNTupleProcessorOptions())
Create an RNTupleProcessor for a join (i.e., a horizontal combination) of RNTuples.
std::string GetRenormalizedTypeName(const std::string &metaNormalizedName)
Given a type name normalized by ROOT meta, renormalize it for RNTuple. E.g., insert std::prefix.
constexpr NTupleSize_t kInvalidNTupleIndex
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.