Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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/RColumnElement.hxx>
21 #include <ROOT/RField.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>
30 #include <TError.h>
31 
32 #include <algorithm>
33 #include <array>
34 #include <iostream>
35 #include <iterator>
36 #include <memory>
37 #include <string>
38 #include <type_traits>
39 #include <typeinfo>
40 #if __cplusplus >= 201703L
41 #include <variant>
42 #endif
43 #include <vector>
44 #include <utility>
45 
46 class TClass;
47 
48 namespace ROOT {
49 namespace Experimental {
50 
51 class RCollectionNTuple;
52 class REntry;
53 class RFieldCollection;
54 class RNTupleModel;
55 
56 namespace Detail {
57 
58 class RFieldFuse;
59 class RNTupleVisitor;
60 class RPageStorage;
61 
62 // clang-format off
63 /**
64 \class ROOT::Experimental::RFieldBase
65 \ingroup NTuple
66 \brief A field translates read and write calls from/to underlying columns to/from tree values
67 
68 A field is a serializable C++ type or a container for a collection of sub fields. The RFieldBase and its
69 type-safe descendants provide the object to column mapper. They map C++ objects to primitive columns. The
70 mapping is trivial for simple types such as 'double'. Complex types resolve to multiple primitive columns.
71 The field knows based on its type and the field name the type(s) and name(s) of the columns.
72 */
73 // clang-format on
74 class RFieldBase {
75  friend class ROOT::Experimental::Detail::RFieldFuse; // to connect the columns to a page storage
76  friend class ROOT::Experimental::RFieldCollection; // to change the field names when collections are attached
77 private:
78  /// The field name relative to its parent field
79  std::string fName;
80  /// The C++ type captured by this field
81  std::string fType;
82  /// The role of this field in the data model structure
83  ENTupleStructure fStructure;
84  /// For fixed sized arrays, the array length
85  std::size_t fNRepetitions;
86  /// A field on a trivial type that maps as-is to a single column
87  bool fIsSimple;
88  /// Describes where the field is located inside the ntuple.
89  struct RLevelInfo {
90  private:
91  /// Tells how deep the field is in the ntuple. Rootfield has fLevel 0, direct subfield of Rootfield has fLevel 1, etc.
92  int fLevel = 1;
93  /// First subfield of parentfield has fOrder 1, the next fOrder 2, etc. Value set by RFieldBase::fOrder
94  int fOrder = 1;
95  /// The field itself is also included in this number.
96  int fNumSiblingFields = 1;
97  public:
98  RLevelInfo() = default;
99  RLevelInfo(const RFieldBase *field) : RLevelInfo() {
100  fLevel = GetLevel(field);
101  fOrder = GetOrder(field);
102  fNumSiblingFields = GetNumSiblings(field);
103  }
104  int GetNumSiblings(const RFieldBase *field = nullptr) const {
105  if (field && field->GetParent())
106  return static_cast<int>(field->GetParent()->fSubFields.size());
107  return fNumSiblingFields;
108  }
109  int GetLevel(const RFieldBase *field = nullptr) const {
110  if(!field)
111  return fLevel;
112  int level{0};
113  const RFieldBase *parentPtr{field->GetParent()};
114  while (parentPtr) {
115  parentPtr = parentPtr->GetParent();
116  ++level;
117  }
118  return level;
119  }
120  int GetOrder(const RFieldBase *field = nullptr) const {
121  if(field)
122  return field->fOrder;
123  return fOrder;
124  }
125  };
126  /// First subfield of parentfield has fOrder 1, the next fOrder 2, etc. Value set by RFieldBase::Attach()
127  int fOrder = 1;
128 protected:
129  /// Collections and classes own sub fields
130  std::vector<std::unique_ptr<RFieldBase>> fSubFields;
131  /// Sub fields point to their mother field
132  RFieldBase* fParent;
133  /// Points into fColumns. All fields that have columns have a distinct main column. For simple fields
134  /// (float, int, ...), the principal column corresponds to the field type. For collection fields expect std::array,
135  /// the main column is the offset field. Class fields have no column of their own.
136  RColumn* fPrincipalColumn;
137  /// The columns are connected either to a sink or to a source (not to both); they are owned by the field.
138  std::vector<std::unique_ptr<RColumn>> fColumns;
139 
140  /// Creates the backing columns corresponsing to the field type and name
141  virtual void DoGenerateColumns() = 0;
142 
143  /// Operations on values of complex types, e.g. ones that involve multiple columns or for which no direct
144  /// column type exists.
145  virtual void DoAppend(const RFieldValue &value);
146  virtual void DoReadGlobal(NTupleSize_t globalIndex, RFieldValue *value);
147  virtual void DoReadInCluster(const RClusterIndex &clusterIndex, RFieldValue *value) {
148  DoReadGlobal(fPrincipalColumn->GetGlobalIndex(clusterIndex), value);
149  }
150 
151 public:
152  /// Iterates over the sub fields in depth-first search order
153  class RIterator : public std::iterator<std::forward_iterator_tag, Detail::RFieldBase> {
154  private:
155  using iterator = RIterator;
156  struct Position {
157  Position() : fFieldPtr(nullptr), fIdxInParent(-1) { }
158  Position(pointer fieldPtr, int idxInParent) : fFieldPtr(fieldPtr), fIdxInParent(idxInParent) { }
159  pointer fFieldPtr;
160  int fIdxInParent;
161  };
162  /// The stack of nodes visited when walking down the tree of fields
163  std::vector<Position> fStack;
164  public:
165  RIterator() { fStack.emplace_back(Position()); }
166  RIterator(pointer val, int idxInParent) { fStack.emplace_back(Position(val, idxInParent)); }
167  ~RIterator() {}
168  /// Given that the iterator points to a valid field which is not the end iterator, go to the next field
169  /// in depth-first search order
170  void Advance();
171 
172  iterator operator++(int) /* postfix */ { auto r = *this; Advance(); return r; }
173  iterator& operator++() /* prefix */ { Advance(); return *this; }
174  reference operator* () const { return *fStack.back().fFieldPtr; }
175  pointer operator->() const { return fStack.back().fFieldPtr; }
176  bool operator==(const iterator& rh) const { return fStack.back().fFieldPtr == rh.fStack.back().fFieldPtr; }
177  bool operator!=(const iterator& rh) const { return fStack.back().fFieldPtr != rh.fStack.back().fFieldPtr; }
178  };
179 
180  /// The constructor creates the underlying column objects and connects them to either a sink or a source.
181  RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple,
182  std::size_t nRepetitions = 0);
183  RFieldBase(const RFieldBase&) = delete;
184  RFieldBase(RFieldBase&&) = default;
185  RFieldBase& operator =(const RFieldBase&) = delete;
186  RFieldBase& operator =(RFieldBase&&) = default;
187  virtual ~RFieldBase();
188 
189  ///// Copies the field and its sub fields using a possibly new name and a new, unconnected set of columns
190  virtual RFieldBase *Clone(std::string_view newName) = 0;
191 
192  /// Factory method to resurrect a field from the stored on-disk type information
193  static RFieldBase *Create(const std::string &fieldName, const std::string &typeName);
194 
195  /// Generates a tree value of the field type and allocates new initialized memory according to the type.
196  RFieldValue GenerateValue();
197  /// Generates a tree value in a given location of size at least GetValueSize(). Assumes that where has been
198  /// allocated by malloc().
199  virtual RFieldValue GenerateValue(void *where) = 0;
200  /// Releases the resources acquired during GenerateValue (memory and constructor)
201  /// This implementation works for simple types but needs to be overwritten for complex ones
202  virtual void DestroyValue(const RFieldValue &value, bool dtorOnly = false);
203  /// Creates a value from a memory location with an already constructed object
204  virtual RFieldValue CaptureValue(void *where) = 0;
205  /// The number of bytes taken by a value of the appropriate type
206  virtual size_t GetValueSize() const = 0;
207  /// For many types, the alignment requirement is equal to the size; otherwise override.
208  virtual size_t GetAlignment() const { return GetValueSize(); }
209 
210  /// Write the given value into columns. The value object has to be of the same type as the field.
211  void Append(const RFieldValue& value) {
212  if (!fIsSimple) {
213  DoAppend(value);
214  return;
215  }
216  //printf("Appending simple value for %lu %s\n", *(unsigned long *)(value.GetRawPtr()), fName.c_str());
217  fPrincipalColumn->Append(value.fMappedElement);
218  }
219 
220  /// Populate a single value with data from the tree, which needs to be of the fitting type.
221  /// Reading copies data into the memory wrapped by the ntuple value.
222  void Read(NTupleSize_t globalIndex, RFieldValue *value) {
223  if (!fIsSimple) {
224  DoReadGlobal(globalIndex, value);
225  return;
226  }
227  fPrincipalColumn->Read(globalIndex, &value->fMappedElement);
228  }
229 
230  void Read(const RClusterIndex &clusterIndex, RFieldValue *value) {
231  if (!fIsSimple) {
232  DoReadInCluster(clusterIndex, value);
233  return;
234  }
235  fPrincipalColumn->Read(clusterIndex, &value->fMappedElement);
236  }
237 
238  /// Ensure that all received items are written from page buffers to the storage.
239  void Flush() const;
240  /// Perform housekeeping tasks for global to cluster-local index translation
241  virtual void CommitCluster() {}
242 
243  void Attach(std::unique_ptr<Detail::RFieldBase> child);
244 
245  std::string GetName() const { return fName; }
246  std::string GetType() const { return fType; }
247  ENTupleStructure GetStructure() const { return fStructure; }
248  std::size_t GetNRepetitions() const { return fNRepetitions; }
249  const RFieldBase* GetParent() const { return fParent; }
250  bool IsSimple() const { return fIsSimple; }
251 
252  /// Indicates an evolution of the mapping scheme from C++ type to columns
253  virtual RNTupleVersion GetFieldVersion() const { return RNTupleVersion(); }
254  /// Indicates an evolution of the C++ type itself
255  virtual RNTupleVersion GetTypeVersion() const { return RNTupleVersion(); }
256 
257  RIterator begin();
258  RIterator end();
259 
260  /// Used for the visitor design pattern, see for example RNTupleReader::Print()
261  virtual void TraverseVisitor(RNTupleVisitor &visitor, int level = 0) const;
262  virtual void AcceptVisitor(RNTupleVisitor &visitor, int level) const;
263 
264  RLevelInfo GetLevelInfo() const {
265  return RLevelInfo(this);
266  }
267  void SetOrder(int o) { fOrder = o; }
268 };
269 
270 // clang-format off
271 /**
272 \class ROOT::Experimental::RFieldFuse
273 \ingroup NTuple
274 \brief A friend of RFieldBase responsible for connecting a field's columns to the physical page storage
275 
276 Fields and their columns live in the void until connected to a physical page storage. Only once connected, data
277 can be read or written.
278 */
279 // clang-format on
280 class RFieldFuse {
281 public:
282  static void Connect(DescriptorId_t fieldId, RPageStorage &pageStorage, RFieldBase &field);
283 };
284 
285 } // namespace Detail
286 
287 
288 
289 /// The container field for an ntuple model, which itself has no physical representation
290 class RFieldRoot : public Detail::RFieldBase {
291 public:
292  RFieldRoot() : Detail::RFieldBase("", "", ENTupleStructure::kRecord, false /* isSimple */) { SetOrder(-1); }
293  RFieldBase* Clone(std::string_view newName);
294 
295  void DoGenerateColumns() final {}
296  using Detail::RFieldBase::GenerateValue;
297  Detail::RFieldValue GenerateValue(void*) { return Detail::RFieldValue(); }
298  Detail::RFieldValue CaptureValue(void*) final { return Detail::RFieldValue(); }
299  size_t GetValueSize() const final { return 0; }
300 
301  /// Generates managed values for the top-level sub fields
302  REntry* GenerateEntry();
303  void AcceptVisitor(Detail::RNTupleVisitor &visitor, int level) const final;
304 };
305 
306 /// The field for a class with dictionary
307 class RFieldClass : public Detail::RFieldBase {
308 private:
309  TClass* fClass;
310  std::size_t fMaxAlignment = 1;
311 
312 protected:
313  void DoAppend(const Detail::RFieldValue& value) final;
314  void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
315  void DoReadInCluster(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final;
316 public:
317  RFieldClass(std::string_view fieldName, std::string_view className);
318  RFieldClass(RFieldClass&& other) = default;
319  RFieldClass& operator =(RFieldClass&& other) = default;
320  ~RFieldClass() = default;
321  RFieldBase* Clone(std::string_view newName) final;
322 
323  void DoGenerateColumns() final;
324  using Detail::RFieldBase::GenerateValue;
325  Detail::RFieldValue GenerateValue(void* where) override;
326  void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final;
327  Detail::RFieldValue CaptureValue(void *where) final;
328  size_t GetValueSize() const override;
329  size_t GetAlignment() const final { return fMaxAlignment; }
330 };
331 
332 /// The generic field for a (nested) std::vector<Type> except for std::vector<bool>
333 class RFieldVector : public Detail::RFieldBase {
334 private:
335  std::size_t fItemSize;
336  ClusterSize_t fNWritten;
337 
338 protected:
339  void DoAppend(const Detail::RFieldValue& value) final;
340  void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
341 
342 public:
343  RFieldVector(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField);
344  RFieldVector(RFieldVector&& other) = default;
345  RFieldVector& operator =(RFieldVector&& other) = default;
346  ~RFieldVector() = default;
347  RFieldBase* Clone(std::string_view newName) final;
348 
349  void DoGenerateColumns() final;
350  using Detail::RFieldBase::GenerateValue;
351  Detail::RFieldValue GenerateValue(void* where) override;
352  void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final;
353  Detail::RFieldValue CaptureValue(void *where) override;
354  size_t GetValueSize() const override { return sizeof(std::vector<char>); }
355  size_t GetAlignment() const final { return std::alignment_of<std::vector<char>>(); }
356  void CommitCluster() final;
357 };
358 
359 
360 /// The generic field for fixed size arrays, which do not need an offset column
361 class RFieldArray : public Detail::RFieldBase {
362 private:
363  std::size_t fItemSize;
364  std::size_t fArrayLength;
365 
366 protected:
367  void DoAppend(const Detail::RFieldValue& value) final;
368  void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
369  void DoReadInCluster(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final;
370 
371 public:
372  RFieldArray(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField, std::size_t arrayLength);
373  RFieldArray(RFieldArray &&other) = default;
374  RFieldArray& operator =(RFieldArray &&other) = default;
375  ~RFieldArray() = default;
376  RFieldBase *Clone(std::string_view newName) final;
377 
378  void DoGenerateColumns() final;
379  using Detail::RFieldBase::GenerateValue;
380  Detail::RFieldValue GenerateValue(void *where) override;
381  void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) final;
382  Detail::RFieldValue CaptureValue(void *where) final;
383  size_t GetValueSize() const final { return fItemSize * fArrayLength; }
384  size_t GetAlignment() const final { return fSubFields[0]->GetAlignment(); }
385 };
386 
387 #if __cplusplus >= 201703L
388 /// The generic field for std::variant types
389 class RFieldVariant : public Detail::RFieldBase {
390 private:
391  size_t fMaxItemSize = 0;
392  size_t fMaxAlignment = 1;
393  /// In the std::variant memory layout, at which byte number is the index stored
394  size_t fTagOffset = 0;
395  std::vector<ClusterSize_t::ValueType> fNWritten;
396 
397  static std::string GetTypeList(const std::vector<Detail::RFieldBase *> &itemFields);
398  /// Extracts the index from an std::variant and transforms it into the 1-based index used for the switch column
399  std::uint32_t GetTag(void *variantPtr) const;
400  void SetTag(void *variantPtr, std::uint32_t tag) const;
401 
402 protected:
403  void DoAppend(const Detail::RFieldValue& value) final;
404  void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
405 
406 public:
407  // TODO(jblomer): use std::span in signature
408  RFieldVariant(std::string_view fieldName, const std::vector<Detail::RFieldBase *> &itemFields);
409  RFieldVariant(RFieldVariant &&other) = default;
410  RFieldVariant& operator =(RFieldVariant &&other) = default;
411  ~RFieldVariant() = default;
412  RFieldBase *Clone(std::string_view newName) final;
413 
414  void DoGenerateColumns() final;
415  using Detail::RFieldBase::GenerateValue;
416  Detail::RFieldValue GenerateValue(void *where) override;
417  void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly = false) final;
418  Detail::RFieldValue CaptureValue(void *where) final;
419  size_t GetValueSize() const final;
420  size_t GetAlignment() const final { return fMaxAlignment; }
421  void CommitCluster() final;
422 };
423 #endif
424 
425 
426 /// Classes with dictionaries that can be inspected by TClass
427 template <typename T, typename=void>
428 class RField : public RFieldClass {
429 public:
430  static std::string TypeName() { return ROOT::Internal::GetDemangledTypeName(typeid(T)); }
431  RField(std::string_view name) : RFieldClass(name, TypeName()) {
432  static_assert(std::is_class<T>::value, "no I/O support for this basic C++ type");
433  }
434  RField(RField&& other) = default;
435  RField& operator =(RField&& other) = default;
436  ~RField() = default;
437 
438  using Detail::RFieldBase::GenerateValue;
439  template <typename... ArgsT>
440  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
441  {
442  return Detail::RFieldValue(this, static_cast<T*>(where), std::forward<ArgsT>(args)...);
443  }
444  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, T()); }
445 };
446 
447 
448 class RFieldCollection : public ROOT::Experimental::Detail::RFieldBase {
449 private:
450  /// Save the link to the collection ntuple in order to reset the offset counter when committing the cluster
451  std::shared_ptr<RCollectionNTuple> fCollectionNTuple;
452 public:
453  static std::string TypeName() { return ":RFieldCollection:"; }
454  RFieldCollection(std::string_view name,
455  std::shared_ptr<RCollectionNTuple> collectionNTuple,
456  std::unique_ptr<RNTupleModel> collectionModel);
457  RFieldCollection(RFieldCollection&& other) = default;
458  RFieldCollection& operator =(RFieldCollection&& other) = default;
459  ~RFieldCollection() = default;
460  RFieldBase* Clone(std::string_view newName) final;
461 
462  void DoGenerateColumns() final;
463 
464  using Detail::RFieldBase::GenerateValue;
465  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final {
466  return Detail::RFieldValue(
467  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>(static_cast<ClusterSize_t*>(where)),
468  this, static_cast<ClusterSize_t*>(where));
469  }
470  Detail::RFieldValue CaptureValue(void* where) final {
471  return Detail::RFieldValue(true /* captureFlag */,
472  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>(static_cast<ClusterSize_t*>(where)), this, where);
473  }
474  size_t GetValueSize() const final { return 0; }
475  void CommitCluster() final;
476 };
477 
478 
479 /// Template specializations for concrete C++ types
480 
481 
482 template <>
483 class RField<ClusterSize_t> : public Detail::RFieldBase {
484 public:
485  static std::string TypeName() { return "ROOT::Experimental::ClusterSize_t"; }
486  explicit RField(std::string_view name)
487  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
488  RField(RField&& other) = default;
489  RField& operator =(RField&& other) = default;
490  ~RField() = default;
491  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
492 
493  void DoGenerateColumns() final;
494 
495  ClusterSize_t *Map(NTupleSize_t globalIndex) {
496  return fPrincipalColumn->Map<ClusterSize_t, EColumnType::kIndex>(globalIndex);
497  }
498  ClusterSize_t *Map(const RClusterIndex &clusterIndex) {
499  return fPrincipalColumn->Map<ClusterSize_t, EColumnType::kIndex>(clusterIndex);
500  }
501 
502  using Detail::RFieldBase::GenerateValue;
503  template <typename... ArgsT>
504  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
505  {
506  return Detail::RFieldValue(
507  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>(static_cast<ClusterSize_t*>(where)),
508  this, static_cast<ClusterSize_t*>(where), std::forward<ArgsT>(args)...);
509  }
510  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
511  Detail::RFieldValue CaptureValue(void *where) final {
512  return Detail::RFieldValue(true /* captureFlag */,
513  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>(static_cast<ClusterSize_t*>(where)), this, where);
514  }
515  size_t GetValueSize() const final { return sizeof(ClusterSize_t); }
516 
517  /// Special help for offset fields
518  void GetCollectionInfo(NTupleSize_t globalIndex, RClusterIndex *collectionStart, ClusterSize_t *size) {
519  fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
520  }
521  void GetCollectionInfo(const RClusterIndex &clusterIndex, RClusterIndex *collectionStart, ClusterSize_t *size) {
522  fPrincipalColumn->GetCollectionInfo(clusterIndex, collectionStart, size);
523  }
524 };
525 
526 
527 template <>
528 class RField<bool> : public Detail::RFieldBase {
529 public:
530  static std::string TypeName() { return "bool"; }
531  explicit RField(std::string_view name)
532  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
533  RField(RField&& other) = default;
534  RField& operator =(RField&& other) = default;
535  ~RField() = default;
536  RFieldBase *Clone(std::string_view newName) final { return new RField(newName); }
537 
538  void DoGenerateColumns() final;
539 
540  bool *Map(NTupleSize_t globalIndex) {
541  return fPrincipalColumn->Map<bool, EColumnType::kBit>(globalIndex);
542  }
543  bool *Map(const RClusterIndex &clusterIndex) {
544  return fPrincipalColumn->Map<bool, EColumnType::kBit>(clusterIndex);
545  }
546 
547  using Detail::RFieldBase::GenerateValue;
548  template <typename... ArgsT>
549  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
550  {
551  return Detail::RFieldValue(
552  Detail::RColumnElement<bool, EColumnType::kBit>(static_cast<bool*>(where)),
553  this, static_cast<bool*>(where), std::forward<ArgsT>(args)...);
554  }
555  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, false); }
556  Detail::RFieldValue CaptureValue(void *where) final {
557  return Detail::RFieldValue(true /* captureFlag */,
558  Detail::RColumnElement<bool, EColumnType::kBit>(static_cast<bool*>(where)), this, where);
559  }
560  size_t GetValueSize() const final { return sizeof(bool); }
561 };
562 
563 template <>
564 class RField<float> : public Detail::RFieldBase {
565 public:
566  static std::string TypeName() { return "float"; }
567  explicit RField(std::string_view name)
568  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
569  RField(RField&& other) = default;
570  RField& operator =(RField&& other) = default;
571  ~RField() = default;
572  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
573 
574  void DoGenerateColumns() final;
575 
576  float *Map(NTupleSize_t globalIndex) {
577  return fPrincipalColumn->Map<float, EColumnType::kReal32>(globalIndex);
578  }
579  float *Map(const RClusterIndex &clusterIndex) {
580  return fPrincipalColumn->Map<float, EColumnType::kReal32>(clusterIndex);
581  }
582 
583  using Detail::RFieldBase::GenerateValue;
584  template <typename... ArgsT>
585  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
586  {
587  return Detail::RFieldValue(
588  Detail::RColumnElement<float, EColumnType::kReal32>(static_cast<float*>(where)),
589  this, static_cast<float*>(where), std::forward<ArgsT>(args)...);
590  }
591  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0.0); }
592  Detail::RFieldValue CaptureValue(void *where) final {
593  return Detail::RFieldValue(true /* captureFlag */,
594  Detail::RColumnElement<float, EColumnType::kReal32>(static_cast<float*>(where)), this, where);
595  }
596  size_t GetValueSize() const final { return sizeof(float); }
597 };
598 
599 
600 template <>
601 class RField<double> : public Detail::RFieldBase {
602 public:
603  static std::string TypeName() { return "double"; }
604  explicit RField(std::string_view name)
605  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
606  RField(RField&& other) = default;
607  RField& operator =(RField&& other) = default;
608  ~RField() = default;
609  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
610 
611  void DoGenerateColumns() final;
612 
613  double *Map(NTupleSize_t globalIndex) {
614  return fPrincipalColumn->Map<double, EColumnType::kReal64>(globalIndex);
615  }
616  double *Map(const RClusterIndex &clusterIndex) {
617  return fPrincipalColumn->Map<double, EColumnType::kReal64>(clusterIndex);
618  }
619 
620  using Detail::RFieldBase::GenerateValue;
621  template <typename... ArgsT>
622  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
623  {
624  return Detail::RFieldValue(
625  Detail::RColumnElement<double, EColumnType::kReal64>(static_cast<double*>(where)),
626  this, static_cast<double*>(where), std::forward<ArgsT>(args)...);
627  }
628  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0.0); }
629  Detail::RFieldValue CaptureValue(void *where) final {
630  return Detail::RFieldValue(true /* captureFlag */,
631  Detail::RColumnElement<double, EColumnType::kReal64>(static_cast<double*>(where)), this, where);
632  }
633  size_t GetValueSize() const final { return sizeof(double); }
634 };
635 
636 template <>
637 class RField<std::uint8_t> : public Detail::RFieldBase {
638 public:
639  static std::string TypeName() { return "std::uint8_t"; }
640  explicit RField(std::string_view name)
641  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
642  RField(RField&& other) = default;
643  RField& operator =(RField&& other) = default;
644  ~RField() = default;
645  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
646 
647  void DoGenerateColumns() final;
648 
649  std::uint8_t *Map(NTupleSize_t globalIndex) {
650  return fPrincipalColumn->Map<std::uint8_t, EColumnType::kByte>(globalIndex);
651  }
652  std::uint8_t *Map(const RClusterIndex &clusterIndex) {
653  return fPrincipalColumn->Map<std::uint8_t, EColumnType::kByte>(clusterIndex);
654  }
655 
656  using Detail::RFieldBase::GenerateValue;
657  template <typename... ArgsT>
658  ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
659  {
660  return Detail::RFieldValue(
661  Detail::RColumnElement<std::uint8_t, EColumnType::kByte>(static_cast<std::uint8_t*>(where)),
662  this, static_cast<std::uint8_t*>(where), std::forward<ArgsT>(args)...);
663  }
664  ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final { return GenerateValue(where, 0); }
665  Detail::RFieldValue CaptureValue(void *where) final {
666  return Detail::RFieldValue(true /* captureFlag */,
667  Detail::RColumnElement<std::uint8_t, EColumnType::kByte>(static_cast<std::uint8_t*>(where)), this, where);
668  }
669  size_t GetValueSize() const final { return sizeof(std::uint8_t); }
670 };
671 
672 template <>
673 class RField<std::int32_t> : public Detail::RFieldBase {
674 public:
675  static std::string TypeName() { return "std::int32_t"; }
676  explicit RField(std::string_view name)
677  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
678  RField(RField&& other) = default;
679  RField& operator =(RField&& other) = default;
680  ~RField() = default;
681  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
682 
683  void DoGenerateColumns() final;
684 
685  std::int32_t *Map(NTupleSize_t globalIndex) {
686  return fPrincipalColumn->Map<std::int32_t, EColumnType::kInt32>(globalIndex);
687  }
688  std::int32_t *Map(const RClusterIndex &clusterIndex) {
689  return fPrincipalColumn->Map<std::int32_t, EColumnType::kInt32>(clusterIndex);
690  }
691 
692  using Detail::RFieldBase::GenerateValue;
693  template <typename... ArgsT>
694  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
695  {
696  return Detail::RFieldValue(
697  Detail::RColumnElement<std::int32_t, EColumnType::kInt32>(static_cast<std::int32_t*>(where)),
698  this, static_cast<std::int32_t*>(where), std::forward<ArgsT>(args)...);
699  }
700  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
701  Detail::RFieldValue CaptureValue(void *where) final {
702  return Detail::RFieldValue(true /* captureFlag */,
703  Detail::RColumnElement<std::int32_t, EColumnType::kInt32>(static_cast<std::int32_t*>(where)), this, where);
704  }
705  size_t GetValueSize() const final { return sizeof(std::int32_t); }
706 };
707 
708 template <>
709 class RField<std::uint32_t> : public Detail::RFieldBase {
710 public:
711  static std::string TypeName() { return "std::uint32_t"; }
712  explicit RField(std::string_view name)
713  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
714  RField(RField&& other) = default;
715  RField& operator =(RField&& other) = default;
716  ~RField() = default;
717  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
718 
719  void DoGenerateColumns() final;
720 
721  std::uint32_t *Map(NTupleSize_t globalIndex) {
722  return fPrincipalColumn->Map<std::uint32_t, EColumnType::kInt32>(globalIndex);
723  }
724  std::uint32_t *Map(const RClusterIndex clusterIndex) {
725  return fPrincipalColumn->Map<std::uint32_t, EColumnType::kInt32>(clusterIndex);
726  }
727 
728  using Detail::RFieldBase::GenerateValue;
729  template <typename... ArgsT>
730  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
731  {
732  return Detail::RFieldValue(
733  Detail::RColumnElement<std::uint32_t, EColumnType::kInt32>(static_cast<std::uint32_t*>(where)),
734  this, static_cast<std::uint32_t*>(where), std::forward<ArgsT>(args)...);
735  }
736  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
737  Detail::RFieldValue CaptureValue(void *where) final {
738  return Detail::RFieldValue(true /* captureFlag */,
739  Detail::RColumnElement<std::uint32_t, EColumnType::kInt32>(static_cast<std::uint32_t*>(where)), this, where);
740  }
741  size_t GetValueSize() const final { return sizeof(std::uint32_t); }
742 };
743 
744 template <>
745 class RField<std::uint64_t> : public Detail::RFieldBase {
746 public:
747  static std::string TypeName() { return "std::uint64_t"; }
748  explicit RField(std::string_view name)
749  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
750  RField(RField&& other) = default;
751  RField& operator =(RField&& other) = default;
752  ~RField() = default;
753  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
754 
755  void DoGenerateColumns() final;
756 
757  std::uint64_t *Map(NTupleSize_t globalIndex) {
758  return fPrincipalColumn->Map<std::uint64_t, EColumnType::kInt64>(globalIndex);
759  }
760  std::uint64_t *Map(const RClusterIndex &clusterIndex) {
761  return fPrincipalColumn->Map<std::uint64_t, EColumnType::kInt64>(clusterIndex);
762  }
763 
764  using Detail::RFieldBase::GenerateValue;
765  template <typename... ArgsT>
766  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
767  {
768  return Detail::RFieldValue(
769  Detail::RColumnElement<std::uint64_t, EColumnType::kInt64>(static_cast<std::uint64_t*>(where)),
770  this, static_cast<std::uint64_t*>(where), std::forward<ArgsT>(args)...);
771  }
772  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
773  Detail::RFieldValue CaptureValue(void *where) final {
774  return Detail::RFieldValue(true /* captureFlag */,
775  Detail::RColumnElement<std::uint64_t, EColumnType::kInt64>(static_cast<std::uint64_t*>(where)), this, where);
776  }
777  size_t GetValueSize() const final { return sizeof(std::uint64_t); }
778 };
779 
780 
781 template <>
782 class RField<std::string> : public Detail::RFieldBase {
783 private:
784  ClusterSize_t fIndex;
785  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> fElemIndex;
786 
787  void DoAppend(const ROOT::Experimental::Detail::RFieldValue& value) final;
788  void DoReadGlobal(ROOT::Experimental::NTupleSize_t globalIndex,
789  ROOT::Experimental::Detail::RFieldValue *value) final;
790 
791 public:
792  static std::string TypeName() { return "std::string"; }
793  explicit RField(std::string_view name)
794  : Detail::RFieldBase(name, TypeName(), ENTupleStructure::kLeaf, false /* isSimple */)
795  , fIndex(0), fElemIndex(&fIndex) {}
796  RField(RField&& other) = default;
797  RField& operator =(RField&& other) = default;
798  ~RField() = default;
799  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
800 
801  void DoGenerateColumns() final;
802 
803  using Detail::RFieldBase::GenerateValue;
804  template <typename... ArgsT>
805  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
806  {
807  return Detail::RFieldValue(this, static_cast<std::string*>(where), std::forward<ArgsT>(args)...);
808  }
809  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, ""); }
810  void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) {
811  auto str = value.Get<std::string>();
812  str->~basic_string(); // TODO(jblomer) C++17 std::destroy_at
813  if (!dtorOnly)
814  free(str);
815  }
816  Detail::RFieldValue CaptureValue(void *where) {
817  return Detail::RFieldValue(true /* captureFlag */, this, where);
818  }
819  size_t GetValueSize() const final { return sizeof(std::string); }
820  size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
821  void CommitCluster() final;
822 };
823 
824 
825 template <typename ItemT, std::size_t N>
826 class RField<std::array<ItemT, N>> : public RFieldArray {
827  using ContainerT = typename std::array<ItemT, N>;
828 public:
829  static std::string TypeName() {
830  return "std::array<" + RField<ItemT>::TypeName() + "," + std::to_string(N) + ">";
831  }
832  explicit RField(std::string_view name)
833  : RFieldArray(name, std::make_unique<RField<ItemT>>(RField<ItemT>::TypeName()), N)
834  {}
835  RField(RField&& other) = default;
836  RField& operator =(RField&& other) = default;
837  ~RField() = default;
838 
839  using Detail::RFieldBase::GenerateValue;
840  template <typename... ArgsT>
841  ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
842  {
843  return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
844  }
845  ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final {
846  return GenerateValue(where, ContainerT());
847  }
848 };
849 
850 
851 #if __cplusplus >= 201703L
852 template <typename... ItemTs>
853 class RField<std::variant<ItemTs...>> : public RFieldVariant {
854  using ContainerT = typename std::variant<ItemTs...>;
855 private:
856  template <typename HeadT, typename... TailTs>
857  static std::string BuildItemTypes()
858  {
859  std::string result = RField<HeadT>::TypeName();
860  if constexpr(sizeof...(TailTs) > 0)
861  result += "," + BuildItemTypes<TailTs...>();
862  return result;
863  }
864 
865  template <typename HeadT, typename... TailTs>
866  static std::vector<Detail::RFieldBase *> BuildItemFields(unsigned int index = 0)
867  {
868  std::vector<Detail::RFieldBase *> result;
869  result.emplace_back(new RField<HeadT>("variant" + std::to_string(index)));
870  if constexpr(sizeof...(TailTs) > 0) {
871  auto tailFields = BuildItemFields<TailTs...>(index + 1);
872  result.insert(result.end(), tailFields.begin(), tailFields.end());
873  }
874  return result;
875  }
876 
877 public:
878  static std::string TypeName() { return "std::variant<" + BuildItemTypes<ItemTs...>() + ">"; }
879  explicit RField(std::string_view name) : RFieldVariant(name, BuildItemFields<ItemTs...>()) {}
880  RField(RField&& other) = default;
881  RField& operator =(RField&& other) = default;
882  ~RField() = default;
883 
884  using Detail::RFieldBase::GenerateValue;
885  template <typename... ArgsT>
886  ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
887  {
888  return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
889  }
890  ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final {
891  return GenerateValue(where, ContainerT());
892  }
893 };
894 #endif
895 
896 template <typename ItemT>
897 class RField<std::vector<ItemT>> : public RFieldVector {
898  using ContainerT = typename std::vector<ItemT>;
899 public:
900  static std::string TypeName() { return "std::vector<" + RField<ItemT>::TypeName() + ">"; }
901  explicit RField(std::string_view name)
902  : RFieldVector(name, std::make_unique<RField<ItemT>>(RField<ItemT>::TypeName()))
903  {}
904  RField(RField&& other) = default;
905  RField& operator =(RField&& other) = default;
906  ~RField() = default;
907 
908  using Detail::RFieldBase::GenerateValue;
909  template <typename... ArgsT>
910  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
911  {
912  return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
913  }
914  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final {
915  return GenerateValue(where, ContainerT());
916  }
917  Detail::RFieldValue CaptureValue(void *where) final {
918  return Detail::RFieldValue(true /* captureFlag */, this, where);
919  }
920  size_t GetValueSize() const final { return sizeof(ContainerT); }
921 };
922 
923 // std::vector<bool> is a template specialization and needs special treatment
924 template <>
925 class RField<std::vector<bool>> : public Detail::RFieldBase {
926 private:
927  ClusterSize_t fNWritten{0};
928 
929 protected:
930  void DoAppend(const Detail::RFieldValue& value) final;
931  void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final;
932  void DoGenerateColumns() final;
933 
934 public:
935  static std::string TypeName() { return "std::vector<bool>"; }
936  explicit RField(std::string_view name);
937  RField(RField&& other) = default;
938  RField& operator =(RField&& other) = default;
939  ~RField() = default;
940  RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
941 
942  using Detail::RFieldBase::GenerateValue;
943  template <typename... ArgsT>
944  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
945  {
946  return Detail::RFieldValue(this, static_cast<std::vector<bool>*>(where), std::forward<ArgsT>(args)...);
947  }
948  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final {
949  return GenerateValue(where, std::vector<bool>());
950  }
951  Detail::RFieldValue CaptureValue(void *where) final {
952  return Detail::RFieldValue(true /* captureFlag */, this, where);
953  }
954  void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final;
955 
956  size_t GetValueSize() const final { return sizeof(std::vector<bool>); }
957  size_t GetAlignment() const final { return std::alignment_of<std::vector<bool>>(); }
958  void CommitCluster() final { fNWritten = 0; }
959 };
960 
961 
962 /**
963  * The RVec type has different layouts depending on the item type, therefore we cannot go with a generic
964  * RVec implementation as we can with std::vector
965  */
966 template <typename ItemT>
967 class RField<ROOT::VecOps::RVec<ItemT>> : public Detail::RFieldBase {
968  using ContainerT = typename ROOT::VecOps::RVec<ItemT>;
969 private:
970  size_t fItemSize;
971  ClusterSize_t fNWritten;
972 
973 protected:
974  void DoAppend(const Detail::RFieldValue& value) final {
975  auto typedValue = value.Get<ContainerT>();
976  auto count = typedValue->size();
977  for (unsigned i = 0; i < count; ++i) {
978  auto itemValue = fSubFields[0]->CaptureValue(&typedValue->data()[i]);
979  fSubFields[0]->Append(itemValue);
980  }
981  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> elemIndex(&fNWritten);
982  fNWritten += count;
983  fColumns[0]->Append(elemIndex);
984  }
985  void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final {
986  auto typedValue = value->Get<ContainerT>();
987  ClusterSize_t nItems;
988  RClusterIndex collectionStart;
989  fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
990  typedValue->resize(nItems);
991  for (unsigned i = 0; i < nItems; ++i) {
992  auto itemValue = fSubFields[0]->GenerateValue(&typedValue->data()[i]);
993  fSubFields[0]->Read(collectionStart + i, &itemValue);
994  }
995  }
996 
997 public:
998  RField(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
999  : ROOT::Experimental::Detail::RFieldBase(
1000  fieldName, "ROOT::VecOps::RVec<" + itemField->GetType() + ">", ENTupleStructure::kCollection, false)
1001  , fItemSize(itemField->GetValueSize()), fNWritten(0)
1002  {
1003  Attach(std::move(itemField));
1004  }
1005  explicit RField(std::string_view name)
1006  : RField(name, std::make_unique<RField<ItemT>>(RField<ItemT>::TypeName()))
1007  {
1008  }
1009  RField(RField&& other) = default;
1010  RField& operator =(RField&& other) = default;
1011  ~RField() = default;
1012  RFieldBase* Clone(std::string_view newName) final {
1013  auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
1014  return new RField<ROOT::VecOps::RVec<ItemT>>(newName, std::unique_ptr<Detail::RFieldBase>(newItemField));
1015  }
1016 
1017  void DoGenerateColumns() final {
1018  RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
1019  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
1020  Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
1021  fPrincipalColumn = fColumns[0].get();
1022  }
1023  void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final {
1024  auto vec = reinterpret_cast<ContainerT*>(value.GetRawPtr());
1025  auto nItems = vec->size();
1026  for (unsigned i = 0; i < nItems; ++i) {
1027  auto itemValue = fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize));
1028  fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1029  }
1030  vec->~RVec();
1031  if (!dtorOnly)
1032  free(vec);
1033  }
1034  void CommitCluster() final { fNWritten = 0; }
1035 
1036  static std::string TypeName() { return "ROOT::VecOps::RVec<" + RField<ItemT>::TypeName() + ">"; }
1037 
1038  using Detail::RFieldBase::GenerateValue;
1039  template <typename... ArgsT>
1040  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
1041  {
1042  return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
1043  }
1044  ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final {
1045  return GenerateValue(where, ContainerT());
1046  }
1047  Detail::RFieldValue CaptureValue(void *where) final {
1048  return Detail::RFieldValue(true /* captureFlag */, this, static_cast<ContainerT*>(where));
1049  }
1050  size_t GetValueSize() const final { return sizeof(ContainerT); }
1051  size_t GetAlignment() const final { return std::alignment_of<ContainerT>(); }
1052 };
1053 
1054 /**
1055  * RVec<bool> needs special treatment due to std::vector<bool> sepcialization
1056  */
1057 template <>
1058 class RField<ROOT::VecOps::RVec<bool>> : public Detail::RFieldBase {
1059  using ContainerT = typename ROOT::VecOps::RVec<bool>;
1060 private:
1061  ClusterSize_t fNWritten{0};
1062 
1063 protected:
1064  void DoAppend(const Detail::RFieldValue& value) final {
1065  auto typedValue = value.Get<ContainerT>();
1066  auto count = typedValue->size();
1067  for (unsigned i = 0; i < count; ++i) {
1068  bool bval = (*typedValue)[i];
1069  auto itemValue = fSubFields[0]->CaptureValue(&bval);
1070  fSubFields[0]->Append(itemValue);
1071  }
1072  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> elemIndex(&fNWritten);
1073  fNWritten += count;
1074  fColumns[0]->Append(elemIndex);
1075  }
1076  void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final {
1077  auto typedValue = value->Get<ContainerT>();
1078  ClusterSize_t nItems;
1079  RClusterIndex collectionStart;
1080  fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1081  typedValue->resize(nItems);
1082  for (unsigned i = 0; i < nItems; ++i) {
1083  bool bval = (*typedValue)[i];
1084  auto itemValue = fSubFields[0]->GenerateValue(&bval);
1085  fSubFields[0]->Read(collectionStart + i, &itemValue);
1086  (*typedValue)[i] = bval;
1087  }
1088  }
1089 
1090 public:
1091  RField(std::string_view name)
1092  : ROOT::Experimental::Detail::RFieldBase(name, "ROOT::VecOps::RVec<bool>", ENTupleStructure::kCollection, false)
1093  {
1094  Attach(std::make_unique<RField<bool>>("bool"));
1095  }
1096  RField(RField&& other) = default;
1097  RField& operator =(RField&& other) = default;
1098  ~RField() = default;
1099  RFieldBase* Clone(std::string_view newName) final {
1100  return new RField<ROOT::VecOps::RVec<bool>>(newName);
1101  }
1102 
1103  void DoGenerateColumns() final {
1104  RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
1105  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
1106  Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
1107  fPrincipalColumn = fColumns[0].get();
1108  }
1109  void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final {
1110  auto vec = reinterpret_cast<ContainerT*>(value.GetRawPtr());
1111  vec->~RVec();
1112  if (!dtorOnly)
1113  free(vec);
1114  }
1115  void CommitCluster() final { fNWritten = 0; }
1116 
1117  static std::string TypeName() { return "ROOT::VecOps::RVec<bool>"; }
1118 
1119  using Detail::RFieldBase::GenerateValue;
1120  template <typename... ArgsT>
1121  ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT&&... args)
1122  {
1123  return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
1124  }
1125  ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final {
1126  return GenerateValue(where, ContainerT());
1127  }
1128  Detail::RFieldValue CaptureValue(void *where) final {
1129  return Detail::RFieldValue(true /* captureFlag */, this, static_cast<ContainerT*>(where));
1130  }
1131  size_t GetValueSize() const final { return sizeof(ContainerT); }
1132  size_t GetAlignment() const final { return std::alignment_of<ContainerT>(); }
1133 };
1134 
1135 } // namespace Experimental
1136 } // namespace ROOT
1137 
1138 #endif