Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleView.hxx
Go to the documentation of this file.
1/// \file ROOT/RNTupleView.hxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-05
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#ifndef ROOT7_RNTupleView
17#define ROOT7_RNTupleView
18
19#include <ROOT/RError.hxx>
20#include <ROOT/RField.hxx>
21#include <ROOT/RNTupleRange.hxx>
22#include <ROOT/RNTupleUtil.hxx>
23#include <string_view>
24
25#include <iterator>
26#include <memory>
27#include <type_traits>
28#include <utility>
29#include <unordered_map>
30
31namespace ROOT {
32namespace Experimental {
33
34namespace Internal {
35
36/// Helper to get the iteration space of the given field that needs to be connected to the given page source.
37/// The indexes are given by the number of elements of the principal column of the field or, if none exists,
38/// by the number of elements of the first principal column found in the subfields searched by BFS.
39/// If the field hierarchy is empty on columns, the returned field range is invalid (start and end set to
40/// kInvalidNTupleIndex). An attempt to use such a field range in RNTupleViewBase::GetFieldRange will throw.
41RNTupleGlobalRange GetFieldRange(const RFieldBase &field, const RPageSource &pageSource);
42
43} // namespace Internal
44
45// clang-format off
46/**
47\class ROOT::Experimental::RNTupleViewBase
48\ingroup NTuple
49\brief An RNTupleView provides read-only access to a single field of the ntuple
50
51\tparam T The type of the object that will be read by the view; can be void if unknown at compile time.
52
53The view owns a field and its underlying columns in order to fill an RField::RValue object with data. Data can be
54accessed by index. For top-level fields, the index refers to the entry number. Fields that are part of
55nested collections have global index numbers that are derived from their parent indexes.
56
57View can only be created by a reader or by a collection view.
58*/
59// clang-format on
60template <typename T>
62protected:
63 std::unique_ptr<RFieldBase> fField;
66
67 static std::unique_ptr<RFieldBase> CreateField(DescriptorId_t fieldId, Internal::RPageSource &pageSource)
68 {
69 std::unique_ptr<RFieldBase> field;
70 {
71 const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
72 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
73 if constexpr (std::is_void_v<T>) {
74 field = fieldDesc.CreateField(desc);
75 } else {
76 field = std::make_unique<RField<T>>(fieldDesc.GetFieldName());
77 }
78 }
79 field->SetOnDiskId(fieldId);
81 return field;
82 }
83
84 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
85 : fField(std::move(field)), fFieldRange(range), fValue(fField->CreateValue())
86 {
87 }
88
89 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
90 : fField(std::move(field)), fFieldRange(range), fValue(fField->BindValue(objPtr))
91 {
92 }
93
94 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, T *rawPtr)
95 : fField(std::move(field)), fFieldRange(range), fValue(fField->BindValue(Internal::MakeAliasedSharedPtr(rawPtr)))
96 {
97 }
98
99public:
100 RNTupleViewBase(const RNTupleViewBase &other) = delete;
104 ~RNTupleViewBase() = default;
105
106 const RFieldBase &GetField() const { return *fField; }
107 RFieldBase::RBulk CreateBulk() { return fField->CreateBulk(); }
108
109 const RFieldBase::RValue &GetValue() const { return fValue; }
111 {
112 if (!fFieldRange.IsValid()) {
113 throw RException(R__FAIL("field iteration over empty fields is unsupported: " + fField->GetFieldName()));
114 }
115 return fFieldRange;
116 }
117
118 void Bind(std::shared_ptr<T> objPtr) { fValue.Bind(objPtr); }
119 void BindRawPtr(T *rawPtr) { fValue.BindRawPtr(rawPtr); }
121};
122
123// clang-format off
124/**
125\class ROOT::Experimental::RNTupleView
126\ingroup NTuple
127\brief An RNTupleView for a known type. See RNTupleViewBase.
128*/
129// clang-format on
130template <typename T>
131class RNTupleView : public RNTupleViewBase<T> {
132 friend class RNTupleReader;
134
135protected:
136 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
137 : RNTupleViewBase<T>(std::move(field), range)
138 {
139 }
140
141 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
142 : RNTupleViewBase<T>(std::move(field), range, objPtr)
143 {
144 }
145
146 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, T *rawPtr)
147 : RNTupleViewBase<T>(std::move(field), range, rawPtr)
148 {
149 }
150
151public:
152 RNTupleView(const RNTupleView &other) = delete;
153 RNTupleView(RNTupleView &&other) = default;
154 RNTupleView &operator=(const RNTupleView &other) = delete;
155 RNTupleView &operator=(RNTupleView &&other) = default;
156 ~RNTupleView() = default;
157
158 const T &operator()(NTupleSize_t globalIndex)
159 {
160 RNTupleViewBase<T>::fValue.Read(globalIndex);
161 return RNTupleViewBase<T>::fValue.template GetRef<T>();
162 }
163
164 const T &operator()(RClusterIndex clusterIndex)
165 {
166 RNTupleViewBase<T>::fValue.Read(clusterIndex);
167 return RNTupleViewBase<T>::fValue.template GetRef<T>();
168 }
169};
170
171// clang-format off
172/**
173\class ROOT::Experimental::RNTupleView
174\ingroup NTuple
175\brief An RNTupleView that can be used when the type is unknown at compile time. See RNTupleViewBase.
176*/
177// clang-format on
178template <>
179class RNTupleView<void> final : public RNTupleViewBase<void> {
180 friend class RNTupleReader;
182
183protected:
184 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
185 : RNTupleViewBase<void>(std::move(field), range)
186 {
187 }
188
189 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<void> objPtr)
190 : RNTupleViewBase<void>(std::move(field), range, objPtr)
191 {
192 }
193
194 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, void *rawPtr)
195 : RNTupleViewBase<void>(std::move(field), range, rawPtr)
196 {
197 }
198
199public:
200 RNTupleView(const RNTupleView &other) = delete;
201 RNTupleView(RNTupleView &&other) = default;
202 RNTupleView &operator=(const RNTupleView &other) = delete;
203 RNTupleView &operator=(RNTupleView &&other) = default;
204 ~RNTupleView() = default;
205
206 void operator()(NTupleSize_t globalIndex) { fValue.Read(globalIndex); }
207 void operator()(RClusterIndex clusterIndex) { fValue.Read(clusterIndex); }
208};
209
210// clang-format off
211/**
212\class ROOT::Experimental::RNTupleDirectAccessView
213\ingroup NTuple
214\brief A view variant that provides direct access to the I/O buffers. Only works for mappable fields.
215*/
216// clang-format on
217template <typename T>
219 friend class RNTupleReader;
221
222protected:
225
227 {
228 const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
229 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
230 if (fieldDesc.GetTypeName() != RField<T>::TypeName()) {
231 throw RException(R__FAIL("type mismatch for field " + fieldDesc.GetFieldName() + ": " +
232 fieldDesc.GetTypeName() + " vs. " + RField<T>::TypeName()));
233 }
234 RField<T> field(fieldDesc.GetFieldName());
235 field.SetOnDiskId(fieldId);
237 return field;
238 }
239
240 RNTupleDirectAccessView(RField<T> field, RNTupleGlobalRange range) : fField(std::move(field)), fFieldRange(range) {}
241
242public:
248
249 const RFieldBase &GetField() const { return fField; }
251
252 const T &operator()(NTupleSize_t globalIndex) { return *fField.Map(globalIndex); }
253 const T &operator()(RClusterIndex clusterIndex) { return *fField.Map(clusterIndex); }
254};
255
256// clang-format off
257/**
258\class ROOT::Experimental::RNTupleCollectionView
259\ingroup NTuple
260\brief A view for a collection, that can itself generate new ntuple views for its nested fields.
261*/
262// clang-format on
264 friend class RNTupleReader;
265
266private:
270
271 RNTupleCollectionView(DescriptorId_t fieldId, const std::string &fieldName, Internal::RPageSource *source)
272 : fSource(source), fField(fieldName), fValue(fField.CreateValue())
273 {
274 fField.SetOnDiskId(fieldId);
276 }
277
279 {
280 std::string fieldName;
281 {
282 const auto &desc = source->GetSharedDescriptorGuard().GetRef();
283 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
284 if (fieldDesc.GetStructure() != ENTupleStructure::kCollection) {
285 throw RException(
286 R__FAIL("invalid attemt to create collection view on non-collection field " + fieldDesc.GetFieldName()));
287 }
288 fieldName = fieldDesc.GetFieldName();
289 }
290 return RNTupleCollectionView(fieldId, fieldName, source);
291 }
292
293 DescriptorId_t GetFieldId(std::string_view fieldName)
294 {
295 auto descGuard = fSource->GetSharedDescriptorGuard();
296 auto fieldId = descGuard->FindFieldId(fieldName, fField.GetOnDiskId());
297 if (fieldId == kInvalidDescriptorId) {
298 throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in collection '" +
299 descGuard->GetQualifiedFieldName(fField.GetOnDiskId()) + "'"));
300 }
301 return fieldId;
302 }
303
304public:
310
313 RClusterIndex collectionStart;
314 fField.GetCollectionInfo(globalIndex, &collectionStart, &size);
315 return RNTupleClusterRange(collectionStart.GetClusterId(), collectionStart.GetIndex(),
316 collectionStart.GetIndex() + size);
317 }
319 {
321 RClusterIndex collectionStart;
322 fField.GetCollectionInfo(clusterIndex, &collectionStart, &size);
323 return RNTupleClusterRange(collectionStart.GetClusterId(), collectionStart.GetIndex(),
324 collectionStart.GetIndex() + size);
325 }
326
327 /// Raises an exception if there is no field with the given name.
328 template <typename T>
329 RNTupleView<T> GetView(std::string_view fieldName)
330 {
331 auto field = RNTupleView<T>::CreateField(GetFieldId(fieldName), *fSource);
332 auto range = Internal::GetFieldRange(*field, *fSource);
333 return RNTupleView<T>(std::move(field), range);
334 }
335
336 /// Raises an exception if there is no field with the given name.
337 template <typename T>
339 {
341 auto range = Internal::GetFieldRange(field, *fSource);
342 return RNTupleDirectAccessView<T>(std::move(field), range);
343 }
344
345 /// Raises an exception if there is no field with the given name.
346 RNTupleCollectionView GetCollectionView(std::string_view fieldName)
347 {
349 }
350
351 std::uint64_t operator()(NTupleSize_t globalIndex)
352 {
353 fValue.Read(globalIndex);
354 return fValue.GetRef<std::uint64_t>();
355 }
356
357 std::uint64_t operator()(RClusterIndex clusterIndex)
358 {
359 fValue.Read(clusterIndex);
360 return fValue.GetRef<std::uint64_t>();
361 }
362};
363
364} // namespace Experimental
365} // namespace ROOT
366
367#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:299
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Abstract interface to read data from an ntuple.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
DescriptorId_t GetClusterId() const
ClusterSize_t::ValueType GetIndex() const
Similar to RValue but manages an array of consecutive values.
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
void Read(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)
A field translates read and write calls from/to underlying columns to/from tree values.
void SetOnDiskId(DescriptorId_t id)
std::unique_ptr< RFieldBase > CreateField(const RNTupleDescriptor &ntplDesc, bool continueOnError=false) const
In general, we create a field simply from the C++ type name.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:242
Used to loop over entries of collections in a single cluster.
A view for a collection, that can itself generate new ntuple views for its nested fields.
RNTupleCollectionView & operator=(RNTupleCollectionView &&other)=default
RNTupleClusterRange GetCollectionRange(RClusterIndex clusterIndex)
RNTupleCollectionView(RNTupleCollectionView &&other)=default
RNTupleCollectionView GetCollectionView(std::string_view fieldName)
Raises an exception if there is no field with the given name.
RNTupleCollectionView & operator=(const RNTupleCollectionView &other)=delete
RField< RNTupleCardinality< std::uint64_t > > fField
RNTupleView< T > GetView(std::string_view fieldName)
Raises an exception if there is no field with the given name.
std::uint64_t operator()(RClusterIndex clusterIndex)
DescriptorId_t GetFieldId(std::string_view fieldName)
RNTupleDirectAccessView< T > GetDirectAccessView(std::string_view fieldName)
Raises an exception if there is no field with the given name.
RNTupleCollectionView(DescriptorId_t fieldId, const std::string &fieldName, Internal::RPageSource *source)
RNTupleClusterRange GetCollectionRange(NTupleSize_t globalIndex)
RNTupleCollectionView(const RNTupleCollectionView &other)=delete
std::uint64_t operator()(NTupleSize_t globalIndex)
static RNTupleCollectionView Create(DescriptorId_t fieldId, Internal::RPageSource *source)
DescriptorId_t FindFieldId(std::string_view fieldName, DescriptorId_t parentId) const
const RFieldDescriptor & GetFieldDescriptor(DescriptorId_t fieldId) const
A view variant that provides direct access to the I/O buffers.
const T & operator()(NTupleSize_t globalIndex)
RNTupleDirectAccessView & operator=(const RNTupleDirectAccessView &other)=delete
RNTupleDirectAccessView(RField< T > field, RNTupleGlobalRange range)
static RField< T > CreateField(DescriptorId_t fieldId, Internal::RPageSource &pageSource)
RNTupleDirectAccessView(const RNTupleDirectAccessView &other)=delete
RNTupleDirectAccessView(RNTupleDirectAccessView &&other)=default
RNTupleDirectAccessView & operator=(RNTupleDirectAccessView &&other)=default
const T & operator()(RClusterIndex clusterIndex)
Used to loop over indexes (entries or collections) between start and end.
An RNTuple that is used to read data from storage.
An RNTupleView provides read-only access to a single field of the ntuple.
const RFieldBase & GetField() const
RNTupleViewBase(const RNTupleViewBase &other)=delete
RNTupleViewBase & operator=(const RNTupleViewBase &other)=delete
RNTupleViewBase(RNTupleViewBase &&other)=default
std::unique_ptr< RFieldBase > fField
const RFieldBase::RValue & GetValue() const
RNTupleViewBase(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range, std::shared_ptr< T > objPtr)
RNTupleViewBase(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range)
void Bind(std::shared_ptr< T > objPtr)
RNTupleViewBase & operator=(RNTupleViewBase &&other)=default
RNTupleViewBase(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range, T *rawPtr)
RNTupleGlobalRange GetFieldRange() const
static std::unique_ptr< RFieldBase > CreateField(DescriptorId_t fieldId, Internal::RPageSource &pageSource)
void operator()(NTupleSize_t globalIndex)
RNTupleView(RNTupleView &&other)=default
RNTupleView(const RNTupleView &other)=delete
RNTupleView(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range)
RNTupleView & operator=(RNTupleView &&other)=default
void operator()(RClusterIndex clusterIndex)
RNTupleView(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range, void *rawPtr)
RNTupleView & operator=(const RNTupleView &other)=delete
RNTupleView(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range, std::shared_ptr< void > objPtr)
An RNTupleView for a known type.
RNTupleView & operator=(RNTupleView &&other)=default
const T & operator()(RClusterIndex clusterIndex)
RNTupleView(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range)
RNTupleView & operator=(const RNTupleView &other)=delete
RNTupleView(RNTupleView &&other)=default
RNTupleView(const RNTupleView &other)=delete
RNTupleView(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range, std::shared_ptr< T > objPtr)
const T & operator()(NTupleSize_t globalIndex)
RNTupleView(std::unique_ptr< RFieldBase > field, RNTupleGlobalRange range, T *rawPtr)
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
RNTupleGlobalRange GetFieldRange(const RFieldBase &field, const RPageSource &pageSource)
Helper to get the iteration space of the given field that needs to be connected to the given page sou...
void CallConnectPageSourceOnField(RFieldBase &, RPageSource &)
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
constexpr DescriptorId_t kInvalidDescriptorId
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Wrap the integer in a struct in order to avoid template specialization clash with std::uint64_t.