Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldSTLMisc.hxx
Go to the documentation of this file.
1/// \file ROOT/RField/STLMisc.hxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-09
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_RField_STLMisc
17#define ROOT7_RField_STLMisc
18
19#ifndef ROOT7_RField
20#error "Please include RField.hxx!"
21#endif
22
23#include <ROOT/RFieldBase.hxx>
24#include <ROOT/RNTupleUtil.hxx>
25
26#include <atomic>
27#include <bitset>
28#include <cstddef>
29#include <memory>
30#include <optional>
31#include <string>
32#include <string_view>
33#include <variant>
34
35namespace ROOT {
36namespace Experimental {
37
38namespace Detail {
39class RFieldVisitor;
40} // namespace Detail
41
42////////////////////////////////////////////////////////////////////////////////
43/// Template specializations for C++ std::atomic
44////////////////////////////////////////////////////////////////////////////////
45
46class RAtomicField : public RFieldBase {
47protected:
48 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
49
50 void ConstructValue(void *where) const final { CallConstructValueOn(*fSubFields[0], where); }
51 std::unique_ptr<RDeleter> GetDeleter() const final { return GetDeleterOf(*fSubFields[0]); }
52
53 std::size_t AppendImpl(const void *from) final { return CallAppendOn(*fSubFields[0], from); }
54 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final { CallReadOn(*fSubFields[0], globalIndex, to); }
55 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final { CallReadOn(*fSubFields[0], clusterIndex, to); }
56
57public:
58 RAtomicField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
59 RAtomicField(RAtomicField &&other) = default;
60 RAtomicField &operator=(RAtomicField &&other) = default;
61 ~RAtomicField() override = default;
62
63 std::vector<RValue> SplitValue(const RValue &value) const final;
64
65 size_t GetValueSize() const final { return fSubFields[0]->GetValueSize(); }
66 size_t GetAlignment() const final { return fSubFields[0]->GetAlignment(); }
67
68 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
69};
70
71template <typename ItemT>
72class RField<std::atomic<ItemT>> final : public RAtomicField {
73public:
74 static std::string TypeName() { return "std::atomic<" + RField<ItemT>::TypeName() + ">"; }
75 explicit RField(std::string_view name) : RAtomicField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
76 RField(RField &&other) = default;
77 RField &operator=(RField &&other) = default;
78 ~RField() final = default;
79};
80
81////////////////////////////////////////////////////////////////////////////////
82/// Template specializations for C++ std::bitset
83////////////////////////////////////////////////////////////////////////////////
84
85/// The generic field an std::bitset<N>. All compilers we care about store the bits in an array of unsigned long.
86/// TODO(jblomer): reading and writing efficiency should be improved; currently it is one bit at a time
87/// with an array of bools on the page level.
88class RBitsetField : public RFieldBase {
89 using Word_t = unsigned long;
90 static constexpr std::size_t kWordSize = sizeof(Word_t);
91 static constexpr std::size_t kBitsPerWord = kWordSize * 8;
92
93protected:
94 std::size_t fN;
95
96protected:
97 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
98 {
99 return std::make_unique<RBitsetField>(newName, fN);
100 }
101 const RColumnRepresentations &GetColumnRepresentations() const final;
102 void GenerateColumns() final;
103 void GenerateColumns(const RNTupleDescriptor &desc) final;
104 void ConstructValue(void *where) const final { memset(where, 0, GetValueSize()); }
105 std::size_t AppendImpl(const void *from) final;
106 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
107 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final;
108
109public:
110 RBitsetField(std::string_view fieldName, std::size_t N);
111 RBitsetField(RBitsetField &&other) = default;
113 ~RBitsetField() override = default;
114
115 size_t GetValueSize() const final { return kWordSize * ((fN + kBitsPerWord - 1) / kBitsPerWord); }
116 size_t GetAlignment() const final { return alignof(Word_t); }
117 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
118
119 /// Get the number of bits in the bitset, i.e. the N in std::bitset<N>
120 std::size_t GetN() const { return fN; }
121};
122
123template <std::size_t N>
124class RField<std::bitset<N>> final : public RBitsetField {
125public:
126 static std::string TypeName() { return "std::bitset<" + std::to_string(N) + ">"; }
127 explicit RField(std::string_view name) : RBitsetField(name, N) {}
128 RField(RField &&other) = default;
129 RField &operator=(RField &&other) = default;
130 ~RField() final = default;
131};
132
133////////////////////////////////////////////////////////////////////////////////
134/// Template specializations for C++ std::byte
135////////////////////////////////////////////////////////////////////////////////
136
137extern template class RSimpleField<std::byte>;
138
139template <>
140class RField<std::byte> final : public RSimpleField<std::byte> {
141protected:
142 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
143 {
144 return std::make_unique<RField>(newName);
145 }
146
147 const RColumnRepresentations &GetColumnRepresentations() const final;
148
149public:
150 static std::string TypeName() { return "std::byte"; }
151 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
152 RField(RField &&other) = default;
153 RField &operator=(RField &&other) = default;
154 ~RField() final = default;
155
156 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
157};
158
159////////////////////////////////////////////////////////////////////////////////
160/// Template specializations for C++ std::optional and std::unique_ptr
161////////////////////////////////////////////////////////////////////////////////
162
163/// The field for values that may or may not be present in an entry. Parent class for unique pointer field and
164/// optional field. A nullable field cannot be instantiated itself but only its descendants.
165/// The RNullableField takes care of the on-disk representation. Child classes are responsible for the in-memory
166/// representation. Nullable fields use a (Split)Index[64|32] column to point to the available items.
168 /// The number of written non-null items in this cluster
169 ClusterSize_t fNWritten{0};
170
171protected:
173 void GenerateColumns() final;
174 void GenerateColumns(const RNTupleDescriptor &) final;
175
176 std::size_t AppendNull();
177 std::size_t AppendValue(const void *from);
178 void CommitClusterImpl() final { fNWritten = 0; }
179
180 /// Given the index of the nullable field, returns the corresponding global index of the subfield or,
181 /// if it is null, returns kInvalidClusterIndex
182 RClusterIndex GetItemIndex(NTupleSize_t globalIndex);
183
184 RNullableField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
185
186public:
187 RNullableField(RNullableField &&other) = default;
189 ~RNullableField() override = default;
190
191 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
192};
193
195 class ROptionalDeleter : public RDeleter {
196 private:
197 std::unique_ptr<RDeleter> fItemDeleter; // nullptr for trivially destructible items
198 std::size_t fEngagementPtrOffset = 0;
199
200 public:
201 ROptionalDeleter(std::unique_ptr<RDeleter> itemDeleter, std::size_t engagementPtrOffset)
202 : fItemDeleter(std::move(itemDeleter)), fEngagementPtrOffset(engagementPtrOffset) {}
203 void operator()(void *objPtr, bool dtorOnly) final;
204 };
205
206 std::unique_ptr<RDeleter> fItemDeleter;
207
208 /// Given a pointer to an std::optional<T> in `optionalPtr`, extract a pointer to the engagement boolean.
209 /// Assumes that an std::optional<T> is stored as `struct { T t; bool engagement; };`
210 const bool *GetEngagementPtr(const void *optionalPtr) const;
211 bool *GetEngagementPtr(void *optionalPtr) const;
212 std::size_t GetEngagementPtrOffset() const;
213
214protected:
215 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
216
217 void ConstructValue(void *where) const final;
218 std::unique_ptr<RDeleter> GetDeleter() const final;
219
220 std::size_t AppendImpl(const void *from) final;
221 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
222
223public:
224 ROptionalField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
225 ROptionalField(ROptionalField &&other) = default;
226 ROptionalField &operator=(ROptionalField &&other) = default;
227 ~ROptionalField() override = default;
228
229 std::vector<RValue> SplitValue(const RValue &value) const final;
230 size_t GetValueSize() const final;
231 size_t GetAlignment() const final;
232};
233
234template <typename ItemT>
235class RField<std::optional<ItemT>> final : public ROptionalField {
236public:
237 static std::string TypeName() { return "std::optional<" + RField<ItemT>::TypeName() + ">"; }
238 explicit RField(std::string_view name) : ROptionalField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
239 RField(RField &&other) = default;
240 RField &operator=(RField &&other) = default;
241 ~RField() final = default;
242};
243
246 private:
247 std::unique_ptr<RDeleter> fItemDeleter;
248
249 public:
250 explicit RUniquePtrDeleter(std::unique_ptr<RDeleter> itemDeleter) : fItemDeleter(std::move(itemDeleter)) {}
251 void operator()(void *objPtr, bool dtorOnly) final;
252 };
253
254 std::unique_ptr<RDeleter> fItemDeleter;
255
256protected:
257 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
258
259 void ConstructValue(void *where) const final { new (where) std::unique_ptr<char>(); }
260 std::unique_ptr<RDeleter> GetDeleter() const final;
261
262 std::size_t AppendImpl(const void *from) final;
263 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
264
265public:
266 RUniquePtrField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
268 RUniquePtrField &operator=(RUniquePtrField &&other) = default;
269 ~RUniquePtrField() override = default;
270
271 std::vector<RValue> SplitValue(const RValue &value) const final;
272 size_t GetValueSize() const final { return sizeof(std::unique_ptr<char>); }
273 size_t GetAlignment() const final { return alignof(std::unique_ptr<char>); }
274};
275
276template <typename ItemT>
277class RField<std::unique_ptr<ItemT>> final : public RUniquePtrField {
278public:
279 static std::string TypeName() { return "std::unique_ptr<" + RField<ItemT>::TypeName() + ">"; }
280 explicit RField(std::string_view name) : RUniquePtrField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
281 RField(RField &&other) = default;
282 RField &operator=(RField &&other) = default;
283 ~RField() final = default;
284};
285
286////////////////////////////////////////////////////////////////////////////////
287/// Template specializations for C++ std::string
288////////////////////////////////////////////////////////////////////////////////
289
290template <>
291class RField<std::string> final : public RFieldBase {
292private:
293 ClusterSize_t fIndex;
294
295 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
296 {
297 return std::make_unique<RField>(newName);
298 }
299
300 const RColumnRepresentations &GetColumnRepresentations() const final;
301 void GenerateColumns() final;
302 void GenerateColumns(const RNTupleDescriptor &desc) final;
303
304 void ConstructValue(void *where) const final { new (where) std::string(); }
305 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<std::string>>(); }
306
307 std::size_t AppendImpl(const void *from) final;
308 void ReadGlobalImpl(ROOT::Experimental::NTupleSize_t globalIndex, void *to) final;
309
310 void CommitClusterImpl() final { fIndex = 0; }
311
312public:
313 static std::string TypeName() { return "std::string"; }
314 explicit RField(std::string_view name)
315 : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, false /* isSimple */), fIndex(0)
316 {
317 }
318 RField(RField &&other) = default;
319 RField &operator=(RField &&other) = default;
320 ~RField() final = default;
321
322 size_t GetValueSize() const final { return sizeof(std::string); }
323 size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
324 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
325};
326
327////////////////////////////////////////////////////////////////////////////////
328/// Template specializations for C++ std::variant
329////////////////////////////////////////////////////////////////////////////////
330
331/// The generic field for std::variant types
332class RVariantField : public RFieldBase {
333private:
334 // Most compilers support at least 255 variants (256 - 1 value for the empty variant).
335 // Some compilers switch to a two-byte tag field already with 254 variants.
336 // MSVC only supports 163 variants in older versions, 250 in newer ones. It switches to a 2 byte
337 // tag as of 128 variants (at least in debug mode), so for simplicity we set the limit to 125 variants.
338 static constexpr std::size_t kMaxVariants = 125;
339
340 class RVariantDeleter : public RDeleter {
341 private:
342 std::size_t fTagOffset;
343 std::size_t fVariantOffset;
344 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
345
346 public:
347 RVariantDeleter(std::size_t tagOffset, std::size_t variantOffset,
348 std::vector<std::unique_ptr<RDeleter>> itemDeleters)
349 : fTagOffset(tagOffset), fVariantOffset(variantOffset), fItemDeleters(std::move(itemDeleters))
350 {
351 }
352 void operator()(void *objPtr, bool dtorOnly) final;
353 };
354
355 size_t fMaxItemSize = 0;
356 size_t fMaxAlignment = 1;
357 /// In the std::variant memory layout, at which byte number is the index stored
358 size_t fTagOffset = 0;
359 /// In the std::variant memory layout, the actual union of types may start at an offset > 0
360 size_t fVariantOffset = 0;
361 std::vector<ClusterSize_t::ValueType> fNWritten;
362
363 static std::string GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields);
364 /// Extracts the index from an std::variant and transforms it into the 1-based index used for the switch column
365 /// The implementation supports two memory layouts that are in use: a trailing unsigned byte, zero-indexed,
366 /// having the exception caused empty state encoded by the max tag value,
367 /// or a trailing unsigned int instead of a char.
368 static std::uint8_t GetTag(const void *variantPtr, std::size_t tagOffset);
369 static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag);
370
371 RVariantField(std::string_view name, const RVariantField &source); // Used by CloneImpl()
372
373protected:
374 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
375
376 const RColumnRepresentations &GetColumnRepresentations() const final;
377 void GenerateColumns() final;
378 void GenerateColumns(const RNTupleDescriptor &desc) final;
379
380 void ConstructValue(void *where) const final;
381 std::unique_ptr<RDeleter> GetDeleter() const final;
382
383 std::size_t AppendImpl(const void *from) final;
384 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
385
386 void CommitClusterImpl() final;
387
388public:
389 RVariantField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
390 RVariantField(RVariantField &&other) = default;
391 RVariantField &operator=(RVariantField &&other) = default;
392 ~RVariantField() override = default;
393
394 size_t GetValueSize() const final;
395 size_t GetAlignment() const final;
396};
397
398template <typename... ItemTs>
399class RField<std::variant<ItemTs...>> final : public RVariantField {
400private:
401 template <typename HeadT, typename... TailTs>
402 static std::string BuildItemTypes()
403 {
404 std::string result = RField<HeadT>::TypeName();
405 if constexpr (sizeof...(TailTs) > 0)
406 result += "," + BuildItemTypes<TailTs...>();
407 return result;
408 }
409
410 template <typename HeadT, typename... TailTs>
411 static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
412 {
413 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
414 if constexpr (sizeof...(TailTs) > 0)
415 _BuildItemFields<TailTs...>(itemFields, index + 1);
416 }
417 static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
418 {
419 std::vector<std::unique_ptr<RFieldBase>> result;
420 _BuildItemFields<ItemTs...>(result);
421 return result;
422 }
423
424public:
425 static std::string TypeName() { return "std::variant<" + BuildItemTypes<ItemTs...>() + ">"; }
426 explicit RField(std::string_view name) : RVariantField(name, BuildItemFields()) {}
427 RField(RField &&other) = default;
428 RField &operator=(RField &&other) = default;
429 ~RField() final = default;
430};
431
432} // namespace Experimental
433} // namespace ROOT
434
435#endif
ROOT::Experimental::RField< T > RField
#define N
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 result
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
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
TRObject operator()(const T1 &t1) const
Binding & operator=(OUT(*fun)(void))
Abstract base class for classes implementing the visitor design pattern.
Template specializations for C++ std::atomic.
~RAtomicField() override=default
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:955
std::unique_ptr< RDeleter > GetDeleter() const final
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
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 a value for this field.
Definition RField.cxx:962
RAtomicField & operator=(RAtomicField &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
RAtomicField(RAtomicField &&other)=default
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:969
Template specializations for C++ std::bitset.
std::size_t GetN() const
Get the number of bits in the bitset, i.e. the N in std::bitset<N>
RBitsetField(RBitsetField &&other)=default
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
~RBitsetField() override=default
RBitsetField & operator=(RBitsetField &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:154
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.hxx:138
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Some fields have multiple possible column representations, e.g.
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.
virtual void GenerateColumns()
Implementations in derived classes should create the backing columns corresponsing to the field type ...
static std::size_t CallAppendOn(RFieldBase &other, const void *from)
Allow derived classes to call Append and Read on other (sub) fields.
static std::unique_ptr< RDeleter > GetDeleterOf(const RFieldBase &other)
static void CallReadOn(RFieldBase &other, RClusterIndex clusterIndex, void *to)
static void CallConstructValueOn(const RFieldBase &other, void *where)
Allow derived classes to call ConstructValue(void *) and GetDeleter on other (sub) fields.
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:242
RField & operator=(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:244
The on-storage meta-data of an ntuple.
Template specializations for C++ std::optional and std::unique_ptr.
RNullableField & operator=(RNullableField &&other)=default
~RNullableField() override=default
RNullableField(RNullableField &&other)=default
ROptionalDeleter(std::unique_ptr< RDeleter > itemDeleter, std::size_t engagementPtrOffset)
std::size_t GetEngagementPtrOffset() const
std::unique_ptr< RDeleter > fItemDeleter
RUniquePtrDeleter(std::unique_ptr< RDeleter > itemDeleter)
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
std::unique_ptr< RDeleter > fItemDeleter
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
std::vector< std::unique_ptr< RDeleter > > fItemDeleters
RVariantDeleter(std::size_t tagOffset, std::size_t variantOffset, std::vector< std::unique_ptr< RDeleter > > itemDeleters)
Template specializations for C++ std::variant.
std::vector< ClusterSize_t::ValueType > fNWritten
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
RClusterSize ClusterSize_t
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
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.