Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RField.hxx
Go to the documentation of this file.
1/// \file ROOT/RField.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
17#define ROOT7_RField
18
19#include <ROOT/RColumn.hxx>
20#include <ROOT/RError.hxx>
22#include <ROOT/RNTupleUtil.hxx>
23#include <ROOT/RSpan.hxx>
24#include <string_view>
25#include <ROOT/RVec.hxx>
26#include <ROOT/TypeTraits.hxx>
27
28#include <TGenericClassInfo.h>
30
31#include <algorithm>
32#include <array>
33#include <atomic>
34#include <bitset>
35#include <cstddef>
36#include <functional>
37#include <iostream>
38#include <iterator>
39#include <map>
40#include <memory>
41#include <new>
42#include <optional>
43#include <set>
44#include <string>
45#include <tuple>
46#include <type_traits>
47#include <typeinfo>
48#include <variant>
49#include <vector>
50#include <utility>
51
52class TClass;
53class TEnum;
54class TObject;
55
56namespace ROOT {
57
58class TSchemaRule;
59class RFieldBase;
60
61namespace Experimental {
62
63class RCollectionField;
64class RNTupleCollectionWriter;
65class REntry;
66
67namespace Internal {
68struct RFieldCallbackInjector;
69class RPageSink;
70class RPageSource;
71// TODO(jblomer): find a better way to not have these three methods in the RFieldBase public API
72void CallCommitClusterOnField(RFieldBase &);
73void CallConnectPageSinkOnField(RFieldBase &, RPageSink &, NTupleSize_t firstEntry = 0);
74void CallConnectPageSourceOnField(RFieldBase &, RPageSource &);
75} // namespace Internal
76
77namespace Detail {
78class RFieldVisitor;
79} // namespace Detail
80
81// clang-format off
82/**
83\class ROOT::Experimental::RFieldBase
84\ingroup NTuple
85\brief A field translates read and write calls from/to underlying columns to/from tree values
86
87A field is a serializable C++ type or a container for a collection of sub fields. The RFieldBase and its
88type-safe descendants provide the object to column mapper. They map C++ objects to primitive columns. The
89mapping is trivial for simple types such as 'double'. Complex types resolve to multiple primitive columns.
90The field knows based on its type and the field name the type(s) and name(s) of the columns.
91
92Note: the class hierarchy starting at RFieldBase is not meant to be extended by user-provided child classes.
93This is and can only be partially enforced through C++.
94*/
95// clang-format on
97 friend class ROOT::Experimental::RCollectionField; // to move the fields from the collection model
98 friend struct ROOT::Experimental::Internal::RFieldCallbackInjector; // used for unit tests
102 using ReadCallback_t = std::function<void(void *)>;
103
104protected:
105 /// A functor to release the memory acquired by CreateValue (memory and constructor).
106 /// This implementation works for types with a trivial destructor. More complex fields implement a derived deleter.
107 /// The deleter is operational without the field object and thus can be used to destruct/release a value after
108 /// the field has been destructed.
109 class RDeleter {
110 public:
111 virtual ~RDeleter() = default;
112 virtual void operator()(void *objPtr, bool dtorOnly)
113 {
114 if (!dtorOnly)
115 operator delete(objPtr);
116 }
117 };
118
119 /// A deleter for templated RFieldBase descendents where the value type is known.
120 template <typename T>
121 class RTypedDeleter : public RDeleter {
122 public:
123 void operator()(void *objPtr, bool dtorOnly) final
124 {
125 std::destroy_at(static_cast<T *>(objPtr));
126 RDeleter::operator()(objPtr, dtorOnly);
127 }
128 };
129
130 // We cannot directly use RFieldBase::RDeleter as a shared pointer deleter due to splicing. We use this
131 // wrapper class to store a polymorphic pointer to the actual deleter.
133 std::unique_ptr<RFieldBase::RDeleter> fDeleter;
134 void operator()(void *objPtr) { fDeleter->operator()(objPtr, false /* dtorOnly*/); }
135 explicit RSharedPtrDeleter(std::unique_ptr<RFieldBase::RDeleter> deleter) : fDeleter(std::move(deleter)) {}
136 };
137
138public:
139 static constexpr std::uint32_t kInvalidTypeVersion = -1U;
140 /// No constructor needs to be called, i.e. any bit pattern in the allocated memory represents a valid type
141 /// A trivially constructible field has a no-op ConstructValue() implementation
142 static constexpr int kTraitTriviallyConstructible = 0x01;
143 /// The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
144 static constexpr int kTraitTriviallyDestructible = 0x02;
145 /// A field of a fundamental type that can be directly mapped via `RField<T>::Map()`, i.e. maps as-is to a single
146 /// column
147 static constexpr int kTraitMappable = 0x04;
148 /// Shorthand for types that are both trivially constructible and destructible
150
151 using ColumnRepresentation_t = std::vector<EColumnType>;
152
153 /// During its lifetime, a field undergoes the following possible state transitions:
154 ///
155 /// [*] --> Unconnected --> ConnectedToSink ----
156 /// | | |
157 /// | --> ConnectedToSource ---> [*]
158 /// | |
159 /// -------------------------------
161
162 /// Some fields have multiple possible column representations, e.g. with or without split encoding.
163 /// All column representations supported for writing also need to be supported for reading. In addition,
164 /// fields can support extra column representations for reading only, e.g. a 64bit integer reading from a
165 /// 32bit column.
166 /// The defined column representations must be supported by corresponding column packing/unpacking implementations,
167 /// i.e. for the example above, the unpacking of 32bit ints to 64bit pages must be implemented in RColumnElement.hxx
169 public:
170 using TypesList_t = std::vector<ColumnRepresentation_t>;
172 RColumnRepresentations(const TypesList_t &serializationTypes, const TypesList_t &deserializationExtraTypes);
173
174 /// The first column list from fSerializationTypes is the default for writing.
178
179 private:
181 /// The union of the serialization types and the deserialization extra types. Duplicates the serialization types
182 /// list but the benenfit is that GetDeserializationTypes does not need to compile the list.
184 }; // class RColumnRepresentations
185
186 /// Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
187 /// Only fields can create RValue objects through generation, binding or splitting.
188 class RValue {
189 friend class RFieldBase;
190
191 private:
192 RFieldBase *fField = nullptr; ///< The field that created the RValue
193 std::shared_ptr<void> fObjPtr; ///< Set by Bind() or by RFieldBase::CreateValue(), SplitValue() or BindValue()
194
195 RValue(RFieldBase *field, std::shared_ptr<void> objPtr) : fField(field), fObjPtr(objPtr) {}
196
197 public:
198 RValue(const RValue &) = default;
199 RValue &operator=(const RValue &) = default;
200 RValue(RValue &&other) = default;
201 RValue &operator=(RValue &&other) = default;
202 ~RValue() = default;
203
204 std::size_t Append() { return fField->Append(fObjPtr.get()); }
205 void Read(NTupleSize_t globalIndex) { fField->Read(globalIndex, fObjPtr.get()); }
206 void Read(RClusterIndex clusterIndex) { fField->Read(clusterIndex, fObjPtr.get()); }
207 void Bind(std::shared_ptr<void> objPtr) { fObjPtr = objPtr; }
208 void BindRawPtr(void *rawPtr);
209 /// Replace the current object pointer by a pointer to a new object constructed by the field
210 void EmplaceNew() { fObjPtr = fField->CreateValue().GetPtr<void>(); }
211
212 template <typename T>
213 std::shared_ptr<T> GetPtr() const
214 {
215 return std::static_pointer_cast<T>(fObjPtr);
216 }
217
218 template <typename T>
219 const T &GetRef() const
220 {
221 return *static_cast<T *>(fObjPtr.get());
222 }
223
224 const RFieldBase &GetField() const { return *fField; }
225 }; // class RValue
226
227 /// Similar to RValue but manages an array of consecutive values. Bulks have to come from the same cluster.
228 /// Bulk I/O works with two bit masks: the mask of all the available entries in the current bulk and the mask
229 /// of the required entries in a bulk read. The idea is that a single bulk may serve multiple read operations
230 /// on the same range, where in each read operation a different subset of values is required.
231 /// The memory of the value array is managed by the RBulk class.
232 class RBulk {
233 private:
234 friend class RFieldBase;
235
236 RFieldBase *fField = nullptr; ///< The field that created the array of values
237 std::unique_ptr<RFieldBase::RDeleter> fDeleter; /// Cached deleter of fField
238 void *fValues = nullptr; ///< Pointer to the start of the array
239 std::size_t fValueSize = 0; ///< Cached copy of fField->GetValueSize()
240 std::size_t fCapacity = 0; ///< The size of the array memory block in number of values
241 std::size_t fSize = 0; ///< The number of available values in the array (provided their mask is set)
242 bool fIsAdopted = false; ///< True if the user provides the memory buffer for fValues
243 std::unique_ptr<bool[]> fMaskAvail; ///< Masks invalid values in the array
244 std::size_t fNValidValues = 0; ///< The sum of non-zero elements in the fMask
245 RClusterIndex fFirstIndex; ///< Index of the first value of the array
246 /// Reading arrays of complex values may require additional memory, for instance for the elements of
247 /// arrays of vectors. A pointer to the fAuxData array is passed to the field's BulkRead method.
248 /// The RBulk class does not modify the array in-between calls to the field's BulkRead method.
249 std::vector<unsigned char> fAuxData;
250
251 void ReleaseValues();
252 /// Sets a new range for the bulk. If there is enough capacity, the fValues array will be reused.
253 /// Otherwise a new array is allocated. After reset, fMaskAvail is false for all values.
254 void Reset(RClusterIndex firstIndex, std::size_t size);
255 void CountValidValues();
256
257 bool ContainsRange(RClusterIndex firstIndex, std::size_t size) const
258 {
259 if (firstIndex.GetClusterId() != fFirstIndex.GetClusterId())
260 return false;
261 return (firstIndex.GetIndex() >= fFirstIndex.GetIndex()) &&
262 ((firstIndex.GetIndex() + size) <= (fFirstIndex.GetIndex() + fSize));
263 }
264
265 void *GetValuePtrAt(std::size_t idx) const
266 {
267 return reinterpret_cast<unsigned char *>(fValues) + idx * fValueSize;
268 }
269
270 explicit RBulk(RFieldBase *field)
271 : fField(field), fDeleter(field->GetDeleter()), fValueSize(field->GetValueSize())
272 {
273 }
274
275 public:
276 ~RBulk();
277 RBulk(const RBulk &) = delete;
278 RBulk &operator=(const RBulk &) = delete;
279 RBulk(RBulk &&other);
280 RBulk &operator=(RBulk &&other);
281
282 // Sets fValues and fSize/fCapacity to the given values. The capacity is specified in number of values.
283 // Once a buffer is adopted, an attempt to read more values then available throws an exception.
284 void AdoptBuffer(void *buf, std::size_t capacity);
285
286 /// Reads 'size' values from the associated field, starting from 'firstIndex'. Note that the index is given
287 /// relative to a certain cluster. The return value points to the array of read objects.
288 /// The 'maskReq' parameter is a bool array of at least 'size' elements. Only objects for which the mask is
289 /// true are guaranteed to be read in the returned value array.
290 void *ReadBulk(RClusterIndex firstIndex, const bool *maskReq, std::size_t size)
291 {
292 if (!ContainsRange(firstIndex, size))
293 Reset(firstIndex, size);
294
295 // We may read a sub range of the currently available range
296 auto offset = firstIndex.GetIndex() - fFirstIndex.GetIndex();
297
298 if (fNValidValues == fSize)
299 return GetValuePtrAt(offset);
300
301 RBulkSpec bulkSpec;
302 bulkSpec.fFirstIndex = firstIndex;
303 bulkSpec.fCount = size;
304 bulkSpec.fMaskReq = maskReq;
305 bulkSpec.fMaskAvail = &fMaskAvail[offset];
306 bulkSpec.fValues = GetValuePtrAt(offset);
307 bulkSpec.fAuxData = &fAuxData;
308 auto nRead = fField->ReadBulk(bulkSpec);
309 if (nRead == RBulkSpec::kAllSet) {
310 if ((offset == 0) && (size == fSize)) {
312 } else {
314 }
315 } else {
316 fNValidValues += nRead;
317 }
318 return GetValuePtrAt(offset);
319 }
320 }; // class RBulk
321
322private:
323 /// The field name relative to its parent field
324 std::string fName;
325 /// The C++ type captured by this field
326 std::string fType;
327 /// The role of this field in the data model structure
329 /// For fixed sized arrays, the array length
330 std::size_t fNRepetitions;
331 /// A field qualifies as simple if it is both mappable and has no post-read callback
333 /// When the columns are connected to a page source or page sink, the field represents a field id in the
334 /// corresponding RNTuple descriptor. This on-disk ID is set in RPageSink::Create() for writing and by
335 /// RFieldDescriptor::CreateField() when recreating a field / model from the stored descriptor.
337 /// Free text set by the user
338 std::string fDescription;
339 /// Changed by ConnectTo[Sink,Source], reset by Clone()
341
343 {
344 for (const auto &func : fReadCallbacks)
345 func(target);
346 }
347
348 /// Translate an entry index to a column element index of the principal column and viceversa. These functions
349 /// take into account the role and number of repetitions on each level of the field hierarchy as follows:
350 /// - Top level fields: element index == entry index
351 /// - Record fields propagate their principal column index to the principal columns of direct descendant fields
352 /// - Collection and variant fields set the principal column index of their childs to 0
353 ///
354 /// The column element index also depends on the number of repetitions of each field in the hierarchy, e.g., given a
355 /// field with type `std::array<std::array<float, 4>, 2>`, this function returns 8 for the inner-most field.
357
358 /// Flushes data from active columns to disk and calls CommitClusterImpl
359 void CommitCluster();
360 /// Fields and their columns live in the void until connected to a physical page storage. Only once connected, data
361 /// can be read or written. In order to find the field in the page storage, the field's on-disk ID has to be set.
362 /// \param firstEntry The global index of the first entry with on-disk data for the connected field
363 void ConnectPageSink(Internal::RPageSink &pageSink, NTupleSize_t firstEntry = 0);
364 /// Connects the field and its sub field tree to the given page source. Once connected, data can be read.
365 /// Only unconnected fields may be connected, i.e. the method is not idempotent. The field ID has to be set prior to
366 /// calling this function. For sub fields, a field ID may or may not be set. If the field ID is unset, it will be
367 /// determined using the page source descriptor, based on the parent field ID and the sub field name.
369
370 /// Factory method for the field's type. The caller owns the returned pointer
371 void *CreateObjectRawPtr() const;
372
373protected:
374 /// Input parameter to ReadBulk() and ReadBulkImpl(). See RBulk class for more information
375 struct RBulkSpec {
376 /// As a return value of ReadBulk and ReadBulkImpl(), indicates that the full bulk range was read
377 /// independent of the provided masks.
378 static const std::size_t kAllSet = std::size_t(-1);
379
380 RClusterIndex fFirstIndex; ///< Start of the bulk range
381 std::size_t fCount = 0; ///< Size of the bulk range
382 /// A bool array of size fCount, indicating the required values in the requested range
383 const bool *fMaskReq = nullptr;
384 bool *fMaskAvail = nullptr; ///< A bool array of size fCount, indicating the valid values in fValues
385 /// The destination area, which has to be a big enough array of valid objects of the correct type
386 void *fValues = nullptr;
387 /// Reference to memory owned by the RBulk class. The field implementing BulkReadImpl may use fAuxData
388 /// as memory that stays persistent between calls.
389 std::vector<unsigned char> *fAuxData = nullptr;
390 };
391
392 /// Collections and classes own sub fields
393 std::vector<std::unique_ptr<RFieldBase>> fSubFields;
394 /// Sub fields point to their mother field
396 /// Points into fColumns. All fields that have columns have a distinct main column. For simple fields
397 /// (float, int, ...), the principal column corresponds to the field type. For collection fields expect std::array,
398 /// the main column is the offset field. Class fields have no column of their own.
400 /// The columns are connected either to a sink or to a source (not to both); they are owned by the field.
401 std::vector<std::unique_ptr<Internal::RColumn>> fColumns;
402 /// Properties of the type that allow for optimizations of collections of that type
403 int fTraits = 0;
404 /// A typedef or using name that was used when creating the field
405 std::string fTypeAlias;
406 /// List of functions to be called after reading a value
407 std::vector<ReadCallback_t> fReadCallbacks;
408 /// C++ type version cached from the descriptor after a call to `ConnectPageSource()`
410 /// Points into the static vector GetColumnRepresentations().GetSerializationTypes() when SetColumnRepresentative
411 /// is called. Otherwise GetColumnRepresentative returns the default representation.
413
414 /// Implementations in derived classes should return a static RColumnRepresentations object. The default
415 /// implementation does not attach any columns to the field.
417 /// Implementations in derived classes should create the backing columns corresponsing to the field type for
418 /// writing. The default implementation does not attach any columns to the field.
419 virtual void GenerateColumnsImpl() {}
420 /// Implementations in derived classes should create the backing columns corresponsing to the field type for reading.
421 /// The default implementation does not attach any columns to the field. The method should check, using the page
422 /// source and fOnDiskId, if the column types match and throw if they don't.
423 virtual void GenerateColumnsImpl(const RNTupleDescriptor & /*desc*/) {}
424 /// Returns the on-disk column types found in the provided descriptor for fOnDiskId. Throws an exception if the types
425 /// don't match any of the deserialization types from GetColumnRepresentations().
427 /// When connecting a field to a page sink, the field's default column representation is subject
428 /// to adjustment according to the write options. E.g., if compression is turned off, encoded columns
429 /// are changed to their unencoded counterparts.
430 void AutoAdjustColumnTypes(const RNTupleWriteOptions &options);
431
432 /// Called by Clone(), which additionally copies the on-disk ID
433 virtual std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const = 0;
434
435 /// Constructs value in a given location of size at least GetValueSize(). Called by the base class' CreateValue().
436 virtual void ConstructValue(void *where) const = 0;
437 virtual std::unique_ptr<RDeleter> GetDeleter() const { return std::make_unique<RDeleter>(); }
438 /// Allow derived classes to call ConstructValue(void *) and GetDeleter on other (sub) fields.
439 static void CallConstructValueOn(const RFieldBase &other, void *where) { other.ConstructValue(where); }
440 static std::unique_ptr<RDeleter> GetDeleterOf(const RFieldBase &other) { return other.GetDeleter(); }
441
442 /// Operations on values of complex types, e.g. ones that involve multiple columns or for which no direct
443 /// column type exists.
444 virtual std::size_t AppendImpl(const void *from);
445 virtual void ReadGlobalImpl(NTupleSize_t globalIndex, void *to);
446 virtual void ReadInClusterImpl(RClusterIndex clusterIndex, void *to)
447 {
449 }
450
451 /// Write the given value into columns. The value object has to be of the same type as the field.
452 /// Returns the number of uncompressed bytes written.
453 std::size_t Append(const void *from)
454 {
455 if (~fTraits & kTraitMappable)
456 return AppendImpl(from);
457
460 }
461
462 /// Populate a single value with data from the field. The memory location pointed to by to needs to be of the
463 /// fitting type. The fast path is conditioned by the field qualifying as simple, i.e. maps as-is
464 /// to a single column and has no read callback.
465 void Read(NTupleSize_t globalIndex, void *to)
466 {
467 if (fIsSimple)
468 return (void)fPrincipalColumn->Read(globalIndex, to);
469
471 fPrincipalColumn->Read(globalIndex, to);
472 else
473 ReadGlobalImpl(globalIndex, to);
474 if (R__unlikely(!fReadCallbacks.empty()))
476 }
477
478 void Read(RClusterIndex clusterIndex, void *to)
479 {
480 if (fIsSimple)
481 return (void)fPrincipalColumn->Read(clusterIndex, to);
482
484 fPrincipalColumn->Read(clusterIndex, to);
485 else
486 ReadInClusterImpl(clusterIndex, to);
487 if (R__unlikely(!fReadCallbacks.empty()))
489 }
490
491 /// General implementation of bulk read. Loop over the required range and read values that are required
492 /// and not already present. Derived classes may implement more optimized versions of this method.
493 /// See ReadBulk() for the return value.
494 virtual std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec);
495
496 /// Returns the number of newly available values, that is the number of bools in bulkSpec.fMaskAvail that
497 /// flipped from false to true. As a special return value, kAllSet can be used if all values are read
498 /// independent from the masks.
499 std::size_t ReadBulk(const RBulkSpec &bulkSpec)
500 {
501 if (fIsSimple) {
502 /// For simple types, ignore the mask and memcopy the values into the destination
503 fPrincipalColumn->ReadV(bulkSpec.fFirstIndex, bulkSpec.fCount, bulkSpec.fValues);
504 std::fill(bulkSpec.fMaskAvail, bulkSpec.fMaskAvail + bulkSpec.fCount, true);
505 return RBulkSpec::kAllSet;
506 }
507
508 return ReadBulkImpl(bulkSpec);
509 }
510
511 /// Allow derived classes to call Append and Read on other (sub) fields.
512 static std::size_t CallAppendOn(RFieldBase &other, const void *from) { return other.Append(from); }
513 static void CallReadOn(RFieldBase &other, RClusterIndex clusterIndex, void *to) { other.Read(clusterIndex, to); }
514 static void CallReadOn(RFieldBase &other, NTupleSize_t globalIndex, void *to) { other.Read(globalIndex, to); }
515
516 /// Fields may need direct access to the principal column of their sub fields, e.g. in RRVecField::ReadBulk
518
519 /// Set a user-defined function to be called after reading a value, giving a chance to inspect and/or modify the
520 /// value object.
521 /// Returns an index that can be used to remove the callback.
522 size_t AddReadCallback(ReadCallback_t func);
523 void RemoveReadCallback(size_t idx);
524
525 // Perform housekeeping tasks for global to cluster-local index translation
526 virtual void CommitClusterImpl() {}
527
528 /// Add a new subfield to the list of nested fields
529 void Attach(std::unique_ptr<RFieldBase> child);
530
531 /// Called by `ConnectPageSource()` only once connected; derived classes may override this
532 /// as appropriate
533 virtual void OnConnectPageSource() {}
534
535 /// Factory method to resurrect a field from the stored on-disk type information. This overload takes an already
536 /// normalized type name and type alias
537 /// TODO(jalopezg): this overload may eventually be removed leaving only the `RFieldBase::Create()` that takes a
538 /// single type name
539 static RResult<std::unique_ptr<RFieldBase>> Create(const std::string &fieldName, const std::string &canonicalType,
540 const std::string &typeAlias, bool fContinueOnError = false);
541
542public:
543 /// Iterates over the sub tree of fields in depth-first search order
544 template <bool IsConstT>
546 private:
547 struct Position {
548 using FieldPtr_t = std::conditional_t<IsConstT, const RFieldBase *, RFieldBase *>;
549 Position() : fFieldPtr(nullptr), fIdxInParent(-1) { }
550 Position(FieldPtr_t fieldPtr, int idxInParent) : fFieldPtr(fieldPtr), fIdxInParent(idxInParent) {}
553 };
554 /// The stack of nodes visited when walking down the tree of fields
555 std::vector<Position> fStack;
556 public:
558 using iterator_category = std::forward_iterator_tag;
559 using difference_type = std::ptrdiff_t;
560 using value_type = std::conditional_t<IsConstT, const RFieldBase, RFieldBase>;
561 using pointer = std::conditional_t<IsConstT, const RFieldBase *, RFieldBase *>;
562 using reference = std::conditional_t<IsConstT, const RFieldBase &, RFieldBase &>;
563
565 RSchemaIteratorTemplate(pointer val, int idxInParent) { fStack.emplace_back(Position(val, idxInParent)); }
567 /// Given that the iterator points to a valid field which is not the end iterator, go to the next field
568 /// in depth-first search order
569 void Advance()
570 {
571 auto itr = fStack.rbegin();
572 if (!itr->fFieldPtr->fSubFields.empty()) {
573 fStack.emplace_back(Position(itr->fFieldPtr->fSubFields[0].get(), 0));
574 return;
575 }
576
577 unsigned int nextIdxInParent = ++(itr->fIdxInParent);
578 while (nextIdxInParent >= itr->fFieldPtr->fParent->fSubFields.size()) {
579 if (fStack.size() == 1) {
580 itr->fFieldPtr = itr->fFieldPtr->fParent;
581 itr->fIdxInParent = -1;
582 return;
583 }
584 fStack.pop_back();
585 itr = fStack.rbegin();
586 nextIdxInParent = ++(itr->fIdxInParent);
587 }
588 itr->fFieldPtr = itr->fFieldPtr->fParent->fSubFields[nextIdxInParent].get();
589 }
590
591 iterator operator++(int) /* postfix */ { auto r = *this; Advance(); return r; }
592 iterator& operator++() /* prefix */ { Advance(); return *this; }
593 reference operator* () const { return *fStack.back().fFieldPtr; }
594 pointer operator->() const { return fStack.back().fFieldPtr; }
595 bool operator==(const iterator& rh) const { return fStack.back().fFieldPtr == rh.fStack.back().fFieldPtr; }
596 bool operator!=(const iterator& rh) const { return fStack.back().fFieldPtr != rh.fStack.back().fFieldPtr; }
597 };
600
601 // This is used in CreateObject and is specialized for void
602 template <typename T>
604 using deleter = std::default_delete<T>;
605 };
606
607 /// Used in the return value of the Check() method
609 std::string fFieldName; ///< Qualified field name causing the error
610 std::string fTypeName; ///< Type name corresponding to the (sub) field
611 std::string fErrMsg; ///< Cause of the failure, e.g. unsupported type
612 };
613
614 /// The constructor creates the underlying column objects and connects them to either a sink or a source.
615 /// If `isSimple` is `true`, the trait `kTraitMappable` is automatically set on construction. However, the
616 /// field might be demoted to non-simple if a post-read callback is set.
617 RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple,
618 std::size_t nRepetitions = 0);
619 RFieldBase(const RFieldBase&) = delete;
620 RFieldBase(RFieldBase&&) = default;
623 virtual ~RFieldBase() = default;
624
625 /// Copies the field and its sub fields using a possibly new name and a new, unconnected set of columns
626 std::unique_ptr<RFieldBase> Clone(std::string_view newName) const;
627
628 /// Factory method to resurrect a field from the stored on-disk type information
630 Create(const std::string &fieldName, const std::string &typeName);
631 /// Checks if the given type is supported by RNTuple. In case of success, the result vector is empty.
632 /// Otherwise there is an error record for each failing sub field (sub type).
633 static std::vector<RCheckResult> Check(const std::string &fieldName, const std::string &typeName);
634 /// Check whether a given string is a valid field name
635 static RResult<void> EnsureValidFieldName(std::string_view fieldName);
636
637 /// Generates an object of the field type and allocates new initialized memory according to the type.
638 /// Implemented at the end of this header because the implementation is using RField<T>::TypeName()
639 /// The returned object can be released with `delete`, i.e. it is valid to call
640 /// auto ptr = field->CreateObject();
641 /// delete ptr.release();
642 ///
643 /// Note that CreateObject<void> is supported. The returned unique_ptr has a custom deleter that reports an error
644 /// if it is called. The intended use of the returned unique_ptr<void> is to call `release()`. In this way, the
645 /// transfer of pointer ownership is explicit.
646 template <typename T>
647 std::unique_ptr<T, typename RCreateObjectDeleter<T>::deleter> CreateObject() const;
648 /// Generates an object of the field type and wraps the created object in a shared pointer and returns it an RValue
649 /// connected to the field.
651 /// The returned bulk is initially empty; RBulk::ReadBulk will construct the array of values
652 RBulk CreateBulk() { return RBulk(this); }
653 /// Creates a value from a memory location with an already constructed object
654 RValue BindValue(std::shared_ptr<void> objPtr) { return RValue(this, objPtr); }
655 /// Creates the list of direct child values given a value for this field. E.g. a single value for the
656 /// correct variant or all the elements of a collection. The default implementation assumes no sub values
657 /// and returns an empty vector.
658 virtual std::vector<RValue> SplitValue(const RValue &value) const;
659 /// The number of bytes taken by a value of the appropriate type
660 virtual size_t GetValueSize() const = 0;
661 /// As a rule of thumb, the alignment is equal to the size of the type. There are, however, various exceptions
662 /// to this rule depending on OS and CPU architecture. So enforce the alignment to be explicitly spelled out.
663 virtual size_t GetAlignment() const = 0;
664 int GetTraits() const { return fTraits; }
665 bool HasReadCallbacks() const { return !fReadCallbacks.empty(); }
666
667 std::string GetFieldName() const { return fName; }
668 /// Returns the field name and parent field names separated by dots ("grandparent.parent.child")
669 std::string GetQualifiedFieldName() const;
670 std::string GetTypeName() const { return fType; }
671 std::string GetTypeAlias() const { return fTypeAlias; }
673 std::size_t GetNRepetitions() const { return fNRepetitions; }
675 const RFieldBase *GetParent() const { return fParent; }
676 std::vector<RFieldBase *> GetSubFields();
677 std::vector<const RFieldBase *> GetSubFields() const;
678 bool IsSimple() const { return fIsSimple; }
679 /// Get the field's description
680 std::string GetDescription() const { return fDescription; }
681 void SetDescription(std::string_view description);
682 EState GetState() const { return fState; }
683
686
687 /// Returns the fColumnRepresentative pointee or, if unset, the field's default representative
689 /// Fixes a column representative. This can only be done _before_ connecting the field to a page sink.
690 /// Otherwise, or if the provided representation is not in the list of GetColumnRepresentations,
691 /// an exception is thrown
692 void SetColumnRepresentative(const ColumnRepresentation_t &representative);
693 /// Whether or not an explicit column representative was set
694 bool HasDefaultColumnRepresentative() const { return fColumnRepresentative == nullptr; }
695
696 /// Indicates an evolution of the mapping scheme from C++ type to columns
697 virtual std::uint32_t GetFieldVersion() const { return 0; }
698 /// Indicates an evolution of the C++ type itself
699 virtual std::uint32_t GetTypeVersion() const { return 0; }
700 /// Return the C++ type version stored in the field descriptor; only valid after a call to `ConnectPageSource()`
701 std::uint32_t GetOnDiskTypeVersion() const { return fOnDiskTypeVersion; }
702
704 {
705 return fSubFields.empty() ? RSchemaIterator(this, -1) : RSchemaIterator(fSubFields[0].get(), 0);
706 }
707 RSchemaIterator end() { return RSchemaIterator(this, -1); }
709 {
710 return fSubFields.empty() ? RConstSchemaIterator(this, -1) : RConstSchemaIterator(fSubFields[0].get(), 0);
711 }
712 RConstSchemaIterator cend() const { return RConstSchemaIterator(this, -1); }
713
714 virtual void AcceptVisitor(Detail::RFieldVisitor &visitor) const;
715}; // class RFieldBase
716
717/// The container field for an ntuple model, which itself has no physical representation.
718/// Therefore, the zero field must not be connected to a page source or sink.
719class RFieldZero final : public RFieldBase {
720protected:
721 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
722 void ConstructValue(void *) const final {}
723
724public:
725 RFieldZero() : RFieldBase("", "", ENTupleStructure::kRecord, false /* isSimple */) {}
726
727 using RFieldBase::Attach;
728 size_t GetValueSize() const final { return 0; }
729 size_t GetAlignment() const final { return 0; }
730
731 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
732};
733
734/// Used in RFieldBase::Check() to record field creation failures.
735class RInvalidField final : public RFieldBase {
736 std::string fError;
737
738protected:
739 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
740 {
741 return std::make_unique<RInvalidField>(newName, GetTypeName(), fError);
742 }
743 void ConstructValue(void *) const final {}
744
745public:
746 RInvalidField(std::string_view name, std::string_view type, std::string_view error)
747 : RFieldBase(name, type, ENTupleStructure::kLeaf, false /* isSimple */), fError(error)
748 {
749 }
750
751 std::string GetError() const { return fError; }
752
753 size_t GetValueSize() const final { return 0; }
754 size_t GetAlignment() const final { return 0; }
755}; // RInvalidField
756
757/// The field for a class with dictionary
758class RClassField : public RFieldBase {
759private:
763 };
766 std::size_t fOffset;
767 };
768 /// Prefix used in the subfield names generated for base classes
769 static constexpr const char *kPrefixInherited{":"};
770
771 class RClassDeleter : public RDeleter {
772 private:
774
775 public:
776 explicit RClassDeleter(TClass *cl) : fClass(cl) {}
777 void operator()(void *objPtr, bool dtorOnly) final;
778 };
779
781 /// Additional information kept for each entry in `fSubFields`
782 std::vector<RSubFieldInfo> fSubFieldsInfo;
783 std::size_t fMaxAlignment = 1;
784
785private:
786 RClassField(std::string_view fieldName, std::string_view className, TClass *classp);
787 void Attach(std::unique_ptr<RFieldBase> child, RSubFieldInfo info);
788 /// Register post-read callbacks corresponding to a list of ROOT I/O customization rules. `classp` is used to
789 /// fill the `TVirtualObject` instance passed to the user function.
790 void AddReadCallbacksFromIORules(const std::span<const TSchemaRule *> rules, TClass *classp = nullptr);
791
792protected:
793 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
794
795 void ConstructValue(void *where) const override;
796 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RClassDeleter>(fClass); }
797
798 std::size_t AppendImpl(const void *from) final;
799 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
800 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final;
801 void OnConnectPageSource() final;
802
803public:
804 RClassField(std::string_view fieldName, std::string_view className);
805 RClassField(RClassField&& other) = default;
806 RClassField& operator =(RClassField&& other) = default;
807 ~RClassField() override = default;
808
809 std::vector<RValue> SplitValue(const RValue &value) const final;
810 size_t GetValueSize() const override;
811 size_t GetAlignment() const final { return fMaxAlignment; }
812 std::uint32_t GetTypeVersion() const final;
813 void AcceptVisitor(Detail::RFieldVisitor &visitor) const override;
814};
815
816/// The field for a class in unsplit mode, which is using ROOT standard streaming
817class RUnsplitField final : public RFieldBase {
818private:
819 class RUnsplitDeleter : public RDeleter {
820 private:
822
823 public:
824 explicit RUnsplitDeleter(TClass *cl) : fClass(cl) {}
825 void operator()(void *objPtr, bool dtorOnly) final;
826 };
827
828 TClass *fClass = nullptr;
829 ClusterSize_t fIndex; ///< number of bytes written in the current cluster
830
831private:
832 // Note that className may be different from classp->GetName(), e.g. through different canonicalization of RNTuple
833 // vs. TClass. Also, classp may be nullptr for types unsupported by the ROOT I/O.
834 RUnsplitField(std::string_view fieldName, std::string_view className, TClass *classp);
835
836protected:
837 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
838
840 void GenerateColumnsImpl() final;
841 void GenerateColumnsImpl(const RNTupleDescriptor &) final;
842
843 void ConstructValue(void *where) const final;
844 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RUnsplitDeleter>(fClass); }
845
846 std::size_t AppendImpl(const void *from) final;
847 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
848
849 void CommitClusterImpl() final { fIndex = 0; }
850
851public:
852 RUnsplitField(std::string_view fieldName, std::string_view className, std::string_view typeAlias = "");
853 RUnsplitField(RUnsplitField &&other) = default;
855 ~RUnsplitField() override = default;
856
857 size_t GetValueSize() const final;
858 size_t GetAlignment() const final;
859 std::uint32_t GetTypeVersion() const final;
860 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
861};
862
863/// The field for an unscoped or scoped enum with dictionary
864class REnumField : public RFieldBase {
865private:
866 REnumField(std::string_view fieldName, std::string_view enumName, TEnum *enump);
867 REnumField(std::string_view fieldName, std::string_view enumName, std::unique_ptr<RFieldBase> intField);
868
869protected:
870 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
871
872 void ConstructValue(void *where) const final { CallConstructValueOn(*fSubFields[0], where); }
873
874 std::size_t AppendImpl(const void *from) final { return CallAppendOn(*fSubFields[0], from); }
875 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final { CallReadOn(*fSubFields[0], globalIndex, to); }
876 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final { CallReadOn(*fSubFields[0], clusterIndex, to); }
877
878public:
879 REnumField(std::string_view fieldName, std::string_view enumName);
880 REnumField(REnumField &&other) = default;
881 REnumField &operator=(REnumField &&other) = default;
882 ~REnumField() override = default;
883
884 std::vector<RValue> SplitValue(const RValue &value) const final;
885 size_t GetValueSize() const final { return fSubFields[0]->GetValueSize(); }
886 size_t GetAlignment() const final { return fSubFields[0]->GetAlignment(); }
887 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
888};
889
890/// The field for a class representing a collection of elements via `TVirtualCollectionProxy`.
891/// Objects of such type behave as collections that can be accessed through the corresponding member functions in
892/// `TVirtualCollectionProxy`. For STL collections, these proxies are provided. Custom classes need to implement the
893/// corresponding member functions in `TVirtualCollectionProxy`. At a bare minimum, the user is required to provide an
894/// implementation for the following functions in `TVirtualCollectionProxy`: `HasPointers()`, `GetProperties()`,
895/// `GetValueClass()`, `GetType()`, `PushProxy()`, `PopProxy()`, `GetFunctionCreateIterators()`, `GetFunctionNext()`,
896/// and `GetFunctionDeleteTwoIterators()`.
897///
898/// The collection proxy for a given class can be set via `TClass::CopyCollectionProxy()`.
900protected:
901 /// Allows for iterating over the elements of a proxied collection. RCollectionIterableOnce avoids an additional
902 /// iterator copy (see `TVirtualCollectionProxy::GetFunctionCopyIterator`) and thus can only be iterated once.
904 public:
909 };
910 static RIteratorFuncs GetIteratorFuncs(TVirtualCollectionProxy *proxy, bool readFromDisk);
911
912 private:
913 class RIterator {
915 void *fIterator = nullptr;
916 void *fElementPtr = nullptr;
917
918 void Advance()
919 {
920 auto fnNext_Contig = [&]() {
921 // Array-backed collections (e.g. kSTLvector) directly use the pointer-to-iterator-data as a
922 // pointer-to-element, thus saving an indirection level (see documentation for TVirtualCollectionProxy)
923 auto &iter = reinterpret_cast<unsigned char *&>(fIterator), p = iter;
924 iter += fOwner.fStride;
925 return p;
926 };
927 fElementPtr = fOwner.fStride ? fnNext_Contig() : fOwner.fIFuncs.fNext(fIterator, fOwner.fEnd);
928 }
929
930 public:
931 using iterator_category = std::forward_iterator_tag;
933 using difference_type = std::ptrdiff_t;
934 using pointer = void *;
935
936 RIterator(const RCollectionIterableOnce &owner) : fOwner(owner) {}
937 RIterator(const RCollectionIterableOnce &owner, void *iter) : fOwner(owner), fIterator(iter) { Advance(); }
939 {
940 Advance();
941 return *this;
942 }
943 pointer operator*() const { return fElementPtr; }
944 bool operator!=(const iterator &rh) const { return fElementPtr != rh.fElementPtr; }
945 bool operator==(const iterator &rh) const { return fElementPtr == rh.fElementPtr; }
946 };
947
949 const std::size_t fStride;
950 unsigned char fBeginSmallBuf[TVirtualCollectionProxy::fgIteratorArenaSize];
952 void *fBegin = &fBeginSmallBuf;
953 void *fEnd = &fEndSmallBuf;
954 public:
955 /// Construct a `RCollectionIterableOnce` that iterates over `collection`. If elements are guaranteed to be
956 /// contiguous in memory (e.g. a vector), `stride` can be provided for faster iteration, i.e. the address of each
957 /// element is known given the base pointer.
958 RCollectionIterableOnce(void *collection, const RIteratorFuncs &ifuncs, TVirtualCollectionProxy *proxy,
959 std::size_t stride = 0U)
960 : fIFuncs(ifuncs), fStride(stride)
961 {
962 fIFuncs.fCreateIterators(collection, &fBegin, &fEnd, proxy);
963 }
965
966 RIterator begin() { return RIterator(*this, fBegin); }
967 RIterator end() { return fStride ? RIterator(*this, fEnd) : RIterator(*this); }
968 }; // class RCollectionIterableOnce
969
971 private:
972 std::shared_ptr<TVirtualCollectionProxy> fProxy;
973 std::unique_ptr<RDeleter> fItemDeleter;
974 std::size_t fItemSize = 0;
976
977 public:
978 explicit RProxiedCollectionDeleter(std::shared_ptr<TVirtualCollectionProxy> proxy) : fProxy(proxy) {}
979 RProxiedCollectionDeleter(std::shared_ptr<TVirtualCollectionProxy> proxy, std::unique_ptr<RDeleter> itemDeleter,
980 size_t itemSize)
981 : fProxy(proxy), fItemDeleter(std::move(itemDeleter)), fItemSize(itemSize)
982 {
983 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readFromDisk */);
984 }
985 void operator()(void *objPtr, bool dtorOnly) final;
986 };
987
988 /// The collection proxy is needed by the deleters and thus defined as a shared pointer
989 std::shared_ptr<TVirtualCollectionProxy> fProxy;
992 /// Two sets of functions to operate on iterators, to be used depending on the access type. The direction preserves
993 /// the meaning from TVirtualCollectionProxy, i.e. read from disk / write to disk, respectively
996 std::size_t fItemSize;
998
999 /// Constructor used when the value type of the collection is not known in advance, i.e. in the case of custom
1000 /// collections.
1001 RProxiedCollectionField(std::string_view fieldName, std::string_view typeName, TClass *classp);
1002 /// Constructor used when the value type of the collection is known in advance, e.g. in `RSetField`.
1003 RProxiedCollectionField(std::string_view fieldName, std::string_view typeName,
1004 std::unique_ptr<RFieldBase> itemField);
1005
1006protected:
1007 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
1008 const RColumnRepresentations &GetColumnRepresentations() const final;
1009 void GenerateColumnsImpl() final;
1010 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1011
1012 void ConstructValue(void *where) const override;
1013 std::unique_ptr<RDeleter> GetDeleter() const override;
1014
1015 std::size_t AppendImpl(const void *from) override;
1016 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) override;
1017
1018 void CommitClusterImpl() final { fNWritten = 0; }
1019
1020public:
1021 RProxiedCollectionField(std::string_view fieldName, std::string_view typeName);
1024 ~RProxiedCollectionField() override = default;
1025
1026 std::vector<RValue> SplitValue(const RValue &value) const override;
1027 size_t GetValueSize() const override { return fProxy->Sizeof(); }
1028 size_t GetAlignment() const override { return alignof(std::max_align_t); }
1029 void AcceptVisitor(Detail::RFieldVisitor &visitor) const override;
1030 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
1031 {
1032 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
1033 }
1034 void GetCollectionInfo(RClusterIndex clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
1035 {
1036 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
1037 }
1038};
1039
1040/// The field for an untyped record. The subfields are stored consequitively in a memory block, i.e.
1041/// the memory layout is identical to one that a C++ struct would have
1042class RRecordField : public RFieldBase {
1043private:
1044 class RRecordDeleter : public RDeleter {
1045 private:
1046 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
1047 std::vector<std::size_t> fOffsets;
1048
1049 public:
1050 RRecordDeleter(std::vector<std::unique_ptr<RDeleter>> &itemDeleters, const std::vector<std::size_t> &offsets)
1051 : fItemDeleters(std::move(itemDeleters)), fOffsets(offsets)
1052 {
1053 }
1054 void operator()(void *objPtr, bool dtorOnly) final;
1055 };
1056
1057protected:
1058 std::size_t fMaxAlignment = 1;
1059 std::size_t fSize = 0;
1060 std::vector<std::size_t> fOffsets;
1061
1062 std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const;
1063
1064 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
1065
1066 void ConstructValue(void *where) const override;
1067 std::unique_ptr<RDeleter> GetDeleter() const override;
1068
1069 std::size_t AppendImpl(const void *from) final;
1070 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1071 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final;
1072
1073 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> &&itemFields,
1074 const std::vector<std::size_t> &offsets, std::string_view typeName = "");
1075
1076 template <std::size_t N>
1077 RRecordField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, N> &&itemFields,
1078 const std::array<std::size_t, N> &offsets, std::string_view typeName = "")
1079 : ROOT::Experimental::RFieldBase(fieldName, typeName, ENTupleStructure::kRecord, false /* isSimple */)
1080 {
1081 fTraits |= kTraitTrivialType;
1082 for (unsigned i = 0; i < N; ++i) {
1083 fOffsets.push_back(offsets[i]);
1084 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
1085 fSize += GetItemPadding(fSize, itemFields[i]->GetAlignment()) + itemFields[i]->GetValueSize();
1086 fTraits &= itemFields[i]->GetTraits();
1087 Attach(std::move(itemFields[i]));
1088 }
1089 }
1090public:
1091 /// Construct a RRecordField based on a vector of child fields. The ownership of the child fields is transferred
1092 /// to the RRecordField instance.
1093 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> &&itemFields);
1094 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> &itemFields);
1095 RRecordField(RRecordField&& other) = default;
1097 ~RRecordField() override = default;
1098
1099 std::vector<RValue> SplitValue(const RValue &value) const final;
1100 size_t GetValueSize() const final { return fSize; }
1101 size_t GetAlignment() const final { return fMaxAlignment; }
1102 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1103};
1104
1105/// The generic field for a (nested) std::vector<Type> except for std::vector<bool>
1106class RVectorField : public RFieldBase {
1107private:
1108 class RVectorDeleter : public RDeleter {
1109 private:
1110 std::size_t fItemSize = 0;
1111 std::unique_ptr<RDeleter> fItemDeleter;
1112
1113 public:
1114 RVectorDeleter() = default;
1115 RVectorDeleter(std::size_t itemSize, std::unique_ptr<RDeleter> itemDeleter)
1116 : fItemSize(itemSize), fItemDeleter(std::move(itemDeleter))
1117 {
1118 }
1119 void operator()(void *objPtr, bool dtorOnly) final;
1120 };
1121
1122 std::size_t fItemSize;
1124 std::unique_ptr<RDeleter> fItemDeleter;
1125
1126protected:
1127 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1128
1129 const RColumnRepresentations &GetColumnRepresentations() const final;
1130 void GenerateColumnsImpl() final;
1131 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1132
1133 void ConstructValue(void *where) const override { new (where) std::vector<char>(); }
1134 std::unique_ptr<RDeleter> GetDeleter() const final;
1135
1136 std::size_t AppendImpl(const void *from) final;
1137 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1138
1139 void CommitClusterImpl() final { fNWritten = 0; }
1140
1141public:
1142 RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField);
1143 RVectorField(RVectorField&& other) = default;
1145 ~RVectorField() override = default;
1146
1147 std::vector<RValue> SplitValue(const RValue &value) const final;
1148 size_t GetValueSize() const override { return sizeof(std::vector<char>); }
1149 size_t GetAlignment() const final { return std::alignment_of<std::vector<char>>(); }
1150 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1151 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const {
1152 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
1153 }
1154 void GetCollectionInfo(RClusterIndex clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
1155 {
1156 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
1157 }
1158};
1159
1160/// The type-erased field for a RVec<Type>
1161class RRVecField : public RFieldBase {
1162public:
1163 /// the RRVecDeleter is also used by RArrayAsRVecField and therefore declared public
1164 class RRVecDeleter : public RDeleter {
1165 private:
1166 std::size_t fItemAlignment;
1167 std::size_t fItemSize = 0;
1168 std::unique_ptr<RDeleter> fItemDeleter;
1169
1170 public:
1171 explicit RRVecDeleter(std::size_t itemAlignment) : fItemAlignment(itemAlignment) {}
1172 RRVecDeleter(std::size_t itemAlignment, std::size_t itemSize, std::unique_ptr<RDeleter> itemDeleter)
1173 : fItemAlignment(itemAlignment), fItemSize(itemSize), fItemDeleter(std::move(itemDeleter))
1174 {
1175 }
1176 void operator()(void *objPtr, bool dtorOnly) final;
1177 };
1178
1179 std::unique_ptr<RDeleter> fItemDeleter;
1180
1181protected:
1182 std::size_t fItemSize;
1184 std::size_t fValueSize;
1185
1186 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
1187 const RColumnRepresentations &GetColumnRepresentations() const final;
1188 void GenerateColumnsImpl() final;
1189 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1190
1191 void ConstructValue(void *where) const override;
1192 std::unique_ptr<RDeleter> GetDeleter() const override;
1193
1194 std::size_t AppendImpl(const void *from) override;
1195 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) override;
1196 std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec) final;
1197
1198 void CommitClusterImpl() final { fNWritten = 0; }
1199
1200public:
1201 RRVecField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField);
1202 RRVecField(RRVecField &&) = default;
1204 RRVecField(const RRVecField &) = delete;
1206 ~RRVecField() override = default;
1207
1208 std::vector<RValue> SplitValue(const RValue &value) const final;
1209 size_t GetValueSize() const override;
1210 size_t GetAlignment() const override;
1211 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1212 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
1213 {
1214 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
1215 }
1216 void GetCollectionInfo(RClusterIndex clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
1217 {
1218 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
1219 }
1220};
1221
1222/// The generic field for fixed size arrays, which do not need an offset column
1223class RArrayField : public RFieldBase {
1224private:
1225 class RArrayDeleter : public RDeleter {
1226 private:
1227 std::size_t fItemSize = 0;
1228 std::size_t fArrayLength = 0;
1229 std::unique_ptr<RDeleter> fItemDeleter;
1230
1231 public:
1232 RArrayDeleter(std::size_t itemSize, std::size_t arrayLength, std::unique_ptr<RDeleter> itemDeleter)
1233 : fItemSize(itemSize), fArrayLength(arrayLength), fItemDeleter(std::move(itemDeleter))
1234 {
1235 }
1236 void operator()(void *objPtr, bool dtorOnly) final;
1237 };
1238
1239 std::size_t fItemSize;
1240 std::size_t fArrayLength;
1241
1242protected:
1243 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1244
1245 void ConstructValue(void *where) const override;
1246 std::unique_ptr<RDeleter> GetDeleter() const final;
1247
1248 std::size_t AppendImpl(const void *from) final;
1249 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1250 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final;
1251
1252public:
1253 RArrayField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField, std::size_t arrayLength);
1254 RArrayField(RArrayField &&other) = default;
1255 RArrayField& operator =(RArrayField &&other) = default;
1256 ~RArrayField() override = default;
1257
1258 std::vector<RValue> SplitValue(const RValue &value) const final;
1259 size_t GetLength() const { return fArrayLength; }
1260 size_t GetValueSize() const final { return fItemSize * fArrayLength; }
1261 size_t GetAlignment() const final { return fSubFields[0]->GetAlignment(); }
1262 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1263};
1264
1265/**
1266\class ROOT::Experimental::RArrayAsRVecField
1267\brief A field for fixed-size arrays that are represented as RVecs in memory.
1268\ingroup ntuple
1269This class is used only for reading. In particular, it helps exposing
1270arbitrarily-nested std::array on-disk fields as RVecs for usage in RDataFrame.
1271*/
1272class RArrayAsRVecField final : public RFieldBase {
1273private:
1274 std::unique_ptr<RDeleter> fItemDeleter; /// Sub field deleter or nullptr for simple fields
1275 std::size_t fItemSize; /// The size of a child field's item
1276 std::size_t fArrayLength; /// The length of the arrays in this field
1277 std::size_t fValueSize; /// The size of a value of this field, i.e. an RVec
1278
1279protected:
1280 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1281
1282 void GenerateColumnsImpl() final { R__ASSERT(false && "RArrayAsRVec fields must only be used for reading"); }
1283
1284 void ConstructValue(void *where) const final;
1285 /// Returns an RRVecField::RRVecDeleter
1286 std::unique_ptr<RDeleter> GetDeleter() const final;
1287
1288 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1289 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final;
1290
1291public:
1292 /**
1293 Constructor of the field. the \p itemField argument represents the inner
1294 item of the on-disk array, i.e. for an `std::array<float>` it is the `float`
1295 field and not the `std::array` itself.
1296 */
1297 RArrayAsRVecField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField, std::size_t arrayLength);
1298 RArrayAsRVecField(const RArrayAsRVecField &other) = delete;
1299 RArrayAsRVecField &operator=(const RArrayAsRVecField &other) = delete;
1301 RArrayAsRVecField &operator=(RArrayAsRVecField &&other) = default;
1302 ~RArrayAsRVecField() final = default;
1303
1304 std::size_t GetValueSize() const final { return fValueSize; }
1305 std::size_t GetAlignment() const final;
1306
1307 std::vector<RFieldBase::RValue> SplitValue(const RFieldBase::RValue &value) const final;
1308 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1309};
1310
1311/// The generic field an std::bitset<N>. All compilers we care about store the bits in an array of unsigned long.
1312/// TODO(jblomer): reading and writing efficiency should be improved; currently it is one bit at a time
1313/// with an array of bools on the page level.
1314class RBitsetField : public RFieldBase {
1315 using Word_t = unsigned long;
1316 static constexpr std::size_t kWordSize = sizeof(Word_t);
1317 static constexpr std::size_t kBitsPerWord = kWordSize * 8;
1318
1319protected:
1320 std::size_t fN;
1321
1322protected:
1323 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
1324 {
1325 return std::make_unique<RBitsetField>(newName, fN);
1326 }
1327 const RColumnRepresentations &GetColumnRepresentations() const final;
1328 void GenerateColumnsImpl() final;
1329 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1330 void ConstructValue(void *where) const final { memset(where, 0, GetValueSize()); }
1331 std::size_t AppendImpl(const void *from) final;
1332 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1333
1334public:
1335 RBitsetField(std::string_view fieldName, std::size_t N);
1336 RBitsetField(RBitsetField &&other) = default;
1338 ~RBitsetField() override = default;
1339
1340 size_t GetValueSize() const final { return kWordSize * ((fN + kBitsPerWord - 1) / kBitsPerWord); }
1341 size_t GetAlignment() const final { return alignof(Word_t); }
1342 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1343
1344 /// Get the number of bits in the bitset, i.e. the N in std::bitset<N>
1345 std::size_t GetN() const { return fN; }
1346};
1347
1348/// The generic field for std::variant types
1350private:
1351 class RVariantDeleter : public RDeleter {
1352 private:
1353 std::size_t fTagOffset;
1354 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
1355
1356 public:
1357 RVariantDeleter(std::size_t tagOffset, std::vector<std::unique_ptr<RDeleter>> &itemDeleters)
1358 : fTagOffset(tagOffset), fItemDeleters(std::move(itemDeleters))
1359 {
1360 }
1361 void operator()(void *objPtr, bool dtorOnly) final;
1362 };
1363
1364 size_t fMaxItemSize = 0;
1365 size_t fMaxAlignment = 1;
1366 /// In the std::variant memory layout, at which byte number is the index stored
1367 size_t fTagOffset = 0;
1368 std::vector<ClusterSize_t::ValueType> fNWritten;
1369
1370 static std::string GetTypeList(const std::vector<RFieldBase *> &itemFields);
1371 /// Extracts the index from an std::variant and transforms it into the 1-based index used for the switch column
1372 static std::uint32_t GetTag(const void *variantPtr, std::size_t tagOffset);
1373 static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint32_t tag);
1374
1375protected:
1376 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1377
1378 const RColumnRepresentations &GetColumnRepresentations() const final;
1379 void GenerateColumnsImpl() final;
1380 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1381
1382 void ConstructValue(void *where) const override;
1383 std::unique_ptr<RDeleter> GetDeleter() const final;
1384
1385 std::size_t AppendImpl(const void *from) final;
1386 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1387
1388 void CommitClusterImpl() final;
1389
1390public:
1391 // TODO(jblomer): use std::span in signature
1392 RVariantField(std::string_view fieldName, const std::vector<RFieldBase *> &itemFields);
1393 RVariantField(RVariantField &&other) = default;
1394 RVariantField& operator =(RVariantField &&other) = default;
1395 ~RVariantField() override = default;
1396
1397 size_t GetValueSize() const final;
1398 size_t GetAlignment() const final { return fMaxAlignment; }
1399};
1400
1401/// The generic field for a std::set<Type> and std::unordered_set<Type>
1403protected:
1404 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1405
1406public:
1407 RSetField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
1408 RSetField(RSetField &&other) = default;
1409 RSetField &operator=(RSetField &&other) = default;
1410 ~RSetField() override = default;
1411
1412 size_t GetAlignment() const override { return std::alignment_of<std::set<std::max_align_t>>(); }
1413};
1414
1415/// The generic field for a std::map<KeyType, ValueType> and std::unordered_map<KeyType, ValueType>
1417private:
1419
1420protected:
1421 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1422
1423 std::size_t AppendImpl(const void *from) final;
1424 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1425
1426public:
1427 RMapField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
1428 RMapField(RMapField &&other) = default;
1429 RMapField &operator=(RMapField &&other) = default;
1430 ~RMapField() override = default;
1431
1432 std::vector<RValue> SplitValue(const RValue &value) const final;
1433
1434 size_t GetAlignment() const override { return std::alignment_of<std::map<std::max_align_t, std::max_align_t>>(); }
1435};
1436
1437/// The field for values that may or may not be present in an entry. Parent class for unique pointer field and
1438/// optional field. A nullable field cannot be instantiated itself but only its descendants.
1439/// The RNullableField takes care of the on-disk representation. Child classes are responsible for the in-memory
1440/// representation. The on-disk representation can be "dense" or "sparse". Dense nullable fields have a bitmask
1441/// (true: item available, false: item missing) and serialize a default-constructed item for missing items.
1442/// Sparse nullable fields use a (Split)Index[64|32] column to point to the available items.
1443/// By default, items whose size is smaller or equal to 4 bytes (size of (Split)Index32 column element) are stored
1444/// densely.
1446 /// For a dense nullable field, used to write a default-constructed item for missing ones.
1447 std::unique_ptr<RValue> fDefaultItemValue;
1448 /// For a sparse nullable field, the number of written non-null items in this cluster
1449 ClusterSize_t fNWritten{0};
1450
1451protected:
1452 const RFieldBase::RColumnRepresentations &GetColumnRepresentations() const final;
1453 void GenerateColumnsImpl() final;
1454 void GenerateColumnsImpl(const RNTupleDescriptor &) final;
1455
1456 std::size_t AppendNull();
1457 std::size_t AppendValue(const void *from);
1458 void CommitClusterImpl() final { fNWritten = 0; }
1459
1460 /// Given the index of the nullable field, returns the corresponding global index of the subfield or,
1461 /// if it is null, returns kInvalidClusterIndex
1462 RClusterIndex GetItemIndex(NTupleSize_t globalIndex);
1463
1464 RNullableField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
1465
1466public:
1467 RNullableField(RNullableField &&other) = default;
1469 ~RNullableField() override = default;
1470
1471 bool IsDense() const { return GetColumnRepresentative()[0] == EColumnType::kBit; }
1472 bool IsSparse() const { return !IsDense(); }
1473 void SetDense() { SetColumnRepresentative({EColumnType::kBit}); }
1474 void SetSparse() { SetColumnRepresentative({EColumnType::kSplitIndex32}); }
1475
1476 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1477};
1478
1481 private:
1482 std::unique_ptr<RDeleter> fItemDeleter;
1483
1484 public:
1485 explicit RUniquePtrDeleter(std::unique_ptr<RDeleter> itemDeleter) : fItemDeleter(std::move(itemDeleter)) {}
1486 void operator()(void *objPtr, bool dtorOnly) final;
1487 };
1488
1489 std::unique_ptr<RDeleter> fItemDeleter;
1490
1491protected:
1492 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1493
1494 void ConstructValue(void *where) const final { new (where) std::unique_ptr<char>(); }
1495 std::unique_ptr<RDeleter> GetDeleter() const final;
1496
1497 std::size_t AppendImpl(const void *from) final;
1498 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1499
1500public:
1501 RUniquePtrField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
1503 RUniquePtrField &operator=(RUniquePtrField &&other) = default;
1504 ~RUniquePtrField() override = default;
1505
1506 std::vector<RValue> SplitValue(const RValue &value) const final;
1507 size_t GetValueSize() const final { return sizeof(std::unique_ptr<char>); }
1508 size_t GetAlignment() const final { return alignof(std::unique_ptr<char>); }
1509};
1510
1513 private:
1514 std::unique_ptr<RDeleter> fItemDeleter;
1515
1516 public:
1517 explicit ROptionalDeleter(std::unique_ptr<RDeleter> itemDeleter) : fItemDeleter(std::move(itemDeleter)) {}
1518 void operator()(void *objPtr, bool dtorOnly) final;
1519 };
1520
1521 std::unique_ptr<RDeleter> fItemDeleter;
1522
1523 /// Given a pointer to an std::optional<T> in `optionalPtr`, extract a pointer to the value T* and a pointer
1524 /// to the engagement boolean. Assumes that an std::optional<T> is stored as
1525 /// `struct { T t; bool engagement; };`
1526 std::pair<const void *, const bool *> GetValueAndEngagementPtrs(const void *optionalPtr) const;
1527 std::pair<void *, bool *> GetValueAndEngagementPtrs(void *optionalPtr) const;
1528
1529protected:
1530 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1531
1532 void ConstructValue(void *where) const final;
1533 std::unique_ptr<RDeleter> GetDeleter() const final;
1534
1535 std::size_t AppendImpl(const void *from) final;
1536 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1537
1538public:
1539 ROptionalField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
1540 ROptionalField(ROptionalField &&other) = default;
1541 ROptionalField &operator=(ROptionalField &&other) = default;
1542 ~ROptionalField() override = default;
1543
1544 std::vector<RValue> SplitValue(const RValue &value) const final;
1545 size_t GetValueSize() const final;
1546 size_t GetAlignment() const final;
1547};
1548
1549class RAtomicField : public RFieldBase {
1550protected:
1551 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1552
1553 void ConstructValue(void *where) const final { CallConstructValueOn(*fSubFields[0], where); }
1554 std::unique_ptr<RDeleter> GetDeleter() const final { return GetDeleterOf(*fSubFields[0]); }
1555
1556 std::size_t AppendImpl(const void *from) final { return CallAppendOn(*fSubFields[0], from); }
1557 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final { CallReadOn(*fSubFields[0], globalIndex, to); }
1558 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final { CallReadOn(*fSubFields[0], clusterIndex, to); }
1559
1560public:
1561 RAtomicField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField);
1562 RAtomicField(RAtomicField &&other) = default;
1564 ~RAtomicField() override = default;
1565
1566 std::vector<RValue> SplitValue(const RValue &value) const final;
1567
1568 size_t GetValueSize() const final { return fSubFields[0]->GetValueSize(); }
1569 size_t GetAlignment() const final { return fSubFields[0]->GetAlignment(); }
1570
1571 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1572};
1573
1574/// Classes with dictionaries that can be inspected by TClass
1575template <typename T, typename = void>
1576class RField final : public RClassField {
1577protected:
1578 void ConstructValue(void *where) const final
1579 {
1580 if constexpr (std::is_default_constructible_v<T>) {
1581 new (where) T();
1582 } else {
1583 // If there is no default constructor, try with the IO constructor
1584 new (where) T(static_cast<TRootIOCtor *>(nullptr));
1585 }
1586 }
1587
1588public:
1589 static std::string TypeName() { return ROOT::Internal::GetDemangledTypeName(typeid(T)); }
1590 RField(std::string_view name) : RClassField(name, TypeName()) {
1591 static_assert(std::is_class_v<T>, "no I/O support for this basic C++ type");
1592 }
1593 RField(RField &&other) = default;
1594 RField &operator=(RField &&other) = default;
1595 ~RField() override = default;
1596};
1597
1598template <typename T>
1599class RField<T, typename std::enable_if<std::is_enum_v<T>>::type> : public REnumField {
1600public:
1601 static std::string TypeName() { return ROOT::Internal::GetDemangledTypeName(typeid(T)); }
1602 RField(std::string_view name) : REnumField(name, TypeName()) {}
1603 RField(RField &&other) = default;
1604 RField &operator=(RField &&other) = default;
1605 ~RField() override = default;
1606};
1607
1608template <typename T, typename = void>
1609struct HasCollectionProxyMemberType : std::false_type {
1610};
1611template <typename T>
1613 T, typename std::enable_if<std::is_same<typename T::IsCollectionProxy, std::true_type>::value>::type>
1614 : std::true_type {
1615};
1616
1617/// The point here is that we can only tell at run time if a class has an associated collection proxy.
1618/// For compile time, in the first iteration of this PR we had an extra template argument that acted as a "tag" to
1619/// differentiate the RField specialization for classes with an associated collection proxy (inherits
1620/// `RProxiedCollectionField`) from the RField primary template definition (`RClassField`-derived), as in:
1621/// ```
1622/// auto field = std::make_unique<RField<MyClass>>("klass");
1623/// // vs
1624/// auto otherField = std::make_unique<RField<MyClass, ROOT::Experimental::TagIsCollectionProxy>>("klass");
1625/// ```
1626///
1627/// That is convenient only for non-nested types, i.e. it doesn't work with, e.g. `RField<std::vector<MyClass>,
1628/// ROOT::Experimental::TagIsCollectionProxy>`, as the tag is not forwarded to the instantiation of the inner RField
1629/// (that for the value type of the vector). The following two possible solutions were considered:
1630/// - A wrapper type (much like `ntuple/v7/inc/ROOT/RNTupleUtil.hxx:49`), that helps to differentiate both cases.
1631/// There we would have:
1632/// ```
1633/// auto field = std::make_unique<RField<RProxiedCollection<MyClass>>>("klass"); // Using collection proxy
1634/// ```
1635/// - A helper `IsCollectionProxy<T>` type, that can be used in a similar way to those in the `<type_traits>` header.
1636/// We found this more convenient and is the implemented thing below. Here, classes can be marked as a
1637/// collection proxy with either of the following two forms (whichever is more convenient for the user):
1638/// ```
1639/// template <>
1640/// struct IsCollectionProxy<MyClass> : std::true_type {};
1641/// ```
1642/// or by adding a member type to the class as follows:
1643/// ```
1644/// class MyClass {
1645/// public:
1646/// using IsCollectionProxy = std::true_type;
1647/// };
1648/// ```
1649///
1650/// Of course, there is another possible solution which is to have a single `RClassField` that implements both
1651/// the regular-class and the collection-proxy behaviors, and always chooses appropriately at run time.
1652/// We found that less clean and probably has more overhead, as most probably it involves an additional branch + call
1653/// in each of the member functions.
1654template <typename T, typename = void>
1656};
1657
1658/// Classes behaving as a collection of elements that can be queried via the `TVirtualCollectionProxy` interface
1659/// The use of a collection proxy for a particular class can be enabled via:
1660/// ```
1661/// namespace ROOT::Experimental {
1662/// template <> struct IsCollectionProxy<Classname> : std::true_type {};
1663/// }
1664/// ```
1665/// Alternatively, this can be achieved by adding a member type to the class definition as follows:
1666/// ```
1667/// class Classname {
1668/// public:
1669/// using IsCollectionProxy = std::true_type;
1670/// };
1671/// ```
1672template <typename T>
1673class RField<T, typename std::enable_if<IsCollectionProxy<T>::value>::type> final : public RProxiedCollectionField {
1674protected:
1675 void ConstructValue(void *where) const final { new (where) T(); }
1676
1677public:
1678 static std::string TypeName() { return ROOT::Internal::GetDemangledTypeName(typeid(T)); }
1679 RField(std::string_view name) : RProxiedCollectionField(name, TypeName())
1680 {
1681 static_assert(std::is_class<T>::value, "collection proxy unsupported for fundamental types");
1682 }
1683 RField(RField&& other) = default;
1684 RField& operator =(RField&& other) = default;
1685 ~RField() override = default;
1686};
1687
1688/// The collection field is only used for writing; when reading, untyped collections are projected to an std::vector
1690private:
1691 /// Save the link to the collection ntuple in order to reset the offset counter when committing the cluster
1692 std::shared_ptr<RNTupleCollectionWriter> fCollectionWriter;
1693
1694protected:
1695 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
1696 const RColumnRepresentations &GetColumnRepresentations() const final;
1697 void GenerateColumnsImpl() final;
1698 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1699 void ConstructValue(void *) const final {}
1700
1701 std::size_t AppendImpl(const void *from) final;
1702 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
1703
1704 void CommitClusterImpl() final;
1705
1706public:
1707 static std::string TypeName() { return ""; }
1708 RCollectionField(std::string_view name, std::shared_ptr<RNTupleCollectionWriter> collectionWriter,
1709 std::unique_ptr<RFieldZero> collectionParent);
1712 ~RCollectionField() override = default;
1713
1714 size_t GetValueSize() const final { return sizeof(ClusterSize_t); }
1715 size_t GetAlignment() const final { return alignof(ClusterSize_t); }
1716};
1717
1718/// The generic field for `std::pair<T1, T2>` types
1719class RPairField : public RRecordField {
1720private:
1721 class RPairDeleter : public RDeleter {
1722 private:
1724
1725 public:
1726 explicit RPairDeleter(TClass *cl) : fClass(cl) {}
1727 void operator()(void *objPtr, bool dtorOnly) final;
1728 };
1729
1730 TClass *fClass = nullptr;
1731 static std::string GetTypeList(const std::array<std::unique_ptr<RFieldBase>, 2> &itemFields);
1732
1733protected:
1734 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
1735
1736 void ConstructValue(void *where) const override;
1737 std::unique_ptr<RDeleter> GetDeleter() const override { return std::make_unique<RPairDeleter>(fClass); }
1738
1739 RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> &&itemFields,
1740 const std::array<std::size_t, 2> &offsets);
1741
1742public:
1743 RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> &itemFields);
1744 RPairField(RPairField &&other) = default;
1745 RPairField &operator=(RPairField &&other) = default;
1746 ~RPairField() override = default;
1747};
1748
1749/// The generic field for `std::tuple<Ts...>` types
1751private:
1752 class RTupleDeleter : public RDeleter {
1753 private:
1755
1756 public:
1757 explicit RTupleDeleter(TClass *cl) : fClass(cl) {}
1758 void operator()(void *objPtr, bool dtorOnly) final;
1759 };
1760
1761 TClass *fClass = nullptr;
1762 static std::string GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields);
1763
1764protected:
1765 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
1766
1767 void ConstructValue(void *where) const override;
1768 std::unique_ptr<RDeleter> GetDeleter() const override { return std::make_unique<RTupleDeleter>(fClass); }
1769
1770 RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> &&itemFields,
1771 const std::vector<std::size_t> &offsets);
1772
1773public:
1774 RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> &itemFields);
1775 RTupleField(RTupleField &&other) = default;
1776 RTupleField &operator=(RTupleField &&other) = default;
1777 ~RTupleField() override = default;
1778};
1779
1780/// An artificial field that transforms an RNTuple column that contains the offset of collections into
1781/// collection sizes. It is only used for reading, e.g. as projected field or as an artificial field that provides the
1782/// "number of" RDF columns for collections (e.g. `R_rdf_sizeof_jets` for a collection named `jets`).
1783/// It is used in the templated RField<RNTupleCardinality<SizeT>> form, which represents the collection sizes either
1784/// as 32bit unsigned int (std::uint32_t) or as 64bit unsigned int (std::uint64_t).
1786protected:
1787 RCardinalityField(std::string_view fieldName, std::string_view typeName)
1788 : RFieldBase(fieldName, typeName, ENTupleStructure::kLeaf, false /* isSimple */)
1789 {
1790 }
1791
1792 const RColumnRepresentations &GetColumnRepresentations() const final;
1793 // Field is only used for reading
1794 void GenerateColumnsImpl() final { throw RException(R__FAIL("Cardinality fields must only be used for reading")); }
1795 void GenerateColumnsImpl(const RNTupleDescriptor &) final;
1796
1797public:
1800 ~RCardinalityField() override = default;
1801
1802 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1803
1804 const RField<RNTupleCardinality<std::uint32_t>> *As32Bit() const;
1805 const RField<RNTupleCardinality<std::uint64_t>> *As64Bit() const;
1806};
1807
1808////////////////////////////////////////////////////////////////////////////////
1809/// Template specializations for concrete C++ types
1810////////////////////////////////////////////////////////////////////////////////
1811
1812template <>
1813class RField<void> : public RFieldBase {
1814public:
1815 static std::string TypeName() { return "void"; }
1816 // RField<void> should never be constructed.
1817 RField() = delete;
1818 RField(const RField &) = delete;
1819 RField &operator=(const RField &) = delete;
1820};
1821
1822template <>
1823class RField<ClusterSize_t> final : public RFieldBase {
1824protected:
1825 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
1826 {
1827 return std::make_unique<RField>(newName);
1828 }
1829
1831 void GenerateColumnsImpl() final;
1832 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1833 void ConstructValue(void *where) const final { new (where) ClusterSize_t(0); }
1834
1835public:
1836 static std::string TypeName() { return "ROOT::Experimental::ClusterSize_t"; }
1837 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1838 {
1839 fTraits |= kTraitTrivialType;
1840 }
1841 RField(RField&& other) = default;
1842 RField& operator =(RField&& other) = default;
1843 ~RField() override = default;
1844
1846 return fPrincipalColumn->Map<ClusterSize_t>(globalIndex);
1847 }
1848 ClusterSize_t *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<ClusterSize_t>(clusterIndex); }
1850 return fPrincipalColumn->MapV<ClusterSize_t>(globalIndex, nItems);
1851 }
1853 {
1854 return fPrincipalColumn->MapV<ClusterSize_t>(clusterIndex, nItems);
1855 }
1856
1857 size_t GetValueSize() const final { return sizeof(ClusterSize_t); }
1858 size_t GetAlignment() const final { return alignof(ClusterSize_t); }
1859
1860 /// Special help for offset fields
1861 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) {
1862 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
1863 }
1864 void GetCollectionInfo(RClusterIndex clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size)
1865 {
1866 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
1867 }
1868 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1869};
1870
1871template <typename SizeT>
1872class RField<RNTupleCardinality<SizeT>> final : public RCardinalityField {
1873protected:
1874 std::unique_ptr<ROOT::Experimental::RFieldBase> CloneImpl(std::string_view newName) const final
1875 {
1876 return std::make_unique<RField<RNTupleCardinality<SizeT>>>(newName);
1877 }
1878 void ConstructValue(void *where) const final { new (where) RNTupleCardinality<SizeT>(0); }
1879
1880public:
1881 static std::string TypeName() { return "ROOT::Experimental::RNTupleCardinality<" + RField<SizeT>::TypeName() + ">"; }
1882 explicit RField(std::string_view name) : RCardinalityField(name, TypeName()) {}
1883 RField(RField &&other) = default;
1884 RField &operator=(RField &&other) = default;
1885 ~RField() override = default;
1886
1887 size_t GetValueSize() const final { return sizeof(RNTupleCardinality<SizeT>); }
1888 size_t GetAlignment() const final { return alignof(RNTupleCardinality<SizeT>); }
1889
1890 /// Get the number of elements of the collection identified by globalIndex
1891 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
1892 {
1893 RClusterIndex collectionStart;
1895 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &size);
1896 *static_cast<RNTupleCardinality<SizeT> *>(to) = size;
1897 }
1898
1899 /// Get the number of elements of the collection identified by clusterIndex
1900 void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
1901 {
1902 RClusterIndex collectionStart;
1904 fPrincipalColumn->GetCollectionInfo(clusterIndex, &collectionStart, &size);
1905 *static_cast<RNTupleCardinality<SizeT> *>(to) = size;
1906 }
1907
1908 std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec) final
1909 {
1910 RClusterIndex collectionStart;
1911 ClusterSize_t collectionSize;
1912 fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &collectionStart, &collectionSize);
1913
1914 auto typedValues = static_cast<RNTupleCardinality<SizeT> *>(bulkSpec.fValues);
1915 typedValues[0] = collectionSize;
1916
1917 auto lastOffset = collectionStart.GetIndex() + collectionSize;
1918 ClusterSize_t::ValueType nRemainingEntries = bulkSpec.fCount - 1;
1919 std::size_t nEntries = 1;
1920 while (nRemainingEntries > 0) {
1921 NTupleSize_t nItemsUntilPageEnd;
1922 auto offsets = fPrincipalColumn->MapV<ClusterSize_t>(bulkSpec.fFirstIndex + nEntries, nItemsUntilPageEnd);
1923 std::size_t nBatch = std::min(nRemainingEntries, nItemsUntilPageEnd);
1924 for (std::size_t i = 0; i < nBatch; ++i) {
1925 typedValues[nEntries + i] = offsets[i] - lastOffset;
1926 lastOffset = offsets[i];
1927 }
1928 nRemainingEntries -= nBatch;
1929 nEntries += nBatch;
1930 }
1931 return RBulkSpec::kAllSet;
1932 }
1933};
1934
1935template <>
1936class RField<bool> final : public RFieldBase {
1937protected:
1938 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
1939 {
1940 return std::make_unique<RField>(newName);
1941 }
1942
1943 const RColumnRepresentations &GetColumnRepresentations() const final;
1944 void GenerateColumnsImpl() final;
1945 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1946 void ConstructValue(void *where) const final { new (where) bool(false); }
1947
1948public:
1949 static std::string TypeName() { return "bool"; }
1950 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1951 {
1952 fTraits |= kTraitTrivialType;
1953 }
1954 RField(RField&& other) = default;
1955 RField& operator =(RField&& other) = default;
1956 ~RField() override = default;
1957
1958 bool *Map(NTupleSize_t globalIndex) {
1959 return fPrincipalColumn->Map<bool>(globalIndex);
1960 }
1961 bool *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<bool>(clusterIndex); }
1962 bool *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1963 return fPrincipalColumn->MapV<bool>(globalIndex, nItems);
1964 }
1965 bool *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
1966 {
1967 return fPrincipalColumn->MapV<bool>(clusterIndex, nItems);
1968 }
1969
1970 size_t GetValueSize() const final { return sizeof(bool); }
1971 size_t GetAlignment() const final { return alignof(bool); }
1972 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1973};
1974
1975template <>
1976class RField<float> final : public RFieldBase {
1977protected:
1978 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
1979 {
1980 return std::make_unique<RField>(newName);
1981 }
1982
1983 const RColumnRepresentations &GetColumnRepresentations() const final;
1984 void GenerateColumnsImpl() final;
1985 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1986 void ConstructValue(void *where) const final { new (where) float(0.0); }
1987
1988public:
1989 static std::string TypeName() { return "float"; }
1990 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1991 {
1992 fTraits |= kTraitTrivialType;
1993 }
1994 RField(RField&& other) = default;
1995 RField& operator =(RField&& other) = default;
1996 ~RField() override = default;
1997
1998 float *Map(NTupleSize_t globalIndex) {
1999 return fPrincipalColumn->Map<float>(globalIndex);
2000 }
2001 float *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<float>(clusterIndex); }
2002 float *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2003 return fPrincipalColumn->MapV<float>(globalIndex, nItems);
2004 }
2005 float *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2006 {
2007 return fPrincipalColumn->MapV<float>(clusterIndex, nItems);
2008 }
2009
2010 size_t GetValueSize() const final { return sizeof(float); }
2011 size_t GetAlignment() const final { return alignof(float); }
2012 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2013
2014 void SetHalfPrecision();
2015};
2016
2017template <>
2018class RField<double> final : public RFieldBase {
2019protected:
2020 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2021 {
2022 return std::make_unique<RField>(newName);
2023 }
2024
2025 const RColumnRepresentations &GetColumnRepresentations() const final;
2026 void GenerateColumnsImpl() final;
2027 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2028 void ConstructValue(void *where) const final { new (where) double(0.0); }
2029
2030public:
2031 static std::string TypeName() { return "double"; }
2032 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2033 {
2034 fTraits |= kTraitTrivialType;
2035 }
2036 RField(RField&& other) = default;
2037 RField& operator =(RField&& other) = default;
2038 ~RField() override = default;
2039
2040 double *Map(NTupleSize_t globalIndex) {
2041 return fPrincipalColumn->Map<double>(globalIndex);
2042 }
2043 double *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<double>(clusterIndex); }
2044 double *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2045 return fPrincipalColumn->MapV<double>(globalIndex, nItems);
2046 }
2047 double *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2048 {
2049 return fPrincipalColumn->MapV<double>(clusterIndex, nItems);
2050 }
2051
2052 size_t GetValueSize() const final { return sizeof(double); }
2053 size_t GetAlignment() const final { return alignof(double); }
2054 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2055
2056 // Set the column representation to 32 bit floating point and the type alias to Double32_t
2057 void SetDouble32();
2058};
2059
2060template <>
2061class RField<std::byte> final : public RFieldBase {
2062protected:
2063 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2064 {
2065 return std::make_unique<RField>(newName);
2066 }
2067
2068 const RColumnRepresentations &GetColumnRepresentations() const final;
2069 void GenerateColumnsImpl() final;
2070 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2071 void ConstructValue(void *where) const final { new (where) std::byte{0}; }
2072
2073public:
2074 static std::string TypeName() { return "std::byte"; }
2075 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2076 {
2077 fTraits |= kTraitTrivialType;
2078 }
2079 RField(RField &&other) = default;
2080 RField &operator=(RField &&other) = default;
2081 ~RField() override = default;
2082
2083 std::byte *Map(NTupleSize_t globalIndex) { return fPrincipalColumn->Map<std::byte>(globalIndex); }
2084 std::byte *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<std::byte>(clusterIndex); }
2085 std::byte *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
2086 {
2087 return fPrincipalColumn->MapV<std::byte>(globalIndex, nItems);
2088 }
2089 std::byte *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2090 {
2091 return fPrincipalColumn->MapV<std::byte>(clusterIndex, nItems);
2092 }
2093
2094 size_t GetValueSize() const final { return sizeof(std::byte); }
2095 size_t GetAlignment() const final { return alignof(std::byte); }
2096 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2097};
2098
2099template <>
2100class RField<char> final : public RFieldBase {
2101protected:
2102 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2103 {
2104 return std::make_unique<RField>(newName);
2105 }
2106
2107 const RColumnRepresentations &GetColumnRepresentations() const final;
2108 void GenerateColumnsImpl() final;
2109 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2110 void ConstructValue(void *where) const final { new (where) char(0); }
2111
2112public:
2113 static std::string TypeName() { return "char"; }
2114 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2115 {
2116 fTraits |= kTraitTrivialType;
2117 }
2118 RField(RField&& other) = default;
2119 RField& operator =(RField&& other) = default;
2120 ~RField() override = default;
2121
2122 char *Map(NTupleSize_t globalIndex) {
2123 return fPrincipalColumn->Map<char>(globalIndex);
2124 }
2125 char *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<char>(clusterIndex); }
2126 char *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2127 return fPrincipalColumn->MapV<char>(globalIndex, nItems);
2128 }
2129 char *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2130 {
2131 return fPrincipalColumn->MapV<char>(clusterIndex, nItems);
2132 }
2133
2134 size_t GetValueSize() const final { return sizeof(char); }
2135 size_t GetAlignment() const final { return alignof(char); }
2136 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2137};
2138
2139template <>
2140class RField<std::int8_t> final : public RFieldBase {
2141protected:
2142 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2143 {
2144 return std::make_unique<RField>(newName);
2145 }
2146
2147 const RColumnRepresentations &GetColumnRepresentations() const final;
2148 void GenerateColumnsImpl() final;
2149 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2150 void ConstructValue(void *where) const final { new (where) int8_t(0); }
2151
2152public:
2153 static std::string TypeName() { return "std::int8_t"; }
2154 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2155 {
2156 fTraits |= kTraitTrivialType;
2157 }
2158 RField(RField&& other) = default;
2159 RField& operator =(RField&& other) = default;
2160 ~RField() override = default;
2161
2162 std::int8_t *Map(NTupleSize_t globalIndex) {
2163 return fPrincipalColumn->Map<std::int8_t>(globalIndex);
2164 }
2165 std::int8_t *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<std::int8_t>(clusterIndex); }
2166 std::int8_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2167 return fPrincipalColumn->MapV<std::int8_t>(globalIndex, nItems);
2168 }
2169 std::int8_t *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2170 {
2171 return fPrincipalColumn->MapV<std::int8_t>(clusterIndex, nItems);
2172 }
2173
2174 size_t GetValueSize() const final { return sizeof(std::int8_t); }
2175 size_t GetAlignment() const final { return alignof(std::int8_t); }
2176 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2177};
2178
2179template <>
2180class RField<std::uint8_t> final : public RFieldBase {
2181protected:
2182 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2183 {
2184 return std::make_unique<RField>(newName);
2185 }
2186
2187 const RColumnRepresentations &GetColumnRepresentations() const final;
2188 void GenerateColumnsImpl() final;
2189 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2190 void ConstructValue(void *where) const final { new (where) uint8_t(0); }
2191
2192public:
2193 static std::string TypeName() { return "std::uint8_t"; }
2194 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2195 {
2196 fTraits |= kTraitTrivialType;
2197 }
2198 RField(RField&& other) = default;
2199 RField& operator =(RField&& other) = default;
2200 ~RField() override = default;
2201
2202 std::uint8_t *Map(NTupleSize_t globalIndex) {
2203 return fPrincipalColumn->Map<std::uint8_t>(globalIndex);
2204 }
2205 std::uint8_t *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<std::uint8_t>(clusterIndex); }
2206 std::uint8_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2207 return fPrincipalColumn->MapV<std::uint8_t>(globalIndex, nItems);
2208 }
2209 std::uint8_t *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2210 {
2211 return fPrincipalColumn->MapV<std::uint8_t>(clusterIndex, nItems);
2212 }
2213
2214 size_t GetValueSize() const final { return sizeof(std::uint8_t); }
2215 size_t GetAlignment() const final { return alignof(std::uint8_t); }
2216 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2217};
2218
2219template <>
2220class RField<std::int16_t> final : public RFieldBase {
2221protected:
2222 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2223 {
2224 return std::make_unique<RField>(newName);
2225 }
2226
2227 const RColumnRepresentations &GetColumnRepresentations() const final;
2228 void GenerateColumnsImpl() final;
2229 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2230 void ConstructValue(void *where) const final { new (where) int16_t(0); }
2231
2232public:
2233 static std::string TypeName() { return "std::int16_t"; }
2234 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2235 {
2236 fTraits |= kTraitTrivialType;
2237 }
2238 RField(RField&& other) = default;
2239 RField& operator =(RField&& other) = default;
2240 ~RField() override = default;
2241
2242 std::int16_t *Map(NTupleSize_t globalIndex) {
2243 return fPrincipalColumn->Map<std::int16_t>(globalIndex);
2244 }
2245 std::int16_t *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<std::int16_t>(clusterIndex); }
2246 std::int16_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2247 return fPrincipalColumn->MapV<std::int16_t>(globalIndex, nItems);
2248 }
2249 std::int16_t *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2250 {
2251 return fPrincipalColumn->MapV<std::int16_t>(clusterIndex, nItems);
2252 }
2253
2254 size_t GetValueSize() const final { return sizeof(std::int16_t); }
2255 size_t GetAlignment() const final { return alignof(std::int16_t); }
2256 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2257};
2258
2259template <>
2260class RField<std::uint16_t> final : public RFieldBase {
2261protected:
2262 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2263 {
2264 return std::make_unique<RField>(newName);
2265 }
2266
2267 const RColumnRepresentations &GetColumnRepresentations() const final;
2268 void GenerateColumnsImpl() final;
2269 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2270 void ConstructValue(void *where) const final { new (where) int16_t(0); }
2271
2272public:
2273 static std::string TypeName() { return "std::uint16_t"; }
2274 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2275 {
2276 fTraits |= kTraitTrivialType;
2277 }
2278 RField(RField&& other) = default;
2279 RField& operator =(RField&& other) = default;
2280 ~RField() override = default;
2281
2282 std::uint16_t *Map(NTupleSize_t globalIndex) {
2283 return fPrincipalColumn->Map<std::uint16_t>(globalIndex);
2284 }
2285 std::uint16_t *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<std::uint16_t>(clusterIndex); }
2286 std::uint16_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2287 return fPrincipalColumn->MapV<std::uint16_t>(globalIndex, nItems);
2288 }
2289 std::uint16_t *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2290 {
2291 return fPrincipalColumn->MapV<std::uint16_t>(clusterIndex, nItems);
2292 }
2293
2294 size_t GetValueSize() const final { return sizeof(std::uint16_t); }
2295 size_t GetAlignment() const final { return alignof(std::uint16_t); }
2296 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2297};
2298
2299template <>
2300class RField<std::int32_t> final : public RFieldBase {
2301protected:
2302 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2303 {
2304 return std::make_unique<RField>(newName);
2305 }
2306
2307 const RColumnRepresentations &GetColumnRepresentations() const final;
2308 void GenerateColumnsImpl() final;
2309 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2310 void ConstructValue(void *where) const final { new (where) int32_t(0); }
2311
2312public:
2313 static std::string TypeName() { return "std::int32_t"; }
2314 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2315 {
2316 fTraits |= kTraitTrivialType;
2317 }
2318 RField(RField&& other) = default;
2319 RField& operator =(RField&& other) = default;
2320 ~RField() override = default;
2321
2322 std::int32_t *Map(NTupleSize_t globalIndex) {
2323 return fPrincipalColumn->Map<std::int32_t>(globalIndex);
2324 }
2325 std::int32_t *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<std::int32_t>(clusterIndex); }
2326 std::int32_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2327 return fPrincipalColumn->MapV<std::int32_t>(globalIndex, nItems);
2328 }
2329 std::int32_t *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2330 {
2331 return fPrincipalColumn->MapV<std::int32_t>(clusterIndex, nItems);
2332 }
2333
2334 size_t GetValueSize() const final { return sizeof(std::int32_t); }
2335 size_t GetAlignment() const final { return alignof(std::int32_t); }
2336 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2337};
2338
2339template <>
2340class RField<std::uint32_t> final : public RFieldBase {
2341protected:
2342 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2343 {
2344 return std::make_unique<RField>(newName);
2345 }
2346
2347 const RColumnRepresentations &GetColumnRepresentations() const final;
2348 void GenerateColumnsImpl() final;
2349 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2350 void ConstructValue(void *where) const final { new (where) uint32_t(0); }
2351
2352public:
2353 static std::string TypeName() { return "std::uint32_t"; }
2354 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2355 {
2356 fTraits |= kTraitTrivialType;
2357 }
2358 RField(RField&& other) = default;
2359 RField& operator =(RField&& other) = default;
2360 ~RField() override = default;
2361
2362 std::uint32_t *Map(NTupleSize_t globalIndex) {
2363 return fPrincipalColumn->Map<std::uint32_t>(globalIndex);
2364 }
2365 std::uint32_t *Map(const RClusterIndex clusterIndex) {
2366 return fPrincipalColumn->Map<std::uint32_t>(clusterIndex);
2367 }
2368 std::uint32_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2369 return fPrincipalColumn->MapV<std::uint32_t>(globalIndex, nItems);
2370 }
2371 std::uint32_t *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2372 {
2373 return fPrincipalColumn->MapV<std::uint32_t>(clusterIndex, nItems);
2374 }
2375
2376 size_t GetValueSize() const final { return sizeof(std::uint32_t); }
2377 size_t GetAlignment() const final { return alignof(std::uint32_t); }
2378 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2379};
2380
2381template <>
2382class RField<std::uint64_t> final : public RFieldBase {
2383protected:
2384 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2385 {
2386 return std::make_unique<RField>(newName);
2387 }
2388
2389 const RColumnRepresentations &GetColumnRepresentations() const final;
2390 void GenerateColumnsImpl() final;
2391 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2392 void ConstructValue(void *where) const final { new (where) uint64_t(0); }
2393
2394public:
2395 static std::string TypeName() { return "std::uint64_t"; }
2396 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2397 {
2398 fTraits |= kTraitTrivialType;
2399 }
2400 RField(RField&& other) = default;
2401 RField& operator =(RField&& other) = default;
2402 ~RField() override = default;
2403
2404 std::uint64_t *Map(NTupleSize_t globalIndex) {
2405 return fPrincipalColumn->Map<std::uint64_t>(globalIndex);
2406 }
2407 std::uint64_t *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<std::uint64_t>(clusterIndex); }
2408 std::uint64_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2409 return fPrincipalColumn->MapV<std::uint64_t>(globalIndex, nItems);
2410 }
2411 std::uint64_t *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2412 {
2413 return fPrincipalColumn->MapV<std::uint64_t>(clusterIndex, nItems);
2414 }
2415
2416 size_t GetValueSize() const final { return sizeof(std::uint64_t); }
2417 size_t GetAlignment() const final { return alignof(std::uint64_t); }
2418 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2419};
2420
2421template <>
2422class RField<std::int64_t> final : public RFieldBase {
2423protected:
2424 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2425 {
2426 return std::make_unique<RField>(newName);
2427 }
2428
2429 const RColumnRepresentations &GetColumnRepresentations() const final;
2430 void GenerateColumnsImpl() final;
2431 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2432 void ConstructValue(void *where) const final { new (where) int64_t(0); }
2433
2434public:
2435 static std::string TypeName() { return "std::int64_t"; }
2436 explicit RField(std::string_view name) : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
2437 {
2438 fTraits |= kTraitTrivialType;
2439 }
2440 RField(RField&& other) = default;
2441 RField& operator =(RField&& other) = default;
2442 ~RField() override = default;
2443
2444 std::int64_t *Map(NTupleSize_t globalIndex) {
2445 return fPrincipalColumn->Map<std::int64_t>(globalIndex);
2446 }
2447 std::int64_t *Map(RClusterIndex clusterIndex) { return fPrincipalColumn->Map<std::int64_t>(clusterIndex); }
2448 std::int64_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
2449 return fPrincipalColumn->MapV<std::int64_t>(globalIndex, nItems);
2450 }
2451 std::int64_t *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
2452 {
2453 return fPrincipalColumn->MapV<std::int64_t>(clusterIndex, nItems);
2454 }
2455
2456 size_t GetValueSize() const final { return sizeof(std::int64_t); }
2457 size_t GetAlignment() const final { return alignof(std::int64_t); }
2458 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2459};
2460
2461template <>
2462class RField<std::string> final : public RFieldBase {
2463private:
2464 ClusterSize_t fIndex;
2465
2466 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2467 {
2468 return std::make_unique<RField>(newName);
2469 }
2470
2471 const RColumnRepresentations &GetColumnRepresentations() const final;
2472 void GenerateColumnsImpl() final;
2473 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2474
2475 void ConstructValue(void *where) const final { new (where) std::string(); }
2476 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<std::string>>(); }
2477
2478 std::size_t AppendImpl(const void *from) final;
2479 void ReadGlobalImpl(ROOT::Experimental::NTupleSize_t globalIndex, void *to) final;
2480
2481 void CommitClusterImpl() final { fIndex = 0; }
2482
2483public:
2484 static std::string TypeName() { return "std::string"; }
2485 explicit RField(std::string_view name)
2486 : RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, false /* isSimple */), fIndex(0)
2487 {
2488 }
2489 RField(RField&& other) = default;
2490 RField& operator =(RField&& other) = default;
2491 ~RField() override = default;
2492
2493 size_t GetValueSize() const final { return sizeof(std::string); }
2494 size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
2495 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2496};
2497
2498/// TObject requires special handling of the fBits and fUniqueID members
2499template <>
2500class RField<TObject> final : public RFieldBase {
2501 static std::size_t GetOffsetOfMember(const char *name);
2502 static std::size_t GetOffsetUniqueID() { return GetOffsetOfMember("fUniqueID"); }
2503 static std::size_t GetOffsetBits() { return GetOffsetOfMember("fBits"); }
2504
2505protected:
2506 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
2507
2508 void ConstructValue(void *where) const override;
2509 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<TObject>>(); }
2510
2511 std::size_t AppendImpl(const void *from) final;
2512 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
2513
2514 void OnConnectPageSource() final;
2515
2516public:
2517 static std::string TypeName() { return "TObject"; }
2518
2519 RField(std::string_view fieldName);
2520 RField(RField &&other) = default;
2521 RField &operator=(RField &&other) = default;
2522 ~RField() override = default;
2523
2524 std::vector<RValue> SplitValue(const RValue &value) const final;
2525 size_t GetValueSize() const final;
2526 size_t GetAlignment() const final;
2527 std::uint32_t GetTypeVersion() const final;
2528 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2529};
2530
2531template <typename ItemT, std::size_t N>
2532class RField<std::array<ItemT, N>> : public RArrayField {
2533 using ContainerT = typename std::array<ItemT, N>;
2534
2535protected:
2536 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2537
2538public:
2539 static std::string TypeName() {
2540 return "std::array<" + RField<ItemT>::TypeName() + "," + std::to_string(N) + ">";
2541 }
2542 explicit RField(std::string_view name) : RArrayField(name, std::make_unique<RField<ItemT>>("_0"), N)
2543 {}
2544 RField(RField&& other) = default;
2545 RField& operator =(RField&& other) = default;
2546 ~RField() override = default;
2547};
2548
2549template <typename ItemT, std::size_t N>
2550class RField<ItemT[N]> final : public RField<std::array<ItemT, N>> {
2551public:
2552 explicit RField(std::string_view name) : RField<std::array<ItemT, N>>(name) {}
2553 RField(RField &&other) = default;
2554 RField &operator=(RField &&other) = default;
2555 ~RField() override = default;
2556};
2557
2558template <typename ItemT>
2559class RField<std::set<ItemT>> : public RSetField {
2560 using ContainerT = typename std::set<ItemT>;
2561
2562protected:
2563 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2564 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<ContainerT>>(); }
2565
2566public:
2567 static std::string TypeName() { return "std::set<" + RField<ItemT>::TypeName() + ">"; }
2568
2569 explicit RField(std::string_view name) : RSetField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
2570 RField(RField &&other) = default;
2571 RField &operator=(RField &&other) = default;
2572 ~RField() override = default;
2573
2574 size_t GetValueSize() const final { return sizeof(ContainerT); }
2575 size_t GetAlignment() const final { return std::alignment_of<ContainerT>(); }
2576};
2577
2578template <typename ItemT>
2579class RField<std::unordered_set<ItemT>> final : public RSetField {
2580 using ContainerT = typename std::unordered_set<ItemT>;
2581
2582protected:
2583 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2584 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<ContainerT>>(); }
2585
2586public:
2587 static std::string TypeName() { return "std::unordered_set<" + RField<ItemT>::TypeName() + ">"; }
2588
2589 explicit RField(std::string_view name) : RSetField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
2590 RField(RField &&other) = default;
2591 RField &operator=(RField &&other) = default;
2592 ~RField() override = default;
2593
2594 size_t GetValueSize() const final { return sizeof(ContainerT); }
2595 size_t GetAlignment() const final { return std::alignment_of<ContainerT>(); }
2596};
2597
2598template <typename KeyT, typename ValueT>
2599class RField<std::map<KeyT, ValueT>> final : public RMapField {
2600 using ContainerT = typename std::map<KeyT, ValueT>;
2601
2602protected:
2603 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2604 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<ContainerT>>(); }
2605
2606public:
2607 static std::string TypeName()
2608 {
2609 return "std::map<" + RField<KeyT>::TypeName() + "," + RField<ValueT>::TypeName() + ">";
2610 }
2611
2612 explicit RField(std::string_view name)
2613 : RMapField(name, TypeName(), std::make_unique<RField<std::pair<KeyT, ValueT>>>("_0"))
2614 {
2615 }
2616 RField(RField &&other) = default;
2617 RField &operator=(RField &&other) = default;
2618 ~RField() override = default;
2619
2620 size_t GetValueSize() const final { return sizeof(ContainerT); }
2621 size_t GetAlignment() const final { return std::alignment_of<ContainerT>(); }
2622};
2623
2624template <typename KeyT, typename ValueT>
2625class RField<std::unordered_map<KeyT, ValueT>> final : public RMapField {
2626 using ContainerT = typename std::unordered_map<KeyT, ValueT>;
2627
2628protected:
2629 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2630 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<ContainerT>>(); }
2631
2632public:
2633 static std::string TypeName()
2634 {
2635 return "std::unordered_map<" + RField<KeyT>::TypeName() + "," + RField<ValueT>::TypeName() + ">";
2636 }
2637
2638 explicit RField(std::string_view name)
2639 : RMapField(name, TypeName(), std::make_unique<RField<std::pair<KeyT, ValueT>>>("_0"))
2640 {
2641 }
2642 RField(RField &&other) = default;
2643 RField &operator=(RField &&other) = default;
2644 ~RField() override = default;
2645
2646 size_t GetValueSize() const final { return sizeof(ContainerT); }
2647 size_t GetAlignment() const final { return std::alignment_of<ContainerT>(); }
2648};
2649
2650template <typename... ItemTs>
2651class RField<std::variant<ItemTs...>> final : public RVariantField {
2652 using ContainerT = typename std::variant<ItemTs...>;
2653private:
2654 template <typename HeadT, typename... TailTs>
2655 static std::string BuildItemTypes()
2656 {
2657 std::string result = RField<HeadT>::TypeName();
2658 if constexpr(sizeof...(TailTs) > 0)
2659 result += "," + BuildItemTypes<TailTs...>();
2660 return result;
2661 }
2662
2663 template <typename HeadT, typename... TailTs>
2664 static std::vector<RFieldBase *> BuildItemFields(unsigned int index = 0)
2665 {
2666 std::vector<RFieldBase *> result;
2667 result.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
2668 if constexpr(sizeof...(TailTs) > 0) {
2669 auto tailFields = BuildItemFields<TailTs...>(index + 1);
2670 result.insert(result.end(), tailFields.begin(), tailFields.end());
2671 }
2672 return result;
2673 }
2674
2675protected:
2676 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2677
2678public:
2679 static std::string TypeName() { return "std::variant<" + BuildItemTypes<ItemTs...>() + ">"; }
2680 explicit RField(std::string_view name) : RVariantField(name, BuildItemFields<ItemTs...>()) {}
2681 RField(RField&& other) = default;
2682 RField& operator =(RField&& other) = default;
2683 ~RField() override = default;
2684};
2685
2686template <typename ItemT>
2687class RField<std::vector<ItemT>> final : public RVectorField {
2688 using ContainerT = typename std::vector<ItemT>;
2689
2690protected:
2691 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2692
2693public:
2694 static std::string TypeName() { return "std::vector<" + RField<ItemT>::TypeName() + ">"; }
2695 explicit RField(std::string_view name)
2696 : RVectorField(name, std::make_unique<RField<ItemT>>("_0"))
2697 {}
2698 RField(RField&& other) = default;
2699 RField& operator =(RField&& other) = default;
2700 ~RField() override = default;
2701
2702 size_t GetValueSize() const final { return sizeof(ContainerT); }
2703};
2704
2705// std::vector<bool> is a template specialization and needs special treatment
2706template <>
2707class RField<std::vector<bool>> final : public RFieldBase {
2708private:
2709 ClusterSize_t fNWritten{0};
2710
2711protected:
2712 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2713 {
2714 return std::make_unique<RField>(newName);
2715 }
2716
2717 const RColumnRepresentations &GetColumnRepresentations() const final;
2718 void GenerateColumnsImpl() final;
2719 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
2720
2721 void ConstructValue(void *where) const final { new (where) std::vector<bool>(); }
2722 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<std::vector<bool>>>(); }
2723
2724 std::size_t AppendImpl(const void *from) final;
2725 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final;
2726
2727 void CommitClusterImpl() final { fNWritten = 0; }
2728
2729public:
2730 static std::string TypeName() { return "std::vector<bool>"; }
2731 explicit RField(std::string_view name);
2732 RField(RField&& other) = default;
2733 RField& operator =(RField&& other) = default;
2734 ~RField() override = default;
2735
2736 std::vector<RValue> SplitValue(const RValue &value) const final;
2737
2738 size_t GetValueSize() const final { return sizeof(std::vector<bool>); }
2739 size_t GetAlignment() const final { return std::alignment_of<std::vector<bool>>(); }
2740 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
2741 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const {
2742 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
2743 }
2744 void GetCollectionInfo(RClusterIndex clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
2745 {
2746 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
2747 }
2748};
2749
2750template <typename ItemT>
2751class RField<ROOT::VecOps::RVec<ItemT>> final : public RRVecField {
2753protected:
2754 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2755 {
2756 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
2757 return std::make_unique<RField<ROOT::VecOps::RVec<ItemT>>>(newName, std::move(newItemField));
2758 }
2759
2760 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2761 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<ContainerT>>(); }
2762
2763 std::size_t AppendImpl(const void *from) final
2764 {
2765 auto typedValue = static_cast<const ContainerT *>(from);
2766 auto nbytes = 0;
2767 auto count = typedValue->size();
2768 for (unsigned i = 0; i < count; ++i) {
2769 nbytes += CallAppendOn(*fSubFields[0], &typedValue->data()[i]);
2770 }
2771 this->fNWritten += count;
2772 fColumns[0]->Append(&this->fNWritten);
2773 return nbytes + fColumns[0]->GetElement()->GetPackedSize();
2774 }
2775 void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
2776 {
2777 auto typedValue = static_cast<ContainerT *>(to);
2778 ClusterSize_t nItems;
2779 RClusterIndex collectionStart;
2780 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
2781 typedValue->resize(nItems);
2782 for (unsigned i = 0; i < nItems; ++i) {
2783 CallReadOn(*fSubFields[0], collectionStart + i, &typedValue->data()[i]);
2784 }
2785 }
2786
2787public:
2788 RField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
2789 : RRVecField(fieldName, std::move(itemField))
2790 {
2791 }
2792
2793 explicit RField(std::string_view name)
2794 : RField(name, std::make_unique<RField<ItemT>>("_0"))
2795 {
2796 }
2797 RField(RField&& other) = default;
2798 RField& operator =(RField&& other) = default;
2799 ~RField() override = default;
2800
2801 static std::string TypeName() { return "ROOT::VecOps::RVec<" + RField<ItemT>::TypeName() + ">"; }
2802
2803 size_t GetValueSize() const final { return sizeof(ContainerT); }
2804 size_t GetAlignment() const final { return std::alignment_of<ContainerT>(); }
2805};
2806
2807template <typename T1, typename T2>
2808class RField<std::pair<T1, T2>> final : public RPairField {
2809 using ContainerT = typename std::pair<T1,T2>;
2810private:
2811 template <typename Ty1, typename Ty2>
2812 static std::array<std::unique_ptr<RFieldBase>, 2> BuildItemFields()
2813 {
2814 return {std::make_unique<RField<Ty1>>("_0"), std::make_unique<RField<Ty2>>("_1")};
2815 }
2816
2817 static std::array<std::size_t, 2> BuildItemOffsets()
2818 {
2819 auto pair = ContainerT();
2820 auto offsetFirst = reinterpret_cast<std::uintptr_t>(&(pair.first)) - reinterpret_cast<std::uintptr_t>(&pair);
2821 auto offsetSecond = reinterpret_cast<std::uintptr_t>(&(pair.second)) - reinterpret_cast<std::uintptr_t>(&pair);
2822 return {offsetFirst, offsetSecond};
2823 }
2824
2825protected:
2826 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2827 {
2828 std::array<std::unique_ptr<RFieldBase>, 2> items{fSubFields[0]->Clone(fSubFields[0]->GetFieldName()),
2829 fSubFields[1]->Clone(fSubFields[1]->GetFieldName())};
2830 return std::make_unique<RField<std::pair<T1, T2>>>(newName, std::move(items));
2831 }
2832
2833 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2834 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<ContainerT>>(); }
2835
2836public:
2837 static std::string TypeName() {
2838 return "std::pair<" + RField<T1>::TypeName() + "," + RField<T2>::TypeName() + ">";
2839 }
2840 explicit RField(std::string_view name, std::array<std::unique_ptr<RFieldBase>, 2> &&itemFields)
2841 : RPairField(name, std::move(itemFields), BuildItemOffsets())
2842 {
2843 fMaxAlignment = std::max(alignof(T1), alignof(T2));
2844 fSize = sizeof(ContainerT);
2845 }
2846 explicit RField(std::string_view name) : RField(name, BuildItemFields<T1, T2>()) {}
2847 RField(RField&& other) = default;
2848 RField& operator =(RField&& other) = default;
2849 ~RField() override = default;
2850};
2851
2852template <typename... ItemTs>
2853class RField<std::tuple<ItemTs...>> final : public RTupleField {
2854 using ContainerT = typename std::tuple<ItemTs...>;
2855private:
2856 template <typename HeadT, typename... TailTs>
2857 static std::string BuildItemTypes()
2858 {
2859 std::string result = RField<HeadT>::TypeName();
2860 if constexpr (sizeof...(TailTs) > 0)
2861 result += "," + BuildItemTypes<TailTs...>();
2862 return result;
2863 }
2864
2865 template <typename HeadT, typename... TailTs>
2866 static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
2867 {
2868 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
2869 if constexpr (sizeof...(TailTs) > 0)
2870 _BuildItemFields<TailTs...>(itemFields, index + 1);
2871 }
2872 template <typename... Ts>
2873 static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
2874 {
2875 std::vector<std::unique_ptr<RFieldBase>> result;
2876 _BuildItemFields<Ts...>(result);
2877 return result;
2878 }
2879
2880 template <unsigned Index, typename HeadT, typename... TailTs>
2881 static void _BuildItemOffsets(std::vector<std::size_t> &offsets, const ContainerT &tuple)
2882 {
2883 auto offset =
2884 reinterpret_cast<std::uintptr_t>(&std::get<Index>(tuple)) - reinterpret_cast<std::uintptr_t>(&tuple);
2885 offsets.emplace_back(offset);
2886 if constexpr (sizeof...(TailTs) > 0)
2887 _BuildItemOffsets<Index + 1, TailTs...>(offsets, tuple);
2888 }
2889 template <typename... Ts>
2890 static std::vector<std::size_t> BuildItemOffsets()
2891 {
2892 std::vector<std::size_t> result;
2893 _BuildItemOffsets<0, Ts...>(result, ContainerT());
2894 return result;
2895 }
2896
2897protected:
2898 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
2899 {
2900 std::vector<std::unique_ptr<RFieldBase>> items;
2901 for (auto &item : fSubFields)
2902 items.push_back(item->Clone(item->GetFieldName()));
2903 return std::make_unique<RField<std::tuple<ItemTs...>>>(newName, std::move(items));
2904 }
2905
2906 void ConstructValue(void *where) const final { new (where) ContainerT(); }
2907 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<ContainerT>>(); }
2908
2909public:
2910 static std::string TypeName() { return "std::tuple<" + BuildItemTypes<ItemTs...>() + ">"; }
2911 explicit RField(std::string_view name, std::vector<std::unique_ptr<RFieldBase>> &&itemFields)
2912 : RTupleField(name, std::move(itemFields), BuildItemOffsets<ItemTs...>())
2913 {
2914 fMaxAlignment = std::max({alignof(ItemTs)...});
2915 fSize = sizeof(ContainerT);
2916 }
2917 explicit RField(std::string_view name) : RField(name, BuildItemFields<ItemTs...>()) {}
2918 RField(RField &&other) = default;
2919 RField &operator=(RField &&other) = default;
2920 ~RField() override = default;
2921};
2922
2923template <std::size_t N>
2924class RField<std::bitset<N>> final : public RBitsetField {
2925public:
2926 static std::string TypeName() { return "std::bitset<" + std::to_string(N) + ">"; }
2927 explicit RField(std::string_view name) : RBitsetField(name, N) {}
2928 RField(RField &&other) = default;
2929 RField &operator=(RField &&other) = default;
2930 ~RField() override = default;
2931};
2932
2933template <typename ItemT>
2934class RField<std::unique_ptr<ItemT>> final : public RUniquePtrField {
2935public:
2936 static std::string TypeName() { return "std::unique_ptr<" + RField<ItemT>::TypeName() + ">"; }
2937 explicit RField(std::string_view name) : RUniquePtrField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
2938 RField(RField &&other) = default;
2939 RField &operator=(RField &&other) = default;
2940 ~RField() override = default;
2941};
2942
2943template <typename ItemT>
2944class RField<std::optional<ItemT>> final : public ROptionalField {
2945public:
2946 static std::string TypeName() { return "std::optional<" + RField<ItemT>::TypeName() + ">"; }
2947 explicit RField(std::string_view name) : ROptionalField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
2948 RField(RField &&other) = default;
2949 RField &operator=(RField &&other) = default;
2950 ~RField() override = default;
2951};
2952
2953template <typename ItemT>
2954class RField<std::atomic<ItemT>> final : public RAtomicField {
2955public:
2956 static std::string TypeName() { return "std::atomic<" + RField<ItemT>::TypeName() + ">"; }
2957 explicit RField(std::string_view name) : RAtomicField(name, TypeName(), std::make_unique<RField<ItemT>>("_0")) {}
2958 RField(RField &&other) = default;
2959 RField &operator=(RField &&other) = default;
2960 ~RField() override = default;
2961};
2962
2963// Has to be implemented after the definition of all RField<T> types
2964// The void type is specialized in RField.cxx
2965
2966template <typename T>
2967std::unique_ptr<T, typename RFieldBase::RCreateObjectDeleter<T>::deleter> RFieldBase::CreateObject() const
2968{
2969 if (GetTypeName() != RField<T>::TypeName()) {
2970 throw RException(
2971 R__FAIL("type mismatch for field " + GetFieldName() + ": " + GetTypeName() + " vs. " + RField<T>::TypeName()));
2972 }
2973 return std::unique_ptr<T>(static_cast<T *>(CreateObjectRawPtr()));
2974}
2975
2976template <>
2979 void operator()(void *);
2980};
2981
2982template <>
2983std::unique_ptr<void, typename RFieldBase::RCreateObjectDeleter<void>::deleter>
2984ROOT::Experimental::RFieldBase::CreateObject<void>() const;
2985
2986} // namespace Experimental
2987} // namespace ROOT
2988
2989#endif
size_t fValueSize
Cppyy::TCppType_t fClass
dim_t fSize
#define R__unlikely(expr)
Definition RConfig.hxx:578
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:290
ROOT::Experimental::RField< T > RField
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define R__ASSERT(e)
Definition TError.h:118
#define N
winID h TVirtualViewer3D TVirtualGLPainter p
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
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 r
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 char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t child
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
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.
std::size_t GetPackedSize(std::size_t nElements=1U) const
NTupleSize_t GetGlobalIndex(RClusterIndex clusterIndex)
Definition RColumn.hxx:276
RColumnElementBase * GetElement() const
Definition RColumn.hxx:336
void Append(const void *from)
Definition RColumn.hxx:133
void ReadV(const NTupleSize_t globalIndex, const ClusterSize_t::ValueType count, void *to)
Definition RColumn.hxx:200
void Read(const NTupleSize_t globalIndex, void *to)
Definition RColumn.hxx:178
NTupleSize_t GetNElements() const
Definition RColumn.hxx:335
Abstract interface to write data into an ntuple.
Abstract interface to read data from an ntuple.
A field for fixed-size arrays that are represented as RVecs in memory.
Definition RField.hxx:1272
std::size_t fArrayLength
The size of a child field's item.
Definition RField.hxx:1276
std::size_t fValueSize
The length of the arrays in this field.
Definition RField.hxx:1277
std::size_t fItemSize
Sub field deleter or nullptr for simple fields.
Definition RField.hxx:1275
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1274
void GenerateColumnsImpl() final
Implementations in derived classes should create the backing columns corresponsing to the field type ...
Definition RField.hxx:1282
RArrayDeleter(std::size_t itemSize, std::size_t arrayLength, std::unique_ptr< RDeleter > itemDeleter)
Definition RField.hxx:1232
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1229
The generic field for fixed size arrays, which do not need an offset column.
Definition RField.hxx:1223
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1260
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1261
~RAtomicField() override=default
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Definition RField.hxx:1558
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.hxx:1554
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.hxx:1553
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.hxx:1557
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.hxx:1556
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1569
RAtomicField & operator=(RAtomicField &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1568
RAtomicField(RAtomicField &&other)=default
The generic field an std::bitset<N>.
Definition RField.hxx:1314
std::size_t GetN() const
Get the number of bits in the bitset, i.e. the N in std::bitset<N>
Definition RField.hxx:1345
RBitsetField(RBitsetField &&other)=default
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1341
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:1323
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1340
~RBitsetField() override=default
RBitsetField & operator=(RBitsetField &&other)=default
An artificial field that transforms an RNTuple column that contains the offset of collections into co...
Definition RField.hxx:1785
RCardinalityField & operator=(RCardinalityField &&other)=default
RCardinalityField(RCardinalityField &&other)=default
RCardinalityField(std::string_view fieldName, std::string_view typeName)
Definition RField.hxx:1787
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:1767
The field for a class with dictionary.
Definition RField.hxx:758
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Definition RField.cxx:1729
static constexpr const char * kPrefixInherited
Prefix used in the subfield names generated for base classes.
Definition RField.hxx:769
void Attach(std::unique_ptr< RFieldBase > child, RSubFieldInfo info)
Definition RField.cxx:1678
void OnConnectPageSource() final
Called by ConnectPageSource() only once connected; derived classes may override this as appropriate.
Definition RField.cxx:1736
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:1787
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:1762
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:1713
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:1722
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1706
void AddReadCallbacksFromIORules(const std::span< const TSchemaRule * > rules, TClass *classp=nullptr)
Register post-read callbacks corresponding to a list of ROOT I/O customization rules.
Definition RField.cxx:1685
void AcceptVisitor(Detail::RFieldVisitor &visitor) const override
Definition RField.cxx:1797
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:811
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
Definition RField.cxx:1792
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:1774
std::vector< RSubFieldInfo > fSubFieldsInfo
Additional information kept for each entry in fSubFields
Definition RField.hxx:782
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.hxx:796
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
DescriptorId_t GetClusterId() const
ClusterSize_t::ValueType GetIndex() const
The collection field is only used for writing; when reading, untyped collections are projected to an ...
Definition RField.hxx:1689
std::shared_ptr< RNTupleCollectionWriter > fCollectionWriter
Save the link to the collection ntuple in order to reset the offset counter when committing the clust...
Definition RField.hxx:1692
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1715
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1714
RCollectionField(RCollectionField &&other)=default
The field for an unscoped or scoped enum with dictionary.
Definition RField.hxx:864
~REnumField() override=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:885
REnumField & operator=(REnumField &&other)=default
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Definition RField.hxx:876
REnumField(REnumField &&other)=default
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:886
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.hxx:874
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.hxx:875
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.hxx:872
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Similar to RValue but manages an array of consecutive values.
Definition RField.hxx:232
bool fIsAdopted
True if the user provides the memory buffer for fValues.
Definition RField.hxx:242
void * ReadBulk(RClusterIndex firstIndex, const bool *maskReq, std::size_t size)
Reads 'size' values from the associated field, starting from 'firstIndex'.
Definition RField.hxx:290
RFieldBase * fField
The field that created the array of values.
Definition RField.hxx:236
std::vector< unsigned char > fAuxData
Reading arrays of complex values may require additional memory, for instance for the elements of arra...
Definition RField.hxx:249
bool ContainsRange(RClusterIndex firstIndex, std::size_t size) const
Definition RField.hxx:257
std::size_t fCapacity
The size of the array memory block in number of values.
Definition RField.hxx:240
std::unique_ptr< bool[]> fMaskAvail
Masks invalid values in the array.
Definition RField.hxx:243
std::size_t fValueSize
Cached copy of fField->GetValueSize()
Definition RField.hxx:239
void AdoptBuffer(void *buf, std::size_t capacity)
Definition RField.cxx:505
void * GetValuePtrAt(std::size_t idx) const
Definition RField.hxx:265
RBulk & operator=(const RBulk &)=delete
void Reset(RClusterIndex firstIndex, std::size_t size)
Sets a new range for the bulk.
Definition RField.cxx:472
std::size_t fNValidValues
The sum of non-zero elements in the fMask.
Definition RField.hxx:244
RClusterIndex fFirstIndex
Index of the first value of the array.
Definition RField.hxx:245
std::size_t fSize
The number of available values in the array (provided their mask is set)
Definition RField.hxx:241
void * fValues
Cached deleter of fField.
Definition RField.hxx:238
std::unique_ptr< RFieldBase::RDeleter > fDeleter
Definition RField.hxx:237
Some fields have multiple possible column representations, e.g.
Definition RField.hxx:168
std::vector< ColumnRepresentation_t > TypesList_t
Definition RField.hxx:170
TypesList_t fDeserializationTypes
The union of the serialization types and the deserialization extra types.
Definition RField.hxx:183
const TypesList_t & GetDeserializationTypes() const
Definition RField.hxx:177
const ColumnRepresentation_t & GetSerializationDefault() const
The first column list from fSerializationTypes is the default for writing.
Definition RField.hxx:175
A functor to release the memory acquired by CreateValue (memory and constructor).
Definition RField.hxx:109
virtual void operator()(void *objPtr, bool dtorOnly)
Definition RField.hxx:112
Iterates over the sub tree of fields in depth-first search order.
Definition RField.hxx:545
RSchemaIteratorTemplate(pointer val, int idxInParent)
Definition RField.hxx:565
std::conditional_t< IsConstT, const RFieldBase *, RFieldBase * > pointer
Definition RField.hxx:561
std::vector< Position > fStack
The stack of nodes visited when walking down the tree of fields.
Definition RField.hxx:555
void Advance()
Given that the iterator points to a valid field which is not the end iterator, go to the next field i...
Definition RField.hxx:569
std::conditional_t< IsConstT, const RFieldBase, RFieldBase > value_type
Definition RField.hxx:560
std::conditional_t< IsConstT, const RFieldBase &, RFieldBase & > reference
Definition RField.hxx:562
A deleter for templated RFieldBase descendents where the value type is known.
Definition RField.hxx:121
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.hxx:123
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
Definition RField.hxx:188
RValue & operator=(RValue &&other)=default
void Read(NTupleSize_t globalIndex)
Definition RField.hxx:205
RFieldBase * fField
The field that created the RValue.
Definition RField.hxx:192
RValue & operator=(const RValue &)=default
const RFieldBase & GetField() const
Definition RField.hxx:224
void EmplaceNew()
Replace the current object pointer by a pointer to a new object constructed by the field.
Definition RField.hxx:210
std::shared_ptr< void > fObjPtr
Set by Bind() or by RFieldBase::CreateValue(), SplitValue() or BindValue()
Definition RField.hxx:193
std::shared_ptr< T > GetPtr() const
Definition RField.hxx:213
void Read(RClusterIndex clusterIndex)
Definition RField.hxx:206
void Bind(std::shared_ptr< void > objPtr)
Definition RField.hxx:207
RValue(RFieldBase *field, std::shared_ptr< void > objPtr)
Definition RField.hxx:195
A field translates read and write calls from/to underlying columns to/from tree values.
Definition RField.hxx:96
static constexpr std::uint32_t kInvalidTypeVersion
Definition RField.hxx:139
static constexpr int kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
Definition RField.hxx:144
const RFieldBase * GetParent() const
Definition RField.hxx:675
std::string GetFieldName() const
Definition RField.hxx:667
void Attach(std::unique_ptr< RFieldBase > child)
Add a new subfield to the list of nested fields.
Definition RField.cxx:889
bool HasDefaultColumnRepresentative() const
Whether or not an explicit column representative was set.
Definition RField.hxx:694
std::uint32_t fOnDiskTypeVersion
C++ type version cached from the descriptor after a call to ConnectPageSource()
Definition RField.hxx:409
void AutoAdjustColumnTypes(const RNTupleWriteOptions &options)
When connecting a field to a page sink, the field's default column representation is subject to adjus...
Definition RField.cxx:1011
const ColumnRepresentation_t & EnsureCompatibleColumnTypes(const RNTupleDescriptor &desc) const
Returns the on-disk column types found in the provided descriptor for fOnDiskId.
Definition RField.cxx:974
ENTupleStructure fStructure
The role of this field in the data model structure.
Definition RField.hxx:328
std::vector< RFieldBase * > GetSubFields()
Definition RField.cxx:912
static std::vector< RCheckResult > Check(const std::string &fieldName, const std::string &typeName)
Checks if the given type is supported by RNTuple.
Definition RField.cxx:569
static constexpr int kTraitMappable
A field of a fundamental type that can be directly mapped via RField<T>::Map(), i....
Definition RField.hxx:147
std::function< void(void *)> ReadCallback_t
Definition RField.hxx:102
EState fState
Changed by ConnectTo[Sink,Source], reset by Clone()
Definition RField.hxx:340
static constexpr int kTraitTriviallyConstructible
No constructor needs to be called, i.e.
Definition RField.hxx:142
RSchemaIterator begin()
Definition RField.hxx:703
std::string fTypeAlias
A typedef or using name that was used when creating the field.
Definition RField.hxx:405
std::vector< std::unique_ptr< Internal::RColumn > > fColumns
The columns are connected either to a sink or to a source (not to both); they are owned by the field.
Definition RField.hxx:401
RConstSchemaIterator cbegin() const
Definition RField.hxx:708
RSchemaIteratorTemplate< false > RSchemaIterator
Definition RField.hxx:598
ENTupleStructure GetStructure() const
Definition RField.hxx:672
RValue BindValue(std::shared_ptr< void > objPtr)
Creates a value from a memory location with an already constructed object.
Definition RField.hxx:654
RFieldBase(RFieldBase &&)=default
std::string GetTypeName() const
Definition RField.hxx:670
virtual void AcceptVisitor(Detail::RFieldVisitor &visitor) const
Definition RField.cxx:1111
std::string fDescription
Free text set by the user.
Definition RField.hxx:338
static Internal::RColumn * GetPrincipalColumnOf(const RFieldBase &other)
Fields may need direct access to the principal column of their sub fields, e.g. in RRVecField::ReadBu...
Definition RField.hxx:517
friend struct ROOT::Experimental::Internal::RFieldCallbackInjector
Definition RField.hxx:98
std::size_t fNRepetitions
For fixed sized arrays, the array length.
Definition RField.hxx:330
RFieldBase & operator=(const RFieldBase &)=delete
RFieldBase * fParent
Sub fields point to their mother field.
Definition RField.hxx:395
std::unique_ptr< T, typename RCreateObjectDeleter< T >::deleter > CreateObject() const
Generates an object of the field type and allocates new initialized memory according to the type.
Definition RField.hxx:2967
static std::size_t CallAppendOn(RFieldBase &other, const void *from)
Allow derived classes to call Append and Read on other (sub) fields.
Definition RField.hxx:512
int fTraits
Properties of the type that allow for optimizations of collections of that type.
Definition RField.hxx:403
static std::unique_ptr< RDeleter > GetDeleterOf(const RFieldBase &other)
Definition RField.hxx:440
void ConnectPageSink(Internal::RPageSink &pageSink, NTupleSize_t firstEntry=0)
Fields and their columns live in the void until connected to a physical page storage.
Definition RField.cxx:1046
DescriptorId_t fOnDiskId
When the columns are connected to a page source or page sink, the field represents a field id in the ...
Definition RField.hxx:336
virtual std::size_t AppendImpl(const void *from)
Operations on values of complex types, e.g.
Definition RField.cxx:838
RConstSchemaIterator cend() const
Definition RField.hxx:712
const ColumnRepresentation_t * fColumnRepresentative
Points into the static vector GetColumnRepresentations().GetSerializationTypes() when SetColumnRepres...
Definition RField.hxx:412
void Read(NTupleSize_t globalIndex, void *to)
Populate a single value with data from the field.
Definition RField.hxx:465
bool fIsSimple
A field qualifies as simple if it is both mappable and has no post-read callback.
Definition RField.hxx:332
std::uint32_t GetOnDiskTypeVersion() const
Return the C++ type version stored in the field descriptor; only valid after a call to ConnectPageSou...
Definition RField.hxx:701
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots ("grandparent.parent....
Definition RField.cxx:549
virtual std::uint32_t GetTypeVersion() const
Indicates an evolution of the C++ type itself.
Definition RField.hxx:699
std::vector< EColumnType > ColumnRepresentation_t
Definition RField.hxx:151
virtual std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec)
General implementation of bulk read.
Definition RField.cxx:849
virtual std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const =0
Called by Clone(), which additionally copies the on-disk ID.
std::size_t Append(const void *from)
Write the given value into columns.
Definition RField.hxx:453
RFieldBase(const RFieldBase &)=delete
void RemoveReadCallback(size_t idx)
Definition RField.cxx:1005
void * CreateObjectRawPtr() const
Factory method for the field's type. The caller owns the returned pointer.
Definition RField.cxx:869
void CommitCluster()
Flushes data from active columns to disk and calls CommitClusterImpl.
Definition RField.cxx:932
void ConnectPageSource(Internal::RPageSource &pageSource)
Connects the field and its sub field tree to the given page source.
Definition RField.cxx:1066
RValue CreateValue()
Generates an object of the field type and wraps the created object in a shared pointer and returns it...
Definition RField.cxx:877
std::unique_ptr< RFieldBase > Clone(std::string_view newName) const
Copies the field and its sub fields using a possibly new name and a new, unconnected set of columns.
Definition RField.cxx:827
std::size_t ReadBulk(const RBulkSpec &bulkSpec)
Returns the number of newly available values, that is the number of bools in bulkSpec....
Definition RField.hxx:499
virtual std::unique_ptr< RDeleter > GetDeleter() const
Definition RField.hxx:437
virtual void ReadInClusterImpl(RClusterIndex clusterIndex, void *to)
Definition RField.hxx:446
static void CallReadOn(RFieldBase &other, RClusterIndex clusterIndex, void *to)
Definition RField.hxx:513
virtual std::uint32_t GetFieldVersion() const
Indicates an evolution of the mapping scheme from C++ type to columns.
Definition RField.hxx:697
virtual void GenerateColumnsImpl(const RNTupleDescriptor &)
Implementations in derived classes should create the backing columns corresponsing to the field type ...
Definition RField.hxx:423
virtual void ConstructValue(void *where) const =0
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &canonicalType, const std::string &typeAlias, bool fContinueOnError=false)
Factory method to resurrect a field from the stored on-disk type information.
Definition RField.cxx:590
virtual void GenerateColumnsImpl()
Implementations in derived classes should create the backing columns corresponsing to the field type ...
Definition RField.hxx:419
RSchemaIteratorTemplate< true > RConstSchemaIterator
Definition RField.hxx:599
std::string GetDescription() const
Get the field's description.
Definition RField.hxx:680
size_t AddReadCallback(ReadCallback_t func)
Set a user-defined function to be called after reading a value, giving a chance to inspect and/or mod...
Definition RField.cxx:998
virtual std::vector< RValue > SplitValue(const RValue &value) const
Creates the list of direct child values given a value for this field.
Definition RField.cxx:884
void SetOnDiskId(DescriptorId_t id)
Definition RField.cxx:947
std::size_t GetNRepetitions() const
Definition RField.hxx:673
virtual ~RFieldBase()=default
std::string fName
The field name relative to its parent field.
Definition RField.hxx:324
virtual size_t GetAlignment() const =0
As a rule of thumb, the alignment is equal to the size of the type.
RBulk CreateBulk()
The returned bulk is initially empty; RBulk::ReadBulk will construct the array of values.
Definition RField.hxx:652
void InvokeReadCallbacks(void *target)
Definition RField.hxx:342
virtual void OnConnectPageSource()
Called by ConnectPageSource() only once connected; derived classes may override this as appropriate.
Definition RField.hxx:533
static void CallReadOn(RFieldBase &other, NTupleSize_t globalIndex, void *to)
Definition RField.hxx:514
void Read(RClusterIndex clusterIndex, void *to)
Definition RField.hxx:478
void SetColumnRepresentative(const ColumnRepresentation_t &representative)
Fixes a column representative.
Definition RField.cxx:962
static void CallConstructValueOn(const RFieldBase &other, void *where)
Allow derived classes to call ConstructValue(void *) and GetDeleter on other (sub) fields.
Definition RField.hxx:439
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Definition RField.hxx:393
std::string fType
The C++ type captured by this field.
Definition RField.hxx:326
Internal::RColumn * fPrincipalColumn
Points into fColumns.
Definition RField.hxx:399
DescriptorId_t GetOnDiskId() const
Definition RField.hxx:684
virtual size_t GetValueSize() const =0
The number of bytes taken by a value of the appropriate type.
static constexpr int kTraitTrivialType
Shorthand for types that are both trivially constructible and destructible.
Definition RField.hxx:149
const ColumnRepresentation_t & GetColumnRepresentative() const
Returns the fColumnRepresentative pointee or, if unset, the field's default representative.
Definition RField.cxx:955
std::string GetTypeAlias() const
Definition RField.hxx:671
EState
During its lifetime, a field undergoes the following possible state transitions:
Definition RField.hxx:160
std::vector< ReadCallback_t > fReadCallbacks
List of functions to be called after reading a value.
Definition RField.hxx:407
void SetDescription(std::string_view description)
Definition RField.cxx:940
static RResult< void > EnsureValidFieldName(std::string_view fieldName)
Check whether a given string is a valid field name.
Definition RField.cxx:810
NTupleSize_t EntryToColumnElementIndex(NTupleSize_t globalIndex) const
Translate an entry index to a column element index of the principal column and viceversa.
Definition RField.cxx:900
virtual void ReadGlobalImpl(NTupleSize_t globalIndex, void *to)
Definition RField.cxx:844
NTupleSize_t GetNElements() const
Definition RField.hxx:674
virtual void CommitClusterImpl()
Definition RField.hxx:526
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:821
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:719
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1128
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:729
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:728
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1119
void ConstructValue(void *) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.hxx:722
ClusterSize_t * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition RField.hxx:1849
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:1825
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1857
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
ClusterSize_t * Map(NTupleSize_t globalIndex)
Definition RField.hxx:1845
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size)
Special help for offset fields.
Definition RField.hxx:1861
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1858
ClusterSize_t * Map(RClusterIndex clusterIndex)
Definition RField.hxx:1848
void GetCollectionInfo(RClusterIndex clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size)
Definition RField.hxx:1864
ClusterSize_t * MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
Definition RField.hxx:1852
RField & operator=(RField &&other)=default
RField(RField &&other)=default
RField(std::string_view name)
Definition RField.hxx:2552
std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec) final
General implementation of bulk read.
Definition RField.hxx:1908
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.hxx:1878
std::unique_ptr< ROOT::Experimental::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:1874
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Get the number of elements of the collection identified by clusterIndex.
Definition RField.hxx:1900
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Get the number of elements of the collection identified by globalIndex.
Definition RField.hxx:1891
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1887
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1888
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:2803
typename ROOT::VecOps::RVec< ItemT > ContainerT
Definition RField.hxx:2752
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.hxx:2763
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.hxx:2775
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:2754
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.hxx:2761
RField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
Definition RField.hxx:2788
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:2804
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.hxx:2760
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.hxx:2509
static std::size_t GetOffsetUniqueID()
Definition RField.hxx:2502
RField(RField &&other)=default
static std::size_t GetOffsetBits()
Definition RField.hxx:2503
RField & operator=(RField &&other)=default
bool * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition RField.hxx:1962
RField(std::string_view name)
Definition RField.hxx:1950
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1970
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:1938
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1971
bool * MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
Definition RField.hxx:1965
bool * Map(RClusterIndex clusterIndex)
Definition RField.hxx:1961
static std::string TypeName()
Definition RField.hxx:1949
RField(RField &&other)=default
bool * Map(NTupleSize_t globalIndex)
Definition RField.hxx:1958
char * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition RField.hxx:2126
RField(std::string_view name)
Definition RField.hxx:2114
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:2135
char * Map(RClusterIndex clusterIndex)
Definition RField.hxx:2125
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:2134
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:2102
char * Map(NTupleSize_t globalIndex)
Definition RField.hxx:2122
RField(RField &&other)=default
char * MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
Definition RField.hxx:2129
static std::string TypeName()
Definition RField.hxx:2113
double * Map(RClusterIndex clusterIndex)
Definition RField.hxx:2043
double * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition RField.hxx:2044
RField(std::string_view name)
Definition RField.hxx:2032
double * MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
Definition RField.hxx:2047
double * Map(NTupleSize_t globalIndex)
Definition RField.hxx:2040
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:2053
RField(RField &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:2052
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:2020
static std::string TypeName()
Definition RField.hxx:1989
RField(RField &&other)=default
float * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition RField.hxx:2002
RField(std::string_view name)
Definition RField.hxx:1990
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:2010
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:2011
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:1978
float * MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
Definition RField.hxx:2005
float * Map(NTupleSize_t globalIndex)
Definition RField.hxx:1998
float * Map(RClusterIndex clusterIndex)
Definition RField.hxx:2001
RField(const RField &)=delete
static std::string TypeName()
Definition RField.hxx:1815
RField & operator=(const RField &)=delete
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:1576
RField(std::string_view name)
Definition RField.hxx:1590
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.hxx:1578
RField & operator=(RField &&other)=default
RField(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:1589
~RField() override=default
Used in RFieldBase::Check() to record field creation failures.
Definition RField.hxx:735
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:753
RInvalidField(std::string_view name, std::string_view type, std::string_view error)
Definition RField.hxx:746
std::string GetError() const
Definition RField.hxx:751
void ConstructValue(void *) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.hxx:743
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.hxx:739
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:754
The generic field for a std::map<KeyType, ValueType> and std::unordered_map<KeyType,...
Definition RField.hxx:1416
size_t GetAlignment() const override
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1434
RMapField(RMapField &&other)=default
~RMapField() override=default
RMapField & operator=(RMapField &&other)=default
The on-storage meta-data of an ntuple.
Common user-tunable settings for storing ntuples.
The field for values that may or may not be present in an entry.
Definition RField.hxx:1445
RNullableField & operator=(RNullableField &&other)=default
~RNullableField() override=default
RNullableField(RNullableField &&other)=default
std::unique_ptr< RValue > fDefaultItemValue
For a dense nullable field, used to write a default-constructed item for missing ones.
Definition RField.hxx:1447
ROptionalDeleter(std::unique_ptr< RDeleter > itemDeleter)
Definition RField.hxx:1517
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1521
The generic field for std::pair<T1, T2> types.
Definition RField.hxx:1719
~RPairField() override=default
static std::string GetTypeList(const std::array< std::unique_ptr< RFieldBase >, 2 > &itemFields)
RPairField(RPairField &&other)=default
std::unique_ptr< RDeleter > GetDeleter() const override
Definition RField.hxx:1737
RPairField & operator=(RPairField &&other)=default
RIterator(const RCollectionIterableOnce &owner, void *iter)
Definition RField.hxx:937
Allows for iterating over the elements of a proxied collection.
Definition RField.hxx:903
RCollectionIterableOnce(void *collection, const RIteratorFuncs &ifuncs, TVirtualCollectionProxy *proxy, std::size_t stride=0U)
Construct a RCollectionIterableOnce that iterates over collection.
Definition RField.hxx:958
RProxiedCollectionDeleter(std::shared_ptr< TVirtualCollectionProxy > proxy, std::unique_ptr< RDeleter > itemDeleter, size_t itemSize)
Definition RField.hxx:979
RProxiedCollectionDeleter(std::shared_ptr< TVirtualCollectionProxy > proxy)
Definition RField.hxx:978
The field for a class representing a collection of elements via TVirtualCollectionProxy.
Definition RField.hxx:899
void GetCollectionInfo(RClusterIndex clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
Definition RField.hxx:1034
std::shared_ptr< TVirtualCollectionProxy > fProxy
The collection proxy is needed by the deleters and thus defined as a shared pointer.
Definition RField.hxx:989
RCollectionIterableOnce::RIteratorFuncs fIFuncsRead
Two sets of functions to operate on iterators, to be used depending on the access type.
Definition RField.hxx:994
RProxiedCollectionField(RProxiedCollectionField &&other)=default
void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
Definition RField.hxx:1030
RCollectionIterableOnce::RIteratorFuncs fIFuncsWrite
Definition RField.hxx:995
size_t GetAlignment() const override
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1028
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1027
RProxiedCollectionField & operator=(RProxiedCollectionField &&other)=default
the RRVecDeleter is also used by RArrayAsRVecField and therefore declared public
Definition RField.hxx:1164
RRVecDeleter(std::size_t itemAlignment)
Definition RField.hxx:1171
RRVecDeleter(std::size_t itemAlignment, std::size_t itemSize, std::unique_ptr< RDeleter > itemDeleter)
Definition RField.hxx:1172
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1168
The type-erased field for a RVec<Type>
Definition RField.hxx:1161
void GetCollectionInfo(RClusterIndex clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
Definition RField.hxx:1216
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1179
RRVecField(RRVecField &&)=default
~RRVecField() override=default
RRVecField(const RRVecField &)=delete
RRVecField & operator=(RRVecField &&)=default
RRVecField & operator=(RRVecField &)=delete
void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
Definition RField.hxx:1212
std::vector< std::unique_ptr< RDeleter > > fItemDeleters
Definition RField.hxx:1046
RRecordDeleter(std::vector< std::unique_ptr< RDeleter > > &itemDeleters, const std::vector< std::size_t > &offsets)
Definition RField.hxx:1050
The field for an untyped record.
Definition RField.hxx:1042
RRecordField(std::string_view fieldName, std::array< std::unique_ptr< RFieldBase >, N > &&itemFields, const std::array< std::size_t, N > &offsets, std::string_view typeName="")
Definition RField.hxx:1077
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1100
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1101
std::vector< std::size_t > fOffsets
Definition RField.hxx:1060
RRecordField(RRecordField &&other)=default
~RRecordField() override=default
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:194
The generic field for a std::set<Type> and std::unordered_set<Type>
Definition RField.hxx:1402
RSetField(RSetField &&other)=default
RSetField & operator=(RSetField &&other)=default
size_t GetAlignment() const override
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1412
~RSetField() override=default
The generic field for std::tuple<Ts...> types.
Definition RField.hxx:1750
std::unique_ptr< RDeleter > GetDeleter() const override
Definition RField.hxx:1768
RTupleField & operator=(RTupleField &&other)=default
static std::string GetTypeList(const std::vector< std::unique_ptr< RFieldBase > > &itemFields)
~RTupleField() override=default
RTupleField(RTupleField &&other)=default
RUniquePtrDeleter(std::unique_ptr< RDeleter > itemDeleter)
Definition RField.hxx:1485
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.hxx:1494
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1489
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1508
The field for a class in unsplit mode, which is using ROOT standard streaming.
Definition RField.hxx:817