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