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
71 RIterator begin() const { return RIterator(fStart); }
72 RIterator end() const { return RIterator(fEnd); }
73 NTupleSize_t size() const { 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 NTupleSize_t size() const { return fEnd - fStart; }
119};
120
121namespace Internal {
122
123/// Helper to get the iteration space of the given field that needs to be connected to the given page source.
124/// The indexes are given by the number of elements of the principal column of the field or, if none exists,
125/// by the number of elements of the first principal column found in the subfields searched by BFS.
126/// If the field hierarchy is empty on columns, the returned field range is invalid (start and end set to
127/// kInvalidNTupleIndex). An attempt to use such a field range in RNTupleViewBase::GetFieldRange will throw.
128RNTupleGlobalRange GetFieldRange(const RFieldBase &field, const RPageSource &pageSource);
129
130} // namespace Internal
131
132// clang-format off
133/**
134\class ROOT::Experimental::RNTupleViewBase
135\ingroup NTuple
136\brief An RNTupleView provides read-only access to a single field of the ntuple
137
138\tparam T The type of the object that will be read by the view; can be void if unknown at compile time.
139
140The view owns a field and its underlying columns in order to fill an RField::RValue object with data. Data can be
141accessed by index. For top-level fields, the index refers to the entry number. Fields that are part of
142nested collections have global index numbers that are derived from their parent indexes.
143
144View can only be created by a reader or by a collection view.
145*/
146// clang-format on
147template <typename T>
149protected:
150 std::unique_ptr<RFieldBase> fField;
153
154 static std::unique_ptr<RFieldBase> CreateField(DescriptorId_t fieldId, Internal::RPageSource &pageSource)
155 {
156 std::unique_ptr<RFieldBase> field;
157 {
158 const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
159 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
160 if constexpr (std::is_void_v<T>) {
161 field = fieldDesc.CreateField(desc);
162 } else {
163 field = std::make_unique<RField<T>>(fieldDesc.GetFieldName());
164 }
165 }
166 field->SetOnDiskId(fieldId);
167 Internal::CallConnectPageSourceOnField(*field, pageSource);
168 return field;
169 }
170
171 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
172 : fField(std::move(field)), fFieldRange(range), fValue(fField->CreateValue())
173 {
174 }
175
176 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
177 : fField(std::move(field)), fFieldRange(range), fValue(fField->BindValue(objPtr))
178 {
179 }
180
181 RNTupleViewBase(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, T *rawPtr)
182 : fField(std::move(field)), fFieldRange(range), fValue(fField->BindValue(Internal::MakeAliasedSharedPtr(rawPtr)))
183 {
184 }
185
186public:
187 RNTupleViewBase(const RNTupleViewBase &other) = delete;
191 ~RNTupleViewBase() = default;
192
193 const RFieldBase &GetField() const { return *fField; }
194 RFieldBase::RBulk CreateBulk() { return fField->CreateBulk(); }
195
196 const RFieldBase::RValue &GetValue() const { return fValue; }
198 {
199 if (!fFieldRange.IsValid()) {
200 throw RException(R__FAIL("field iteration over empty fields is unsupported: " + fField->GetFieldName()));
201 }
202 return fFieldRange;
203 }
204
205 void Bind(std::shared_ptr<T> objPtr) { fValue.Bind(objPtr); }
206 void BindRawPtr(T *rawPtr) { fValue.BindRawPtr(rawPtr); }
208};
209
210// clang-format off
211/**
212\class ROOT::Experimental::RNTupleView
213\ingroup NTuple
214\brief An RNTupleView for a known type. See RNTupleViewBase.
215*/
216// clang-format on
217template <typename T>
218class RNTupleView : public RNTupleViewBase<T> {
219 friend class RNTupleReader;
221
222protected:
223 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
224 : RNTupleViewBase<T>(std::move(field), range)
225 {
226 }
227
228 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
229 : RNTupleViewBase<T>(std::move(field), range, objPtr)
230 {
231 }
232
233 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, T *rawPtr)
234 : RNTupleViewBase<T>(std::move(field), range, rawPtr)
235 {
236 }
237
238public:
239 RNTupleView(const RNTupleView &other) = delete;
240 RNTupleView(RNTupleView &&other) = default;
241 RNTupleView &operator=(const RNTupleView &other) = delete;
242 RNTupleView &operator=(RNTupleView &&other) = default;
243 ~RNTupleView() = default;
244
245 const T &operator()(NTupleSize_t globalIndex)
246 {
247 RNTupleViewBase<T>::fValue.Read(globalIndex);
248 return RNTupleViewBase<T>::fValue.template GetRef<T>();
249 }
250
251 const T &operator()(RClusterIndex clusterIndex)
252 {
253 RNTupleViewBase<T>::fValue.Read(clusterIndex);
254 return RNTupleViewBase<T>::fValue.template GetRef<T>();
255 }
256};
257
258// clang-format off
259/**
260\class ROOT::Experimental::RNTupleView
261\ingroup NTuple
262\brief An RNTupleView that can be used when the type is unknown at compile time. See RNTupleViewBase.
263*/
264// clang-format on
265template <>
266class RNTupleView<void> final : public RNTupleViewBase<void> {
267 friend class RNTupleReader;
269
270protected:
271 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range)
272 : RNTupleViewBase<void>(std::move(field), range)
273 {
274 }
275
276 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, std::shared_ptr<void> objPtr)
277 : RNTupleViewBase<void>(std::move(field), range, objPtr)
278 {
279 }
280
281 RNTupleView(std::unique_ptr<RFieldBase> field, RNTupleGlobalRange range, void *rawPtr)
282 : RNTupleViewBase<void>(std::move(field), range, rawPtr)
283 {
284 }
285
286public:
287 RNTupleView(const RNTupleView &other) = delete;
288 RNTupleView(RNTupleView &&other) = default;
289 RNTupleView &operator=(const RNTupleView &other) = delete;
290 RNTupleView &operator=(RNTupleView &&other) = default;
291 ~RNTupleView() = default;
292
293 void operator()(NTupleSize_t globalIndex) { fValue.Read(globalIndex); }
294 void operator()(RClusterIndex clusterIndex) { fValue.Read(clusterIndex); }
295};
296
297// clang-format off
298/**
299\class ROOT::Experimental::RNTupleDirectAccessView
300\ingroup NTuple
301\brief A view variant that provides direct access to the I/O buffers. Only works for mappable fields.
302*/
303// clang-format on
304template <typename T>
306 friend class RNTupleReader;
308
309protected:
312
314 {
315 const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
316 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
317 if (fieldDesc.GetTypeName() != RField<T>::TypeName()) {
318 throw RException(R__FAIL("type mismatch for field " + fieldDesc.GetFieldName() + ": " +
319 fieldDesc.GetTypeName() + " vs. " + RField<T>::TypeName()));
320 }
321 RField<T> field(fieldDesc.GetFieldName());
322 field.SetOnDiskId(fieldId);
324 return field;
325 }
326
327 RNTupleDirectAccessView(RField<T> field, RNTupleGlobalRange range) : fField(std::move(field)), fFieldRange(range) {}
328
329public:
335
336 const RFieldBase &GetField() const { return fField; }
338
339 const T &operator()(NTupleSize_t globalIndex) { return *fField.Map(globalIndex); }
340 const T &operator()(RClusterIndex clusterIndex) { return *fField.Map(clusterIndex); }
341};
342
343// clang-format off
344/**
345\class ROOT::Experimental::RNTupleCollectionView
346\ingroup NTuple
347\brief A view for a collection, that can itself generate new ntuple views for its nested fields.
348*/
349// clang-format on
351 friend class RNTupleReader;
352
353private:
357
358 RNTupleCollectionView(DescriptorId_t fieldId, const std::string &fieldName, Internal::RPageSource *source)
359 : fSource(source), fField(fieldName), fValue(fField.CreateValue())
360 {
361 fField.SetOnDiskId(fieldId);
363 }
364
366 {
367 std::string fieldName;
368 {
369 const auto &desc = source->GetSharedDescriptorGuard().GetRef();
370 const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
371 if (fieldDesc.GetStructure() != ENTupleStructure::kCollection) {
372 throw RException(
373 R__FAIL("invalid attemt to create collection view on non-collection field " + fieldDesc.GetFieldName()));
374 }
375 fieldName = fieldDesc.GetFieldName();
376 }
377 return RNTupleCollectionView(fieldId, fieldName, source);
378 }
379
380 DescriptorId_t GetFieldId(std::string_view fieldName)
381 {
382 auto descGuard = fSource->GetSharedDescriptorGuard();
383 auto fieldId = descGuard->FindFieldId(fieldName, fField.GetOnDiskId());
384 if (fieldId == kInvalidDescriptorId) {
385 throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in collection '" +
386 descGuard->GetQualifiedFieldName(fField.GetOnDiskId()) + "'"));
387 }
388 return fieldId;
389 }
390
391public:
397
400 RClusterIndex collectionStart;
401 fField.GetCollectionInfo(globalIndex, &collectionStart, &size);
402 return RNTupleClusterRange(collectionStart.GetClusterId(), collectionStart.GetIndex(),
403 collectionStart.GetIndex() + size);
404 }
406 {
408 RClusterIndex collectionStart;
409 fField.GetCollectionInfo(clusterIndex, &collectionStart, &size);
410 return RNTupleClusterRange(collectionStart.GetClusterId(), collectionStart.GetIndex(),
411 collectionStart.GetIndex() + size);
412 }
413
414 /// Raises an exception if there is no field with the given name.
415 template <typename T>
416 RNTupleView<T> GetView(std::string_view fieldName)
417 {
418 auto field = RNTupleView<T>::CreateField(GetFieldId(fieldName), *fSource);
419 auto range = Internal::GetFieldRange(*field, *fSource);
420 return RNTupleView<T>(std::move(field), range);
421 }
422
423 /// Raises an exception if there is no field with the given name.
424 template <typename T>
426 {
428 auto range = Internal::GetFieldRange(field, *fSource);
429 return RNTupleDirectAccessView<T>(std::move(field), range);
430 }
431
432 /// Raises an exception if there is no field with the given name.
433 RNTupleCollectionView GetCollectionView(std::string_view fieldName)
434 {
436 }
437
438 std::uint64_t operator()(NTupleSize_t globalIndex)
439 {
440 fValue.Read(globalIndex);
441 return fValue.GetRef<std::uint64_t>();
442 }
443
444 std::uint64_t operator()(RClusterIndex clusterIndex)
445 {
446 fValue.Read(clusterIndex);
447 return fValue.GetRef<std::uint64_t>();
448 }
449};
450
451} // namespace Experimental
452} // namespace ROOT
453
454#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
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: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 &)
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.