Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldProxiedCollection.hxx
Go to the documentation of this file.
1/// \file ROOT/RField/ProxiedCollection.hxx
2/// \ingroup NTuple
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-09
5
6/*************************************************************************
7 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#ifndef ROOT_RField_ProxiedCollection
15#define ROOT_RField_ProxiedCollection
16
17#ifndef ROOT_RField
18#error "Please include RField.hxx!"
19#endif
20
21#include <ROOT/RFieldBase.hxx>
22#include <ROOT/RNTupleUtil.hxx>
23
25
26#include <iterator>
27#include <map>
28#include <set>
29#include <string>
30#include <string_view>
31#include <type_traits>
32#include <unordered_map>
33#include <unordered_set>
34#include <vector>
35
36namespace ROOT {
37
38namespace Detail {
39class RFieldVisitor;
40} // namespace Detail
41
42/// The field for a class representing a collection of elements via TVirtualCollectionProxy.
43/// Objects of such type behave as collections that can be accessed through the corresponding member functions in
44/// TVirtualCollectionProxy. For STL collections, these proxies are provided. Custom classes need to implement the
45/// corresponding member functions in TVirtualCollectionProxy. At a bare minimum, the user is required to provide an
46/// implementation for the following functions in TVirtualCollectionProxy: HasPointers(), GetProperties(),
47/// GetValueClass(), GetType(), PushProxy(), PopProxy(), GetFunctionCreateIterators(), GetFunctionNext(),
48/// and GetFunctionDeleteTwoIterators().
49///
50/// The collection proxy for a given class can be set via TClass::CopyCollectionProxy().
52protected:
53 /// Allows for iterating over the elements of a proxied collection. RCollectionIterableOnce avoids an additional
54 /// iterator copy (see TVirtualCollectionProxy::GetFunctionCopyIterator) and thus can only be iterated once.
56 public:
63
64 private:
65 class RIterator {
67 void *fIterator = nullptr;
68 void *fElementPtr = nullptr;
69
70 void Advance()
71 {
72 auto fnNext_Contig = [&]() {
73 // Array-backed collections (e.g. `kSTLvector`) directly use the pointer-to-iterator-data as a
74 // pointer-to-element, thus saving an indirection level (see documentation for TVirtualCollectionProxy)
75 auto &iter = reinterpret_cast<unsigned char *&>(fIterator), p = iter;
76 iter += fOwner.fStride;
77 return p;
78 };
79 fElementPtr = fOwner.fStride ? fnNext_Contig() : fOwner.fIFuncs.fNext(fIterator, fOwner.fEnd);
80 }
81
82 public:
83 using iterator_category = std::forward_iterator_tag;
85 using difference_type = std::ptrdiff_t;
86 using pointer = void *;
87
88 RIterator(const RCollectionIterableOnce &owner) : fOwner(owner) {}
89 RIterator(const RCollectionIterableOnce &owner, void *iter) : fOwner(owner), fIterator(iter) { Advance(); }
91 {
92 Advance();
93 return *this;
94 }
95 pointer operator*() const { return fElementPtr; }
96 bool operator!=(const iterator &rh) const { return fElementPtr != rh.fElementPtr; }
97 bool operator==(const iterator &rh) const { return fElementPtr == rh.fElementPtr; }
98 };
99
101 const std::size_t fStride;
106
107 public:
108 /// Construct a RCollectionIterableOnce that iterates over `collection`. If elements are guaranteed to be
109 /// contiguous in memory (e.g. a vector), `stride` can be provided for faster iteration, i.e. the address of each
110 /// element is known given the base pointer.
112 std::size_t stride = 0U)
114 {
115 fIFuncs.fCreateIterators(collection, &fBegin, &fEnd, proxy);
116 }
117 ~RCollectionIterableOnce() { fIFuncs.fDeleteTwoIterators(fBegin, fEnd); }
118
119 RIterator begin() { return RIterator(*this, fBegin); }
120 RIterator end() { return fStride ? RIterator(*this, fEnd) : RIterator(*this); }
121 }; // class RCollectionIterableOnce
122
124 private:
125 std::shared_ptr<TVirtualCollectionProxy> fProxy;
126 std::unique_ptr<RDeleter> fItemDeleter;
127 std::size_t fItemSize = 0;
129
130 public:
131 explicit RProxiedCollectionDeleter(std::shared_ptr<TVirtualCollectionProxy> proxy) : fProxy(proxy) {}
132 RProxiedCollectionDeleter(std::shared_ptr<TVirtualCollectionProxy> proxy, std::unique_ptr<RDeleter> itemDeleter,
133 size_t itemSize)
135 {
136 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readFromDisk */);
137 }
138 void operator()(void *objPtr, bool dtorOnly) final;
139 };
140
141 /// The collection proxy is needed by the deleters and thus defined as a shared pointer
142 std::shared_ptr<TVirtualCollectionProxy> fProxy;
145 /// Two sets of functions to operate on iterators, to be used depending on the access type. The direction preserves
146 /// the meaning from TVirtualCollectionProxy, i.e. read from disk / write to disk, respectively
149 std::size_t fItemSize;
151
152 /// Constructor used when the value type of the collection is not known in advance, i.e. in the case of custom
153 /// collections.
155 /// Constructor used when the value type of the collection is known in advance, e.g. in RSetField.
156 RProxiedCollectionField(std::string_view fieldName, std::string_view typeName,
157 std::unique_ptr<RFieldBase> itemField);
158
159protected:
160 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
162 void GenerateColumns() final;
164
165 void ConstructValue(void *where) const final;
166 std::unique_ptr<RDeleter> GetDeleter() const final;
167
168 std::size_t AppendImpl(const void *from) final;
170
172
173public:
174 RProxiedCollectionField(std::string_view fieldName, std::string_view typeName);
177 ~RProxiedCollectionField() override = default;
178
179 std::vector<RValue> SplitValue(const RValue &value) const final;
180 size_t GetValueSize() const final { return fProxy->Sizeof(); }
181 size_t GetAlignment() const final { return alignof(std::max_align_t); }
183 void
188 void
193};
194
195////////////////////////////////////////////////////////////////////////////////
196/// Template specializations for classes with collection proxies
197////////////////////////////////////////////////////////////////////////////////
198
199template <typename T, typename = void>
200struct HasCollectionProxyMemberType : std::false_type {
201};
202template <typename T>
204 T, typename std::enable_if<std::is_same<typename T::IsCollectionProxy, std::true_type>::value>::type>
205 : std::true_type {
206};
207
208/* The point here is that we can only tell at run time if a class has an associated collection proxy.
209For compile time, in the first iteration of this PR we had an extra template argument that acted as a "tag" to
210differentiate the RField specialization for classes with an associated collection proxy (inherits
211RProxiedCollectionField) from the RField primary template definition (RClassField-derived), as in:
212```
213auto field = std::make_unique<RField<MyClass>>("klass");
214// vs
215auto otherField = std::make_unique<RField<MyClass, ROOT::Experimental::TagIsCollectionProxy>>("klass");
216```
217
218That is convenient only for non-nested types, i.e. it doesn't work with, e.g. `RField<std::vector<MyClass>,
219ROOT::Experimental::TagIsCollectionProxy>`, as the tag is not forwarded to the instantiation of the inner RField
220(that for the value type of the vector). The following two possible solutions were considered:
221- A wrapper type that helps to differentiate both cases.
222There we would have:
223```
224auto field = std::make_unique<RField<RProxiedCollection<MyClass>>>("klass"); // Using collection proxy
225```
226- A helper IsCollectionProxy<T> type, that can be used in a similar way to those in the `<type_traits>` header.
227We found this more convenient and is the implemented thing below. Here, classes can be marked as a
228collection proxy with either of the following two forms (whichever is more convenient for the user):
229```
230template <>
231struct IsCollectionProxy<MyClass> : std::true_type {};
232```
233or by adding a member type to the class as follows:
234```
235class MyClass {
236public:
237 using IsCollectionProxy = std::true_type;
238};
239```
240
241Of course, there is another possible solution which is to have a single RClassField that implements both
242the regular-class and the collection-proxy behaviors, and always chooses appropriately at run time.
243We found that less clean and probably has more overhead, as most probably it involves an additional branch + call
244in each of the member functions. */
245/// Helper type trait for marking classes as a collection proxy.
246/// This type trait must be set for collection proxy-based RNTuple fields created through MakeField<T>.
247template <typename T, typename = void>
250
251/// Classes behaving as a collection of elements that can be queried via the TVirtualCollectionProxy interface
252/// The use of a collection proxy for a particular class can be enabled via:
253/// ```
254/// namespace ROOT::Experimental {
255/// template <> struct IsCollectionProxy<Classname> : std::true_type {};
256/// }
257/// ```
258/// Alternatively, this can be achieved by adding a member type to the class definition as follows:
259/// ```
260/// class Classname {
261/// public:
262/// using IsCollectionProxy = std::true_type;
263/// };
264/// ```
265template <typename T>
266class RField<T, typename std::enable_if<IsCollectionProxy<T>::value>::type> final : public RProxiedCollectionField {
267public:
268 static std::string TypeName() { return ROOT::Internal::GetRenormalizedDemangledTypeName(typeid(T)); }
269 RField(std::string_view name) : RProxiedCollectionField(name, TypeName())
270 {
271 static_assert(std::is_class<T>::value, "collection proxy unsupported for fundamental types");
272 }
273 RField(RField &&other) = default;
274 RField &operator=(RField &&other) = default;
276};
277
278////////////////////////////////////////////////////////////////////////////////
279/// Template specializations for C++ std::[unordered_][multi]map
280////////////////////////////////////////////////////////////////////////////////
281
282/// The generic field for a `std::map<KeyType, ValueType>` and `std::unordered_map<KeyType, ValueType>`
284public:
285 RMapField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
288 ~RMapField() override = default;
289};
290
291template <typename KeyT, typename ValueT>
292class RField<std::map<KeyT, ValueT>> final : public RMapField {
293public:
294 static std::string TypeName()
295 {
296 return "std::map<" + RField<KeyT>::TypeName() + "," + RField<ValueT>::TypeName() + ">";
297 }
298
299 explicit RField(std::string_view name)
300 : RMapField(name, TypeName(), std::make_unique<RField<std::pair<KeyT, ValueT>>>("_0"))
301 {
302 }
303 RField(RField &&other) = default;
304 RField &operator=(RField &&other) = default;
306};
307
309class RField<std::unordered_map<KeyT, ValueT>> final : public RMapField {
310public:
311 static std::string TypeName()
312 {
313 return "std::unordered_map<" + RField<KeyT>::TypeName() + "," + RField<ValueT>::TypeName() + ">";
314 }
315
316 explicit RField(std::string_view name)
317 : RMapField(name, TypeName(), std::make_unique<RField<std::pair<KeyT, ValueT>>>("_0"))
318 {
319 }
320 RField(RField &&other) = default;
321 RField &operator=(RField &&other) = default;
323};
324
326class RField<std::multimap<KeyT, ValueT>> final : public RMapField {
327public:
328 static std::string TypeName()
329 {
330 return "std::multimap<" + RField<KeyT>::TypeName() + "," + RField<ValueT>::TypeName() + ">";
331 }
332
333 explicit RField(std::string_view name)
334 : RMapField(name, TypeName(), std::make_unique<RField<std::pair<KeyT, ValueT>>>("_0"))
335 {
336 }
337 RField(RField &&other) = default;
338 RField &operator=(RField &&other) = default;
340};
341
343class RField<std::unordered_multimap<KeyT, ValueT>> final : public RMapField {
344public:
345 static std::string TypeName()
346 {
347 return "std::unordered_multimap<" + RField<KeyT>::TypeName() + "," + RField<ValueT>::TypeName() + ">";
348 }
349
350 explicit RField(std::string_view name)
351 : RMapField(name, TypeName(), std::make_unique<RField<std::pair<KeyT, ValueT>>>("_0"))
352 {
353 }
354 RField(RField &&other) = default;
355 RField &operator=(RField &&other) = default;
357};
358
359////////////////////////////////////////////////////////////////////////////////
360/// Template specializations for C++ std::[unordered_][multi]set
361////////////////////////////////////////////////////////////////////////////////
362
363/// The generic field for a `std::set<Type>` and `std::unordered_set<Type>`
365public:
366 RSetField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
369 ~RSetField() override = default;
370};
371
372template <typename ItemT>
373class RField<std::set<ItemT>> final : public RSetField {
374public:
375 static std::string TypeName() { return "std::set<" + RField<ItemT>::TypeName() + ">"; }
376
377 explicit RField(std::string_view name) : RSetField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
378 RField(RField &&other) = default;
379 RField &operator=(RField &&other) = default;
380 ~RField() final = default;
381};
382
384class RField<std::unordered_set<ItemT>> final : public RSetField {
385public:
386 static std::string TypeName() { return "std::unordered_set<" + RField<ItemT>::TypeName() + ">"; }
387
388 explicit RField(std::string_view name) : RSetField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
389 RField(RField &&other) = default;
390 RField &operator=(RField &&other) = default;
391 ~RField() final = default;
392};
393
395class RField<std::multiset<ItemT>> final : public RSetField {
396public:
397 static std::string TypeName() { return "std::multiset<" + RField<ItemT>::TypeName() + ">"; }
398
399 explicit RField(std::string_view name) : RSetField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
400 RField(RField &&other) = default;
401 RField &operator=(RField &&other) = default;
402 ~RField() final = default;
403};
404
406class RField<std::unordered_multiset<ItemT>> final : public RSetField {
407public:
408 static std::string TypeName() { return "std::unordered_multiset<" + RField<ItemT>::TypeName() + ">"; }
409
410 explicit RField(std::string_view name) : RSetField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
411 RField(RField &&other) = default;
412 RField &operator=(RField &&other) = default;
413 ~RField() final = default;
414};
415
416} // namespace ROOT
417
418#endif
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.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
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 Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
void operator=(const TProof &)
Abstract base class for classes implementing the visitor design pattern.
The in-memory representation of a 32bit or 64bit on-disk index column.
void GetCollectionInfo(const ROOT::NTupleSize_t globalIndex, RNTupleLocalIndex *collectionStart, ROOT::NTupleSize_t *collectionSize)
For offset columns only, look at the two adjacent values that define a collection's coordinates.
Definition RColumn.hxx:283
The list of column representations a field can have.
A functor to release the memory acquired by CreateValue() (memory and constructor).
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
A field translates read and write calls from/to underlying columns to/from tree values.
ROOT::Internal::RColumn * fPrincipalColumn
All fields that have columns have a distinct main column.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:285
~RField() final=default
RField & operator=(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:287
RField(std::string_view name)
Definition RField.hxx:288
Template specializations for C++ std::[unordered_][multi]map.
RMapField(RMapField &&other)=default
~RMapField() override=default
RMapField & operator=(RMapField &&other)=default
The on-storage metadata of an RNTuple.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Allows for iterating over the elements of a proxied collection.
unsigned char fEndSmallBuf[TVirtualCollectionProxy::fgIteratorArenaSize]
RCollectionIterableOnce(void *collection, const RIteratorFuncs &ifuncs, TVirtualCollectionProxy *proxy, std::size_t stride=0U)
Construct a RCollectionIterableOnce that iterates over collection.
static RIteratorFuncs GetIteratorFuncs(TVirtualCollectionProxy *proxy, bool readFromDisk)
unsigned char fBeginSmallBuf[TVirtualCollectionProxy::fgIteratorArenaSize]
RProxiedCollectionDeleter(std::shared_ptr< TVirtualCollectionProxy > proxy, std::unique_ptr< RDeleter > itemDeleter, size_t itemSize)
RProxiedCollectionDeleter(std::shared_ptr< TVirtualCollectionProxy > proxy)
void operator()(void *objPtr, bool dtorOnly) final
The field for a class representing a collection of elements via TVirtualCollectionProxy.
RProxiedCollectionField & operator=(RProxiedCollectionField &&other)=default
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
void GetCollectionInfo(ROOT::NTupleSize_t globalIndex, RNTupleLocalIndex *collectionStart, ROOT::NTupleSize_t *size) const
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
~RProxiedCollectionField() override=default
RProxiedCollectionField(RProxiedCollectionField &&other)=default
void GetCollectionInfo(RNTupleLocalIndex localIndex, RNTupleLocalIndex *collectionStart, ROOT::NTupleSize_t *size) const
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
RProxiedCollectionField(std::string_view fieldName, TClass *classp)
Constructor used when the value type of the collection is not known in advance, i....
RCollectionIterableOnce::RIteratorFuncs fIFuncsWrite
ROOT::Internal::RColumnIndex fNWritten
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
RCollectionIterableOnce::RIteratorFuncs fIFuncsRead
Two sets of functions to operate on iterators, to be used depending on the access type.
std::shared_ptr< TVirtualCollectionProxy > fProxy
The collection proxy is needed by the deleters and thus defined as a shared pointer.
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::unique_ptr< RDeleter > GetDeleter() const final
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Template specializations for C++ std::[unordered_][multi]set.
RSetField & operator=(RSetField &&other)=default
~RSetField() override=default
RSetField(RSetField &&other)=default
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
Defines a common interface to inspect/change the contents of an object that represents a collection.
void(* CreateIterators_t)(void *collection, void **begin_arena, void **end_arena, TVirtualCollectionProxy *proxy)
*begin_arena and *end_arena should contain the location of a memory arena of size fgIteratorArenaSize...
void *(* Next_t)(void *iter, const void *end)
iter and end should be pointers to an iterator to be incremented and an iterator that points to the e...
void(* DeleteTwoIterators_t)(void *begin, void *end)
static const Int_t fgIteratorArenaSize
The size of a small buffer that can be allocated on the stack to store iterator-specific information.
std::string GetRenormalizedDemangledTypeName(const std::type_info &ti)
Given a type info ask ROOT meta to demangle it, then renormalize the resulting type name for RNTuple.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Template specializations for classes with collection proxies.
Helper type trait for marking classes as a collection proxy.