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