Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleView.hxx
Go to the documentation of this file.
1/// \file ROOT/RNTupleView.hxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2018-10-05
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#ifndef ROOT_RNTupleView
14#define ROOT_RNTupleView
15
16#include <ROOT/RError.hxx>
17#include <ROOT/RField.hxx>
18#include <ROOT/RNTupleRange.hxx>
19#include <ROOT/RNTupleTypes.hxx>
20#include <ROOT/RNTupleUtils.hxx>
21#include <string_view>
22
23#include <iterator>
24#include <memory>
25#include <type_traits>
26#include <utility>
27#include <unordered_map>
28
29namespace ROOT {
30
31class RNTupleReader;
32
33namespace Internal {
34
35/// Helper to get the iteration space of the given field that needs to be connected to the given page source.
36/// The indexes are given by the number of elements of the principal column of the field or, if none exists,
37/// by the number of elements of the first principal column found in the subfields searched by BFS.
38/// If the field hierarchy is empty on columns, the returned field range is invalid (start and end set to
39/// kInvalidNTupleIndex). An attempt to use such a field range in RNTupleViewBase::GetFieldRange will throw.
41
42} // namespace Internal
43
44// clang-format off
45/**
46\class ROOT::RNTupleViewBase
47\ingroup NTuple
48\brief An RNTupleView provides read-only access to a single field of an RNTuple
49
50\tparam T The type of the object that will be read by the view; can be void if unknown at compile time.
51
52The view owns a field and its underlying columns in order to fill an RField::RValue object with data. Data can be
53accessed by index. For top-level fields, the index refers to the entry number. Fields that are part of
54nested collections have global index numbers that are derived from their parent indexes (\see GetFieldRange()).
55
56View can only be created by a reader or by a collection view.
57
58**Example: read an RNTuple's field with a view**
59~~~ {.cpp}
60auto reader = RNTupleReader::Open("myNtuple", "myntuple.root");
61auto viewFoo = reader->GetView<float>("foo");
62for (auto idx : reader->GetEntryRange()) {
63 float foo = viewFoo(idx); // read field "foo" of the `idx`-th entry
64 std::cout << foo << "\n";
65}
66~~~
67
68**Example: read an RNTuple's collection subfield with a view**
69~~~ {.cpp}
70auto reader = RNTupleReader::Open("myNtuple", "myntuple.root");
71// Assuming "v" is a std::vector<int>:
72auto view = reader->GetView<int>("v._0");
73// Effectively flattens all fields "v" in all entries and reads their elements.
74for (auto idx : view.GetFieldRange()) {
75 int x = view(idx);
76 std::cout << x << "\n";
77}
78~~~
79*/
80// clang-format on
81template <typename T>
83protected:
84 std::unique_ptr<ROOT::RFieldBase> fField;
87
88 static std::unique_ptr<ROOT::RFieldBase>
90 {
93 std::unique_ptr<ROOT::RFieldBase> field;
94 {
95 auto descGuard = pageSource.GetSharedDescriptorGuard();
96 const auto &desc = descGuard.GetRef();
97 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
98 if constexpr (std::is_void_v<T>) {
99 if (typeName.empty())
100 field = fieldDesc.CreateField(desc);
101 else
102 field = ROOT::RFieldBase::Create(fieldDesc.GetFieldName(), std::string(typeName)).Unwrap();
103 } else {
104 field = std::make_unique<ROOT::RField<T>>(fieldDesc.GetFieldName());
105 }
106 }
107 field->SetOnDiskId(fieldId);
108 fieldZero.Attach(std::move(field));
110 return std::move(fieldZero.ReleaseSubfields()[0]);
111 }
112
113 RNTupleViewBase(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range)
114 : fField(std::move(field)), fFieldRange(range), fValue(fField->CreateValue())
115 {
116 }
117
118 RNTupleViewBase(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
119 : fField(std::move(field)), fFieldRange(range), fValue(fField->BindValue(std::move(objPtr)))
120 {
121 }
122
123 RNTupleViewBase(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, T *rawPtr)
124 : fField(std::move(field)),
126 fValue(fField->BindValue(ROOT::Internal::MakeAliasedSharedPtr(rawPtr)))
127 {
128 }
129
130public:
135 ~RNTupleViewBase() = default;
136
137 const ROOT::RFieldBase &GetField() const { return *fField; }
139
140 const ROOT::RFieldBase::RValue &GetValue() const { return fValue; }
141 /// Returns the global field range of this view.
142 /// This may differ from the RNTuple's entry range in case of subfields and can be used to iterate
143 /// over all the concatenated elements of the subfield without caring which entry they belong to.
144 /// Throws an RException if the underlying field of this view is empty, i.e. if it's a class or
145 /// record field with no associated columns.
147 {
148 if (!fFieldRange.IsValid()) {
149 throw RException(R__FAIL("field iteration over empty fields in vectors or variants is unsupported: " +
150 fField->GetFieldName()));
151 }
152 return fFieldRange;
153 }
154
155 void Bind(std::shared_ptr<T> objPtr) { fValue.Bind(objPtr); }
158};
159
160// clang-format off
161/**
162\class ROOT::RNTupleView
163\ingroup NTuple
164\brief An RNTupleView for a known type. See RNTupleViewBase.
165*/
166// clang-format on
167template <typename T>
168class RNTupleView : public RNTupleViewBase<T> {
171
172protected:
173 RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range)
174 : RNTupleViewBase<T>(std::move(field), range)
175 {
176 }
177
178 RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
180 {
181 }
182
183 RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, T *rawPtr)
185 {
186 }
187
188 const T &GetValueRef() const
189 {
190 // We created the RValue and know its type, avoid extra checks.
191 void *ptr = RNTupleViewBase<T>::fValue.template GetPtr<void>().get();
192 return *static_cast<T *>(ptr);
193 }
194
195public:
196 RNTupleView(const RNTupleView &other) = delete;
200 ~RNTupleView() = default;
201
202 /// Reads the value of this view for the entry with the provided `globalIndex`.
208
209 /// Reads the value of this view for the entry with the provided `localIndex`.
210 /// See RNTupleLocalIndex for more details.
216};
217
218// clang-format off
219/**
220\class ROOT::RNTupleView
221\ingroup NTuple
222\brief An RNTupleView that can be used when the type is unknown at compile time. See RNTupleViewBase.
223*/
224// clang-format on
225template <>
226class RNTupleView<void> final : public RNTupleViewBase<void> {
229
230protected:
231 RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range)
232 : RNTupleViewBase<void>(std::move(field), range)
233 {
234 }
235
236 RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, std::shared_ptr<void> objPtr)
237 : RNTupleViewBase<void>(std::move(field), range, std::move(objPtr))
238 {
239 }
240
241 RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, void *rawPtr)
242 : RNTupleViewBase<void>(std::move(field), range, rawPtr)
243 {
244 }
245
246public:
247 RNTupleView(const RNTupleView &other) = delete;
251 ~RNTupleView() = default;
252
253 /// \see RNTupleView::operator()(ROOT::NTupleSize_t)
255 /// \see RNTupleView::operator()(RNTupleLocalIndex)
257};
258
259// clang-format off
260/**
261\class ROOT::RNTupleDirectAccessView
262\ingroup NTuple
263\brief A view variant that provides direct access to the I/O buffers. Only works for mappable fields.
264*/
265// clang-format on
266template <typename T>
270
271protected:
274
276 {
277 auto descGuard = pageSource.GetSharedDescriptorGuard();
278 const auto &desc = descGuard.GetRef();
279 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
280 if (!Internal::IsMatchingFieldType<T>(fieldDesc.GetTypeName())) {
281 throw RException(R__FAIL("type mismatch for field " + fieldDesc.GetFieldName() + ": " +
282 fieldDesc.GetTypeName() + " vs. " + ROOT::RField<T>::TypeName()));
283 }
284 ROOT::RField<T> field(fieldDesc.GetFieldName());
285 field.SetOnDiskId(fieldId);
287 return field;
288 }
289
294
295public:
301
302 const ROOT::RFieldBase &GetField() const { return fField; }
303 /// \see RNTupleView::GetFieldRange()
305
306 /// \see RNTupleView::operator()(ROOT::NTupleSize_t)
308 /// \see RNTupleView::operator()(RNTupleLocalIndex)
310};
311
312// clang-format off
313/**
314\class ROOT::RNTupleCollectionView
315\ingroup NTuple
316\brief A view for a collection, that can itself generate new ntuple views for its nested fields.
317*
318* The collection view's call operator returns the size of the collection. The collection view can also return
319* the element range and it can create subviews for fields inside the collection.
320*/
321// clang-format on
324
325private:
329
337
339 {
340 std::string fieldName;
341 {
342 auto descGuard = source->GetSharedDescriptorGuard();
343 const auto &desc = descGuard.GetRef();
344 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
345 if (fieldDesc.GetStructure() != ROOT::ENTupleStructure::kCollection) {
346 throw RException(
347 R__FAIL("invalid attemt to create collection view on non-collection field " + fieldDesc.GetFieldName()));
348 }
349 fieldName = fieldDesc.GetFieldName();
350 }
352 }
353
355 {
357 auto fieldId = descGuard->FindFieldId(fieldName, fField.GetOnDiskId());
359 throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in collection '" +
360 descGuard->GetQualifiedFieldName(fField.GetOnDiskId()) + "'"));
361 }
362 return fieldId;
363 }
364
365 std::uint64_t GetCardinalityValue() const
366 {
367 // We created the RValue and know its type, avoid extra checks.
368 void *ptr = fValue.GetPtr<void>().get();
369 return *static_cast<RNTupleCardinality<std::uint64_t> *>(ptr);
370 }
371
372public:
380 {
381 if (this == &other)
382 return *this;
383 std::swap(fSource, other.fSource);
384 std::swap(fField, other.fField);
385 fValue = fField.CreateValue();
386 return *this;
387 }
389
398
407
408 /// Provides access to an individual (sub)field.
409 ///
410 /// Raises an exception if there is no field with the given name.
411 ///
412 /// \sa ROOT::RNTupleReader::GetView(std::string_view)
413 template <typename T>
420
421 /// Provides direct access to the I/O buffers of a **mappable** (sub)field.
422 ///
423 /// Raises an exception if there is no field with the given name.
424 /// Attempting to access the values of a direct-access view for non-mappable fields will yield compilation errors.
425 ///
426 /// \sa ROOT::RNTupleReader::DirectAccessView(std::string_view)
427 template <typename T>
434
435 /// Provides access to a collection field, that can itself generate new RNTupleViews for its nested fields.
436 ///
437 /// Raises an exception if:
438 /// * there is no field with the given name or,
439 /// * the field is not a collection
440 ///
441 /// \sa ROOT::RNTupleReader::GetCollectionView(std::string_view)
446
447 /// \see RNTupleView::operator()(ROOT::NTupleSize_t)
453
454 /// \see RNTupleView::operator()(RNTupleLocalIndex)
456 {
458 return GetCardinalityValue();
459 }
460};
461
462} // namespace ROOT
463
464#endif
#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
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Abstract interface to read data from an ntuple.
RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Points to an array of objects with RNTuple I/O support, used for bulk reading.
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
void Read(ROOT::NTupleSize_t globalIndex)
void EmplaceNew()
Replace the current object pointer by a pointer to a new object constructed by the field.
void Bind(std::shared_ptr< void > objPtr)
std::shared_ptr< T > GetPtr() const
void BindRawPtr(void *rawPtr)
A field translates read and write calls from/to underlying columns to/from tree values.
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
Factory method to resurrect a field from the stored on-disk type information.
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:58
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:331
A view for a collection, that can itself generate new ntuple views for its nested fields.
ROOT::DescriptorId_t GetFieldId(std::string_view fieldName)
RNTupleCollectionView & operator=(const RNTupleCollectionView &other)=delete
std::uint64_t GetCardinalityValue() const
RNTupleView< T > GetView(std::string_view fieldName)
Provides access to an individual (sub)field.
RNTupleCollectionView(const RNTupleCollectionView &other)=delete
RNTupleCollectionView(ROOT::DescriptorId_t fieldId, const std::string &fieldName, ROOT::Internal::RPageSource *source)
ROOT::Internal::RPageSource * fSource
ROOT::RNTupleLocalRange GetCollectionRange(ROOT::NTupleSize_t globalIndex)
std::uint64_t operator()(ROOT::NTupleSize_t globalIndex)
RNTupleCollectionView GetCollectionView(std::string_view fieldName)
Provides access to a collection field, that can itself generate new RNTupleViews for its nested field...
ROOT::RField< RNTupleCardinality< std::uint64_t > > fField
RNTupleCollectionView & operator=(RNTupleCollectionView &&other)
ROOT::RFieldBase::RValue fValue
static RNTupleCollectionView Create(ROOT::DescriptorId_t fieldId, ROOT::Internal::RPageSource *source)
RNTupleDirectAccessView< T > GetDirectAccessView(std::string_view fieldName)
Provides direct access to the I/O buffers of a mappable (sub)field.
RNTupleCollectionView(RNTupleCollectionView &&other)
std::uint64_t operator()(RNTupleLocalIndex localIndex)
ROOT::RNTupleLocalRange GetCollectionRange(RNTupleLocalIndex localIndex)
A view variant that provides direct access to the I/O buffers.
ROOT::RNTupleGlobalRange GetFieldRange() const
RNTupleDirectAccessView & operator=(RNTupleDirectAccessView &&other)=default
RNTupleDirectAccessView(ROOT::RField< T > field, ROOT::RNTupleGlobalRange range)
RNTupleDirectAccessView & operator=(const RNTupleDirectAccessView &other)=delete
static ROOT::RField< T > CreateField(ROOT::DescriptorId_t fieldId, ROOT::Internal::RPageSource &pageSource)
ROOT::RNTupleGlobalRange fFieldRange
RNTupleDirectAccessView(const RNTupleDirectAccessView &other)=delete
const T & operator()(RNTupleLocalIndex localIndex)
const T & operator()(ROOT::NTupleSize_t globalIndex)
RNTupleDirectAccessView(RNTupleDirectAccessView &&other)=default
const ROOT::RFieldBase & GetField() const
Used to loop over indexes (entries or collections) between start and end.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Used to loop over entries of collections in a single cluster.
Reads RNTuple data from storage.
An RNTupleView provides read-only access to a single field of an RNTuple.
const ROOT::RFieldBase & GetField() const
const ROOT::RFieldBase::RValue & GetValue() const
void BindRawPtr(T *rawPtr)
RNTupleViewBase & operator=(const RNTupleViewBase &other)=delete
static std::unique_ptr< ROOT::RFieldBase > CreateField(ROOT::DescriptorId_t fieldId, Internal::RPageSource &pageSource, std::string_view typeName="")
std::unique_ptr< ROOT::RFieldBase > fField
RNTupleViewBase(RNTupleViewBase &&other)=default
ROOT::RNTupleGlobalRange GetFieldRange() const
Returns the global field range of this view.
ROOT::RFieldBase::RBulkValues CreateBulk()
ROOT::RNTupleGlobalRange fFieldRange
ROOT::RFieldBase::RValue fValue
RNTupleViewBase & operator=(RNTupleViewBase &&other)=default
~RNTupleViewBase()=default
RNTupleViewBase(const RNTupleViewBase &other)=delete
RNTupleViewBase(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range)
void Bind(std::shared_ptr< T > objPtr)
RNTupleViewBase(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range, std::shared_ptr< T > objPtr)
RNTupleViewBase(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range, T *rawPtr)
RNTupleView(const RNTupleView &other)=delete
void operator()(ROOT::NTupleSize_t globalIndex)
RNTupleView(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range, void *rawPtr)
RNTupleView & operator=(const RNTupleView &other)=delete
RNTupleView(RNTupleView &&other)=default
RNTupleView(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range)
void operator()(RNTupleLocalIndex localIndex)
RNTupleView & operator=(RNTupleView &&other)=default
RNTupleView(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range, std::shared_ptr< void > objPtr)
An RNTupleView for a known type.
RNTupleView & operator=(const RNTupleView &other)=delete
RNTupleView(RNTupleView &&other)=default
RNTupleView(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range, T *rawPtr)
RNTupleView(const RNTupleView &other)=delete
const T & GetValueRef() const
const T & operator()(RNTupleLocalIndex localIndex)
Reads the value of this view for the entry with the provided localIndex.
RNTupleView & operator=(RNTupleView &&other)=default
RNTupleView(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range)
const T & operator()(ROOT::NTupleSize_t globalIndex)
Reads the value of this view for the entry with the provided globalIndex.
RNTupleView(std::unique_ptr< ROOT::RFieldBase > field, ROOT::RNTupleGlobalRange range, std::shared_ptr< T > objPtr)
~RNTupleView()=default
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:35
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
ROOT::RNTupleGlobalRange GetFieldRange(const ROOT::RFieldBase &field, ROOT::Internal::RPageSource &pageSource)
Helper to get the iteration space of the given field that needs to be connected to the given page sou...
auto MakeAliasedSharedPtr(T *rawPtr)
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
constexpr DescriptorId_t kInvalidDescriptorId