Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RFieldRecord.hxx
Go to the documentation of this file.
1/// \file ROOT/RField/Fundamental.hxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2018-10-09
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#ifndef ROOT_RField_Record
14#define ROOT_RField_Record
15
16#ifndef ROOT_RField
17#error "Please include RField.hxx!"
18#endif
19
20#include <ROOT/RFieldBase.hxx>
21#include <ROOT/RNTupleTypes.hxx>
22#include <ROOT/StringUtils.hxx>
23
24#include <string>
25#include <string_view>
26#include <tuple>
27#include <unordered_set>
28#include <utility>
29#include <vector>
30
31namespace ROOT {
32
33class RRecordField;
34
35namespace Detail {
36class RFieldVisitor;
37} // namespace Detail
38
39namespace Internal {
40std::unique_ptr<RFieldBase> CreateEmulatedRecordField(std::string_view fieldName,
41 std::vector<std::unique_ptr<RFieldBase>> itemFields,
42 std::string_view emulatedFromType);
43// Used by to late-model-extend fields to untyped records
44void AddItemToRecord(RRecordField &record, std::unique_ptr<RFieldBase> newItem);
45} // namespace Internal
46
47/// The field for an untyped record. The subfields are stored consecutively in a memory block, i.e.
48/// the memory layout is identical to one that a C++ struct would have
49class RRecordField : public RFieldBase {
50 friend std::unique_ptr<RFieldBase>
51 Internal::CreateEmulatedRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
52 std::string_view emulatedFromType);
53 friend void Internal::AddItemToRecord(RRecordField &record, std::unique_ptr<RFieldBase> newItem);
54
55 class RRecordDeleter : public RDeleter {
56 private:
57 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
58 std::vector<std::size_t> fOffsets;
59
60 public:
61 RRecordDeleter(std::vector<std::unique_ptr<RDeleter>> itemDeleters, const std::vector<std::size_t> &offsets)
62 : fItemDeleters(std::move(itemDeleters)), fOffsets(offsets)
63 {
64 }
65 void operator()(void *objPtr, bool dtorOnly) final;
66 };
67
68 std::unordered_set<std::string> fSubfieldNames; ///< Efficient detection of duplicate field names
69
70 RRecordField(std::string_view name, const RRecordField &source); // Used by CloneImpl()
71
72 /// If `emulatedFromType` is non-empty, this field was created as a replacement for a ClassField that we lack a
73 /// dictionary for and reconstructed from the on-disk information.
74 /// Used by the public constructor and by Internal::CreateEmulatedRecordField().
75 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
76 std::string_view emulatedFromType);
77
78 bool IsPairOrTuple() const
79 {
80 return StartsWith(GetTypeName(), "std::pair<") || StartsWith(GetTypeName(), "std::tuple<");
81 }
82
83 /// Adds an additional item field. Note that the derived RPairField and RTupleField have a sub field handling
84 /// that differs from a struct-like record: their sub field names must be numbered and these derived fields have
85 /// their own member offset calculation.
86 void AddItem(std::unique_ptr<RFieldBase> item);
87
88protected:
89 std::size_t fMaxAlignment = 1;
90 std::size_t fSize = 0;
91 std::vector<std::size_t> fOffsets;
92
93 std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const;
94
95 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
96
97 void ConstructValue(void *where) const final;
98 std::unique_ptr<RDeleter> GetDeleter() const final;
99
100 std::size_t AppendImpl(const void *from) final;
101 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
102 void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
103
104 /// Used by RPairField and RTupleField descendants. These descendants have their own logic to attach the subfields
105 /// that ensure that the resulting memory layout matches std::pair or std::tuple, resp.
106 RRecordField(std::string_view fieldName, std::string_view typeName);
107
108 template <typename ContainerT>
109 void AttachItemFields(ContainerT &&itemFields)
110 {
111 static_assert(std::is_same_v<typename ContainerT::value_type, std::unique_ptr<ROOT::RFieldBase>>,
112 "ContainerT must hold std::unique_ptr<ROOT::RFieldBase>");
113
114 if (!IsPairOrTuple()) {
115 assert(fOffsets.empty());
116 fOffsets.reserve(itemFields.size());
117 }
118
120 for (auto &&item : itemFields) {
121 AddItem(std::move(item));
122 }
123 // Trailing padding: although this is implementation-dependent, most add enough padding to comply with the
124 // requirements of the type with strictest alignment
126 }
127
128 void ReconcileOnDiskField(const RNTupleDescriptor &desc) override;
129
130public:
131 /// Construct a RRecordField based on a vector of child fields. The ownership of the child fields is transferred
132 /// to the RRecordField instance.
133 /// The resulting field uses a memory layout for its values as if there was a struct consisting of the passed
134 /// item fields.
135 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
136 RRecordField(RRecordField &&other) = default;
138 ~RRecordField() override = default;
139
140 std::vector<RValue> SplitValue(const RValue &value) const final;
141 size_t GetValueSize() const final
142 {
143 // The minimum size is 1 to support having vectors of empty records
144 return std::max<size_t>(1ul, fSize);
145 }
146 size_t GetAlignment() const final { return fMaxAlignment; }
147 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
148
149 const std::vector<std::size_t> &GetOffsets() const { return fOffsets; }
150};
151
152////////////////////////////////////////////////////////////////////////////////
153/// Template specializations for C++ std::pair
154////////////////////////////////////////////////////////////////////////////////
155
156/// The generic field for `std::pair<T1, T2>` types
157class RPairField : public RRecordField {
158protected:
159 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
160
161 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
162
163public:
164 RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields);
165 RPairField(RPairField &&other) = default;
166 RPairField &operator=(RPairField &&other) = default;
167 ~RPairField() override = default;
168};
169
170template <typename T1, typename T2>
171class RField<std::pair<T1, T2>> final : public RPairField {
172 using ContainerT = typename std::pair<T1, T2>;
173
174private:
175 static std::array<std::unique_ptr<RFieldBase>, 2> BuildItemFields()
176 {
177 return {std::make_unique<RField<T1>>("_0"), std::make_unique<RField<T2>>("_1")};
178 }
179
180public:
181 static std::string TypeName() { return "std::pair<" + RField<T1>::TypeName() + "," + RField<T2>::TypeName() + ">"; }
182 explicit RField(std::string_view name) : RPairField(name, BuildItemFields())
183 {
184 R__ASSERT(fMaxAlignment >= std::max(alignof(T1), alignof(T2)));
185 R__ASSERT(fSize >= sizeof(ContainerT));
186 }
187 RField(RField &&other) = default;
188 RField &operator=(RField &&other) = default;
189 ~RField() final = default;
190};
191
192////////////////////////////////////////////////////////////////////////////////
193/// Template specializations for C++ std::tuple
194////////////////////////////////////////////////////////////////////////////////
195
196/// The generic field for `std::tuple<Ts...>` types
197class RTupleField : public RRecordField {
198protected:
199 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
200
201 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
202
203public:
204 RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
205 RTupleField(RTupleField &&other) = default;
206 RTupleField &operator=(RTupleField &&other) = default;
207 ~RTupleField() override = default;
208};
209
210template <typename... ItemTs>
211class RField<std::tuple<ItemTs...>> final : public RTupleField {
212 using ContainerT = typename std::tuple<ItemTs...>;
213
214private:
215 template <typename HeadT, typename... TailTs>
216 static std::string BuildItemTypes()
217 {
218 std::string result = RField<HeadT>::TypeName();
219 if constexpr (sizeof...(TailTs) > 0)
220 result += "," + BuildItemTypes<TailTs...>();
221 return result;
222 }
223
224 template <typename HeadT, typename... TailTs>
225 static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
226 {
227 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
228 if constexpr (sizeof...(TailTs) > 0)
229 _BuildItemFields<TailTs...>(itemFields, index + 1);
230 }
231 static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
232 {
233 std::vector<std::unique_ptr<RFieldBase>> result;
234 _BuildItemFields<ItemTs...>(result);
235 return result;
236 }
237
238public:
239 static std::string TypeName() { return "std::tuple<" + BuildItemTypes<ItemTs...>() + ">"; }
240 explicit RField(std::string_view name) : RTupleField(name, BuildItemFields())
241 {
242 R__ASSERT(fMaxAlignment >= std::max({alignof(ItemTs)...}));
243 R__ASSERT(fSize >= sizeof(ContainerT));
244 }
245 RField(RField &&other) = default;
246 RField &operator=(RField &&other) = default;
247 ~RField() final = default;
248};
249
250} // namespace ROOT
251
252#endif
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
char name[80]
Definition TGX11.cxx:148
Abstract base class for classes implementing the visitor design pattern.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
std::size_t fMaxAlignment
Definition RField.hxx:167
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
A functor to release the memory acquired by CreateValue() (memory and constructor).
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
@ kTraitTrivialType
Shorthand for types that are both trivially constructible and destructible.
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
RFieldBase(std::string_view name, std::string_view type, ROOT::ENTupleStructure structure, bool isSimple, std::size_t nRepetitions=0)
The constructor creates the underlying column objects and connects them to either a sink or a source.
const std::string & GetTypeName() const
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:320
~RField() final=default
RField & operator=(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:322
RField(std::string_view name)
Definition RField.hxx:323
The on-storage metadata of an RNTuple.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Template specializations for C++ std::pair.
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
RPairField(std::string_view fieldName, std::array< std::unique_ptr< RFieldBase >, 2 > itemFields)
~RPairField() override=default
RPairField(RPairField &&other)=default
RPairField & operator=(RPairField &&other)=default
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
std::vector< std::size_t > fOffsets
RRecordDeleter(std::vector< std::unique_ptr< RDeleter > > itemDeleters, const std::vector< std::size_t > &offsets)
std::vector< std::unique_ptr< RDeleter > > fItemDeleters
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:718
The field for an untyped record.
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Definition RField.cxx:736
std::size_t fMaxAlignment
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:658
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
Definition RField.cxx:679
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
RRecordField & operator=(RRecordField &&other)=default
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
std::unordered_set< std::string > fSubfieldNames
Efficient detection of duplicate field names.
RRecordField(std::string_view name, const RRecordField &source)
Definition RField.cxx:572
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:748
void AttachItemFields(ContainerT &&itemFields)
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:726
RRecordField(RRecordField &&other)=default
bool IsPairOrTuple() const
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:648
void AddItem(std::unique_ptr< RFieldBase > item)
Adds an additional item field.
Definition RField.cxx:620
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:672
~RRecordField() override=default
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:711
std::vector< std::size_t > fOffsets
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:663
const std::vector< std::size_t > & GetOffsets() const
void ReconcileOnDiskField(const RNTupleDescriptor &desc) override
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
Definition RField.cxx:686
Template specializations for C++ std::tuple.
~RTupleField() override=default
RTupleField(RTupleField &&other)=default
RTupleField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields)
RTupleField & operator=(RTupleField &&other)=default
STL class.
STL class.
#define T2
Definition md5.inl:147
#define T1
Definition md5.inl:146
Special implementation of ROOT::RRangeCast for TCollection, including a check that the cast target ty...
Definition TObject.h:395
std::unique_ptr< RFieldBase > CreateEmulatedRecordField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields, std::string_view emulatedFromType)
Definition RField.cxx:590
void AddItemToRecord(RRecordField &record, std::unique_ptr< RFieldBase > newItem)
Definition RField.cxx:641
bool StartsWith(std::string_view string, std::string_view prefix)
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.