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