Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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/RField.hxx>
20#include <ROOT/RNTupleUtil.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 {
30namespace Experimental {
31
32
33// clang-format off
34/**
35\class ROOT::Experimental::RNTupleGlobalRange
36\ingroup NTuple
37\brief Used to loop over indexes (entries or collections) between start and end
38*/
39// clang-format on
41private:
44public:
45 class RIterator {
46 private:
48 public:
50 using iterator_category = std::forward_iterator_tag;
55
56 RIterator() = default;
58 ~RIterator() = default;
59
60 iterator operator++(int) /* postfix */ { auto r = *this; fIndex++; return r; }
61 iterator& operator++() /* prefix */ { ++fIndex; return *this; }
63 pointer operator->() { return &fIndex; }
64 bool operator==(const iterator& rh) const { return fIndex == rh.fIndex; }
65 bool operator!=(const iterator& rh) const { return fIndex != rh.fIndex; }
66 };
67
70 RIterator end() { return RIterator(fEnd); }
71};
72
73
74// clang-format off
75/**
76\class ROOT::Experimental::RNTupleClusterRange
77\ingroup NTuple
78\brief Used to loop over entries of collections in a single cluster
79*/
80// clang-format on
82private:
86public:
87 class RIterator {
88 private:
90 public:
92 using iterator_category = std::forward_iterator_tag;
97
98 RIterator() = default;
100 ~RIterator() = default;
101
102 iterator operator++(int) /* postfix */ { auto r = *this; fIndex++; return r; }
103 iterator& operator++() /* prefix */ { fIndex++; return *this; }
105 pointer operator->() { return &fIndex; }
106 bool operator==(const iterator& rh) const { return fIndex == rh.fIndex; }
107 bool operator!=(const iterator& rh) const { return fIndex != rh.fIndex; }
108 };
109
114};
115
116
117namespace Internal {
118// TODO(bgruber): convert this trait into a requires clause in C++20
119template <typename FieldT, typename SFINAE = void>
120inline constexpr bool isMappable = false;
121
122template <typename FieldT>
124} // namespace Internal
125
126
127// clang-format off
128/**
129\class ROOT::Experimental::RNTupleView
130\ingroup NTuple
131\brief An RNTupleView provides read-only access to a single field of the ntuple
132
133\tparam T The type of the object that will be read by the view
134\tparam UserProvidedAddress Whether the user provided an external memory location to read data into
135
136The view owns a field and its underlying columns in order to fill an ntuple value object with data. Data can be
137accessed by index. For top-level fields, the index refers to the entry number. Fields that are part of
138nested collections have global index numbers that are derived from their parent indexes.
139
140Fields of simple types with a Map() method will use that and thus expose zero-copy access.
141*/
142// clang-format on
143template <typename T, bool UserProvidedAddress>
145 friend class RNTupleReader;
147
149
150private:
151 /// fFieldId has fParent always set to null; views access nested fields without looking at the parent
153 /// Used as a Read() destination for fields that are not mappable
155
157 {
158 fField.SetOnDiskId(fieldId);
160 if constexpr (!UserProvidedAddress) {
161 if ((fField.GetTraits() & RFieldBase::kTraitMappable) && fField.HasReadCallbacks())
162 throw RException(R__FAIL("view disallowed on field with mappable type and read callback"));
163 }
164 }
165
167 : fField(pageSource->GetSharedDescriptorGuard()->GetFieldDescriptor(fieldId).GetFieldName()),
168 fValue(fField.CreateValue())
169 {
171 }
172
174 : fField(pageSource->GetSharedDescriptorGuard()->GetFieldDescriptor(fieldId).GetFieldName()),
175 fValue(fField.BindValue(objPtr))
176 {
178 }
179
181 : fField(pageSource->GetSharedDescriptorGuard()->GetFieldDescriptor(fieldId).GetFieldName()),
182 fValue(fField.BindValue(Internal::MakeAliasedSharedPtr(rawPtr)))
183 {
185 }
186
187public:
188 RNTupleView(const RNTupleView& other) = delete;
192 ~RNTupleView() = default;
193
194 const FieldT &GetField() const { return fField; }
195 RNTupleGlobalRange GetFieldRange() const { return RNTupleGlobalRange(0, fField.GetNElements()); }
196
198 {
199 if constexpr (Internal::isMappable<FieldT> && !UserProvidedAddress) {
200 return *fField.Map(globalIndex);
201 } else {
203 return fValue.GetRef<T>();
204 }
205 }
206
208 {
209 if constexpr (Internal::isMappable<FieldT> && !UserProvidedAddress) {
210 return *fField.Map(clusterIndex);
211 } else {
213 return fValue.GetRef<T>();
214 }
215 }
216
217 // TODO(bgruber): turn enable_if into requires clause with C++20
218 template <typename C = T, std::enable_if_t<Internal::isMappable<FieldT>, C*> = nullptr>
220 {
221 return fField.MapV(globalIndex, nItems);
222 }
223
224 // TODO(bgruber): turn enable_if into requires clause with C++20
225 template <typename C = T, std::enable_if_t<Internal::isMappable<FieldT>, C *> = nullptr>
227 {
228 return fField.MapV(clusterIndex, nItems);
229 }
230
231 void Bind(std::shared_ptr<T> objPtr)
232 {
233 static_assert(
235 "Only views which were created with an external memory location at construction time can be bound to a "
236 "different memory location afterwards. Call the RNTupleReader::GetView overload with a shared_ptr.");
238 }
239
241 {
242 static_assert(
244 "Only views which were created with an external memory location at construction time can be bound to a "
245 "different memory location afterwards. Call the RNTupleReader::GetView overload with a shared_ptr.");
247 }
248
250 {
251 // Let the user know they are misusing this function in case the field is
252 // mappable and they are providing an external address after construction.
253 // This would mean creating a new RValue member but not using it since
254 // reading would be done by RField::Map directly.
255 static_assert(!(Internal::isMappable<FieldT> && !UserProvidedAddress),
256 "Cannot emplace a new value into a view of a mappable type, unless an external memory location is "
257 "provided at construction time.");
259 }
260};
261
262// clang-format off
263/**
264\class ROOT::Experimental::RNTupleView<void>
265\ingroup NTuple
266\brief An RNTupleView where the type is not known at compile time.
267
268Can be used to read individual fields whose type is unknown. The void view gives access to the RValue
269in addition to the field, so that the read object can be retrieved.
270*/
271// clang-format on
272template <bool UserProvidedAddress>
274 friend class RNTupleReader;
276
277private:
278 std::unique_ptr<RFieldBase> fField;
280
281 static std::unique_ptr<RFieldBase> CreateField(DescriptorId_t fieldId, const RNTupleDescriptor &desc)
282 {
283 return desc.GetFieldDescriptor(fieldId).CreateField(desc);
284 }
285
291
293 : fField(CreateField(fieldId, pageSource->GetSharedDescriptorGuard().GetRef())), fValue(fField->CreateValue())
294 {
296 }
297
299 : fField(CreateField(fieldId, pageSource->GetSharedDescriptorGuard().GetRef())), fValue(fField->BindValue(objPtr))
300 {
302 }
303
305 : fField(CreateField(fieldId, pageSource->GetSharedDescriptorGuard().GetRef())),
306 fValue(fField->BindValue(Internal::MakeAliasedSharedPtr(rawPtr)))
307 {
309 }
310
311public:
312 RNTupleView(const RNTupleView &other) = delete;
316 ~RNTupleView() = default;
317
318 const RFieldBase &GetField() const { return *fField; }
319 const RFieldBase::RValue &GetValue() const { return fValue; }
320 RNTupleGlobalRange GetFieldRange() const { return RNTupleGlobalRange(0, fField->GetNElements()); }
321
324
325 void Bind(std::shared_ptr<void> objPtr)
326 {
327 static_assert(
329 "Only views which were created with an external memory location at construction time can be bound to a "
330 "different memory location afterwards. Call the RNTupleReader::GetView overload with a shared_ptr.");
332 }
333
334 void BindRawPtr(void *rawPtr)
335 {
336 static_assert(
338 "Only views which were created with an external memory location at construction time can be bound to a "
339 "different memory location afterwards. Call the RNTupleReader::GetView overload with a shared_ptr.");
341 }
342
344};
345
346// clang-format off
347/**
348\class ROOT::Experimental::RNTupleCollectionView
349\ingroup NTuple
350\brief A view for a collection, that can itself generate new ntuple views for its nested fields.
351*/
352// clang-format on
353class RNTupleCollectionView : public RNTupleView<ClusterSize_t, false> {
354 friend class RNTupleReader;
355
356private:
359
363
364public:
370
386
387 /// Raises an exception if there is no field with the given name.
388 template <typename T>
390 {
393 throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in RNTuple '" +
394 fSource->GetSharedDescriptorGuard()->GetName() + "'"));
395 }
397 }
398 /// Raises an exception if there is no field with the given name.
400 {
403 throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in RNTuple '" +
404 fSource->GetSharedDescriptorGuard()->GetName() + "'"));
405 }
407 }
408
422};
423
424} // namespace Experimental
425} // namespace ROOT
426
427#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
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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...
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.
Definition RField.hxx:186
void Read(NTupleSize_t globalIndex)
Definition RField.hxx:203
void EmplaceNew()
Replace the current object pointer by a pointer to a new object constructed by the field.
Definition RField.hxx:208
void Bind(std::shared_ptr< void > objPtr)
Definition RField.hxx:205
A field translates read and write calls from/to underlying columns to/from tree values.
Definition RField.hxx:94
static constexpr int kTraitMappable
A field of a fundamental type that can be directly mapped via RField<T>::Map(), i....
Definition RField.hxx:145
void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size)
Special help for offset fields.
Definition RField.hxx:1790
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)
ClusterSize_t operator()(RClusterIndex clusterIndex)
RNTupleCollectionView(RNTupleCollectionView &&other)=default
ClusterSize_t operator()(NTupleSize_t globalIndex)
RNTupleCollectionView GetCollectionView(std::string_view fieldName)
Raises an exception if there is no field with the given name.
RNTupleCollectionView & operator=(const RNTupleCollectionView &other)=delete
RNTupleView< T, false > GetView(std::string_view fieldName)
Raises an exception if there is no field with the given name.
RNTupleCollectionView(DescriptorId_t fieldId, Internal::RPageSource *source)
RNTupleClusterRange GetCollectionRange(NTupleSize_t globalIndex)
RNTupleCollectionView(const RNTupleCollectionView &other)=delete
The on-storage meta-data of an ntuple.
const RFieldDescriptor & GetFieldDescriptor(DescriptorId_t fieldId) const
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.
RNTupleView & operator=(const RNTupleView &other)=delete
RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource, void *rawPtr)
RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource)
RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource, std::shared_ptr< void > objPtr)
void SetupField(DescriptorId_t fieldId, Internal::RPageSource *pageSource)
static std::unique_ptr< RFieldBase > CreateField(DescriptorId_t fieldId, const RNTupleDescriptor &desc)
RNTupleView & operator=(RNTupleView &&other)=default
An RNTupleView provides read-only access to a single field of the ntuple.
RNTupleView & operator=(RNTupleView &&other)=default
const T & operator()(RClusterIndex clusterIndex)
void SetupField(DescriptorId_t fieldId, Internal::RPageSource *pageSource)
RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource, std::shared_ptr< T > objPtr)
const C * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
RNTupleView & operator=(const RNTupleView &other)=delete
RFieldBase::RValue fValue
Used as a Read() destination for fields that are not mappable.
FieldT fField
fFieldId has fParent always set to null; views access nested fields without looking at the parent
RNTupleView(const RNTupleView &other)=delete
const C * MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
void Bind(std::shared_ptr< T > objPtr)
RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource, T *rawPtr)
const FieldT & GetField() const
RNTupleGlobalRange GetFieldRange() const
RNTupleView(RNTupleView &&other)=default
const T & operator()(NTupleSize_t globalIndex)
RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource)
void CallConnectPageSourceOnField(RFieldBase &, RPageSource &)
Definition RField.cxx:363
constexpr NTupleSize_t kInvalidNTupleIndex
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.