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/RNTupleUtil.hxx>
22#include <string_view>
23
24#include <iterator>
25#include <memory>
26#include <type_traits>
27#include <utility>
28#include <unordered_map>
29
30namespace ROOT {
31namespace Experimental {
32
33
34// clang-format off
35/**
36\class ROOT::Experimental::RNTupleGlobalRange
37\ingroup NTuple
38\brief Used to loop over indexes (entries or collections) between start and end
39*/
40// clang-format on
42private:
45
46public:
47 class RIterator {
48 private:
50 public:
52 using iterator_category = std::forward_iterator_tag;
57
58 RIterator() = default;
60 ~RIterator() = default;
61
62 iterator operator++(int) /* postfix */ { auto r = *this; fIndex++; return r; }
63 iterator& operator++() /* prefix */ { ++fIndex; return *this; }
65 pointer operator->() { return &fIndex; }
66 bool operator==(const iterator& rh) const { return fIndex == rh.fIndex; }
67 bool operator!=(const iterator& rh) const { return fIndex != rh.fIndex; }
68 };
69
72 RIterator end() { return RIterator(fEnd); }
73 NTupleSize_t size() { return fEnd - fStart; }
74 bool IsValid() const { return (fStart != kInvalidNTupleIndex) && (fEnd != kInvalidNTupleIndex); }
75};
76
77
78// clang-format off
79/**
80\class ROOT::Experimental::RNTupleClusterRange
81\ingroup NTuple
82\brief Used to loop over entries of collections in a single cluster
83*/
84// clang-format on
86private:
90public:
91 class RIterator {
92 private:
94 public:
96 using iterator_category = std::forward_iterator_tag;
101
102 RIterator() = default;
104 ~RIterator() = default;
105
106 iterator operator++(int) /* postfix */ { auto r = *this; fIndex++; return r; }
107 iterator& operator++() /* prefix */ { fIndex++; return *this; }
109 pointer operator->() { return &fIndex; }
110 bool operator==(const iterator& rh) const { return fIndex == rh.fIndex; }
111 bool operator!=(const iterator& rh) const { return fIndex != rh.fIndex; }
112 };
113
115 : fClusterId(clusterId), fStart(start), fEnd(end) {}
118};
119
120namespace Internal {
121
122/// Helper to get the iteration space of the given field that needs to be connected to the given page source.
123/// The indexes are given by the number of elements of the principal column of the field or, if none exists,
124/// by the number of elements of the first principal column found in the subfields searched by BFS.
125/// If the field hierarchy is empty on columns, the returned field range is invalid (start and end set to
126/// kInvalidNTupleIndex). An attempt to use such a field range in RNTupleViewBase::GetFieldRange will throw.
127RNTupleGlobalRange GetFieldRange(const RFieldBase &field, const RPageSource &pageSource);
128
129} // namespace Internal
130
131// clang-format off
132/**
133\class ROOT::Experimental::RNTupleViewBase
134\ingroup NTuple
135\brief An RNTupleView provides read-only access to a single field of the ntuple
136
137\tparam T The type of the object that will be read by the view; can be void if unknown at compile time.
138
139The view owns a field and its underlying columns in order to fill an RField::RValue object with data. Data can be
140accessed by index. For top-level fields, the index refers to the entry number. Fields that are part of
141nested collections have global index numbers that are derived from their parent indexes.
142
143View can only be created by a reader or by a collection view.
144*/
145// clang-format on
146template <typename T>
148protected:
149 std::unique_ptr<RFieldBase> fField;
152
153 static std::unique_ptr<RFieldBase> CreateField(DescriptorId_t fieldId, Internal::RPageSource &pageSource)
154 {
155 std::unique_ptr<RFieldBase> field;
156 {
157 const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
158 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
159 if constexpr (std::is_void_v<T>) {
160 field = fieldDesc.CreateField(desc);
161 } else {
162 field = std::make_unique<RField<T>>(fieldDesc.GetFieldName());
163 }
164 }
165 field->SetOnDiskId(fieldId);
166 Internal::CallConnectPageSourceOnField(*field, pageSource);
167 return field;
168 }
169
170 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
171 : fField(std::move(field)), fFieldRange(range), fValue(fField->CreateValue())
172 {
173 }
174
175 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
176 : fField(std::move(field)), fFieldRange(range), fValue(fField->BindValue(objPtr))
177 {
178 }
179
180 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, T *rawPtr)
181 : fField(std::move(field)), fFieldRange(range), fValue(fField->BindValue(Internal::MakeAliasedSharedPtr(rawPtr)))
182 {
183 }
184
185public:
186 RNTupleViewBase(const RNTupleViewBase &other) = delete;
190 ~RNTupleViewBase() = default;
191
192 const RFieldBase &GetField() const { return *fField; }
193 const RFieldBase::RValue &GetValue() const { return fValue; }
195 {
196 if (!fFieldRange.IsValid()) {
197 throw RException(R__FAIL("field iteration over empty fields is unsupported: " + fField->GetFieldName()));
198 }
199 return fFieldRange;
200 }
201
202 void Bind(std::shared_ptr<T> objPtr) { fValue.Bind(objPtr); }
203 void BindRawPtr(T *rawPtr) { fValue.BindRawPtr(rawPtr); }
205};
206
207// clang-format off
208/**
209\class ROOT::Experimental::RNTupleView
210\ingroup NTuple
211\brief An RNTupleView for a known type. See RNTupleViewBase.
212*/
213// clang-format on
214template <typename T>
215class RNTupleView : public RNTupleViewBase<T> {
216 friend class RNTupleReader;
218
219protected:
220 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
221 : RNTupleViewBase<T>(std::move(field), range)
222 {
223 }
224
225 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
226 : RNTupleViewBase<T>(std::move(field), range, objPtr)
227 {
228 }
229
230 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, T *rawPtr)
231 : RNTupleViewBase<T>(std::move(field), range, rawPtr)
232 {
233 }
234
235public:
236 RNTupleView(const RNTupleView &other) = delete;
237 RNTupleView(RNTupleView &&other) = default;
238 RNTupleView &operator=(const RNTupleView &other) = delete;
239 RNTupleView &operator=(RNTupleView &&other) = default;
240 ~RNTupleView() = default;
241
242 const T &operator()(NTupleSize_t globalIndex)
243 {
244 RNTupleViewBase<T>::fValue.Read(globalIndex);
245 return RNTupleViewBase<T>::fValue.template GetRef<T>();
246 }
247
248 const T &operator()(RClusterIndex clusterIndex)
249 {
250 RNTupleViewBase<T>::fValue.Read(clusterIndex);
251 return RNTupleViewBase<T>::fValue.template GetRef<T>();
252 }
253};
254
255// clang-format off
256/**
257\class ROOT::Experimental::RNTupleView
258\ingroup NTuple
259\brief An RNTupleView that can be used when the type is unknown at compile time. See RNTupleViewBase.
260*/
261// clang-format on
262template <>
263class RNTupleView<void> final : public RNTupleViewBase<void> {
264 friend class RNTupleReader;
266
267protected:
268 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
269 : RNTupleViewBase<void>(std::move(field), range)
270 {
271 }
272
273 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<void> objPtr)
274 : RNTupleViewBase<void>(std::move(field), range, objPtr)
275 {
276 }
277
278 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, void *rawPtr)
279 : RNTupleViewBase<void>(std::move(field), range, rawPtr)
280 {
281 }
282
283public:
284 RNTupleView(const RNTupleView &other) = delete;
285 RNTupleView(RNTupleView &&other) = default;
286 RNTupleView &operator=(const RNTupleView &other) = delete;
287 RNTupleView &operator=(RNTupleView &&other) = default;
288 ~RNTupleView() = default;
289
290 void operator()(NTupleSize_t globalIndex) { fValue.Read(globalIndex); }
291 void operator()(RClusterIndex clusterIndex) { fValue.Read(clusterIndex); }
292};
293
294// clang-format off
295/**
296\class ROOT::Experimental::RNTupleDirectAccessView
297\ingroup NTuple
298\brief A view variant that provides direct access to the I/O buffers. Only works for mappable fields.
299*/
300// clang-format on
301template <typename T>
303 friend class RNTupleReader;
305
306protected:
309
311 {
312 const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
313 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
314 if (fieldDesc.GetTypeName() != RField<T>::TypeName()) {
315 throw RException(R__FAIL("type mismatch for field " + fieldDesc.GetFieldName() + ": " +
316 fieldDesc.GetTypeName() + " vs. " + RField<T>::TypeName()));
317 }
318 RField<T> field(fieldDesc.GetFieldName());
319 field.SetOnDiskId(fieldId);
321 return field;
322 }
323
324 RNTupleDirectAccessView(RField<T> field, RNTupleGlobalRange range) : fField(std::move(field)), fFieldRange(range) {}
325
326public:
332
333 const RFieldBase &GetField() const { return fField; }
335
336 const T &operator()(NTupleSize_t globalIndex) { return *fField.Map(globalIndex); }
337 const T &operator()(RClusterIndex clusterIndex) { return *fField.Map(clusterIndex); }
338};
339
340// clang-format off
341/**
342\class ROOT::Experimental::RNTupleCollectionView
343\ingroup NTuple
344\brief A view for a collection, that can itself generate new ntuple views for its nested fields.
345*/
346// clang-format on
348 friend class RNTupleReader;
349
350private:
354
355 RNTupleCollectionView(DescriptorId_t fieldId, const std::string &fieldName, Internal::RPageSource *source)
356 : fSource(source), fField(fieldName), fValue(fField.CreateValue())
357 {
358 fField.SetOnDiskId(fieldId);
360 }
361
363 {
364 std::string fieldName;
365 {
366 const auto &desc = source->GetSharedDescriptorGuard().GetRef();
367 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
368 if (fieldDesc.GetStructure() != ENTupleStructure::kCollection) {
369 throw RException(
370 R__FAIL("invalid attemt to create collection view on non-collection field " + fieldDesc.GetFieldName()));
371 }
372 fieldName = fieldDesc.GetFieldName();
373 }
374 return RNTupleCollectionView(fieldId, fieldName, source);
375 }
376
377 DescriptorId_t GetFieldId(std::string_view fieldName)
378 {
379 auto descGuard = fSource->GetSharedDescriptorGuard();
380 auto fieldId = descGuard->FindFieldId(fieldName, fField.GetOnDiskId());
381 if (fieldId == kInvalidDescriptorId) {
382 throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in collection '" +
383 descGuard->GetQualifiedFieldName(fField.GetOnDiskId()) + "'"));
384 }
385 return fieldId;
386 }
387
388public:
394
397 RClusterIndex collectionStart;
398 fField.GetCollectionInfo(globalIndex, &collectionStart, &size);
399 return RNTupleClusterRange(collectionStart.GetClusterId(), collectionStart.GetIndex(),
400 collectionStart.GetIndex() + size);
401 }
403 {
405 RClusterIndex collectionStart;
406 fField.GetCollectionInfo(clusterIndex, &collectionStart, &size);
407 return RNTupleClusterRange(collectionStart.GetClusterId(), collectionStart.GetIndex(),
408 collectionStart.GetIndex() + size);
409 }
410
411 /// Raises an exception if there is no field with the given name.
412 template <typename T>
413 RNTupleView<T> GetView(std::string_view fieldName)
414 {
415 auto field = RNTupleView<T>::CreateField(GetFieldId(fieldName), *fSource);
416 auto range = Internal::GetFieldRange(*field, *fSource);
417 return RNTupleView<T>(std::move(field), range);
418 }
419
420 /// Raises an exception if there is no field with the given name.
421 template <typename T>
423 {
425 auto range = Internal::GetFieldRange(field, *fSource);
426 return RNTupleDirectAccessView<T>(std::move(field), range);
427 }
428
429 /// Raises an exception if there is no field with the given name.
430 RNTupleCollectionView GetCollectionView(std::string_view fieldName)
431 {
433 }
434
435 std::uint64_t operator()(NTupleSize_t globalIndex)
436 {
437 fValue.Read(globalIndex);
438 return fValue.GetRef<std::uint64_t>();
439 }
440
441 std::uint64_t operator()(RClusterIndex clusterIndex)
442 {
443 fValue.Read(clusterIndex);
444 return fValue.GetRef<std::uint64_t>();
445 }
446};
447
448} // namespace Experimental
449} // namespace ROOT
450
451#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:290
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
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
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
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)
Definition RField.cxx:1049
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:241
Used to loop over entries of collections in a single cluster.
const ClusterSize_t::ValueType fStart
RNTupleClusterRange(DescriptorId_t clusterId, ClusterSize_t::ValueType start, ClusterSize_t::ValueType end)
const ClusterSize_t::ValueType fEnd
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.
RNTupleGlobalRange(NTupleSize_t start, NTupleSize_t 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)
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 &)
Definition RField.cxx:411
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 NTupleSize_t kInvalidNTupleIndex
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.