Logo ROOT   6.18/05
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>
21#include <ROOT/RField.hxx>
22#include <ROOT/RFieldValue.hxx>
23#include <ROOT/RNTupleUtil.hxx>
24#include <ROOT/RStringView.hxx>
25#include <ROOT/RVec.hxx>
26#include <ROOT/TypeTraits.hxx>
27
28#include <TGenericClassInfo.h>
29#include <TError.h>
30
31#include <algorithm>
32#include <iostream>
33#include <iterator>
34#include <memory>
35#include <string>
36#include <type_traits>
37#include <typeinfo>
38#include <vector>
39#include <utility>
40
41class TClass;
42
43namespace ROOT {
44namespace Experimental {
45
46class RCollectionNTuple;
47class REntry;
48class RNTupleModel;
49class RFieldCollection;
50
51namespace Detail {
52
53class RPageStorage;
54
55// clang-format off
56/**
57\class ROOT::Experimental::RFieldBase
58\ingroup NTuple
59\brief A field translates read and write calls from/to underlying columns to/from tree values
60
61A field is a serializable C++ type or a container for a collection of sub fields. The RFieldBase and its
62type-safe descendants provide the object to column mapper. They map C++ objects to primitive columns. The
63mapping is trivial for simple types such as 'double'. Complex types resolve to multiple primitive columns.
64The field knows based on its type and the field name the type(s) and name(s) of the columns.
65*/
66// clang-format on
68 friend class ROOT::Experimental::RFieldCollection; // to change the field names when collections are attached
69private:
70 /// The field name is a unique within a tree and also the basis for the column name(s)
71 std::string fName;
72 /// The C++ type captured by this field
73 std::string fType;
74 /// The role of this field in the data model structure
76 /// A field on a trivial type that maps as-is to a single column
78
79protected:
80 /// Collections and classes own sub fields
81 std::vector<std::unique_ptr<RFieldBase>> fSubFields;
82 /// Sub fields point to their mother field
84 /// All fields have a main column. For collection fields, the main column is the index field. Points into fColumns.
86 /// The columns are connected either to a sink or to a source (not to both); they are owned by the field.
87 std::vector<std::unique_ptr<RColumn>> fColumns;
88
89 /// Creates the backing columns corresponsing to the field type and name
90 virtual void DoGenerateColumns() = 0;
91
92 /// Operations on values of complex types, e.g. ones that involve multiple columns or for which no direct
93 /// column type exists.
94 virtual void DoAppend(const RFieldValue& value);
95 virtual void DoRead(NTupleSize_t index, RFieldValue* value);
96 virtual void DoReadV(NTupleSize_t index, NTupleSize_t count, void* dst);
97
98public:
99 /// Field names convey the level of subfields; sub fields (nested collections) are separated by a dot
100 static constexpr char kCollectionSeparator = '/';
101
102 /// Iterates over the sub fields in depth-first search order
103 class RIterator : public std::iterator<std::forward_iterator_tag, Detail::RFieldBase> {
104 private:
106 struct Position {
107 Position() : fFieldPtr(nullptr), fIdxInParent(-1) { }
108 Position(pointer fieldPtr, int idxInParent) : fFieldPtr(fieldPtr), fIdxInParent(idxInParent) { }
109 pointer fFieldPtr;
111 };
112 /// The stack of nodes visited when walking down the tree of fields
113 std::vector<Position> fStack;
114 public:
115 RIterator() { fStack.emplace_back(Position()); }
116 RIterator(pointer val, int idxInParent) { fStack.emplace_back(Position(val, idxInParent)); }
118 /// Given that the iterator points to a valid field which is not the end iterator, go to the next field
119 /// in depth-first search order
120 void Advance();
121
122 iterator operator++(int) /* postfix */ { auto r = *this; Advance(); return r; }
123 iterator& operator++() /* prefix */ { Advance(); return *this; }
124 reference operator* () const { return *fStack.back().fFieldPtr; }
125 pointer operator->() const { return fStack.back().fFieldPtr; }
126 bool operator==(const iterator& rh) const { return fStack.back().fFieldPtr == rh.fStack.back().fFieldPtr; }
127 bool operator!=(const iterator& rh) const { return fStack.back().fFieldPtr != rh.fStack.back().fFieldPtr; }
128 };
129
130 /// The constructor creates the underlying column objects and connects them to either a sink or a source.
132 RFieldBase(const RFieldBase&) = delete;
133 RFieldBase(RFieldBase&&) = default;
136 virtual ~RFieldBase();
137
138 ///// Copies the field and its sub fields using a possibly new name and a new, unconnected set of columns
139 virtual RFieldBase* Clone(std::string_view newName) = 0;
140
141 /// Factory method to resurrect a field from the stored on-disk type information
142 static RFieldBase *Create(const std::string &fieldName, const std::string &typeName);
143 /// Get the tail of the field name up to the last dot
144 static std::string GetLeafName(const std::string &fullName);
145 /// Get the name for an item sub field that is part of a collection, e.g. the float field of std::vector<float>
146 static std::string GetCollectionName(const std::string &parentName);
147
148 /// Registeres (or re-registers) the backing columns with the physical storage
149 void ConnectColumns(Detail::RPageStorage *pageStorage);
150 /// Returns the number of columns generated to store data for the field; defaults to 1
151 virtual unsigned int GetNColumns() const = 0;
152
153 /// Generates a tree value of the field type and allocates new initialized memory according to the type.
155 /// Generates a tree value in a given location of size at least GetValueSize(). Assumes that where has been
156 /// allocated by malloc().
157 virtual RFieldValue GenerateValue(void *where) = 0;
158 /// Releases the resources acquired during GenerateValue (memory and constructor)
159 /// This implementation works for simple types but needs to be overwritten for complex ones
160 virtual void DestroyValue(const RFieldValue &value, bool dtorOnly = false);
161 /// Creates a value from a memory location with an already constructed object
162 virtual RFieldValue CaptureValue(void *where) = 0;
163 /// The number of bytes taken by a value of the appropriate type
164 virtual size_t GetValueSize() const = 0;
165
166 /// Write the given value into columns. The value object has to be of the same type as the field.
167 void Append(const RFieldValue& value) {
168 if (!fIsSimple) {
169 DoAppend(value);
170 return;
171 }
172 //printf("Appending simple value for %lu %s\n", *(unsigned long *)(value.GetRawPtr()), fName.c_str());
174 }
175
176 /// Populate a single value with data from the tree, which needs to be of the fitting type.
177 /// Reading copies data into the memory wrapped by the tree value.
178 void Read(NTupleSize_t index, RFieldValue* value) {
179 if (!fIsSimple) {
180 DoRead(index, value);
181 return;
182 }
183 fPrincipalColumn->Read(index, &value->fMappedElement);
184 }
185
186 /// Type unsafe bulk read interface; dst must point to a vector of objects of the field type.
187 /// TODO(jblomer): can this be type safe?
188 void ReadV(NTupleSize_t index, NTupleSize_t count, void *dst)
189 {
190 if (!fIsSimple) {
191 DoReadV(index, count, dst);
192 return;
193 }
194 //fPrincipalColumn->ReadV(index, count, dst);
195 }
196
197 /// The number of elements in the principal column. For top level fields, the number of entries.
199
200 /// Ensure that all received items are written from page buffers to the storage.
201 void Flush() const;
202 /// Perform housekeeping tasks for global to cluster-local index translation
203 virtual void CommitCluster() {}
204
205 void Attach(std::unique_ptr<Detail::RFieldBase> child);
206
207 std::string GetName() const { return fName; }
208 std::string GetType() const { return fType; }
210 const RFieldBase* GetParent() const { return fParent; }
211 bool IsSimple() const { return fIsSimple; }
212
213 /// Indicates an evolution of the mapping scheme from C++ type to columns
214 virtual RNTupleVersion GetFieldVersion() const { return RNTupleVersion(); }
215 /// Indicates an evolution of the C++ type itself
216 virtual RNTupleVersion GetTypeVersion() const { return RNTupleVersion(); }
217
218 RIterator begin();
219 RIterator end();
220};
221
222} // namespace Detail
223
224/// The container field for a tree model, which itself has no physical representation
226public:
227 RFieldRoot() : Detail::RFieldBase("", "", ENTupleStructure::kRecord, false /* isSimple */) {}
229
230 void DoGenerateColumns() final {}
231 unsigned int GetNColumns() const final { return 0; }
235 size_t GetValueSize() const final { return 0; }
236
237 /// Generates managed values for the top-level sub fields
239};
240
241/// The field for a class with dictionary
243private:
245protected:
246 void DoAppend(const Detail::RFieldValue& value) final;
247 void DoRead(NTupleSize_t index, Detail::RFieldValue* value) final;
248public:
249 RFieldClass(std::string_view fieldName, std::string_view className);
250 RFieldClass(RFieldClass&& other) = default;
251 RFieldClass& operator =(RFieldClass&& other) = default;
252 ~RFieldClass() = default;
253 RFieldBase* Clone(std::string_view newName) final;
254
255 void DoGenerateColumns() final;
256 unsigned int GetNColumns() const final;
257 using Detail::RFieldBase::GenerateValue;
258 Detail::RFieldValue GenerateValue(void* where) override;
259 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final;
260 Detail::RFieldValue CaptureValue(void *where) final;
261 size_t GetValueSize() const override;
262};
263
264/// The generic field for a (nested) std::vector<Type>
265class RFieldVector : public Detail::RFieldBase {
266private:
267 size_t fItemSize;
269
270protected:
271 void DoAppend(const Detail::RFieldValue& value) final;
272 void DoRead(NTupleSize_t index, Detail::RFieldValue* value) final;
273
274public:
275 RFieldVector(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField);
276 RFieldVector(RFieldVector&& other) = default;
278 ~RFieldVector() = default;
279 RFieldBase* Clone(std::string_view newName) final;
280
281 void DoGenerateColumns() final;
282 unsigned int GetNColumns() const final;
283 using Detail::RFieldBase::GenerateValue;
284 Detail::RFieldValue GenerateValue(void* where) override;
285 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final;
286 Detail::RFieldValue CaptureValue(void *where) override;
287 size_t GetValueSize() const override;
288 void CommitCluster() final;
289};
290
291
292/// Classes with dictionaries that can be inspected by TClass
293template <typename T, typename=void>
294class RField : public RFieldClass {
295public:
296 static std::string MyTypeName() { return ROOT::Internal::GetDemangledTypeName(typeid(T)); }
298 static_assert(std::is_class<T>::value, "no I/O support for this basic C++ type");
299 }
300 RField(RField&& other) = default;
301 RField& operator =(RField&& other) = default;
302 ~RField() = default;
303
305 template <typename... ArgsT>
307 {
308 return Detail::RFieldValue(this, static_cast<T*>(where), std::forward<ArgsT>(args)...);
309 }
311};
312
313
315private:
316 /// Save the link to the collection ntuple in order to reset the offset counter when committing the cluster
317 std::shared_ptr<RCollectionNTuple> fCollectionNTuple;
318public:
319 static std::string MyTypeName() { return ":RFieldCollection:"; }
321 std::shared_ptr<RCollectionNTuple> collectionNTuple,
322 std::unique_ptr<RNTupleModel> collectionModel);
325 ~RFieldCollection() = default;
326 RFieldBase* Clone(std::string_view newName) final;
327
328 void DoGenerateColumns() final;
329 unsigned int GetNColumns() const final { return 1; }
330
333 return Detail::RFieldValue(
335 this, static_cast<ClusterSize_t*>(where));
336 }
338 return Detail::RFieldValue(true /* captureFlag */,
340 }
341 size_t GetValueSize() const final { return 0; }
342 void CommitCluster() final;
343};
344
345
346/// Template specializations for concrete C++ types
347
348
349template <>
350class RField<ClusterSize_t> : public Detail::RFieldBase {
351public:
352 static std::string MyTypeName() { return "ROOT::Experimental::ClusterSize_t"; }
354 : Detail::RFieldBase(name, MyTypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
355 RField(RField&& other) = default;
356 RField& operator =(RField&& other) = default;
357 ~RField() = default;
358 RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
359
360 void DoGenerateColumns() final;
361 unsigned int GetNColumns() const final { return 1; }
362
365 "(ClusterSize_t, EColumnType::kIndex) is not identical on this platform");
366 return fPrincipalColumn->Map<ClusterSize_t, EColumnType::kIndex>(index, nullptr);
367 }
368
370 template <typename... ArgsT>
372 {
373 return Detail::RFieldValue(
375 this, static_cast<ClusterSize_t*>(where), std::forward<ArgsT>(args)...);
376 }
379 return Detail::RFieldValue(true /* captureFlag */,
381 }
382 size_t GetValueSize() const final { return sizeof(ClusterSize_t); }
383
384 /// Special help for offset fields
386 fPrincipalColumn->GetCollectionInfo(index, idxStart, size);
387 }
388};
389
390
391template <>
392class RField<float> : public Detail::RFieldBase {
393public:
394 static std::string MyTypeName() { return "float"; }
396 : Detail::RFieldBase(name, MyTypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
397 RField(RField&& other) = default;
398 RField& operator =(RField&& other) = default;
399 ~RField() = default;
400 RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
401
402 void DoGenerateColumns() final;
403 unsigned int GetNColumns() const final { return 1; }
404
405 float* Map(NTupleSize_t index) {
407 "(float, EColumnType::kReal32) is not identical on this platform");
408 return fPrincipalColumn->Map<float, EColumnType::kReal32>(index, nullptr);
409 }
410
412 template <typename... ArgsT>
414 {
415 return Detail::RFieldValue(
416 Detail::RColumnElement<float, EColumnType::kReal32>(static_cast<float*>(where)),
417 this, static_cast<float*>(where), std::forward<ArgsT>(args)...);
418 }
419 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0.0); }
421 return Detail::RFieldValue(true /* captureFlag */,
422 Detail::RColumnElement<float, EColumnType::kReal32>(static_cast<float*>(where)), this, where);
423 }
424 size_t GetValueSize() const final { return sizeof(float); }
425};
426
427
428template <>
429class RField<double> : public Detail::RFieldBase {
430public:
431 static std::string MyTypeName() { return "double"; }
433 : Detail::RFieldBase(name, MyTypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
434 RField(RField&& other) = default;
435 RField& operator =(RField&& other) = default;
436 ~RField() = default;
437 RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
438
439 void DoGenerateColumns() final;
440 unsigned int GetNColumns() const final { return 1; }
441
442 double* Map(NTupleSize_t index) {
444 "(double, EColumnType::kReal64) is not identical on this platform");
445 return fPrincipalColumn->Map<double, EColumnType::kReal64>(index, nullptr);
446 }
447
449 template <typename... ArgsT>
451 {
452 return Detail::RFieldValue(
453 Detail::RColumnElement<double, EColumnType::kReal64>(static_cast<double*>(where)),
454 this, static_cast<double*>(where), std::forward<ArgsT>(args)...);
455 }
456 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0.0); }
458 return Detail::RFieldValue(true /* captureFlag */,
459 Detail::RColumnElement<double, EColumnType::kReal64>(static_cast<double*>(where)), this, where);
460 }
461 size_t GetValueSize() const final { return sizeof(double); }
462};
463
464template <>
465class RField<std::int32_t> : public Detail::RFieldBase {
466public:
467 static std::string MyTypeName() { return "std::int32_t"; }
468 explicit RField(std::string_view name)
469 : Detail::RFieldBase(name, MyTypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
470 RField(RField&& other) = default;
471 RField& operator =(RField&& other) = default;
472 ~RField() = default;
473 RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
474
475 void DoGenerateColumns() final;
476 unsigned int GetNColumns() const final { return 1; }
477
478 std::int32_t* Map(NTupleSize_t index) {
479 static_assert(Detail::RColumnElement<std::int32_t, EColumnType::kInt32>::kIsMappable,
480 "(std::int32_t, EColumnType::kInt32) is not identical on this platform");
481 return fPrincipalColumn->Map<std::int32_t, EColumnType::kInt32>(index, nullptr);
482 }
483
485 template <typename... ArgsT>
486 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
487 {
488 return Detail::RFieldValue(
489 Detail::RColumnElement<std::int32_t, EColumnType::kInt32>(static_cast<std::int32_t*>(where)),
490 this, static_cast<std::int32_t*>(where), std::forward<ArgsT>(args)...);
491 }
492 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
493 Detail::RFieldValue CaptureValue(void *where) final {
494 return Detail::RFieldValue(true /* captureFlag */,
495 Detail::RColumnElement<std::int32_t, EColumnType::kInt32>(static_cast<std::int32_t*>(where)), this, where);
496 }
497 size_t GetValueSize() const final { return sizeof(std::int32_t); }
498};
499
500template <>
501class RField<std::uint32_t> : public Detail::RFieldBase {
502public:
503 static std::string MyTypeName() { return "std::uint32_t"; }
504 explicit RField(std::string_view name)
505 : Detail::RFieldBase(name, MyTypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
506 RField(RField&& other) = default;
507 RField& operator =(RField&& other) = default;
508 ~RField() = default;
509 RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
510
511 void DoGenerateColumns() final;
512 unsigned int GetNColumns() const final { return 1; }
513
514 std::uint32_t* Map(NTupleSize_t index) {
515 static_assert(Detail::RColumnElement<std::uint32_t, EColumnType::kInt32>::kIsMappable,
516 "(std::uint32_t, EColumnType::kInt32) is not identical on this platform");
517 return fPrincipalColumn->Map<std::uint32_t, EColumnType::kInt32>(index, nullptr);
518 }
519
521 template <typename... ArgsT>
522 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
523 {
524 return Detail::RFieldValue(
525 Detail::RColumnElement<std::uint32_t, EColumnType::kInt32>(static_cast<std::uint32_t*>(where)),
526 this, static_cast<std::uint32_t*>(where), std::forward<ArgsT>(args)...);
527 }
528 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
529 Detail::RFieldValue CaptureValue(void *where) final {
530 return Detail::RFieldValue(true /* captureFlag */,
531 Detail::RColumnElement<std::uint32_t, EColumnType::kInt32>(static_cast<std::uint32_t*>(where)), this, where);
532 }
533 size_t GetValueSize() const final { return sizeof(std::uint32_t); }
534};
535
536template <>
537class RField<std::uint64_t> : public Detail::RFieldBase {
538public:
539 static std::string MyTypeName() { return "std::uint64_t"; }
540 explicit RField(std::string_view name)
541 : Detail::RFieldBase(name, MyTypeName(), ENTupleStructure::kLeaf, true /* isSimple */) {}
542 RField(RField&& other) = default;
543 RField& operator =(RField&& other) = default;
544 ~RField() = default;
545 RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
546
547 void DoGenerateColumns() final;
548 unsigned int GetNColumns() const final { return 1; }
549
550 std::uint64_t* Map(NTupleSize_t index) {
551 static_assert(Detail::RColumnElement<std::uint64_t, EColumnType::kInt64>::kIsMappable,
552 "(std::uint64_t, EColumnType::kInt64) is not identical on this platform");
553 return fPrincipalColumn->Map<std::uint64_t, EColumnType::kInt64>(index, nullptr);
554 }
555
557 template <typename... ArgsT>
558 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
559 {
560 return Detail::RFieldValue(
561 Detail::RColumnElement<std::uint64_t, EColumnType::kInt64>(static_cast<std::uint64_t*>(where)),
562 this, static_cast<std::uint64_t*>(where), std::forward<ArgsT>(args)...);
563 }
564 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, 0); }
565 Detail::RFieldValue CaptureValue(void *where) final {
566 return Detail::RFieldValue(true /* captureFlag */,
567 Detail::RColumnElement<std::uint64_t, EColumnType::kInt64>(static_cast<std::uint64_t*>(where)), this, where);
568 }
569 size_t GetValueSize() const final { return sizeof(std::uint64_t); }
570};
571
572
573template <>
574class RField<std::string> : public Detail::RFieldBase {
575private:
576 ClusterSize_t fIndex;
577 Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> fElemIndex;
578
579 void DoAppend(const ROOT::Experimental::Detail::RFieldValue& value) final;
581
582public:
583 static std::string MyTypeName() { return "std::string"; }
584 explicit RField(std::string_view name)
585 : Detail::RFieldBase(name, MyTypeName(), ENTupleStructure::kLeaf, false /* isSimple */)
586 , fIndex(0), fElemIndex(&fIndex) {}
587 RField(RField&& other) = default;
588 RField& operator =(RField&& other) = default;
589 ~RField() = default;
590 RFieldBase* Clone(std::string_view newName) final { return new RField(newName); }
591
592 void DoGenerateColumns() final;
593 unsigned int GetNColumns() const final { return 2; }
594
596 template <typename... ArgsT>
597 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
598 {
599 return Detail::RFieldValue(this, static_cast<std::string*>(where), std::forward<ArgsT>(args)...);
600 }
601 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where) final { return GenerateValue(where, ""); }
602 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) {
603 auto str = value.Get<std::string>();
604 str->~basic_string(); // TODO(jblomer) C++17 std::destroy_at
605 if (!dtorOnly)
606 free(str);
607 }
608 Detail::RFieldValue CaptureValue(void *where) {
609 return Detail::RFieldValue(true /* captureFlag */, this, where);
610 }
611 size_t GetValueSize() const final { return sizeof(std::string); }
612 void CommitCluster() final;
613};
614
615
616template <typename ItemT>
617class RField<std::vector<ItemT>> : public RFieldVector {
618 using ContainerT = typename std::vector<ItemT>;
619public:
620 static std::string MyTypeName() { return "std::vector<" + RField<ItemT>::MyTypeName() + ">"; }
621 explicit RField(std::string_view name)
622 : RFieldVector(name, std::make_unique<RField<ItemT>>(GetCollectionName(std::string(name))))
623 {}
624 RField(RField&& other) = default;
625 RField& operator =(RField&& other) = default;
626 ~RField() = default;
627
629 template <typename... ArgsT>
630 ROOT::Experimental::Detail::RFieldValue GenerateValue(void* where, ArgsT&&... args)
631 {
632 return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
633 }
635 return GenerateValue(where, ContainerT());
636 }
637 Detail::RFieldValue CaptureValue(void *where) final {
638 return Detail::RFieldValue(true /* captureFlag */, this, where);
639 }
640 size_t GetValueSize() const final { return sizeof(ContainerT); }
641};
642
643
644/**
645 * The RVec type has different layouts depending on the item type, therefore we cannot go with a generic
646 * RVec implementation as we can with std::vector
647 */
648template <typename ItemT>
651private:
652 size_t fItemSize;
654
655protected:
656 void DoAppend(const Detail::RFieldValue& value) final {
657 auto typedValue = value.Get<ContainerT>();
658 auto count = typedValue->size();
659 for (unsigned i = 0; i < count; ++i) {
660 auto itemValue = fSubFields[0]->CaptureValue(&typedValue->data()[i]);
661 fSubFields[0]->Append(itemValue);
662 }
664 fNWritten += count;
665 fColumns[0]->Append(elemIndex);
666 }
667 void DoRead(NTupleSize_t index, Detail::RFieldValue* value) final {
668 auto typedValue = value->Get<ContainerT>();
669 ClusterSize_t nItems;
670 NTupleSize_t idxStart;
671 fPrincipalColumn->GetCollectionInfo(index, &idxStart, &nItems);
672 typedValue->resize(nItems);
673 for (unsigned i = 0; i < nItems; ++i) {
674 auto itemValue = fSubFields[0]->GenerateValue(&typedValue->data()[i]);
675 fSubFields[0]->Read(idxStart + i, &itemValue);
676 }
677 }
678
679public:
680 RField(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
681 : ROOT::Experimental::Detail::RFieldBase(
682 fieldName, "ROOT::VecOps::RVec<" + itemField->GetType() + ">", ENTupleStructure::kCollection, false)
683 , fItemSize(itemField->GetValueSize()), fNWritten(0)
684 {
685 Attach(std::move(itemField));
686 }
688 : RField(name, std::make_unique<RField<ItemT>>(GetCollectionName(std::string(name))))
689 {
690 }
691 RField(RField&& other) = default;
692 RField& operator =(RField&& other) = default;
693 ~RField() = default;
695 auto newItemField = fSubFields[0]->Clone(GetCollectionName(std::string(newName)));
696 return new RField<ROOT::VecOps::RVec<ItemT>>(newName, std::unique_ptr<Detail::RFieldBase>(newItemField));
697 }
698
699 void DoGenerateColumns() final {
700 RColumnModel modelIndex(GetName(), EColumnType::kIndex, true /* isSorted*/);
701 fColumns.emplace_back(std::make_unique<Detail::RColumn>(modelIndex));
702 fPrincipalColumn = fColumns[0].get();
703 }
704 unsigned int GetNColumns() const final { return 1; }
705 void DestroyValue(const Detail::RFieldValue& value, bool dtorOnly = false) final {
706 auto vec = reinterpret_cast<ContainerT*>(value.GetRawPtr());
707 auto nItems = vec->size();
708 for (unsigned i = 0; i < nItems; ++i) {
709 auto itemValue = fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize));
710 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
711 }
712 vec->~RVec();
713 if (!dtorOnly)
714 free(vec);
715 }
716 void CommitCluster() final { fNWritten = 0; }
717
718 static std::string MyTypeName() { return "ROOT::VecOps::RVec<" + RField<ItemT>::MyTypeName() + ">"; }
719
721 template <typename... ArgsT>
723 {
724 return Detail::RFieldValue(this, static_cast<ContainerT*>(where), std::forward<ArgsT>(args)...);
725 }
727 return GenerateValue(where, ContainerT());
728 }
730 return Detail::RFieldValue(true /* captureFlag */, this, static_cast<ContainerT*>(where));
731 }
732 size_t GetValueSize() const final { return sizeof(ContainerT); }
733};
734
735} // namespace Experimental
736} // namespace ROOT
737
738#endif
ROOT::R::TRInterface & r
Definition: Object.C:4
char name[80]
Definition: TGX11.cxx:109
int type
Definition: TGX11.cxx:120
#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:70
CppT * Map(const NTupleSize_t index, RColumnElementBase *element)
Map may fall back to Read() and therefore requires a valid element.
Definition: RColumn.hxx:121
void GetCollectionInfo(const NTupleSize_t index, NTupleSize_t *collectionStart, ClusterSize_t *collectionSize)
For offset columns only, do index arithmetic from cluster-local to global indizes.
Definition: RColumn.hxx:148
void Read(const NTupleSize_t index, RColumnElementBase *element)
Definition: RColumn.hxx:93
Iterates over the sub fields in depth-first search order.
Definition: RField.hxx:103
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:177
bool operator==(const iterator &rh) const
Definition: RField.hxx:126
std::vector< Position > fStack
The stack of nodes visited when walking down the tree of fields.
Definition: RField.hxx:113
bool operator!=(const iterator &rh) const
Definition: RField.hxx:127
RIterator(pointer val, int idxInParent)
Definition: RField.hxx:116
static std::string GetCollectionName(const std::string &parentName)
Get the name for an item sub field that is part of a collection, e.g. the float field of std::vector<...
Definition: RField.cxx:137
void ReadV(NTupleSize_t index, NTupleSize_t count, void *dst)
Type unsafe bulk read interface; dst must point to a vector of objects of the field type.
Definition: RField.hxx:188
void Append(const RFieldValue &value)
Write the given value into columns. The value object has to be of the same type as the field.
Definition: RField.hxx:167
virtual RFieldValue CaptureValue(void *where)=0
Creates a value from a memory location with an already constructed object.
virtual void DoReadV(NTupleSize_t index, NTupleSize_t count, void *dst)
Definition: RField.cxx:103
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Definition: RField.hxx:81
RFieldBase * fParent
Sub fields point to their mother field.
Definition: RField.hxx:83
RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple)
The constructor creates the underlying column objects and connects them to either a sink or a source.
Definition: RField.cxx:37
virtual void DoAppend(const RFieldValue &value)
Operations on values of complex types, e.g.
Definition: RField.cxx:92
virtual void DoGenerateColumns()=0
Creates the backing columns corresponsing to the field type and name.
static constexpr char kCollectionSeparator
Field names convey the level of subfields; sub fields (nested collections) are separated by a dot.
Definition: RField.hxx:100
virtual void DestroyValue(const RFieldValue &value, bool dtorOnly=false)
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:118
virtual RNTupleVersion GetTypeVersion() const
Indicates an evolution of the C++ type itself.
Definition: RField.hxx:216
static std::string GetLeafName(const std::string &fullName)
Get the tail of the field name up to the last dot.
Definition: RField.cxx:131
void Flush() const
Ensure that all received items are written from page buffers to the storage.
Definition: RField.cxx:145
virtual void CommitCluster()
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.hxx:203
virtual size_t GetValueSize() const =0
The number of bytes taken by a value of the appropriate type.
bool fIsSimple
A field on a trivial type that maps as-is to a single column.
Definition: RField.hxx:77
std::string fType
The C++ type captured by this field.
Definition: RField.hxx:73
void ConnectColumns(Detail::RPageStorage *pageStorage)
Registeres (or re-registers) the backing columns with the physical storage.
Definition: RField.cxx:152
std::string fName
The field name is a unique within a tree and also the basis for the column name(s)
Definition: RField.hxx:71
virtual RNTupleVersion GetFieldVersion() const
Indicates an evolution of the mapping scheme from C++ type to columns.
Definition: RField.hxx:214
virtual void DoRead(NTupleSize_t index, RFieldValue *value)
Definition: RField.cxx:96
static 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:48
void Read(NTupleSize_t index, RFieldValue *value)
Populate a single value with data from the tree, which needs to be of the fitting type.
Definition: RField.hxx:178
virtual unsigned int GetNColumns() const =0
Returns the number of columns generated to store data for the field; defaults to 1.
RFieldBase(const RFieldBase &)=delete
ENTupleStructure fStructure
The role of this field in the data model structure.
Definition: RField.hxx:75
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:87
void Attach(std::unique_ptr< Detail::RFieldBase > child)
Definition: RField.cxx:124
virtual RFieldValue GenerateValue(void *where)=0
Generates a tree value in a given location of size at least GetValueSize().
NTupleSize_t GetNItems()
The number of elements in the principal column. For top level fields, the number of entries.
RFieldBase & operator=(const RFieldBase &)=delete
ENTupleStructure GetStructure() const
Definition: RField.hxx:209
const RFieldBase * GetParent() const
Definition: RField.hxx:210
virtual RFieldBase * Clone(std::string_view newName)=0
RFieldValue GenerateValue()
Generates a tree value of the field type and allocates new initialized memory according to the type.
Definition: RField.cxx:111
RColumn * fPrincipalColumn
All fields have a main column. For collection fields, the main column is the index field....
Definition: RField.hxx:85
RColumnElementBase fMappedElement
For simple types, the mapped element drills through the layers from the C++ data representation to th...
Definition: RFieldValue.hxx:53
Manages tree meta-data, which is common for sinks and sources.
Holds the static meta-data of a column in a tree.
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
Definition: REntry.hxx:42
A field translates read and write calls from/to underlying columns to/from tree values.
Definition: RField.hxx:53
The field for a class with dictionary.
Definition: RField.hxx:242
RFieldClass & operator=(RFieldClass &&other)=default
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:368
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:389
void DoRead(NTupleSize_t index, Detail::RFieldValue *value) final
Definition: RField.cxx:358
void DoAppend(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:348
RFieldClass(std::string_view fieldName, std::string_view className)
Definition: RField.cxx:327
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition: RField.cxx:394
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:382
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:343
RFieldClass(RFieldClass &&other)=default
unsigned int GetNColumns() const final
Returns the number of columns generated to store data for the field; defaults to 1.
Definition: RField.cxx:372
RFieldCollection(RFieldCollection &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:341
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:337
std::shared_ptr< RCollectionNTuple > fCollectionNTuple
Save the link to the collection ntuple in order to reset the offset counter when committing the clust...
Definition: RField.hxx:317
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:332
static std::string MyTypeName()
Definition: RField.hxx:319
The container field for a tree model, which itself has no physical representation.
Definition: RField.hxx:225
RFieldBase * Clone(std::string_view newName)
Definition: RField.cxx:203
unsigned int GetNColumns() const final
Returns the number of columns generated to store data for the field; defaults to 1.
Definition: RField.hxx:231
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.hxx:230
REntry * GenerateEntry()
Generates managed values for the top-level sub fields.
Definition: RField.cxx:214
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:235
Detail::RFieldValue CaptureValue(void *) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:234
Detail::RFieldValue GenerateValue(void *)
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:233
Represents transient storage of simple or complex C++ values.
Definition: RFieldValue.hxx:28
The generic field for a (nested) std::vector<Type>
Definition: RField.hxx:265
RFieldVector(RFieldVector &&other)=default
RFieldBase * Clone(std::string_view newName) final
Definition: RField.hxx:358
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:378
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:382
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
void GetCollectionInfo(NTupleSize_t index, NTupleSize_t *idxStart, ClusterSize_t *size)
Special help for offset fields.
Definition: RField.hxx:385
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:371
ClusterSize_t * Map(NTupleSize_t index)
Definition: RField.hxx:363
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:377
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:729
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:726
void DoRead(NTupleSize_t index, Detail::RFieldValue *value) final
Definition: RField.hxx:667
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:732
typename ROOT::VecOps::RVec< ItemT > ContainerT
Definition: RField.hxx:650
RField(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition: RField.hxx:680
void DoAppend(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.hxx:656
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.hxx:699
unsigned int GetNColumns() const final
Returns the number of columns generated to store data for the field; defaults to 1.
Definition: RField.hxx:704
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:722
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.hxx:716
RFieldBase * Clone(std::string_view newName) final
Definition: RField.hxx:694
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:705
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:457
static std::string MyTypeName()
Definition: RField.hxx:431
RField(std::string_view name)
Definition: RField.hxx:432
RFieldBase * Clone(std::string_view newName) final
Definition: RField.hxx:437
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:450
double * Map(NTupleSize_t index)
Definition: RField.hxx:442
RField(RField &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:461
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:456
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where) final
Generates a tree value in a given location of size at least GetValueSize().
Definition: RField.hxx:419
RField(RField &&other)=default
RField(std::string_view name)
Definition: RField.hxx:395
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:413
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:424
static std::string MyTypeName()
Definition: RField.hxx:394
float * Map(NTupleSize_t index)
Definition: RField.hxx:405
RFieldBase * Clone(std::string_view newName) final
Definition: RField.hxx:400
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.hxx:420
Classes with dictionaries that can be inspected by TClass.
Definition: RField.hxx:294
RField(std::string_view name)
Definition: RField.hxx:297
ROOT::Experimental::Detail::RFieldValue GenerateValue(void *where, ArgsT &&... args)
Definition: RField.hxx:306
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:310
static std::string MyTypeName()
Definition: RField.hxx:296
For forward and backward compatibility, attach version information to the consitituents of the file f...
Definition: RNTupleUtil.hxx:73
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition: RVec.hxx:272
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
basic_string_view< char > string_view
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Definition: RNTupleUtil.hxx:44
RClusterSize ClusterSize_t
Definition: RNTupleUtil.hxx:57
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
Definition: RNTupleUtil.hxx:33
std::string GetDemangledTypeName(const std::type_info &)
Returns a string with the demangled and normalized name for the given type.
double T(double x)
Definition: ChebyshevPol.h:34
auto Map(Args &&... args) -> decltype(ROOT::Detail::VecOps::MapFromTuple(std::forward_as_tuple(args...), std::make_index_sequence< sizeof...(args) - 1 >()))
Create new collection applying a callable to the elements of the input collection.
Definition: RVec.hxx:907
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
Wrap the 32bit integer in a struct in order to avoid template specialization clash with std::uint32_t...
Definition: RNTupleUtil.hxx:47