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
57 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
58
59public:
60 RAtomicField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
63 ~RAtomicField() override = default;
64
65 std::vector<RValue> SplitValue(const RValue &value) const final;
66
67 size_t GetValueSize() const final { return fSubfields[0]->GetValueSize(); }
68 size_t GetAlignment() const final { return fSubfields[0]->GetAlignment(); }
69
71};
72
73template <typename ItemT>
74class RField<std::atomic<ItemT>> final : public RAtomicField {
75public:
76 static std::string TypeName() { return "std::atomic<" + RField<ItemT>::TypeName() + ">"; }
77 explicit RField(std::string_view name) : RAtomicField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
78 RField(RField &&other) = default;
79 RField &operator=(RField &&other) = default;
81};
82
83////////////////////////////////////////////////////////////////////////////////
84/// Template specializations for C++ std::bitset
85////////////////////////////////////////////////////////////////////////////////
86
87/// The generic field for a `std::bitset<N>`.
88/// GCC and Clang store the bits in an array of unsigned long, whereas MSVC uses either a single uint32_t for `N <= 32`
89/// or an array of uint64_t for `N > 32` (reference: https://github.com/microsoft/STL/blob/main/stl/inc/bitset).
90/// TODO(jblomer): reading and writing efficiency should be improved; currently it is one bit at a time
91/// with an array of bools on the page level.
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;
105 std::size_t AppendImpl(const void *from) final;
106 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
107 void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
108
109 size_t WordSize() const
110 {
111#if defined(_MSC_VER)
112 const size_t wordSize = (fN <= sizeof(unsigned long) * 8) ? sizeof(unsigned long) : sizeof(unsigned long long);
113#else
114 const size_t wordSize = sizeof(unsigned long);
115#endif
116 return wordSize;
117 }
118
119 template <typename FUlong, typename FUlonglong, typename... Args>
120 void SelectWordSize(FUlong &&fUlong, FUlonglong &&fUlonglong, Args &&...args);
121
122public:
123 RBitsetField(std::string_view fieldName, std::size_t N);
126 ~RBitsetField() override = default;
127
129 {
130 const size_t bitsPerWord = WordSize() * 8;
131 return WordSize() * ((fN + bitsPerWord - 1) / bitsPerWord);
132 }
133
135 {
136#if defined(_MSC_VER)
137 return WordSize() == sizeof(unsigned long) ? alignof(unsigned long) : alignof(unsigned long long);
138#else
139 return alignof(unsigned long);
140#endif
141 }
142
144
145 /// Get the number of bits in the bitset, i.e. the `N` in `std::bitset<N>`
146 std::size_t GetN() const { return fN; }
147};
148
149template <std::size_t N>
150class RField<std::bitset<N>> final : public RBitsetField {
151public:
152 static std::string TypeName() { return "std::bitset<" + std::to_string(N) + ">"; }
153 explicit RField(std::string_view name) : RBitsetField(name, N) {}
154 RField(RField &&other) = default;
155 RField &operator=(RField &&other) = default;
157};
158
159////////////////////////////////////////////////////////////////////////////////
160/// Template specializations for C++ std::byte
161////////////////////////////////////////////////////////////////////////////////
162
163extern template class RSimpleField<std::byte>;
164
165template <>
166class RField<std::byte> final : public RSimpleField<std::byte> {
167protected:
168 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
169 {
170 return std::make_unique<RField>(newName);
171 }
172
173 const RColumnRepresentations &GetColumnRepresentations() const final;
174
175public:
176 static std::string TypeName() { return "std::byte"; }
177 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
178 RField(RField &&other) = default;
179 RField &operator=(RField &&other) = default;
181
182 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
183};
184
185////////////////////////////////////////////////////////////////////////////////
186/// Template specializations for C++ std::optional and std::unique_ptr
187////////////////////////////////////////////////////////////////////////////////
188
189/// The field for values that may or may not be present in an entry. Parent class for unique pointer field and
190/// optional field. A nullable field cannot be instantiated itself but only its descendants.
191/// The RNullableField takes care of the on-disk representation. Child classes are responsible for the in-memory
192/// representation. Nullable fields use a `(Split)Index[64|32]` column to point to the available items.
194 /// The number of written non-null items in this cluster
196
197protected:
199 void GenerateColumns() final;
201
202 std::size_t AppendNull();
203 std::size_t AppendValue(const void *from);
204 void CommitClusterImpl() final { fNWritten = 0; }
205
206 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
207
208 /// Given the index of the nullable field, returns the corresponding global index of the subfield or,
209 /// if it is null, returns `kInvalidNTupleIndex`
211
212 RNullableField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
213
214public:
217 ~RNullableField() override = default;
218
220};
221
223 class ROptionalDeleter : public RDeleter {
224 private:
225 std::unique_ptr<RDeleter> fItemDeleter; // nullptr for trivially destructible items
226 std::size_t fEngagementPtrOffset = 0;
227
228 public:
229 ROptionalDeleter(std::unique_ptr<RDeleter> itemDeleter, std::size_t engagementPtrOffset)
230 : fItemDeleter(std::move(itemDeleter)), fEngagementPtrOffset(engagementPtrOffset) {}
231 void operator()(void *objPtr, bool dtorOnly) final;
232 };
233
234 std::unique_ptr<RDeleter> fItemDeleter;
235
236 /// Given a pointer to an `std::optional<T>` in `optionalPtr`, extract a pointer to the engagement boolean.
237 /// Assumes that an `std::optional<T>` is stored as `struct { T t; bool engagement; };`
238 const bool *GetEngagementPtr(const void *optionalPtr) const;
239 bool *GetEngagementPtr(void *optionalPtr) const;
240 std::size_t GetEngagementPtrOffset() const;
241
242protected:
243 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
244
245 void ConstructValue(void *where) const final;
246 std::unique_ptr<RDeleter> GetDeleter() const final;
247
248 std::size_t AppendImpl(const void *from) final;
249 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
250
251public:
252 ROptionalField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
256
257 std::vector<RValue> SplitValue(const RValue &value) const final;
258 size_t GetValueSize() const final;
259 size_t GetAlignment() const final;
260};
261
263class RField<std::optional<ItemT>> final : public ROptionalField {
264public:
265 static std::string TypeName() { return "std::optional<" + RField<ItemT>::TypeName() + ">"; }
266 explicit RField(std::string_view name) : ROptionalField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
267 RField(RField &&other) = default;
268 RField &operator=(RField &&other) = default;
269 ~RField() final = default;
270};
271
274 private:
275 std::unique_ptr<RDeleter> fItemDeleter;
276
277 public:
278 explicit RUniquePtrDeleter(std::unique_ptr<RDeleter> itemDeleter) : fItemDeleter(std::move(itemDeleter)) {}
279 void operator()(void *objPtr, bool dtorOnly) final;
280 };
281
282 std::unique_ptr<RDeleter> fItemDeleter;
283
284protected:
285 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
286
287 void ConstructValue(void *where) const final { new (where) std::unique_ptr<char>(); }
288 std::unique_ptr<RDeleter> GetDeleter() const final;
289
290 std::size_t AppendImpl(const void *from) final;
291 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
292
293public:
294 RUniquePtrField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
298
299 std::vector<RValue> SplitValue(const RValue &value) const final;
300 size_t GetValueSize() const final { return sizeof(std::unique_ptr<char>); }
301 size_t GetAlignment() const final { return alignof(std::unique_ptr<char>); }
302};
303
304template <typename ItemT>
305class RField<std::unique_ptr<ItemT>> final : public RUniquePtrField {
306public:
307 static std::string TypeName() { return "std::unique_ptr<" + RField<ItemT>::TypeName() + ">"; }
308 explicit RField(std::string_view name) : RUniquePtrField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
309 RField(RField &&other) = default;
310 RField &operator=(RField &&other) = default;
311 ~RField() final = default;
312};
313
314////////////////////////////////////////////////////////////////////////////////
315/// Template specializations for C++ std::string
316////////////////////////////////////////////////////////////////////////////////
317
318template <>
319class RField<std::string> final : public RFieldBase {
320private:
322
323 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
324 {
325 return std::make_unique<RField>(newName);
326 }
327
328 const RColumnRepresentations &GetColumnRepresentations() const final;
329 void GenerateColumns() final;
330 void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final;
331
332 void ConstructValue(void *where) const final { new (where) std::string(); }
333 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<std::string>>(); }
334
335 std::size_t AppendImpl(const void *from) final;
336 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
337
338 void CommitClusterImpl() final { fIndex = 0; }
339
340public:
341 static std::string TypeName() { return "std::string"; }
342 explicit RField(std::string_view name)
343 : RFieldBase(name, TypeName(), ROOT::ENTupleStructure::kPlain, false /* isSimple */), fIndex(0)
344 {
345 }
346 RField(RField &&other) = default;
347 RField &operator=(RField &&other) = default;
348 ~RField() final = default;
349
350 size_t GetValueSize() const final { return sizeof(std::string); }
351 size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
352 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
353};
354
355////////////////////////////////////////////////////////////////////////////////
356/// Template specializations for C++ std::variant
357////////////////////////////////////////////////////////////////////////////////
358
359/// The generic field for std::variant types
360class RVariantField : public RFieldBase {
361private:
362 // Most compilers support at least 255 variants (256 - 1 value for the empty variant).
363 // Some compilers switch to a two-byte tag field already with 254 variants.
364 // MSVC only supports 163 variants in older versions, 250 in newer ones. It switches to a 2 byte
365 // tag as of 128 variants (at least in debug mode), so for simplicity we set the limit to 125 variants.
366 static constexpr std::size_t kMaxVariants = 125;
367
368 class RVariantDeleter : public RDeleter {
369 private:
370 std::size_t fTagOffset;
371 std::size_t fVariantOffset;
372 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
373
374 public:
375 RVariantDeleter(std::size_t tagOffset, std::size_t variantOffset,
376 std::vector<std::unique_ptr<RDeleter>> itemDeleters)
377 : fTagOffset(tagOffset), fVariantOffset(variantOffset), fItemDeleters(std::move(itemDeleters))
378 {
379 }
380 void operator()(void *objPtr, bool dtorOnly) final;
381 };
382
383 size_t fMaxItemSize = 0;
384 size_t fMaxAlignment = 1;
385 /// In the `std::variant` memory layout, at which byte number is the index stored
386 size_t fTagOffset = 0;
387 /// In the `std::variant` memory layout, the actual union of types may start at an offset > 0
388 size_t fVariantOffset = 0;
389 std::vector<ROOT::Internal::RColumnIndex::ValueType> fNWritten;
390
391 static std::string GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields);
392 /// Extracts the index from an `std::variant` and transforms it into the 1-based index used for the switch column
393 /// The implementation supports two memory layouts that are in use: a trailing unsigned byte, zero-indexed,
394 /// having the exception caused empty state encoded by the max tag value,
395 /// or a trailing unsigned int instead of a char.
396 static std::uint8_t GetTag(const void *variantPtr, std::size_t tagOffset);
397 static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag);
398
399 RVariantField(std::string_view name, const RVariantField &source); // Used by CloneImpl()
400
401protected:
402 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
403
404 const RColumnRepresentations &GetColumnRepresentations() const final;
405 void GenerateColumns() final;
406 void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final;
407
408 void ConstructValue(void *where) const final;
409 std::unique_ptr<RDeleter> GetDeleter() const final;
410
411 std::size_t AppendImpl(const void *from) final;
412 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
413
414 void CommitClusterImpl() final;
415
416 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
417
418public:
419 RVariantField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
423
424 size_t GetValueSize() const final;
425 size_t GetAlignment() const final;
426};
427
430private:
431 template <typename HeadT, typename... TailTs>
432 static std::string BuildItemTypes()
433 {
434 std::string result = RField<HeadT>::TypeName();
435 if constexpr (sizeof...(TailTs) > 0)
436 result += "," + BuildItemTypes<TailTs...>();
437 return result;
438 }
439
440 template <typename HeadT, typename... TailTs>
441 static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
442 {
443 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
444 if constexpr (sizeof...(TailTs) > 0)
445 _BuildItemFields<TailTs...>(itemFields, index + 1);
446 }
447 static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
448 {
449 std::vector<std::unique_ptr<RFieldBase>> result;
450 _BuildItemFields<ItemTs...>(result);
451 return result;
452 }
453
454public:
455 static std::string TypeName() { return "std::variant<" + BuildItemTypes<ItemTs...>() + ">"; }
456 explicit RField(std::string_view name) : RVariantField(name, BuildItemFields()) {}
457 RField(RField &&other) = default;
458 RField &operator=(RField &&other) = default;
459 ~RField() final = default;
460};
461
462} // namespace ROOT
463
464#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:1032
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:1065
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:1043
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
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
Definition RField.cxx:1049
~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:1058
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 ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
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:292
~RField() final=default
RField & operator=(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:294
RField(std::string_view name)
Definition RField.hxx:295
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
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.