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;
198
199 public:
200 explicit ROptionalDeleter(std::unique_ptr<RDeleter> itemDeleter) : fItemDeleter(std::move(itemDeleter)) {}
201 void operator()(void *objPtr, bool dtorOnly) final;
202 };
203
204 std::unique_ptr<RDeleter> fItemDeleter;
205
206 /// Given a pointer to an std::optional<T> in `optionalPtr`, extract a pointer to the value T* and a pointer
207 /// to the engagement boolean. Assumes that an std::optional<T> is stored as
208 /// `struct { T t; bool engagement; };`
209 std::pair<const void *, const bool *> GetValueAndEngagementPtrs(const void *optionalPtr) const;
210 std::pair<void *, bool *> GetValueAndEngagementPtrs(void *optionalPtr) const;
211
212protected:
213 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
214
215 void ConstructValue(void *where) const final;
216 std::unique_ptr<RDeleter> GetDeleter() const final;
217
218 std::size_t AppendImpl(const void *from) final;
219 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
220
221public:
222 ROptionalField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
223 ROptionalField(ROptionalField &&other) = default;
224 ROptionalField &operator=(ROptionalField &&other) = default;
225 ~ROptionalField() override = default;
226
227 std::vector<RValue> SplitValue(const RValue &value) const final;
228 size_t GetValueSize() const final;
229 size_t GetAlignment() const final;
230};
231
232template <typename ItemT>
233class RField<std::optional<ItemT>> final : public ROptionalField {
234public:
235 static std::string TypeName() { return "std::optional<" + RField<ItemT>::TypeName() + ">"; }
236 explicit RField(std::string_view name) : ROptionalField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
237 RField(RField &&other) = default;
238 RField &operator=(RField &&other) = default;
239 ~RField() final = default;
240};
241
244 private:
245 std::unique_ptr<RDeleter> fItemDeleter;
246
247 public:
248 explicit RUniquePtrDeleter(std::unique_ptr<RDeleter> itemDeleter) : fItemDeleter(std::move(itemDeleter)) {}
249 void operator()(void *objPtr, bool dtorOnly) final;
250 };
251
252 std::unique_ptr<RDeleter> fItemDeleter;
253
254protected:
255 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
256
257 void ConstructValue(void *where) const final { new (where) std::unique_ptr<char>(); }
258 std::unique_ptr<RDeleter> GetDeleter() const final;
259
260 std::size_t AppendImpl(const void *from) final;
261 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
262
263public:
264 RUniquePtrField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
266 RUniquePtrField &operator=(RUniquePtrField &&other) = default;
267 ~RUniquePtrField() override = default;
268
269 std::vector<RValue> SplitValue(const RValue &value) const final;
270 size_t GetValueSize() const final { return sizeof(std::unique_ptr<char>); }
271 size_t GetAlignment() const final { return alignof(std::unique_ptr<char>); }
272};
273
274template <typename ItemT>
275class RField<std::unique_ptr<ItemT>> final : public RUniquePtrField {
276public:
277 static std::string TypeName() { return "std::unique_ptr<" + RField<ItemT>::TypeName() + ">"; }
278 explicit RField(std::string_view name) : RUniquePtrField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
279 RField(RField &&other) = default;
280 RField &operator=(RField &&other) = default;
281 ~RField() final = default;
282};
283
284////////////////////////////////////////////////////////////////////////////////
285/// Template specializations for C++ std::string
286////////////////////////////////////////////////////////////////////////////////
287
288template <>
289class RField<std::string> final : public RFieldBase {
290private:
291 ClusterSize_t fIndex;
292
293 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
294 {
295 return std::make_unique<RField>(newName);
296 }
297
298 const RColumnRepresentations &GetColumnRepresentations() const final;
299 void GenerateColumns() final;
300 void GenerateColumns(const RNTupleDescriptor &desc) final;
301
302 void ConstructValue(void *where) const final { new (where) std::string(); }
303 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<std::string>>(); }
304
305 std::size_t AppendImpl(const void *from) final;
306 void ReadGlobalImpl(ROOT::Experimental::NTupleSize_t globalIndex, void *to) final;
307
308 void CommitClusterImpl() final { fIndex = 0; }
309
310public:
311 static std::string TypeName() { return "std::string"; }
312 explicit RField(std::string_view name)
313 : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, false /* isSimple */), fIndex(0)
314 {
315 }
316 RField(RField &&other) = default;
317 RField &operator=(RField &&other) = default;
318 ~RField() final = default;
319
320 size_t GetValueSize() const final { return sizeof(std::string); }
321 size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
322 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
323};
324
325////////////////////////////////////////////////////////////////////////////////
326/// Template specializations for C++ std::variant
327////////////////////////////////////////////////////////////////////////////////
328
329/// The generic field for std::variant types
330class RVariantField : public RFieldBase {
331private:
332 // Most compilers support at least 255 variants (256 - 1 value for the empty variant).
333 // Some compilers switch to a two-byte tag field already with 254 variants.
334 // MSVC only supports 163 variants in older versions, 250 in newer ones. It switches to a 2 byte
335 // tag as of 128 variants (at least in debug mode), so for simplicity we set the limit to 125 variants.
336 static constexpr std::size_t kMaxVariants = 125;
337
338 class RVariantDeleter : public RDeleter {
339 private:
340 std::size_t fTagOffset;
341 std::size_t fVariantOffset;
342 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
343
344 public:
345 RVariantDeleter(std::size_t tagOffset, std::size_t variantOffset,
346 std::vector<std::unique_ptr<RDeleter>> itemDeleters)
347 : fTagOffset(tagOffset), fVariantOffset(variantOffset), fItemDeleters(std::move(itemDeleters))
348 {
349 }
350 void operator()(void *objPtr, bool dtorOnly) final;
351 };
352
353 size_t fMaxItemSize = 0;
354 size_t fMaxAlignment = 1;
355 /// In the std::variant memory layout, at which byte number is the index stored
356 size_t fTagOffset = 0;
357 /// In the std::variant memory layout, the actual union of types may start at an offset > 0
358 size_t fVariantOffset = 0;
359 std::vector<ClusterSize_t::ValueType> fNWritten;
360
361 static std::string GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields);
362 /// Extracts the index from an std::variant and transforms it into the 1-based index used for the switch column
363 /// The implementation supports two memory layouts that are in use: a trailing unsigned byte, zero-indexed,
364 /// having the exception caused empty state encoded by the max tag value,
365 /// or a trailing unsigned int instead of a char.
366 static std::uint8_t GetTag(const void *variantPtr, std::size_t tagOffset);
367 static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag);
368
369 RVariantField(std::string_view name, const RVariantField &source); // Used by CloneImpl()
370
371protected:
372 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
373
374 const RColumnRepresentations &GetColumnRepresentations() const final;
375 void GenerateColumns() final;
376 void GenerateColumns(const RNTupleDescriptor &desc) final;
377
378 void ConstructValue(void *where) const final;
379 std::unique_ptr<RDeleter> GetDeleter() const final;
380
381 std::size_t AppendImpl(const void *from) final;
382 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
383
384 void CommitClusterImpl() final;
385
386public:
387 RVariantField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
388 RVariantField(RVariantField &&other) = default;
389 RVariantField &operator=(RVariantField &&other) = default;
390 ~RVariantField() override = default;
391
392 size_t GetValueSize() const final;
393 size_t GetAlignment() const final;
394};
395
396template <typename... ItemTs>
397class RField<std::variant<ItemTs...>> final : public RVariantField {
398private:
399 template <typename HeadT, typename... TailTs>
400 static std::string BuildItemTypes()
401 {
402 std::string result = RField<HeadT>::TypeName();
403 if constexpr (sizeof...(TailTs) > 0)
404 result += "," + BuildItemTypes<TailTs...>();
405 return result;
406 }
407
408 template <typename HeadT, typename... TailTs>
409 static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
410 {
411 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
412 if constexpr (sizeof...(TailTs) > 0)
413 _BuildItemFields<TailTs...>(itemFields, index + 1);
414 }
415 static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
416 {
417 std::vector<std::unique_ptr<RFieldBase>> result;
418 _BuildItemFields<ItemTs...>(result);
419 return result;
420 }
421
422public:
423 static std::string TypeName() { return "std::variant<" + BuildItemTypes<ItemTs...>() + ">"; }
424 explicit RField(std::string_view name) : RVariantField(name, BuildItemFields()) {}
425 RField(RField &&other) = default;
426 RField &operator=(RField &&other) = default;
427 ~RField() final = default;
428};
429
430} // namespace Experimental
431} // namespace ROOT
432
433#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:3956
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:3963
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:3970
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.
Definition RField.cxx:1972
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Definition RField.cxx:1914
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:1898
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:1907
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1893
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:1948
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:153
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1987
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.
Definition RField.cxx:899
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:241
RField & operator=(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:243
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::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.