Logo ROOT  
Reference Guide
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/RFieldValue.hxx>
23#include <ROOT/RNTupleUtil.hxx>
24#include <ROOT/RSpan.hxx>
25#include <ROOT/RStringView.hxx>
26#include <ROOT/RVec.hxx>
27#include <ROOT/TypeTraits.hxx>
28
29#include <TGenericClassInfo.h>
31
32#include <algorithm>
33#include <array>
34#include <cstddef>
35#include <functional>
36#include <iostream>
37#include <iterator>
38#include <memory>
39#include <string>
40#include <type_traits>
41#include <typeinfo>
42#include <variant>
43#include <vector>
44#include <utility>
45
46class TClass;
47
48namespace ROOT {
49
50class TSchemaRule;
51
52namespace Experimental {
53
54class RCollectionField;
55class RCollectionNTupleWriter;
56class REntry;
57class RNTupleModel;
58
59namespace Internal {
60struct RFieldCallbackInjector;
61} // namespace Internal
62
63namespace Detail {
64
65class RFieldVisitor;
66class RPageStorage;
67
68// clang-format off
69/**
70\class ROOT::Experimental::RFieldBase
71\ingroup NTuple
72\brief A field translates read and write calls from/to underlying columns to/from tree values
73
74A field is a serializable C++ type or a container for a collection of sub fields. The RFieldBase and its
75type-safe descendants provide the object to column mapper. They map C++ objects to primitive columns. The
76mapping is trivial for simple types such as 'double'. Complex types resolve to multiple primitive columns.
77The field knows based on its type and the field name the type(s) and name(s) of the columns.
78*/
79// clang-format on
81 friend class ROOT::Experimental::RCollectionField; // to move the fields from the collection model
82 friend struct ROOT::Experimental::Internal::RFieldCallbackInjector; // used for unit tests
84
85public:
86 static constexpr std::uint32_t kInvalidTypeVersion = -1U;
87 /// No constructor needs to be called, i.e. any bit pattern in the allocated memory represents a valid type
88 /// A trivially constructible field has a no-op GenerateValue() implementation
89 static constexpr int kTraitTriviallyConstructible = 0x01;
90 /// The type is cleaned up just by freeing its memory. I.e. DestroyValue() is a no-op.
91 static constexpr int kTraitTriviallyDestructible = 0x02;
92 /// A field of a fundamental type that can be directly mapped via `RField<T>::Map()`, i.e. maps as-is to a single
93 /// column
94 static constexpr int kTraitMappable = 0x04;
95 /// Shorthand for types that are both trivially constructible and destructible
97
98 using ColumnRepresentation_t = std::vector<EColumnType>;
99
100 /// Some fields have multiple possible column representations, e.g. with or without split encoding.
101 /// All column representations supported for writing also need to be supported for reading. In addition,
102 /// fields can support extra column representations for reading only, e.g. a 64bit integer reading from a
103 /// 32bit column.
104 /// The defined column representations must be supported by corresponding column packing/unpacking implementations,
105 /// i.e. for the example above, the unpacking of 32bit ints to 64bit pages must be implemented in RColumnElement.hxx
107 public:
108 using TypesList_t = std::vector<ColumnRepresentation_t>;
110 RColumnRepresentations(const TypesList_t &serializationTypes, const TypesList_t &deserializationExtraTypes);
111
112 /// The first column list from fSerializationTypes is the default for writing.
116
117 private:
119 /// The union of the serialization types and the deserialization extra types. Duplicates the serialization types
120 /// list but the benenfit is that GetDeserializationTypes does not need to compile the list.
122 };
123
124private:
125 /// The field name relative to its parent field
126 std::string fName;
127 /// The C++ type captured by this field
128 std::string fType;
129 /// The role of this field in the data model structure
131 /// For fixed sized arrays, the array length
132 std::size_t fNRepetitions;
133 /// A field qualifies as simple if it is both mappable and has no post-read callback
135 /// When the columns are connected to a page source or page sink, the field represents a field id in the
136 /// corresponding RNTuple descriptor. This on-disk ID is set in RPageSink::Create() for writing and by
137 /// RFieldDescriptor::CreateField() when recreating a field / model from the stored descriptor.
139 /// Free text set by the user
140 std::string fDescription;
141
142protected:
143 /// Collections and classes own sub fields
144 std::vector<std::unique_ptr<RFieldBase>> fSubFields;
145 /// Sub fields point to their mother field
147 /// Points into fColumns. All fields that have columns have a distinct main column. For simple fields
148 /// (float, int, ...), the principal column corresponds to the field type. For collection fields expect std::array,
149 /// the main column is the offset field. Class fields have no column of their own.
151 /// The columns are connected either to a sink or to a source (not to both); they are owned by the field.
152 std::vector<std::unique_ptr<RColumn>> fColumns;
153 /// Properties of the type that allow for optimizations of collections of that type
154 int fTraits = 0;
155 /// List of functions to be called after reading a value
156 std::vector<ReadCallback_t> fReadCallbacks;
157 /// C++ type version cached from the descriptor after a call to `ConnectPageSource()`
159 /// Points into the static vector GetColumnRepresentations().GetSerializationTypes() when SetColumnRepresentative
160 /// is called. Otherwise GetColumnRepresentative returns the default representation.
162
163 /// Implementations in derived classes should return a static RColumnRepresentations object. The default
164 /// implementation does not attach any columns to the field.
166 /// Creates the backing columns corresponsing to the field type for writing
167 virtual void GenerateColumnsImpl() = 0;
168 /// Creates the backing columns corresponsing to the field type for reading.
169 /// The method should to check, using the page source and fOnDiskId, if the column types match
170 /// and throw if they don't.
171 virtual void GenerateColumnsImpl(const RNTupleDescriptor &desc) = 0;
172
173 /// Called by Clone(), which additionally copies the on-disk ID
174 virtual std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const = 0;
175
176 /// Operations on values of complex types, e.g. ones that involve multiple columns or for which no direct
177 /// column type exists.
178 virtual std::size_t AppendImpl(const RFieldValue &value);
179 virtual void ReadGlobalImpl(NTupleSize_t globalIndex, RFieldValue *value);
180 virtual void ReadInClusterImpl(const RClusterIndex &clusterIndex, RFieldValue *value) {
182 }
183
184 /// Returns the on-disk column types found in the provided descriptor for fOnDiskId. Throws an exception if the types
185 /// don't match any of the deserialization types from GetColumnRepresentations().
187
188 /// Set a user-defined function to be called after reading a value, giving a chance to inspect and/or modify the
189 /// value object.
190 /// Returns an index that can be used to remove the callback.
191 size_t AddReadCallback(ReadCallback_t func);
192 void RemoveReadCallback(size_t idx);
193 /// Called by `ConnectPageSource()` only once connected; derived classes may override this
194 /// as appropriate
195 virtual void OnConnectPageSource() {}
196
197private:
199 {
200 for (const auto &func : fReadCallbacks)
201 func(value);
202 }
203
204public:
205 /// Iterates over the sub tree of fields in depth-first search order
207 private:
208 struct Position {
209 Position() : fFieldPtr(nullptr), fIdxInParent(-1) { }
210 Position(RFieldBase *fieldPtr, int idxInParent) : fFieldPtr(fieldPtr), fIdxInParent(idxInParent) { }
213 };
214 /// The stack of nodes visited when walking down the tree of fields
215 std::vector<Position> fStack;
216 public:
218 using iterator_category = std::forward_iterator_tag;
220 using difference_type = std::ptrdiff_t;
223
224 RSchemaIterator() { fStack.emplace_back(Position()); }
225 RSchemaIterator(pointer val, int idxInParent) { fStack.emplace_back(Position(val, idxInParent)); }
227 /// Given that the iterator points to a valid field which is not the end iterator, go to the next field
228 /// in depth-first search order
229 void Advance();
230
231 iterator operator++(int) /* postfix */ { auto r = *this; Advance(); return r; }
232 iterator& operator++() /* prefix */ { Advance(); return *this; }
233 reference operator* () const { return *fStack.back().fFieldPtr; }
234 pointer operator->() const { return fStack.back().fFieldPtr; }
235 bool operator==(const iterator& rh) const { return fStack.back().fFieldPtr == rh.fStack.back().fFieldPtr; }
236 bool operator!=(const iterator& rh) const { return fStack.back().fFieldPtr != rh.fStack.back().fFieldPtr; }
237 };
238
239 /// The constructor creates the underlying column objects and connects them to either a sink or a source.
240 /// If `isSimple` is `true`, the trait `kTraitMappable` is automatically set on construction. However, the
241 /// field might be demoted to non-simple if a post-read callback is set.
243 std::size_t nRepetitions = 0);
244 RFieldBase(const RFieldBase&) = delete;
245 RFieldBase(RFieldBase&&) = default;
248 virtual ~RFieldBase();
249
250 /// Copies the field and its sub fields using a possibly new name and a new, unconnected set of columns
251 std::unique_ptr<RFieldBase> Clone(std::string_view newName) const;
252
253 /// Factory method to resurrect a field from the stored on-disk type information
254 static RResult<std::unique_ptr<RFieldBase>> Create(const std::string &fieldName, const std::string &typeName);
255 /// Check whether a given string is a valid field name
257
258 /// Generates an object of the field type and allocates new initialized memory according to the type.
260 /// Generates a tree value in a given location of size at least GetValueSize(). Assumes that where has been
261 /// allocated by malloc().
262 virtual RFieldValue GenerateValue(void *where) = 0;
263 /// Releases the resources acquired during GenerateValue (memory and constructor)
264 /// This implementation works for simple types but needs to be overwritten for complex ones
265 virtual void DestroyValue(const RFieldValue &value, bool dtorOnly = false);
266 /// Creates a value from a memory location with an already constructed object
267 virtual RFieldValue CaptureValue(void *where) = 0;
268 /// Creates the list of direct child values given a value for this field. E.g. a single value for the
269 /// correct variant or all the elements of a collection. The default implementation assumes no sub values
270 /// and returns an empty vector.
271 virtual std::vector<RFieldValue> SplitValue(const RFieldValue &value) const;
272 /// The number of bytes taken by a value of the appropriate type
273 virtual size_t GetValueSize() const = 0;
274 /// For many types, the alignment requirement is equal to the size; otherwise override.
275 virtual size_t GetAlignment() const { return GetValueSize(); }
276 int GetTraits() const { return fTraits; }
277 bool HasReadCallbacks() const { return !fReadCallbacks.empty(); }
278
279 /// Write the given value into columns. The value object has to be of the same type as the field.
280 /// Returns the number of uncompressed bytes written.
281 std::size_t Append(const RFieldValue& value) {
282 if (~fTraits & kTraitMappable)
283 return AppendImpl(value);
284
285 fPrincipalColumn->Append(value.fMappedElement);
286 return value.fMappedElement.GetSize();
287 }
288
289 /// Populate a single value with data from the tree, which needs to be of the fitting type.
290 /// Reading copies data into the memory wrapped by the ntuple value.
291 /// The fast path is conditioned by the field qualifying as simple, i.e. maps as-is to a single column and has no
292 /// read callback.
293 void Read(NTupleSize_t globalIndex, RFieldValue *value) {
294 if (fIsSimple)
295 return (void)fPrincipalColumn->Read(globalIndex, &value->fMappedElement);
296
298 fPrincipalColumn->Read(globalIndex, &value->fMappedElement);
299 else
300 ReadGlobalImpl(globalIndex, value);
301 if (R__unlikely(!fReadCallbacks.empty()))
303 }
304
305 void Read(const RClusterIndex &clusterIndex, RFieldValue *value) {
306 if (fIsSimple)
307 return (void)fPrincipalColumn->Read(clusterIndex, &value->fMappedElement);
308
310 fPrincipalColumn->Read(clusterIndex, &value->fMappedElement);
311 else
312 ReadInClusterImpl(clusterIndex, value);
313 if (R__unlikely(!fReadCallbacks.empty()))
315 }
316
317 /// Ensure that all received items are written from page buffers to the storage.
318 void Flush() const;
319 /// Perform housekeeping tasks for global to cluster-local index translation
320 virtual void CommitCluster() {}
321
322 /// Add a new subfield to the list of nested fields
323 void Attach(std::unique_ptr<Detail::RFieldBase> child);
324
325 std::string GetName() const { return fName; }
326 /// Returns the field name and parent field names separated by dots ("grandparent.parent.child")
327 std::string GetQualifiedFieldName() const;
328 std::string GetType() const { return fType; }
330 std::size_t GetNRepetitions() const { return fNRepetitions; }
332 RFieldBase *GetParent() const { return fParent; }
333 std::vector<RFieldBase *> GetSubFields() const;
334 bool IsSimple() const { return fIsSimple; }
335 /// Get the field's description
336 std::string GetDescription() const { return fDescription; }
337 void SetDescription(std::string_view description) { fDescription = std::string(description); }
338
341
342 /// Returns the fColumnRepresentative pointee or, if unset, the field's default representative
344 /// Fixes a column representative. This can only be done _before_ connecting the field to a page sink.
345 /// Otherwise, or if the provided representation is not in the list of GetColumnRepresentations,
346 /// an exception is thrown
347 void SetColumnRepresentative(const ColumnRepresentation_t &representative);
348
349 /// Fields and their columns live in the void until connected to a physical page storage. Only once connected, data
350 /// 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.
351 void ConnectPageSink(RPageSink &pageSink);
352 void ConnectPageSource(RPageSource &pageSource);
353
354 /// Indicates an evolution of the mapping scheme from C++ type to columns
355 virtual std::uint32_t GetFieldVersion() const { return 0; }
356 /// Indicates an evolution of the C++ type itself
357 virtual std::uint32_t GetTypeVersion() const { return 0; }
358 /// Return the C++ type version stored in the field descriptor; only valid after a call to `ConnectPageSource()`
359 std::uint32_t GetOnDiskTypeVersion() const { return fOnDiskTypeVersion; }
360
361 RSchemaIterator begin();
362 RSchemaIterator end();
363
364 virtual void AcceptVisitor(RFieldVisitor &visitor) const;
365};
366
367} // namespace Detail
368
369
370
371/// The container field for an ntuple model, which itself has no physical representation
373protected:
374 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const override;
375 void GenerateColumnsImpl() final {}
377
378public:
379 RFieldZero() : Detail::RFieldBase("", "", ENTupleStructure::kRecord, false /* isSimple */) { }
380
384 size_t GetValueSize() const final { return 0; }
385
386 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
387};
388
389/// The field for a class with dictionary
391private:
395 };
398 std::size_t fOffset;
399 };
400 /// Prefix used in the subfield names generated for base classes
401 static constexpr const char *kPrefixInherited{":"};
402
404 /// Additional information kept for each entry in `fSubFields`
405 std::vector<RSubFieldInfo> fSubFieldsInfo;
406 std::size_t fMaxAlignment = 1;
407
408private:
409 RClassField(std::string_view fieldName, std::string_view className, TClass *classp);
410 void Attach(std::unique_ptr<Detail::RFieldBase> child, RSubFieldInfo info);
411 /// Register post-read callbacks corresponding to a list of ROOT I/O customization rules. `classp` is used to
412 /// fill the `TVirtualObject` instance passed to the user function.
413 void AddReadCallbacksFromIORules(const std::span<const TSchemaRule *> rules, TClass *classp = nullptr);
414
415protected:
416 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final;
417 void GenerateColumnsImpl() final {}
419 std::size_t AppendImpl(const Detail::RFieldValue& value) final;
420 void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
421 void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final;
422 void OnConnectPageSource() final;
423
424public:
425 RClassField(std::string_view fieldName, std::string_view className);
426 RClassField(RClassField&& other) = default;
427 RClassField& operator =(RClassField&& other) = default;
428 ~RClassField() override = default;
429
430 using Detail::RFieldBase::GenerateValue;
431 Detail::RFieldValue GenerateValue(void* where) override;
432 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final;
433 Detail::RFieldValue CaptureValue(void *where) final;
434 std::vector<Detail::RFieldValue> SplitValue(const Detail::RFieldValue &value) const final;
435 size_t GetValueSize() const override;
436 size_t GetAlignment() const final { return fMaxAlignment; }
437 std::uint32_t GetTypeVersion() const final;
438 void AcceptVisitor(Detail::RFieldVisitor &visitor) const override;
439};
440
441/// The field for a class representing a collection of elements via `TVirtualCollectionProxy`.
442/// Objects of such type behave as collections that can be accessed through the corresponding member functions in
443/// `TVirtualCollectionProxy`. At a bare minimum, the user is required to provide an implementation for the following
444/// functions in `TVirtualCollectionProxy`: `HasPointers()`, `GetProperties()`, `GetValueClass()`, `GetType()`,
445/// `Sizeof()`, `PushProxy()`, `PopProxy()`, `At()`, `Clear()`, and `Insert()`.
446///
447/// The collection proxy for a given class can be set via `TClass::CopyCollectionProxy()`.
448class RCollectionClassField : public Detail::RFieldBase {
449private:
450 /// Chunk size in bytes used in `ReadGlobalImp()`. Items held in the same chunk will be inserted in
451 /// a single `TVirtualCollectionProxy::Insert()` call.
452 static constexpr const std::size_t kReadChunkSize = 64 * 1024;
453 std::unique_ptr<TVirtualCollectionProxy> fProxy;
454 std::size_t fItemSize;
456
457 RCollectionClassField(std::string_view fieldName, std::string_view className, TClass *classp);
458
459protected:
460 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final;
462 void GenerateColumnsImpl() final;
463 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
464 std::size_t AppendImpl(const Detail::RFieldValue &value) final;
465 void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
466
467public:
468 RCollectionClassField(std::string_view fieldName, std::string_view className);
470 RCollectionClassField &operator=(RCollectionClassField &&other) = default;
471 ~RCollectionClassField() override = default;
472
473 using Detail::RFieldBase::GenerateValue;
474 Detail::RFieldValue GenerateValue(void *where) override;
475 void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) final;
476 Detail::RFieldValue CaptureValue(void *where) override;
477 std::vector<Detail::RFieldValue> SplitValue(const Detail::RFieldValue &value) const final;
478 size_t GetValueSize() const override { return fProxy->Sizeof(); }
479 size_t GetAlignment() const final { return alignof(std::max_align_t); }
480 void CommitCluster() final;
481 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
482 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
483 {
484 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
485 }
486 void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
487 {
488 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
489 }
490};
491
492/// The field for an untyped record. The subfields are stored consequitively in a memory block, i.e.
493/// the memory layout is identical to one that a C++ struct would have
495protected:
496 std::size_t fMaxAlignment = 1;
497 std::size_t fSize = 0;
498 std::vector<std::size_t> fOffsets;
499
500 std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const;
501
502 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const override;
503 void GenerateColumnsImpl() final {}
505 std::size_t AppendImpl(const Detail::RFieldValue& value) final;
506 void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
507 void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final;
508
509 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields,
510 const std::vector<std::size_t> &offsets, std::string_view typeName = "");
511
512 template <std::size_t N>
513 RRecordField(std::string_view fieldName, std::array<std::unique_ptr<Detail::RFieldBase>, N> &&itemFields,
514 const std::array<std::size_t, N> &offsets, std::string_view typeName = "")
515 : ROOT::Experimental::Detail::RFieldBase(fieldName, typeName, ENTupleStructure::kRecord, false /* isSimple */)
516 {
518 for (unsigned i = 0; i < N; ++i) {
519 fOffsets.push_back(offsets[i]);
520 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
521 fSize += GetItemPadding(fSize, itemFields[i]->GetAlignment()) + itemFields[i]->GetValueSize();
522 fTraits &= itemFields[i]->GetTraits();
523 Attach(std::move(itemFields[i]));
524 }
525 }
526public:
527 /// Construct a RRecordField based on a vector of child fields. The ownership of the child fields is transferred
528 /// to the RRecordField instance.
529 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields);
530 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields);
531 RRecordField(RRecordField&& other) = default;
533 ~RRecordField() override = default;
534
536 Detail::RFieldValue GenerateValue(void* where) override;
537 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) override;
538 Detail::RFieldValue CaptureValue(void *where) final;
539 std::vector<Detail::RFieldValue> SplitValue(const Detail::RFieldValue &value) const final;
540 size_t GetValueSize() const final { return fSize; }
541 size_t GetAlignment() const final { return fMaxAlignment; }
542 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
543};
544
545/// The generic field for a (nested) std::vector<Type> except for std::vector<bool>
547private:
548 std::size_t fItemSize;
550
551protected:
552 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final;
554 void GenerateColumnsImpl() final;
555 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
556 std::size_t AppendImpl(const Detail::RFieldValue& value) final;
557 void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
558
559public:
560 RVectorField(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField);
561 RVectorField(RVectorField&& other) = default;
562 RVectorField& operator =(RVectorField&& other) = default;
563 ~RVectorField() override = default;
564
565 using Detail::RFieldBase::GenerateValue;
566 Detail::RFieldValue GenerateValue(void* where) override;
567 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final;
568 Detail::RFieldValue CaptureValue(void *where) override;
569 std::vector<Detail::RFieldValue> SplitValue(const Detail::RFieldValue &value) const final;
570 size_t GetValueSize() const override { return sizeof(std::vector<char>); }
571 size_t GetAlignment() const final { return std::alignment_of<std::vector<char>>(); }
572 void CommitCluster() final;
573 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
574 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const {
575 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
576 }
577 void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const {
578 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
579 }
580};
581
582/// The type-erased field for a RVec<Type>
584private:
585 /// Evaluate the constant returned by GetValueSize.
586 // (we separate evaluation from the getter to avoid repeating the computation).
587 std::size_t EvalValueSize() const;
588
589protected:
590 std::size_t fItemSize;
592 std::size_t fValueSize;
593
594 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const override;
596 void GenerateColumnsImpl() final;
597 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
598 std::size_t AppendImpl(const Detail::RFieldValue &value) override;
599 void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) override;
600
601public:
602 RRVecField(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField);
603 RRVecField(RRVecField &&) = default;
604 RRVecField &operator=(RRVecField &&) = default;
605 RRVecField(const RRVecField &) = delete;
606 RRVecField &operator=(RRVecField &) = delete;
607 ~RRVecField() override = default;
608
609 using Detail::RFieldBase::GenerateValue;
610 Detail::RFieldValue GenerateValue(void *where) override;
611 void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) override;
612 Detail::RFieldValue CaptureValue(void *where) override;
613 std::vector<Detail::RFieldValue> SplitValue(const Detail::RFieldValue &value) const final;
614 size_t GetValueSize() const override;
615 size_t GetAlignment() const override;
616 void CommitCluster() final;
617 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
618 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
619 {
620 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
621 }
622 void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
623 {
624 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
625 }
626};
627
628/// The generic field for fixed size arrays, which do not need an offset column
630private:
631 std::size_t fItemSize;
632 std::size_t fArrayLength;
633
634protected:
635 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final;
636 void GenerateColumnsImpl() final {}
638 std::size_t AppendImpl(const Detail::RFieldValue& value) final;
639 void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
640 void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final;
641
642public:
643 RArrayField(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField, std::size_t arrayLength);
644 RArrayField(RArrayField &&other) = default;
645 RArrayField& operator =(RArrayField &&other) = default;
646 ~RArrayField() override = default;
647
649 Detail::RFieldValue GenerateValue(void *where) override;
650 void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) final;
651 Detail::RFieldValue CaptureValue(void *where) final;
652 std::vector<Detail::RFieldValue> SplitValue(const Detail::RFieldValue &value) const final;
653 size_t GetLength() const { return fArrayLength; }
654 size_t GetValueSize() const final { return fItemSize * fArrayLength; }
655 size_t GetAlignment() const final { return fSubFields[0]->GetAlignment(); }
656 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
657};
658
659/// The generic field for std::variant types
661private:
662 size_t fMaxItemSize = 0;
663 size_t fMaxAlignment = 1;
664 /// In the std::variant memory layout, at which byte number is the index stored
665 size_t fTagOffset = 0;
666 std::vector<ClusterSize_t::ValueType> fNWritten;
667
668 static std::string GetTypeList(const std::vector<Detail::RFieldBase *> &itemFields);
669 /// Extracts the index from an std::variant and transforms it into the 1-based index used for the switch column
670 std::uint32_t GetTag(void *variantPtr) const;
671 void SetTag(void *variantPtr, std::uint32_t tag) const;
672
673protected:
674 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final;
676 void GenerateColumnsImpl() final;
677 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
678 std::size_t AppendImpl(const Detail::RFieldValue& value) final;
679 void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
680
681public:
682 // TODO(jblomer): use std::span in signature
683 RVariantField(std::string_view fieldName, const std::vector<Detail::RFieldBase *> &itemFields);
684 RVariantField(RVariantField &&other) = default;
685 RVariantField& operator =(RVariantField &&other) = default;
686 ~RVariantField() override = default;
687
688 using Detail::RFieldBase::GenerateValue;
689 Detail::RFieldValue GenerateValue(void *where) override;
690 void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) final;
691 Detail::RFieldValue CaptureValue(void *where) final;
692 size_t GetValueSize() const final;
693 size_t GetAlignment() const final { return fMaxAlignment; }
694 void CommitCluster() final;
695};
696
697
698/// Classes with dictionaries that can be inspected by TClass
699template <typename T, typename=void>
700class RField : public RClassField {
701public:
702 static std::string TypeName() { return ROOT::Internal::GetDemangledTypeName(typeid(T)); }
704 static_assert(std::is_class<T>::value, "no I/O support for this basic C++ type");
705 }
706 RField(RField &&other) = default;
707 RField &operator=(RField &&other) = default;
708 ~RField() override = default;
709
711 template <typename... ArgsT>
713 {
714 return Detail::RFieldValue(this, static_cast<T *>(where), std::forward<ArgsT>(args)...);
715 }
717};
718
719template <typename T, typename = void>
720struct HasCollectionProxyMemberType : std::false_type {
721};
722template <typename T>
724 T, typename std::enable_if<std::is_same<typename T::IsCollectionProxy, std::true_type>::value>::type>
725 : std::true_type {
726};
727
728/// The point here is that we can only tell at run time if a class has an associated collection proxy.
729/// For compile time, in the first iteration of this PR we had an extra template argument that acted as a "tag" to
730/// differentiate the RField specialization for classes with an associated collection proxy (inherits
731/// `RCollectionClassField`) from the RField primary template definition (`RClassField`-derived), as in:
732/// ```
733/// auto field = std::make_unique<RField<MyClass>>("klass");
734/// // vs
735/// auto otherField = std::make_unique<RField<MyClass, ROOT::Experimental::TagIsCollectionProxy>>("klass");
736/// ```
737///
738/// That is convenient only for non-nested types, i.e. it doesn't work with, e.g. `RField<std::vector<MyClass>,
739/// ROOT::Experimental::TagIsCollectionProxy>`, as the tag is not forwarded to the instantiation of the inner RField
740/// (that for the value type of the vector). The following two possible solutions were considered:
741/// - A wrapper type (much like `ntuple/v7/inc/ROOT/RNTupleUtil.hxx:49`), that helps to differentiate both cases.
742/// There we would have:
743/// ```
744/// auto field = std::make_unique<RField<RProxiedCollection<MyClass>>>("klass"); // Using collection proxy
745/// ```
746/// - A helper `IsCollectionProxy<T>` type, that can be used in a similar way to those in the `<type_traits>` header.
747/// We found this more convenient and is the implemented thing below. Here, classes can be marked as a
748/// collection proxy with either of the following two forms (whichever is more convenient for the user):
749/// ```
750/// template <>
751/// struct IsCollectionProxy<MyClass> : std::true_type {};
752/// ```
753/// or by adding a member type to the class as follows:
754/// ```
755/// class MyClass {
756/// public:
757/// using IsCollectionProxy = std::true_type;
758/// };
759/// ```
760///
761/// Of course, there is another possible solution which is to have a single `RClassField` that implements both
762/// the regular-class and the collection-proxy behaviors, and always chooses appropriately at run time.
763/// We found that less clean and probably has more overhead, as most probably it involves an additional branch + call
764/// in each of the member functions.
765template <typename T, typename = void>
767};
768
769/// Classes behaving as a collection of elements that can be queried via the `TVirtualCollectionProxy` interface
770/// The use of a collection proxy for a particular class can be enabled via:
771/// ```
772/// namespace ROOT::Experimental {
773/// template <> struct IsCollectionProxy<Classname> : std::true_type {};
774/// }
775/// ```
776/// Alternatively, this can be achieved by adding a member type to the class definition as follows:
777/// ```
778/// class Classname {
779/// public:
780/// using IsCollectionProxy = std::true_type;
781/// };
782/// ```
783template <typename T>
784class RField<T, typename std::enable_if<IsCollectionProxy<T>::value>::type> : public RCollectionClassField {
785public:
786 static std::string TypeName() { return ROOT::Internal::GetDemangledTypeName(typeid(T)); }
787 RField(std::string_view name) : RCollectionClassField(name, TypeName())
788 {
789 static_assert(std::is_class<T>::value, "collection proxy unsupported for fundamental types");
790 }
791 RField(RField&& other) = default;
792 RField& operator =(RField&& other) = default;
793 ~RField() override = default;
794
796 template <typename... ArgsT>
797 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
798 {
799 return Detail::RFieldValue(this, static_cast<T*>(where), std::forward<ArgsT>(args)...);
800 }
801 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, T()); }
802};
803
804/// The collection field is only used for writing; when reading, untyped collections are projected to an std::vector
806private:
807 /// Save the link to the collection ntuple in order to reset the offset counter when committing the cluster
808 std::shared_ptr<RCollectionNTupleWriter> fCollectionNTuple;
809
810protected:
811 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final;
813 void GenerateColumnsImpl() final;
814 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
815
816public:
817 static std::string TypeName() { return ""; }
819 std::shared_ptr<RCollectionNTupleWriter> collectionNTuple,
820 std::unique_ptr<RNTupleModel> collectionModel);
823 ~RCollectionField() override = default;
824
827 return Detail::RFieldValue(
829 this, static_cast<ClusterSize_t*>(where));
830 }
832 return Detail::RFieldValue(true /* captureFlag */,
833 Detail::RColumnElement<ClusterSize_t>(static_cast<ClusterSize_t*>(where)), this, where);
834 }
835 size_t GetValueSize() const final { return sizeof(ClusterSize_t); }
836 void CommitCluster() final;
837};
838
839/// The generic field for `std::pair<T1, T2>` types
840class RPairField : public RRecordField {
841private:
842 TClass *fClass = nullptr;
843 static std::string GetTypeList(const std::array<std::unique_ptr<Detail::RFieldBase>, 2> &itemFields);
844
845protected:
846 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const override;
847
848 RPairField(std::string_view fieldName, std::array<std::unique_ptr<Detail::RFieldBase>, 2> &&itemFields,
849 const std::array<std::size_t, 2> &offsets);
850
851public:
852 RPairField(std::string_view fieldName, std::array<std::unique_ptr<Detail::RFieldBase>, 2> &itemFields);
853 RPairField(RPairField &&other) = default;
854 RPairField &operator=(RPairField &&other) = default;
855 ~RPairField() override = default;
856
858 Detail::RFieldValue GenerateValue(void *where) override;
859 void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) override;
860};
861
862/// The generic field for `std::tuple<Ts...>` types
863class RTupleField : public RRecordField {
864private:
865 TClass *fClass = nullptr;
866 static std::string GetTypeList(const std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields);
867
868protected:
869 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const override;
870
871 RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields,
872 const std::vector<std::size_t> &offsets);
873
874public:
875 RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields);
876 RTupleField(RTupleField &&other) = default;
877 RTupleField &operator=(RTupleField &&other) = default;
878 ~RTupleField() override = default;
879
881 Detail::RFieldValue GenerateValue(void *where) override;
882 void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) override;
883};
884
885/// Template specializations for concrete C++ types
886
887
888template <>
890protected:
891 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
892 return std::make_unique<RField>(newName);
893 }
894
897 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
898
899public:
900 static std::string TypeName() { return "ROOT::Experimental::ClusterSize_t"; }
902 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
903 {
905 }
906 RField(RField&& other) = default;
907 RField& operator =(RField&& other) = default;
908 ~RField() override = default;
909
911 return fPrincipalColumn->Map<ClusterSize_t>(globalIndex);
912 }
913 ClusterSize_t *Map(const RClusterIndex &clusterIndex) {
914 return fPrincipalColumn->Map<ClusterSize_t>(clusterIndex);
915 }
917 return fPrincipalColumn->MapV<ClusterSize_t>(globalIndex, nItems);
918 }
919 ClusterSize_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
920 return fPrincipalColumn->MapV<ClusterSize_t>(clusterIndex, nItems);
921 }
922
924 template <typename... ArgsT>
926 {
927 return Detail::RFieldValue(
929 this, static_cast<ClusterSize_t*>(where), std::forward<ArgsT>(args)...);
930 }
933 return Detail::RFieldValue(true /* captureFlag */,
934 Detail::RColumnElement<ClusterSize_t>(static_cast<ClusterSize_t*>(where)), this, where);
935 }
936 size_t GetValueSize() const final { return sizeof(ClusterSize_t); }
937
938 /// Special help for offset fields
939 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) {
940 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
941 }
942 void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) {
943 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
944 }
945 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
946};
947
948/// An artificial field that transforms an RNTuple column that contains the offset of collections into
949/// collection sizes. It is only used for reading, e.g. as projected field or as an artificial field that provides the
950/// "number of" RDF columns for collections (e.g. `R_rdf_sizeof_jets` for a collection named `jets`).
951template <>
953protected:
954 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> CloneImpl(std::string_view newName) const final
955 {
956 return std::make_unique<RField<RNTupleCardinality>>(newName);
957 }
958
960 // Field is only used for reading
961 void GenerateColumnsImpl() final { throw RException(R__FAIL("Cardinality fields must only be used for reading")); }
963
964public:
965 static std::string TypeName() { return "ROOT::Experimental::RNTupleCardinality"; }
967 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, false /* isSimple */)
968 {
969 }
970 RField(RField &&other) = default;
971 RField &operator=(RField &&other) = default;
972 ~RField() = default;
973
975 template <typename... ArgsT>
977 {
978 return Detail::RFieldValue(this, static_cast<RNTupleCardinality *>(where), std::forward<ArgsT>(args)...);
979 }
981 Detail::RFieldValue CaptureValue(void *where) override
982 {
983 return Detail::RFieldValue(true /* captureFlag */, this, where);
984 }
985 size_t GetValueSize() const final { return sizeof(RNTupleCardinality); }
986
987 /// Get the number of elements of the collection identified by globalIndex
989 {
990 RClusterIndex collectionStart;
992 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &size);
993 *value->Get<RNTupleCardinality>() = size;
994 }
995
996 /// Get the number of elements of the collection identified by clusterIndex
998 {
999 RClusterIndex collectionStart;
1001 fPrincipalColumn->GetCollectionInfo(clusterIndex, &collectionStart, &size);
1002 *value->Get<RNTupleCardinality>() = size;
1003 }
1004
1005 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1006};
1007
1008template <>
1010protected:
1011 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1012 return std::make_unique<RField>(newName);
1013 }
1014
1015 const RColumnRepresentations &GetColumnRepresentations() const final;
1016 void GenerateColumnsImpl() final;
1017 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1018
1019public:
1020 static std::string TypeName() { return "bool"; }
1022 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1023 {
1025 }
1026 RField(RField&& other) = default;
1027 RField& operator =(RField&& other) = default;
1028 ~RField() override = default;
1029
1030 bool *Map(NTupleSize_t globalIndex) {
1031 return fPrincipalColumn->Map<bool>(globalIndex);
1032 }
1033 bool *Map(const RClusterIndex &clusterIndex) {
1034 return fPrincipalColumn->Map<bool>(clusterIndex);
1035 }
1036 bool *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1037 return fPrincipalColumn->MapV<bool>(globalIndex, nItems);
1038 }
1039 bool *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1040 return fPrincipalColumn->MapV<bool>(clusterIndex, nItems);
1041 }
1042
1044 template <typename... ArgsT>
1046 {
1047 return Detail::RFieldValue(
1048 Detail::RColumnElement<bool>(static_cast<bool*>(where)),
1049 this, static_cast<bool*>(where), std::forward<ArgsT>(args)...);
1050 }
1051 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, false); }
1053 return Detail::RFieldValue(true /* captureFlag */,
1054 Detail::RColumnElement<bool>(static_cast<bool*>(where)), this, where);
1055 }
1056 size_t GetValueSize() const final { return sizeof(bool); }
1057 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1058};
1059
1060template <>
1061class RField<float> : public Detail::RFieldBase {
1062protected:
1063 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1064 return std::make_unique<RField>(newName);
1065 }
1066
1067 const RColumnRepresentations &GetColumnRepresentations() const final;
1068 void GenerateColumnsImpl() final;
1069 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1070
1071public:
1072 static std::string TypeName() { return "float"; }
1074 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1075 {
1077 }
1078 RField(RField&& other) = default;
1079 RField& operator =(RField&& other) = default;
1080 ~RField() override = default;
1081
1082 float *Map(NTupleSize_t globalIndex) {
1083 return fPrincipalColumn->Map<float>(globalIndex);
1084 }
1085 float *Map(const RClusterIndex &clusterIndex) {
1086 return fPrincipalColumn->Map<float>(clusterIndex);
1087 }
1088 float *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1089 return fPrincipalColumn->MapV<float>(globalIndex, nItems);
1090 }
1091 float *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1092 return fPrincipalColumn->MapV<float>(clusterIndex, nItems);
1093 }
1094
1096 template <typename... ArgsT>
1098 {
1099 return Detail::RFieldValue(
1100 Detail::RColumnElement<float>(static_cast<float*>(where)),
1101 this, static_cast<float*>(where), std::forward<ArgsT>(args)...);
1102 }
1105 return Detail::RFieldValue(true /* captureFlag */,
1106 Detail::RColumnElement<float>(static_cast<float*>(where)), this, where);
1107 }
1108 size_t GetValueSize() const final { return sizeof(float); }
1109 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1110};
1111
1112
1113template <>
1115protected:
1116 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1117 return std::make_unique<RField>(newName);
1118 }
1119
1120 const RColumnRepresentations &GetColumnRepresentations() const final;
1121 void GenerateColumnsImpl() final;
1122 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1123
1124public:
1125 static std::string TypeName() { return "double"; }
1127 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1128 {
1130 }
1131 RField(RField&& other) = default;
1132 RField& operator =(RField&& other) = default;
1133 ~RField() override = default;
1134
1135 double *Map(NTupleSize_t globalIndex) {
1136 return fPrincipalColumn->Map<double>(globalIndex);
1137 }
1138 double *Map(const RClusterIndex &clusterIndex) {
1139 return fPrincipalColumn->Map<double>(clusterIndex);
1140 }
1141 double *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1142 return fPrincipalColumn->MapV<double>(globalIndex, nItems);
1143 }
1144 double *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1145 return fPrincipalColumn->MapV<double>(clusterIndex, nItems);
1146 }
1147
1149 template <typename... ArgsT>
1151 {
1152 return Detail::RFieldValue(
1153 Detail::RColumnElement<double>(static_cast<double*>(where)),
1154 this, static_cast<double*>(where), std::forward<ArgsT>(args)...);
1155 }
1158 return Detail::RFieldValue(true /* captureFlag */,
1159 Detail::RColumnElement<double>(static_cast<double*>(where)), this, where);
1160 }
1161 size_t GetValueSize() const final { return sizeof(double); }
1162 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1163};
1164
1165template <>
1166class RField<char> : public Detail::RFieldBase {
1167protected:
1168 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1169 return std::make_unique<RField>(newName);
1170 }
1171
1172 const RColumnRepresentations &GetColumnRepresentations() const final;
1173 void GenerateColumnsImpl() final;
1174 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1175
1176public:
1177 static std::string TypeName() { return "char"; }
1179 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1180 {
1182 }
1183 RField(RField&& other) = default;
1184 RField& operator =(RField&& other) = default;
1185 ~RField() override = default;
1186
1187 char *Map(NTupleSize_t globalIndex) {
1188 return fPrincipalColumn->Map<char>(globalIndex);
1189 }
1190 char *Map(const RClusterIndex &clusterIndex) {
1191 return fPrincipalColumn->Map<char>(clusterIndex);
1192 }
1193 char *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1194 return fPrincipalColumn->MapV<char>(globalIndex, nItems);
1195 }
1196 char *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1197 return fPrincipalColumn->MapV<char>(clusterIndex, nItems);
1198 }
1199
1201 template <typename... ArgsT>
1203 {
1204 return Detail::RFieldValue(
1205 Detail::RColumnElement<char>(static_cast<char*>(where)),
1206 this, static_cast<char*>(where), std::forward<ArgsT>(args)...);
1207 }
1210 return Detail::RFieldValue(true /* captureFlag */,
1211 Detail::RColumnElement<char>(static_cast<char*>(where)), this, where);
1212 }
1213 size_t GetValueSize() const final { return sizeof(char); }
1214 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1215};
1216
1217template <>
1218class RField<std::int8_t> : public Detail::RFieldBase {
1219protected:
1220 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1221 return std::make_unique<RField>(newName);
1222 }
1223
1224 const RColumnRepresentations &GetColumnRepresentations() const final;
1225 void GenerateColumnsImpl() final;
1226 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1227
1228public:
1229 static std::string TypeName() { return "std::int8_t"; }
1230 explicit RField(std::string_view name)
1231 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1232 {
1234 }
1235 RField(RField&& other) = default;
1236 RField& operator =(RField&& other) = default;
1237 ~RField() override = default;
1238
1239 std::int8_t *Map(NTupleSize_t globalIndex) {
1240 return fPrincipalColumn->Map<std::int8_t>(globalIndex);
1241 }
1242 std::int8_t *Map(const RClusterIndex &clusterIndex) {
1243 return fPrincipalColumn->Map<std::int8_t>(clusterIndex);
1244 }
1245 std::int8_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1246 return fPrincipalColumn->MapV<std::int8_t>(globalIndex, nItems);
1247 }
1248 std::int8_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1249 return fPrincipalColumn->MapV<std::int8_t>(clusterIndex, nItems);
1250 }
1251
1253 template <typename... ArgsT>
1254 ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
1255 {
1256 return Detail::RFieldValue(
1257 Detail::RColumnElement<std::int8_t>(static_cast<std::int8_t*>(where)),
1258 this, static_cast<std::int8_t*>(where), std::forward<ArgsT>(args)...);
1259 }
1260 ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final { return GenerateValue(where, 0); }
1261 Detail::RFieldValue CaptureValue(void *where) final {
1262 return Detail::RFieldValue(true /* captureFlag */,
1263 Detail::RColumnElement<std::int8_t>(static_cast<std::int8_t*>(where)), this, where);
1264 }
1265 size_t GetValueSize() const final { return sizeof(std::int8_t); }
1266 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1267};
1268
1269template <>
1270class RField<std::uint8_t> : public Detail::RFieldBase {
1271protected:
1272 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1273 return std::make_unique<RField>(newName);
1274 }
1275
1276 const RColumnRepresentations &GetColumnRepresentations() const final;
1277 void GenerateColumnsImpl() final;
1278 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1279
1280public:
1281 static std::string TypeName() { return "std::uint8_t"; }
1282 explicit RField(std::string_view name)
1283 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1284 {
1286 }
1287 RField(RField&& other) = default;
1288 RField& operator =(RField&& other) = default;
1289 ~RField() override = default;
1290
1291 std::uint8_t *Map(NTupleSize_t globalIndex) {
1292 return fPrincipalColumn->Map<std::uint8_t>(globalIndex);
1293 }
1294 std::uint8_t *Map(const RClusterIndex &clusterIndex) {
1295 return fPrincipalColumn->Map<std::uint8_t>(clusterIndex);
1296 }
1297 std::uint8_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1298 return fPrincipalColumn->MapV<std::uint8_t>(globalIndex, nItems);
1299 }
1300 std::uint8_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1301 return fPrincipalColumn->MapV<std::uint8_t>(clusterIndex, nItems);
1302 }
1303
1305 template <typename... ArgsT>
1306 ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
1307 {
1308 return Detail::RFieldValue(
1309 Detail::RColumnElement<std::uint8_t>(static_cast<std::uint8_t*>(where)),
1310 this, static_cast<std::uint8_t*>(where), std::forward<ArgsT>(args)...);
1311 }
1312 ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final { return GenerateValue(where, 0); }
1313 Detail::RFieldValue CaptureValue(void *where) final {
1314 return Detail::RFieldValue(true /* captureFlag */,
1315 Detail::RColumnElement<std::uint8_t>(static_cast<std::uint8_t*>(where)), this, where);
1316 }
1317 size_t GetValueSize() const final { return sizeof(std::uint8_t); }
1318 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1319};
1320
1321template <>
1322class RField<std::int16_t> : public Detail::RFieldBase {
1323protected:
1324 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1325 return std::make_unique<RField>(newName);
1326 }
1327
1328 const RColumnRepresentations &GetColumnRepresentations() const final;
1329 void GenerateColumnsImpl() final;
1330 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1331
1332public:
1333 static std::string TypeName() { return "std::int16_t"; }
1334 explicit RField(std::string_view name)
1335 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1336 {
1338 }
1339 RField(RField&& other) = default;
1340 RField& operator =(RField&& other) = default;
1341 ~RField() override = default;
1342
1343 std::int16_t *Map(NTupleSize_t globalIndex) {
1344 return fPrincipalColumn->Map<std::int16_t>(globalIndex);
1345 }
1346 std::int16_t *Map(const RClusterIndex &clusterIndex) {
1347 return fPrincipalColumn->Map<std::int16_t>(clusterIndex);
1348 }
1349 std::int16_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1350 return fPrincipalColumn->MapV<std::int16_t>(globalIndex, nItems);
1351 }
1352 std::int16_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1353 return fPrincipalColumn->MapV<std::int16_t>(clusterIndex, nItems);
1354 }
1355
1357 template <typename... ArgsT>
1358 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1359 {
1360 return Detail::RFieldValue(
1361 Detail::RColumnElement<std::int16_t>(static_cast<std::int16_t*>(where)),
1362 this, static_cast<std::int16_t*>(where), std::forward<ArgsT>(args)...);
1363 }
1364 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
1365 Detail::RFieldValue CaptureValue(void *where) final {
1366 return Detail::RFieldValue(true /* captureFlag */,
1367 Detail::RColumnElement<std::int16_t>(static_cast<std::int16_t*>(where)), this, where);
1368 }
1369 size_t GetValueSize() const final { return sizeof(std::int16_t); }
1370 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1371};
1372
1373template <>
1374class RField<std::uint16_t> : public Detail::RFieldBase {
1375protected:
1376 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1377 return std::make_unique<RField>(newName);
1378 }
1379
1380 const RColumnRepresentations &GetColumnRepresentations() const final;
1381 void GenerateColumnsImpl() final;
1382 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1383
1384public:
1385 static std::string TypeName() { return "std::uint16_t"; }
1386 explicit RField(std::string_view name)
1387 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1388 {
1390 }
1391 RField(RField&& other) = default;
1392 RField& operator =(RField&& other) = default;
1393 ~RField() override = default;
1394
1395 std::uint16_t *Map(NTupleSize_t globalIndex) {
1396 return fPrincipalColumn->Map<std::uint16_t>(globalIndex);
1397 }
1398 std::uint16_t *Map(const RClusterIndex &clusterIndex) {
1399 return fPrincipalColumn->Map<std::uint16_t>(clusterIndex);
1400 }
1401 std::uint16_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1402 return fPrincipalColumn->MapV<std::uint16_t>(globalIndex, nItems);
1403 }
1404 std::uint16_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1405 return fPrincipalColumn->MapV<std::uint16_t>(clusterIndex, nItems);
1406 }
1407
1409 template <typename... ArgsT>
1410 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1411 {
1412 return Detail::RFieldValue(
1413 Detail::RColumnElement<std::uint16_t>(static_cast<std::uint16_t*>(where)),
1414 this, static_cast<std::uint16_t*>(where), std::forward<ArgsT>(args)...);
1415 }
1416 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
1417 Detail::RFieldValue CaptureValue(void *where) final {
1418 return Detail::RFieldValue(true /* captureFlag */,
1419 Detail::RColumnElement<std::uint16_t>(static_cast<std::uint16_t*>(where)), this, where);
1420 }
1421 size_t GetValueSize() const final { return sizeof(std::uint16_t); }
1422 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1423};
1424
1425template <>
1426class RField<std::int32_t> : public Detail::RFieldBase {
1427protected:
1428 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1429 return std::make_unique<RField>(newName);
1430 }
1431
1432 const RColumnRepresentations &GetColumnRepresentations() const final;
1433 void GenerateColumnsImpl() final;
1434 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1435
1436public:
1437 static std::string TypeName() { return "std::int32_t"; }
1438 explicit RField(std::string_view name)
1439 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1440 {
1442 }
1443 RField(RField&& other) = default;
1444 RField& operator =(RField&& other) = default;
1445 ~RField() override = default;
1446
1447 std::int32_t *Map(NTupleSize_t globalIndex) {
1448 return fPrincipalColumn->Map<std::int32_t>(globalIndex);
1449 }
1450 std::int32_t *Map(const RClusterIndex &clusterIndex) {
1451 return fPrincipalColumn->Map<std::int32_t>(clusterIndex);
1452 }
1453 std::int32_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1454 return fPrincipalColumn->MapV<std::int32_t>(globalIndex, nItems);
1455 }
1456 std::int32_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1457 return fPrincipalColumn->MapV<std::int32_t>(clusterIndex, nItems);
1458 }
1459
1461 template <typename... ArgsT>
1462 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1463 {
1464 return Detail::RFieldValue(
1465 Detail::RColumnElement<std::int32_t>(static_cast<std::int32_t*>(where)),
1466 this, static_cast<std::int32_t*>(where), std::forward<ArgsT>(args)...);
1467 }
1468 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
1469 Detail::RFieldValue CaptureValue(void *where) final {
1470 return Detail::RFieldValue(true /* captureFlag */,
1471 Detail::RColumnElement<std::int32_t>(static_cast<std::int32_t*>(where)), this, where);
1472 }
1473 size_t GetValueSize() const final { return sizeof(std::int32_t); }
1474 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1475};
1476
1477template <>
1478class RField<std::uint32_t> : public Detail::RFieldBase {
1479protected:
1480 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1481 return std::make_unique<RField>(newName);
1482 }
1483
1484 const RColumnRepresentations &GetColumnRepresentations() const final;
1485 void GenerateColumnsImpl() final;
1486 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1487
1488public:
1489 static std::string TypeName() { return "std::uint32_t"; }
1490 explicit RField(std::string_view name)
1491 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1492 {
1494 }
1495 RField(RField&& other) = default;
1496 RField& operator =(RField&& other) = default;
1497 ~RField() override = default;
1498
1499 std::uint32_t *Map(NTupleSize_t globalIndex) {
1500 return fPrincipalColumn->Map<std::uint32_t>(globalIndex);
1501 }
1502 std::uint32_t *Map(const RClusterIndex clusterIndex) {
1503 return fPrincipalColumn->Map<std::uint32_t>(clusterIndex);
1504 }
1505 std::uint32_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1506 return fPrincipalColumn->MapV<std::uint32_t>(globalIndex, nItems);
1507 }
1508 std::uint32_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1509 return fPrincipalColumn->MapV<std::uint32_t>(clusterIndex, nItems);
1510 }
1511
1513 template <typename... ArgsT>
1514 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1515 {
1516 return Detail::RFieldValue(
1517 Detail::RColumnElement<std::uint32_t>(static_cast<std::uint32_t*>(where)),
1518 this, static_cast<std::uint32_t*>(where), std::forward<ArgsT>(args)...);
1519 }
1520 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
1521 Detail::RFieldValue CaptureValue(void *where) final {
1522 return Detail::RFieldValue(true /* captureFlag */,
1523 Detail::RColumnElement<std::uint32_t>(static_cast<std::uint32_t*>(where)), this, where);
1524 }
1525 size_t GetValueSize() const final { return sizeof(std::uint32_t); }
1526 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1527};
1528
1529template <>
1530class RField<std::uint64_t> : public Detail::RFieldBase {
1531protected:
1532 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1533 return std::make_unique<RField>(newName);
1534 }
1535
1536 const RColumnRepresentations &GetColumnRepresentations() const final;
1537 void GenerateColumnsImpl() final;
1538 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1539
1540public:
1541 static std::string TypeName() { return "std::uint64_t"; }
1542 explicit RField(std::string_view name)
1543 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1544 {
1546 }
1547 RField(RField&& other) = default;
1548 RField& operator =(RField&& other) = default;
1549 ~RField() override = default;
1550
1551 std::uint64_t *Map(NTupleSize_t globalIndex) {
1552 return fPrincipalColumn->Map<std::uint64_t>(globalIndex);
1553 }
1554 std::uint64_t *Map(const RClusterIndex &clusterIndex) {
1555 return fPrincipalColumn->Map<std::uint64_t>(clusterIndex);
1556 }
1557 std::uint64_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1558 return fPrincipalColumn->MapV<std::uint64_t>(globalIndex, nItems);
1559 }
1560 std::uint64_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1561 return fPrincipalColumn->MapV<std::uint64_t>(clusterIndex, nItems);
1562 }
1563
1565 template <typename... ArgsT>
1566 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1567 {
1568 return Detail::RFieldValue(
1569 Detail::RColumnElement<std::uint64_t>(static_cast<std::uint64_t*>(where)),
1570 this, static_cast<std::uint64_t*>(where), std::forward<ArgsT>(args)...);
1571 }
1572 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
1573 Detail::RFieldValue CaptureValue(void *where) final {
1574 return Detail::RFieldValue(true /* captureFlag */,
1575 Detail::RColumnElement<std::uint64_t>(static_cast<std::uint64_t*>(where)), this, where);
1576 }
1577 size_t GetValueSize() const final { return sizeof(std::uint64_t); }
1578 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1579};
1580
1581template <>
1582class RField<std::int64_t> : public Detail::RFieldBase {
1583protected:
1584 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1585 return std::make_unique<RField>(newName);
1586 }
1587
1588 const RColumnRepresentations &GetColumnRepresentations() const final;
1589 void GenerateColumnsImpl() final;
1590 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1591
1592public:
1593 static std::string TypeName() { return "std::int64_t"; }
1594 explicit RField(std::string_view name)
1595 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */)
1596 {
1598 }
1599 RField(RField&& other) = default;
1600 RField& operator =(RField&& other) = default;
1601 ~RField() override = default;
1602
1603 std::int64_t *Map(NTupleSize_t globalIndex) {
1604 return fPrincipalColumn->Map<std::int64_t>(globalIndex);
1605 }
1606 std::int64_t *Map(const RClusterIndex &clusterIndex) {
1607 return fPrincipalColumn->Map<std::int64_t>(clusterIndex);
1608 }
1609 std::int64_t *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems) {
1610 return fPrincipalColumn->MapV<std::int64_t>(globalIndex, nItems);
1611 }
1612 std::int64_t *MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems) {
1613 return fPrincipalColumn->MapV<std::int64_t>(clusterIndex, nItems);
1614 }
1615
1617 template <typename... ArgsT>
1618 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1619 {
1620 return Detail::RFieldValue(
1621 Detail::RColumnElement<std::int64_t>(static_cast<std::int64_t*>(where)),
1622 this, static_cast<std::int64_t*>(where), std::forward<ArgsT>(args)...);
1623 }
1624 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
1625 Detail::RFieldValue CaptureValue(void *where) final {
1626 return Detail::RFieldValue(true /* captureFlag */,
1627 Detail::RColumnElement<std::int64_t>(static_cast<std::int64_t*>(where)), this, where);
1628 }
1629 size_t GetValueSize() const final { return sizeof(std::int64_t); }
1630 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1631};
1632
1633template <>
1634class RField<std::string> : public Detail::RFieldBase {
1635private:
1636 ClusterSize_t fIndex;
1637 Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> fElemIndex;
1638
1639 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1640 return std::make_unique<RField>(newName);
1641 }
1642 const RColumnRepresentations &GetColumnRepresentations() const final;
1643 void GenerateColumnsImpl() final;
1644 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1645 std::size_t AppendImpl(const ROOT::Experimental::Detail::RFieldValue& value) final;
1646 void ReadGlobalImpl(ROOT::Experimental::NTupleSize_t globalIndex,
1647 ROOT::Experimental::Detail::RFieldValue *value) final;
1648
1649public:
1650 static std::string TypeName() { return "std::string"; }
1651 explicit RField(std::string_view name)
1652 : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, false /* isSimple */), fIndex(0),
1653 fElemIndex(&fIndex)
1654 {
1655 }
1656 RField(RField&& other) = default;
1657 RField& operator =(RField&& other) = default;
1658 ~RField() override = default;
1659
1661 template <typename... ArgsT>
1662 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1663 {
1664 return Detail::RFieldValue(this, static_cast<std::string*>(where), std::forward<ArgsT>(args)...);
1665 }
1666 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, ""); }
1667 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) override {
1668 auto str = value.Get<std::string>();
1669 str->~basic_string(); // TODO(jblomer) C++17 std::destroy_at
1670 if (!dtorOnly)
1671 free(str);
1672 }
1673 Detail::RFieldValue CaptureValue(void *where) override {
1674 return Detail::RFieldValue(true /* captureFlag */, this, where);
1675 }
1676 size_t GetValueSize() const final { return sizeof(std::string); }
1677 size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
1678 void CommitCluster() final;
1679 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1680};
1681
1682
1683template <typename ItemT, std::size_t N>
1684class RField<std::array<ItemT, N>> : public RArrayField {
1685 using ContainerT = typename std::array<ItemT, N>;
1686public:
1687 static std::string TypeName() {
1688 return "std::array<" + RField<ItemT>::TypeName() + "," + std::to_string(N) + ">";
1689 }
1690 explicit RField(std::string_view name)
1691 : RArrayField(name, std::make_unique<RField<ItemT>>(RField<ItemT>::TypeName()), N)
1692 {}
1693 RField(RField&& other) = default;
1694 RField& operator =(RField&& other) = default;
1695 ~RField() override = default;
1696
1698 template <typename... ArgsT>
1699 ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
1700 {
1701 return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
1702 }
1704 return GenerateValue(where, ContainerT());
1705 }
1706};
1707
1708template <typename ItemT, std::size_t N>
1709class RField<ItemT[N]> : public RField<std::array<ItemT, N>> {
1710public:
1711 explicit RField(std::string_view name) : RField<std::array<ItemT, N>>(name) {}
1712 RField(RField &&other) = default;
1713 RField &operator=(RField &&other) = default;
1714 ~RField() override = default;
1715};
1716
1717template <typename... ItemTs>
1718class RField<std::variant<ItemTs...>> : public RVariantField {
1719 using ContainerT = typename std::variant<ItemTs...>;
1720private:
1721 template <typename HeadT, typename... TailTs>
1722 static std::string BuildItemTypes()
1723 {
1724 std::string result = RField<HeadT>::TypeName();
1725 if constexpr(sizeof...(TailTs) > 0)
1726 result += "," + BuildItemTypes<TailTs...>();
1727 return result;
1728 }
1729
1730 template <typename HeadT, typename... TailTs>
1731 static std::vector<Detail::RFieldBase *> BuildItemFields(unsigned int index = 0)
1732 {
1733 std::vector<Detail::RFieldBase *> result;
1734 result.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
1735 if constexpr(sizeof...(TailTs) > 0) {
1736 auto tailFields = BuildItemFields<TailTs...>(index + 1);
1737 result.insert(result.end(), tailFields.begin(), tailFields.end());
1738 }
1739 return result;
1740 }
1741
1742public:
1743 static std::string TypeName() { return "std::variant<" + BuildItemTypes<ItemTs...>() + ">"; }
1744 explicit RField(std::string_view name) : RVariantField(name, BuildItemFields<ItemTs...>()) {}
1745 RField(RField&& other) = default;
1746 RField& operator =(RField&& other) = default;
1747 ~RField() override = default;
1748
1750 template <typename... ArgsT>
1751 ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
1752 {
1753 return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
1754 }
1756 return GenerateValue(where, ContainerT());
1757 }
1758};
1759
1760template <typename ItemT>
1761class RField<std::vector<ItemT>> : public RVectorField {
1762 using ContainerT = typename std::vector<ItemT>;
1763public:
1764 static std::string TypeName() { return "std::vector<" + RField<ItemT>::TypeName() + ">"; }
1765 explicit RField(std::string_view name)
1766 : RVectorField(name, std::make_unique<RField<ItemT>>("_0"))
1767 {}
1768 RField(RField&& other) = default;
1769 RField& operator =(RField&& other) = default;
1770 ~RField() override = default;
1771
1773 template <typename... ArgsT>
1774 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1775 {
1776 return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
1777 }
1779 return GenerateValue(where, ContainerT());
1780 }
1781 Detail::RFieldValue CaptureValue(void *where) final {
1782 return Detail::RFieldValue(true /* captureFlag */, this, where);
1783 }
1784 size_t GetValueSize() const final { return sizeof(ContainerT); }
1785};
1786
1787// std::vector<bool> is a template specialization and needs special treatment
1788template <>
1789class RField<std::vector<bool>> : public Detail::RFieldBase {
1790private:
1791 ClusterSize_t fNWritten{0};
1792
1793protected:
1794 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1795 return std::make_unique<RField>(newName);
1796 }
1797 std::size_t AppendImpl(const Detail::RFieldValue& value) final;
1798 void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
1799
1800 const RColumnRepresentations &GetColumnRepresentations() const final;
1801 void GenerateColumnsImpl() final;
1802 void GenerateColumnsImpl(const RNTupleDescriptor &desc) final;
1803
1804public:
1805 static std::string TypeName() { return "std::vector<bool>"; }
1806 explicit RField(std::string_view name);
1807 RField(RField&& other) = default;
1808 RField& operator =(RField&& other) = default;
1809 ~RField() override = default;
1810
1812 template <typename... ArgsT>
1813 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1814 {
1815 return Detail::RFieldValue(this, static_cast<std::vector<bool>*>(where), std::forward<ArgsT>(args)...);
1816 }
1818 return GenerateValue(where, std::vector<bool>());
1819 }
1820 Detail::RFieldValue CaptureValue(void *where) final {
1821 return Detail::RFieldValue(true /* captureFlag */, this, where);
1822 }
1823 std::vector<Detail::RFieldValue> SplitValue(const Detail::RFieldValue &value) const final;
1824 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final;
1825
1826 size_t GetValueSize() const final { return sizeof(std::vector<bool>); }
1827 size_t GetAlignment() const final { return std::alignment_of<std::vector<bool>>(); }
1828 void CommitCluster() final { fNWritten = 0; }
1829 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
1830 void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const {
1831 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
1832 }
1833 void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
1834 {
1835 fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
1836 }
1837};
1838
1839template <typename ItemT>
1840class RField<ROOT::VecOps::RVec<ItemT>> : public RRVecField {
1842protected:
1843 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final {
1844 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
1845 return std::make_unique<RField<ROOT::VecOps::RVec<ItemT>>>(newName, std::move(newItemField));
1846 }
1847 std::size_t AppendImpl(const Detail::RFieldValue& value) final {
1848 auto typedValue = value.Get<ContainerT>();
1849 auto nbytes = 0;
1850 auto count = typedValue->size();
1851 for (unsigned i = 0; i < count; ++i) {
1852 auto itemValue = fSubFields[0]->CaptureValue(&typedValue->data()[i]);
1853 nbytes += fSubFields[0]->Append(itemValue);
1854 }
1856 this->fNWritten += count;
1857 fColumns[0]->Append(elemIndex);
1858 return nbytes + sizeof(elemIndex);
1859 }
1861 auto typedValue = value->Get<ContainerT>();
1862 ClusterSize_t nItems;
1863 RClusterIndex collectionStart;
1864 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1865 typedValue->resize(nItems);
1866 for (unsigned i = 0; i < nItems; ++i) {
1867 auto itemValue = fSubFields[0]->CaptureValue(&typedValue->data()[i]);
1868 fSubFields[0]->Read(collectionStart + i, &itemValue);
1869 }
1870 }
1871
1872public:
1873 RField(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
1874 : RRVecField(fieldName, std::move(itemField))
1875 {
1876 }
1877
1879 : RField(name, std::make_unique<RField<ItemT>>("_0"))
1880 {
1881 }
1882 RField(RField&& other) = default;
1883 RField& operator =(RField&& other) = default;
1884 ~RField() override = default;
1885
1886 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final {
1887 auto vec = reinterpret_cast<ContainerT*>(value.GetRawPtr());
1888 vec->~RVec();
1889 if (!dtorOnly)
1890 free(vec);
1891 }
1892
1893 static std::string TypeName() { return "ROOT::VecOps::RVec<" + RField<ItemT>::TypeName() + ">"; }
1894
1896 template <typename... ArgsT>
1898 {
1899 return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
1900 }
1902 return GenerateValue(where, ContainerT());
1903 }
1905 return Detail::RFieldValue(true /* captureFlag */, this, static_cast<ContainerT*>(where));
1906 }
1907 size_t GetValueSize() const final { return sizeof(ContainerT); }
1908 size_t GetAlignment() const final { return std::alignment_of<ContainerT>(); }
1909};
1910
1911template <typename T1, typename T2>
1912class RField<std::pair<T1, T2>> : public RPairField {
1913 using ContainerT = typename std::pair<T1,T2>;
1914private:
1915 template <typename Ty1, typename Ty2>
1916 static std::array<std::unique_ptr<Detail::RFieldBase>, 2> BuildItemFields()
1917 {
1918 return {std::make_unique<RField<Ty1>>("_0"), std::make_unique<RField<Ty2>>("_1")};
1919 }
1920
1921protected:
1922 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final
1923 {
1924 std::array<std::unique_ptr<Detail::RFieldBase>, 2> items{fSubFields[0]->Clone(fSubFields[0]->GetName()),
1925 fSubFields[1]->Clone(fSubFields[1]->GetName())};
1926 return std::make_unique<RField<std::pair<T1, T2>>>(newName, std::move(items));
1927 }
1928
1929public:
1930 static std::string TypeName() {
1931 return "std::pair<" + RField<T1>::TypeName() + "," + RField<T2>::TypeName() + ">";
1932 }
1933 explicit RField(std::string_view name, std::array<std::unique_ptr<Detail::RFieldBase>, 2> &&itemFields)
1934 : RPairField(name, std::move(itemFields), {offsetof(ContainerT, first), offsetof(ContainerT, second)})
1935 {
1936 fMaxAlignment = std::max(alignof(T1), alignof(T2));
1937 fSize = sizeof(ContainerT);
1938 }
1939 explicit RField(std::string_view name) : RField(name, BuildItemFields<T1, T2>()) {}
1940 RField(RField&& other) = default;
1941 RField& operator =(RField&& other) = default;
1942 ~RField() override = default;
1943
1945 template <typename... ArgsT>
1946 ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
1947 {
1948 return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
1949 }
1951 return GenerateValue(where, ContainerT());
1952 }
1953 void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) final
1954 {
1955 reinterpret_cast<ContainerT *>(value.GetRawPtr())->~pair();
1956 if (!dtorOnly)
1957 free(reinterpret_cast<ContainerT *>(value.GetRawPtr()));
1958 }
1959};
1960
1961template <typename... ItemTs>
1962class RField<std::tuple<ItemTs...>> : public RTupleField {
1963 using ContainerT = typename std::tuple<ItemTs...>;
1964private:
1965 template <typename HeadT, typename... TailTs>
1966 static std::string BuildItemTypes()
1967 {
1968 std::string result = RField<HeadT>::TypeName();
1969 if constexpr (sizeof...(TailTs) > 0)
1970 result += "," + BuildItemTypes<TailTs...>();
1971 return result;
1972 }
1973
1974 template <typename HeadT, typename... TailTs>
1975 static void _BuildItemFields(std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields, unsigned int index = 0)
1976 {
1977 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
1978 if constexpr (sizeof...(TailTs) > 0)
1979 _BuildItemFields<TailTs...>(itemFields, index + 1);
1980 }
1981 template <typename... Ts>
1982 static std::vector<std::unique_ptr<Detail::RFieldBase>> BuildItemFields()
1983 {
1984 std::vector<std::unique_ptr<Detail::RFieldBase>> result;
1985 _BuildItemFields<Ts...>(result);
1986 return result;
1987 }
1988
1989 template <unsigned Index, typename HeadT, typename... TailTs>
1990 static void _BuildItemOffsets(std::vector<std::size_t> &offsets, const ContainerT &tuple)
1991 {
1992 auto offset =
1993 reinterpret_cast<std::uintptr_t>(&std::get<Index>(tuple)) - reinterpret_cast<std::uintptr_t>(&tuple);
1994 offsets.emplace_back(offset);
1995 if constexpr (sizeof...(TailTs) > 0)
1996 _BuildItemOffsets<Index + 1, TailTs...>(offsets, tuple);
1997 }
1998 template <typename... Ts>
1999 static std::vector<std::size_t> BuildItemOffsets()
2000 {
2001 std::vector<std::size_t> result;
2002 _BuildItemOffsets<0, Ts...>(result, ContainerT());
2003 return result;
2004 }
2005
2006protected:
2007 std::unique_ptr<Detail::RFieldBase> CloneImpl(std::string_view newName) const final
2008 {
2009 std::vector<std::unique_ptr<Detail::RFieldBase>> items;
2010 for (auto &item : fSubFields)
2011 items.push_back(item->Clone(item->GetName()));
2012 return std::make_unique<RField<std::tuple<ItemTs...>>>(newName, std::move(items));
2013 }
2014
2015public:
2016 static std::string TypeName() { return "std::tuple<" + BuildItemTypes<ItemTs...>() + ">"; }
2017 explicit RField(std::string_view name, std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields)
2018 : RTupleField(name, std::move(itemFields), BuildItemOffsets<ItemTs...>())
2019 {
2020 fMaxAlignment = std::max({alignof(ItemTs)...});
2021 fSize = sizeof(ContainerT);
2022 }
2023 explicit RField(std::string_view name) : RField(name, BuildItemFields<ItemTs...>()) {}
2024 RField(RField &&other) = default;
2025 RField &operator=(RField &&other) = default;
2026 ~RField() override = default;
2027
2029 template <typename... ArgsT>
2030 ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&...args)
2031 {
2032 return Detail::RFieldValue(this, static_cast<ContainerT *>(where), std::forward<ArgsT>(args)...);
2033 }
2035 {
2036 return GenerateValue(where, ContainerT());
2037 }
2038 void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) final
2039 {
2040 reinterpret_cast<ContainerT *>(value.GetRawPtr())->~tuple();
2041 if (!dtorOnly)
2042 free(reinterpret_cast<ContainerT *>(value.GetRawPtr()));
2043 }
2044};
2045
2046} // namespace Experimental
2047} // namespace ROOT
2048
2049#endif
size_t fSize
#define R__unlikely(expr)
Definition: RConfig.hxx:598
#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:303
ROOT::Experimental::RField< T > RField
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define N
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t 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 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 id
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
#define free
Definition: civetweb.c:1539
Pairs of C++ type and column type, like float and EColumnType::kReal32.
void Append(const RColumnElementBase &element)
Definition: RColumn.hxx:117
CppT * MapV(const NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition: RColumn.hxx:226
CppT * Map(const NTupleSize_t globalIndex)
Definition: RColumn.hxx:214
void Read(const NTupleSize_t globalIndex, RColumnElementBase *element)
Definition: RColumn.hxx:158
NTupleSize_t GetGlobalIndex(const RClusterIndex &clusterIndex)
Definition: RColumn.hxx:249
NTupleSize_t GetNElements() const
Definition: RColumn.hxx:308
void GetCollectionInfo(const NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *collectionSize)
For offset columns only, look at the two adjacent values that define a collection's coordinates.
Definition: RColumn.hxx:265
Some fields have multiple possible column representations, e.g.
Definition: RField.hxx:106
TypesList_t fDeserializationTypes
The union of the serialization types and the deserialization extra types.
Definition: RField.hxx:121
std::vector< ColumnRepresentation_t > TypesList_t
Definition: RField.hxx:108
const ColumnRepresentation_t & GetSerializationDefault() const
The first column list from fSerializationTypes is the default for writing.
Definition: RField.hxx:113
Iterates over the sub tree of fields in depth-first search order.
Definition: RField.hxx:206
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.cxx:528
std::vector< Position > fStack
The stack of nodes visited when walking down the tree of fields.
Definition: RField.hxx:215
virtual std::uint32_t GetFieldVersion() const
Indicates an evolution of the mapping scheme from C++ type to columns.
Definition: RField.hxx:355
RFieldBase * GetParent() const
Definition: RField.hxx:332
virtual RFieldValue CaptureValue(void *where)=0
Creates a value from a memory location with an already constructed object.
std::string GetDescription() const
Get the field's description.
Definition: RField.hxx:336
static constexpr std::uint32_t kInvalidTypeVersion
Definition: RField.hxx:86
void SetOnDiskId(DescriptorId_t id)
Definition: RField.hxx:340
virtual void GenerateColumnsImpl(const RNTupleDescriptor &desc)=0
Creates the backing columns corresponsing to the field type for reading.
virtual void GenerateColumnsImpl()=0
Creates the backing columns corresponsing to the field type for writing.
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Definition: RField.hxx:144
RFieldBase * fParent
Sub fields point to their mother field.
Definition: RField.hxx:146
RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple, std::size_t nRepetitions=0)
The constructor creates the underlying column objects and connects them to either a sink or a source.
Definition: RField.cxx:202
std::size_t GetNRepetitions() const
Definition: RField.hxx:330
std::string fDescription
Free text set by the user.
Definition: RField.hxx:140
virtual std::uint32_t GetTypeVersion() const
Indicates an evolution of the C++ type itself.
Definition: RField.hxx:357
int fTraits
Properties of the type that allow for optimizations of collections of that type.
Definition: RField.hxx:154
friend struct ROOT::Experimental::Internal::RFieldCallbackInjector
Definition: RField.hxx:82
virtual void DestroyValue(const RFieldValue &value, bool dtorOnly=false)
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:380
DescriptorId_t GetOnDiskId() const
Definition: RField.hxx:339
static constexpr int kTraitTrivialType
Shorthand for types that are both trivially constructible and destructible.
Definition: RField.hxx:96
void ConnectPageSink(RPageSink &pageSink)
Fields and their columns live in the void until connected to a physical page storage.
Definition: RField.cxx:474
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:359
void Flush() const
Ensure that all received items are written from page buffers to the storage.
Definition: RField.cxx:410
virtual void ReadInClusterImpl(const RClusterIndex &clusterIndex, RFieldValue *value)
Definition: RField.hxx:180
virtual void CommitCluster()
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.hxx:320
virtual size_t GetAlignment() const
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:275
virtual std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const =0
Called by Clone(), which additionally copies the on-disk ID.
virtual size_t GetValueSize() const =0
The number of bytes taken by a value of the appropriate type.
void SetDescription(std::string_view description)
Definition: RField.hxx:337
virtual std::vector< RFieldValue > SplitValue(const RFieldValue &value) const
Creates the list of direct child values given a value for this field.
Definition: RField.cxx:387
static RResult< void > EnsureValidFieldName(std::string_view fieldName)
Check whether a given string is a valid field name.
Definition: RField.cxx:332
bool fIsSimple
A field qualifies as simple if it is both mappable and has no post-read callback.
Definition: RField.hxx:134
std::string fType
The C++ type captured by this field.
Definition: RField.hxx:128
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName)
Factory method to resurrect a field from the stored on-disk type information.
Definition: RField.cxx:225
std::string fName
The field name relative to its parent field.
Definition: RField.hxx:126
const ColumnRepresentation_t * fColumnRepresentative
Points into the static vector GetColumnRepresentations().GetSerializationTypes() when SetColumnRepres...
Definition: RField.hxx:161
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:461
virtual void OnConnectPageSource()
Called by ConnectPageSource() only once connected; derived classes may override this as appropriate.
Definition: RField.hxx:195
NTupleSize_t GetNElements() const
Definition: RField.hxx:331
void ConnectPageSource(RPageSource &pageSource)
Definition: RField.cxx:485
std::uint32_t fOnDiskTypeVersion
C++ type version cached from the descriptor after a call to ConnectPageSource()
Definition: RField.hxx:158
std::size_t Append(const RFieldValue &value)
Write the given value into columns.
Definition: RField.hxx:281
virtual std::size_t AppendImpl(const RFieldValue &value)
Operations on values of complex types, e.g.
Definition: RField.cxx:360
std::function< void(RFieldValue &)> ReadCallback_t
Definition: RField.hxx:83
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
Definition: RField.cxx:343
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:350
std::size_t fNRepetitions
For fixed sized arrays, the array length.
Definition: RField.hxx:132
RFieldBase(const RFieldBase &)=delete
virtual void AcceptVisitor(RFieldVisitor &visitor) const
Definition: RField.cxx:506
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:138
virtual void ReadGlobalImpl(NTupleSize_t globalIndex, RFieldValue *value)
Definition: RField.cxx:366
ENTupleStructure fStructure
The role of this field in the data model structure.
Definition: RField.hxx:130
void Read(const RClusterIndex &clusterIndex, RFieldValue *value)
Definition: RField.hxx:305
void InvokeReadCallbacks(RFieldValue &value)
Definition: RField.hxx:198
std::vector< std::unique_ptr< 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:152
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots ("grandparent.parent....
Definition: RField.cxx:213
const ColumnRepresentation_t & GetColumnRepresentative() const
Returns the fColumnRepresentative pointee or, if unset, the field's default representative.
Definition: RField.cxx:418
static constexpr int kTraitMappable
A field of a fundamental type that can be directly mapped via RField<T>::Map(), i....
Definition: RField.hxx:94
void Attach(std::unique_ptr< Detail::RFieldBase > child)
Add a new subfield to the list of nested fields.
Definition: RField.cxx:392
std::vector< RFieldBase * > GetSubFields() const
Definition: RField.cxx:400
virtual RFieldValue GenerateValue(void *where)=0
Generates a tree value in a given location of size at least GetValueSize().
RFieldBase & operator=(const RFieldBase &)=delete
void SetColumnRepresentative(const ColumnRepresentation_t &representative)
Fixes a column representative.
Definition: RField.cxx:425
ENTupleStructure GetStructure() const
Definition: RField.hxx:329
void Read(NTupleSize_t globalIndex, RFieldValue *value)
Populate a single value with data from the tree, which needs to be of the fitting type.
Definition: RField.hxx:293
static constexpr int kTraitTriviallyConstructible
No constructor needs to be called, i.e.
Definition: RField.hxx:89
static constexpr int kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. DestroyValue() is a no-op.
Definition: RField.hxx:91
const ColumnRepresentation_t & EnsureCompatibleColumnTypes(const RNTupleDescriptor &desc) const
Returns the on-disk column types found in the provided descriptor for fOnDiskId.
Definition: RField.cxx:437
RFieldValue GenerateValue()
Generates an object of the field type and allocates new initialized memory according to the type.
Definition: RField.cxx:373
std::vector< ReadCallback_t > fReadCallbacks
List of functions to be called after reading a value.
Definition: RField.hxx:156
std::vector< EColumnType > ColumnRepresentation_t
Definition: RField.hxx:98
RColumn * fPrincipalColumn
Points into fColumns.
Definition: RField.hxx:150
Abstract base class for classes implementing the visitor design pattern.
Abstract interface to write data into an ntuple.
Abstract interface to read data from an ntuple.
The generic field for fixed size arrays, which do not need an offset column.
Definition: RField.hxx:629
void GenerateColumnsImpl(const RNTupleDescriptor &) final
Creates the backing columns corresponsing to the field type for reading.
Definition: RField.hxx:637
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition: RField.hxx:636
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:654
RArrayField(RArrayField &&other)=default
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:655
~RArrayField() override=default
The field for a class with dictionary.
Definition: RField.hxx:390
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:1136
static constexpr const char * kPrefixInherited
Prefix used in the subfield names generated for base classes.
Definition: RField.hxx:401
void OnConnectPageSource() final
Called by ConnectPageSource() only once connected; derived classes may override this as appropriate.
Definition: RField.cxx:1098
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition: RField.cxx:1154
void Attach(std::unique_ptr< Detail::RFieldBase > child, RSubFieldInfo info)
Definition: RField.cxx:1040
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition: RField.cxx:1143
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.cxx:1068
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:1073
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:1047
RClassField & operator=(RClassField &&other)=default
void AcceptVisitor(Detail::RFieldVisitor &visitor) const override
Definition: RField.cxx:1164
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:436
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
Definition: RField.cxx:1159
void GenerateColumnsImpl(const RNTupleDescriptor &) final
Creates the backing columns corresponsing to the field type for reading.
Definition: RField.hxx:418
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:1090
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition: RField.hxx:417
RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
Definition: RField.cxx:985
std::vector< RSubFieldInfo > fSubFieldsInfo
Additional information kept for each entry in fSubFields
Definition: RField.hxx:405
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:1082
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:1129
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
The field for a class representing a collection of elements via TVirtualCollectionProxy.
Definition: RField.hxx:448
std::unique_ptr< TVirtualCollectionProxy > fProxy
Definition: RField.hxx:453
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:479
void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
Definition: RField.hxx:486
The collection field is only used for writing; when reading, untyped collections are projected to an ...
Definition: RField.hxx:805
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:831
std::shared_ptr< RCollectionNTupleWriter > fCollectionNTuple
Save the link to the collection ntuple in order to reset the offset counter when committing the clust...
Definition: RField.hxx:808
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:835
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:826
RCollectionField(RCollectionField &&other)=default
Base class for all ROOT issued exceptions.
Definition: RError.hxx:78
A field translates read and write calls from/to underlying columns to/from tree values.
Represents transient storage of simple or complex C++ values.
The container field for an ntuple model, which itself has no physical representation.
Definition: RField.hxx:372
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition: RField.cxx:564
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.cxx:555
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:384
Detail::RFieldValue GenerateValue(void *) override
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:382
Detail::RFieldValue CaptureValue(void *) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:383
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition: RField.hxx:375
void GenerateColumnsImpl(const RNTupleDescriptor &) final
Creates the backing columns corresponsing to the field type for reading.
Definition: RField.hxx:376
void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size)
Definition: RField.hxx:942
ClusterSize_t * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition: RField.hxx:916
ClusterSize_t * Map(const RClusterIndex &clusterIndex)
Definition: RField.hxx:913
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:932
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:936
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
ClusterSize_t * Map(NTupleSize_t globalIndex)
Definition: RField.hxx:910
ClusterSize_t * MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems)
Definition: RField.hxx:919
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:939
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:925
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:931
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.hxx:891
RField & operator=(RField &&other)=default
RField(RField &&other)=default
RField(std::string_view name)
Definition: RField.hxx:1711
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:985
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Get the number of elements of the collection identified by clusterIndex.
Definition: RField.hxx:997
RField & operator=(RField &&other)=default
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
void GenerateColumnsImpl(const RNTupleDescriptor &) final
Creates the backing columns corresponsing to the field type for reading.
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:980
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:981
std::unique_ptr< ROOT::Experimental::Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.hxx:954
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&...args)
Definition: RField.hxx:976
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Get the number of elements of the collection identified by globalIndex.
Definition: RField.hxx:988
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:1904
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:1901
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.hxx:1860
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:1907
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.hxx:1847
typename ROOT::VecOps::RVec< ItemT > ContainerT
Definition: RField.hxx:1841
RField(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition: RField.hxx:1873
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.hxx:1843
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:1908
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:1897
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.hxx:1886
bool * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition: RField.hxx:1036
RField(std::string_view name)
Definition: RField.hxx:1021
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:1056
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.hxx:1011
bool * MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems)
Definition: RField.hxx:1039
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:1045
RField(RField &&other)=default
bool * Map(const RClusterIndex &clusterIndex)
Definition: RField.hxx:1033
bool * Map(NTupleSize_t globalIndex)
Definition: RField.hxx:1030
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:1052
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:1051
char * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition: RField.hxx:1193
RField(std::string_view name)
Definition: RField.hxx:1178
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:1213
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:1208
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.hxx:1168
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:1202
char * Map(NTupleSize_t globalIndex)
Definition: RField.hxx:1187
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:1209
RField(RField &&other)=default
char * MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems)
Definition: RField.hxx:1196
char * Map(const RClusterIndex &clusterIndex)
Definition: RField.hxx:1190
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:1157
double * Map(const RClusterIndex &clusterIndex)
Definition: RField.hxx:1138
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.hxx:1116
double * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition: RField.hxx:1141
double * MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems)
Definition: RField.hxx:1144
RField(std::string_view name)
Definition: RField.hxx:1126
double * Map(NTupleSize_t globalIndex)
Definition: RField.hxx:1135
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:1150
RField(RField &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:1161
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:1156
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:1103
RField(RField &&other)=default
float * MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
Definition: RField.hxx:1088
float * MapV(const RClusterIndex &clusterIndex, NTupleSize_t &nItems)
Definition: RField.hxx:1091
RField(std::string_view name)
Definition: RField.hxx:1073
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:1097
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:1108
float * Map(NTupleSize_t globalIndex)
Definition: RField.hxx:1082
float * Map(const RClusterIndex &clusterIndex)
Definition: RField.hxx:1085
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:1104
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition: RField.hxx:1063
Classes with dictionaries that can be inspected by TClass.
Definition: RField.hxx:700
RField(std::string_view name)
Definition: RField.hxx:703
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&...args)
Definition: RField.hxx:712
RField & operator=(RField &&other)=default
RField(RField &&other)=default
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:716
static std::string TypeName()
Definition: RField.hxx:702
~RField() override=default
The on-storage meta-data of an ntuple.
The generic field for std::pair<T1, T2> types.
Definition: RField.hxx:840
~RPairField() override=default
static std::string GetTypeList(const std::array< std::unique_ptr< Detail::RFieldBase >, 2 > &itemFields)
RPairField(RPairField &&other)=default
RPairField & operator=(RPairField &&other)=default
The type-erased field for a RVec<Type>
Definition: RField.hxx:583
void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
Definition: RField.hxx:622
The field for an untyped record.
Definition: RField.hxx:494
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:540
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:541
std::vector< std::size_t > fOffsets
Definition: RField.hxx:498
RRecordField(RRecordField &&other)=default
RRecordField(std::string_view fieldName, std::array< std::unique_ptr< Detail::RFieldBase >, N > &&itemFields, const std::array< std::size_t, N > &offsets, std::string_view typeName="")
Definition: RField.hxx:513
void GenerateColumnsImpl(const RNTupleDescriptor &) final
Creates the backing columns corresponsing to the field type for reading.
Definition: RField.hxx:504
~RRecordField() override=default
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition: RField.hxx:503
RResult<void> has no data member and no Inspect() method but instead a Success() factory method.
Definition: RError.hxx:269
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:207
The generic field for std::tuple<Ts...> types.
Definition: RField.hxx:863
static std::string GetTypeList(const std::vector< std::unique_ptr< Detail::RFieldBase > > &itemFields)
RTupleField & operator=(RTupleField &&other)=default
~RTupleField() override=default
RTupleField(RTupleField &&other)=default
The generic field for std::variant types.
Definition: RField.hxx:660
std::vector< ClusterSize_t::ValueType > fNWritten
Definition: RField.hxx:666
The generic field for a (nested) std::vector<Type> except for std::vector<bool>
Definition: RField.hxx:546
void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) const
Definition: RField.hxx:577
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:571
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition: RVec.hxx:1478
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:81
RooCmdArg Index(RooCategory &icat)
auto Map(Args &&... args)
Create new collection applying a callable to the elements of the input collection.
Definition: RVec.hxx:2096
basic_string_view< char > string_view
#define T2
Definition: md5.inl:147
#define T1
Definition: md5.inl:146
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Definition: RNTupleUtil.hxx:48
RClusterSize ClusterSize_t
Definition: RNTupleUtil.hxx:63
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
Definition: RNTupleUtil.hxx:38
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
constexpr DescriptorId_t kInvalidDescriptorId
void(off) SmallVectorTemplateBase< T
std::string GetDemangledTypeName(const std::type_info &t)
double T(double x)
Definition: ChebyshevPol.h:34
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition: RExports.h:167
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
static constexpr double second
Definition: first.py:1
The point here is that we can only tell at run time if a class has an associated collection proxy.
Definition: RField.hxx:766
Wrap the 32bit integer in a struct in order to avoid template specialization clash with std::uint32_t...
Definition: RNTupleUtil.hxx:51
Helper type to present an offset column as array of collection sizes. See RField<RNTupleCardinality> ...
Definition: RNTupleUtil.hxx:67
Definition: civetweb.c:1856