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
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_STLMisc
15#define ROOT_RField_STLMisc
16
17#ifndef ROOT_RField
18#error "Please include RField.hxx!"
19#endif
20
21#include <ROOT/RFieldBase.hxx>
22#include <ROOT/RNTupleTypes.hxx>
23
24#include <atomic>
25#include <bitset>
26#include <cstddef>
27#include <memory>
28#include <optional>
29#include <string>
30#include <string_view>
31#include <variant>
32
33namespace ROOT {
34namespace Experimental {
35
36namespace Detail {
37class RFieldVisitor;
38} // namespace Detail
39
40} // namespace Experimental
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); }
56
57public:
58 RAtomicField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
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
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;
79};
80
81////////////////////////////////////////////////////////////////////////////////
82/// Template specializations for C++ std::bitset
83////////////////////////////////////////////////////////////////////////////////
84
85/// The generic field for a `std::bitset<N>`.
86/// GCC and Clang store the bits in an array of unsigned long, whereas MSVC uses either a single uint32_t for `N <= 32`
87/// or an array of uint64_t for `N > 32` (reference: https://github.com/microsoft/STL/blob/main/stl/inc/bitset).
88/// TODO(jblomer): reading and writing efficiency should be improved; currently it is one bit at a time
89/// with an array of bools on the page level.
91protected:
92 std::size_t fN;
93
94protected:
95 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
96 {
97 return std::make_unique<RBitsetField>(newName, fN);
98 }
99 const RColumnRepresentations &GetColumnRepresentations() const final;
100 void GenerateColumns() final;
103 std::size_t AppendImpl(const void *from) final;
104 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
105 void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
106
107 size_t WordSize() const
108 {
109#if defined(_MSC_VER)
110 const size_t wordSize = (fN <= sizeof(unsigned long) * 8) ? sizeof(unsigned long) : sizeof(unsigned long long);
111#else
112 const size_t wordSize = sizeof(unsigned long);
113#endif
114 return wordSize;
115 }
116
117 template <typename FUlong, typename FUlonglong, typename... Args>
118 void SelectWordSize(FUlong &&fUlong, FUlonglong &&fUlonglong, Args &&...args);
119
120public:
121 RBitsetField(std::string_view fieldName, std::size_t N);
124 ~RBitsetField() override = default;
125
127 {
128 const size_t bitsPerWord = WordSize() * 8;
129 return WordSize() * ((fN + bitsPerWord - 1) / bitsPerWord);
130 }
131
133 {
134#if defined(_MSC_VER)
135 return WordSize() == sizeof(unsigned long) ? alignof(unsigned long) : alignof(unsigned long long);
136#else
137 return alignof(unsigned long);
138#endif
139 }
140
142
143 /// Get the number of bits in the bitset, i.e. the `N` in `std::bitset<N>`
144 std::size_t GetN() const { return fN; }
145};
146
147template <std::size_t N>
148class RField<std::bitset<N>> final : public RBitsetField {
149public:
150 static std::string TypeName() { return "std::bitset<" + std::to_string(N) + ">"; }
151 explicit RField(std::string_view name) : RBitsetField(name, N) {}
152 RField(RField &&other) = default;
153 RField &operator=(RField &&other) = default;
155};
156
157////////////////////////////////////////////////////////////////////////////////
158/// Template specializations for C++ std::byte
159////////////////////////////////////////////////////////////////////////////////
160
161extern template class RSimpleField<std::byte>;
162
163template <>
164class RField<std::byte> final : public RSimpleField<std::byte> {
165protected:
166 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
167 {
168 return std::make_unique<RField>(newName);
169 }
170
171 const RColumnRepresentations &GetColumnRepresentations() const final;
172
173public:
174 static std::string TypeName() { return "std::byte"; }
175 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
176 RField(RField &&other) = default;
177 RField &operator=(RField &&other) = default;
179
180 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
181};
182
183////////////////////////////////////////////////////////////////////////////////
184/// Template specializations for C++ std::optional and std::unique_ptr
185////////////////////////////////////////////////////////////////////////////////
186
187/// The field for values that may or may not be present in an entry. Parent class for unique pointer field and
188/// optional field. A nullable field cannot be instantiated itself but only its descendants.
189/// The RNullableField takes care of the on-disk representation. Child classes are responsible for the in-memory
190/// representation. Nullable fields use a `(Split)Index[64|32]` column to point to the available items.
192 /// The number of written non-null items in this cluster
194
195protected:
197 void GenerateColumns() final;
199
200 std::size_t AppendNull();
201 std::size_t AppendValue(const void *from);
202 void CommitClusterImpl() final { fNWritten = 0; }
203
204 /// Given the index of the nullable field, returns the corresponding global index of the subfield or,
205 /// if it is null, returns `kInvalidNTupleIndex`
207
208 RNullableField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
209
210public:
213 ~RNullableField() override = default;
214
216};
217
219 class ROptionalDeleter : public RDeleter {
220 private:
221 std::unique_ptr<RDeleter> fItemDeleter; // nullptr for trivially destructible items
222 std::size_t fEngagementPtrOffset = 0;
223
224 public:
225 ROptionalDeleter(std::unique_ptr<RDeleter> itemDeleter, std::size_t engagementPtrOffset)
226 : fItemDeleter(std::move(itemDeleter)), fEngagementPtrOffset(engagementPtrOffset) {}
227 void operator()(void *objPtr, bool dtorOnly) final;
228 };
229
230 std::unique_ptr<RDeleter> fItemDeleter;
231
232 /// Given a pointer to an `std::optional<T>` in `optionalPtr`, extract a pointer to the engagement boolean.
233 /// Assumes that an `std::optional<T>` is stored as `struct { T t; bool engagement; };`
234 const bool *GetEngagementPtr(const void *optionalPtr) const;
235 bool *GetEngagementPtr(void *optionalPtr) const;
236 std::size_t GetEngagementPtrOffset() const;
237
238protected:
239 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
240
241 void ConstructValue(void *where) const final;
242 std::unique_ptr<RDeleter> GetDeleter() const final;
243
244 std::size_t AppendImpl(const void *from) final;
245 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
246
247public:
248 ROptionalField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
252
253 std::vector<RValue> SplitValue(const RValue &value) const final;
254 size_t GetValueSize() const final;
255 size_t GetAlignment() const final;
256};
257
259class RField<std::optional<ItemT>> final : public ROptionalField {
260public:
261 static std::string TypeName() { return "std::optional<" + RField<ItemT>::TypeName() + ">"; }
262 explicit RField(std::string_view name) : ROptionalField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
263 RField(RField &&other) = default;
264 RField &operator=(RField &&other) = default;
265 ~RField() final = default;
266};
267
270 private:
271 std::unique_ptr<RDeleter> fItemDeleter;
272
273 public:
274 explicit RUniquePtrDeleter(std::unique_ptr<RDeleter> itemDeleter) : fItemDeleter(std::move(itemDeleter)) {}
275 void operator()(void *objPtr, bool dtorOnly) final;
276 };
277
278 std::unique_ptr<RDeleter> fItemDeleter;
279
280protected:
281 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
282
283 void ConstructValue(void *where) const final { new (where) std::unique_ptr<char>(); }
284 std::unique_ptr<RDeleter> GetDeleter() const final;
285
286 std::size_t AppendImpl(const void *from) final;
287 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
288
289public:
290 RUniquePtrField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
294
295 std::vector<RValue> SplitValue(const RValue &value) const final;
296 size_t GetValueSize() const final { return sizeof(std::unique_ptr<char>); }
297 size_t GetAlignment() const final { return alignof(std::unique_ptr<char>); }
298};
299
300template <typename ItemT>
301class RField<std::unique_ptr<ItemT>> final : public RUniquePtrField {
302public:
303 static std::string TypeName() { return "std::unique_ptr<" + RField<ItemT>::TypeName() + ">"; }
304 explicit RField(std::string_view name) : RUniquePtrField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
305 RField(RField &&other) = default;
306 RField &operator=(RField &&other) = default;
307 ~RField() final = default;
308};
309
310////////////////////////////////////////////////////////////////////////////////
311/// Template specializations for C++ std::string
312////////////////////////////////////////////////////////////////////////////////
313
314template <>
315class RField<std::string> final : public RFieldBase {
316private:
318
319 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
320 {
321 return std::make_unique<RField>(newName);
322 }
323
324 const RColumnRepresentations &GetColumnRepresentations() const final;
325 void GenerateColumns() final;
326 void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final;
327
328 void ConstructValue(void *where) const final { new (where) std::string(); }
329 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<std::string>>(); }
330
331 std::size_t AppendImpl(const void *from) final;
332 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
333
334 void CommitClusterImpl() final { fIndex = 0; }
335
336public:
337 static std::string TypeName() { return "std::string"; }
338 explicit RField(std::string_view name)
339 : RFieldBase(name, TypeName(), ROOT::ENTupleStructure::kPlain, false /* isSimple */), fIndex(0)
340 {
341 }
342 RField(RField &&other) = default;
343 RField &operator=(RField &&other) = default;
344 ~RField() final = default;
345
346 size_t GetValueSize() const final { return sizeof(std::string); }
347 size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
348 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
349};
350
351////////////////////////////////////////////////////////////////////////////////
352/// Template specializations for C++ std::variant
353////////////////////////////////////////////////////////////////////////////////
354
355/// The generic field for std::variant types
356class RVariantField : public RFieldBase {
357private:
358 // Most compilers support at least 255 variants (256 - 1 value for the empty variant).
359 // Some compilers switch to a two-byte tag field already with 254 variants.
360 // MSVC only supports 163 variants in older versions, 250 in newer ones. It switches to a 2 byte
361 // tag as of 128 variants (at least in debug mode), so for simplicity we set the limit to 125 variants.
362 static constexpr std::size_t kMaxVariants = 125;
363
364 class RVariantDeleter : public RDeleter {
365 private:
366 std::size_t fTagOffset;
367 std::size_t fVariantOffset;
368 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
369
370 public:
371 RVariantDeleter(std::size_t tagOffset, std::size_t variantOffset,
372 std::vector<std::unique_ptr<RDeleter>> itemDeleters)
373 : fTagOffset(tagOffset), fVariantOffset(variantOffset), fItemDeleters(std::move(itemDeleters))
374 {
375 }
376 void operator()(void *objPtr, bool dtorOnly) final;
377 };
378
379 size_t fMaxItemSize = 0;
380 size_t fMaxAlignment = 1;
381 /// In the `std::variant` memory layout, at which byte number is the index stored
382 size_t fTagOffset = 0;
383 /// In the `std::variant` memory layout, the actual union of types may start at an offset > 0
384 size_t fVariantOffset = 0;
385 std::vector<ROOT::Internal::RColumnIndex::ValueType> fNWritten;
386
387 static std::string GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields);
388 /// Extracts the index from an `std::variant` and transforms it into the 1-based index used for the switch column
389 /// The implementation supports two memory layouts that are in use: a trailing unsigned byte, zero-indexed,
390 /// having the exception caused empty state encoded by the max tag value,
391 /// or a trailing unsigned int instead of a char.
392 static std::uint8_t GetTag(const void *variantPtr, std::size_t tagOffset);
393 static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag);
394
395 RVariantField(std::string_view name, const RVariantField &source); // Used by CloneImpl()
396
397protected:
398 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
399
400 const RColumnRepresentations &GetColumnRepresentations() const final;
401 void GenerateColumns() final;
402 void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final;
403
404 void ConstructValue(void *where) const final;
405 std::unique_ptr<RDeleter> GetDeleter() const final;
406
407 std::size_t AppendImpl(const void *from) final;
408 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
409
410 void CommitClusterImpl() final;
411
412public:
413 RVariantField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
417
418 size_t GetValueSize() const final;
419 size_t GetAlignment() const final;
420};
421
424private:
425 template <typename HeadT, typename... TailTs>
426 static std::string BuildItemTypes()
427 {
428 std::string result = RField<HeadT>::TypeName();
429 if constexpr (sizeof...(TailTs) > 0)
430 result += "," + BuildItemTypes<TailTs...>();
431 return result;
432 }
433
434 template <typename HeadT, typename... TailTs>
435 static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
436 {
437 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
438 if constexpr (sizeof...(TailTs) > 0)
439 _BuildItemFields<TailTs...>(itemFields, index + 1);
440 }
441 static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
442 {
443 std::vector<std::unique_ptr<RFieldBase>> result;
444 _BuildItemFields<ItemTs...>(result);
445 return result;
446 }
447
448public:
449 static std::string TypeName() { return "std::variant<" + BuildItemTypes<ItemTs...>() + ">"; }
450 explicit RField(std::string_view name) : RVariantField(name, BuildItemFields()) {}
451 RField(RField &&other) = default;
452 RField &operator=(RField &&other) = default;
453 ~RField() final = default;
454};
455
456} // namespace ROOT
457
458#endif
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#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.
The in-memory representation of a 32bit or 64bit on-disk index column.
Template specializations for C++ std::atomic.
RAtomicField(RAtomicField &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
RAtomicField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:982
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.
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1006
void ReadGlobalImpl(ROOT::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.
Definition RField.cxx:993
void ReadInClusterImpl(RNTupleLocalIndex localIndex, 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
~RAtomicField() override=default
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Definition RField.cxx:999
RAtomicField & operator=(RAtomicField &&other)=default
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>
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
size_t WordSize() const
~RBitsetField() override=default
RBitsetField & operator=(RBitsetField &&other)=default
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(RBitsetField &&other)=default
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) 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 AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
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.
std::vector< std::unique_ptr< RFieldBase > > fSubfields
Collections and classes own subfields.
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
virtual void GenerateColumns()
Implementations in derived classes should create the backing columns corresponding to the field type ...
static std::unique_ptr< RDeleter > GetDeleterOf(const RFieldBase &other)
static std::size_t CallAppendOn(RFieldBase &other, const void *from)
Allow derived classes to call Append() and Read() on other (sub)fields.
virtual void CommitClusterImpl()
static void CallReadOn(RFieldBase &other, RNTupleLocalIndex localIndex, void *to)
static void CallConstructValueOn(const RFieldBase &other, void *where)
Allow derived classes to call ConstructValue(void *) and GetDeleter() on other (sub)fields.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:287
~RField() final=default
RField & operator=(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:289
RField(std::string_view name)
Definition RField.hxx:290
The on-storage metadata of an RNTuple.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Template specializations for C++ std::optional and std::unique_ptr.
~RNullableField() override=default
RNullableField & operator=(RNullableField &&other)=default
RNullableField(RNullableField &&other)=default
ROptionalDeleter(std::unique_ptr< RDeleter > itemDeleter, std::size_t engagementPtrOffset)
std::unique_ptr< RDeleter > fItemDeleter
std::size_t GetEngagementPtrOffset() const
std::unique_ptr< RDeleter > fItemDeleter
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< ROOT::Internal::RColumnIndex::ValueType > fNWritten
Namespace for new ROOT classes and functions.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.