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 <optional>
25#include <string>
26#include <string_view>
27#include <tuple>
28#include <unordered_set>
29#include <utility>
30#include <vector>
31
32namespace ROOT {
33
34class RRecordField;
35
36namespace Detail {
37class RFieldVisitor;
38} // namespace Detail
39
40namespace Internal {
41// TODO(gparolini): consider using a different type than RFieldDescriptor to pass around type name/version/checksum
42// to CreateEmulated* functions
43std::unique_ptr<RFieldBase> CreateEmulatedRecordField(std::string_view fieldName,
44 std::vector<std::unique_ptr<RFieldBase>> itemFields,
45 const RFieldDescriptor &emulatedFrom);
46// Used by to late-model-extend fields to untyped records
47void AddItemToRecord(RRecordField &record, std::unique_ptr<RFieldBase> newItem);
48} // namespace Internal
49
50/// The field for an untyped record. The subfields are stored consecutively in a memory block, i.e.
51/// the memory layout is identical to one that a C++ struct would have
52class RRecordField : public RFieldBase {
53 friend std::unique_ptr<RFieldBase>
54 Internal::CreateEmulatedRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
55 const RFieldDescriptor &emulatedFrom);
56 friend void Internal::AddItemToRecord(RRecordField &record, std::unique_ptr<RFieldBase> newItem);
57
58 class RRecordDeleter : public RDeleter {
59 private:
60 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
61 std::vector<std::size_t> fOffsets;
62
63 public:
64 RRecordDeleter(std::vector<std::unique_ptr<RDeleter>> itemDeleters, const std::vector<std::size_t> &offsets,
65 std::size_t alignment)
66 : RDeleter(alignment), fItemDeleters(std::move(itemDeleters)), fOffsets(offsets)
67 {
68 }
69 void operator()(void *objPtr, bool dtorOnly) final;
70 };
71
72 std::unordered_set<std::string> fSubfieldNames; ///< Efficient detection of duplicate field names
73 // These are only valid if the record field is emulated (i.e. (fTraits & kTraitEmulatedField) != 0).
74 std::uint32_t fEmulatedTypeVersion = 0;
75 std::uint32_t fEmulatedTypeChecksum = 0;
76
77 RRecordField(std::string_view name, const RRecordField &source); // Used by CloneImpl()
78
79 /// If `emulatedFrom` is non-null, this field was created as a replacement for a ClassField that we lack a
80 /// dictionary for and reconstructed from the on-disk information.
81 /// Used by the public constructor and by Internal::CreateEmulatedRecordField().
82 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
83 const RFieldDescriptor *emulatedFrom);
84
85 bool IsPairOrTuple() const
86 {
87 return StartsWith(GetTypeName(), "std::pair<") || StartsWith(GetTypeName(), "std::tuple<");
88 }
89
90 /// Adds an additional item field. Note that the derived RPairField and RTupleField have a sub field handling
91 /// that differs from a struct-like record: their sub field names must be numbered and these derived fields have
92 /// their own member offset calculation.
93 void AddItem(std::unique_ptr<RFieldBase> item);
94
95protected:
96 std::size_t fMaxAlignment = 1;
97 std::size_t fSize = 0;
98 std::vector<std::size_t> fOffsets;
99
100 std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const;
101
102 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
103
104 void ConstructValue(void *where) const final;
105 std::unique_ptr<RDeleter> GetDeleter() const final;
106
107 std::size_t AppendImpl(const void *from) final;
108 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
109 void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
110
111 /// Used by RPairField and RTupleField descendants. These descendants have their own logic to attach the subfields
112 /// that ensure that the resulting memory layout matches std::pair or std::tuple, resp.
113 RRecordField(std::string_view fieldName, std::string_view typeName);
114
115 template <typename ContainerT>
116 void AttachItemFields(ContainerT &&itemFields)
117 {
118 static_assert(std::is_same_v<typename ContainerT::value_type, std::unique_ptr<ROOT::RFieldBase>>,
119 "ContainerT must hold std::unique_ptr<ROOT::RFieldBase>");
120
121 if (!IsPairOrTuple()) {
122 assert(fOffsets.empty());
123 fOffsets.reserve(itemFields.size());
124 }
125
127 for (auto &&item : itemFields) {
128 AddItem(std::move(item));
129 }
130 // Trailing padding: although this is implementation-dependent, most add enough padding to comply with the
131 // requirements of the type with strictest alignment
133 }
134
135 void ReconcileOnDiskField(const RNTupleDescriptor &desc) override;
136
137public:
138 /// Construct a RRecordField based on a vector of child fields. The ownership of the child fields is transferred
139 /// to the RRecordField instance.
140 /// The resulting field uses a memory layout for its values as if there was a struct consisting of the passed
141 /// item fields.
142 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
143 RRecordField(RRecordField &&other) = default;
145 ~RRecordField() override = default;
146
147 std::vector<RValue> SplitValue(const RValue &value) const final;
148 size_t GetValueSize() const final
149 {
150 // The minimum size is 1 to support having vectors of empty records
151 return std::max<size_t>(1ul, fSize);
152 }
153 size_t GetAlignment() const final { return fMaxAlignment; }
154 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
155
156 const std::vector<std::size_t> &GetOffsets() const { return fOffsets; }
157
158 std::uint32_t GetTypeVersion() const final { return (fTraits & kTraitEmulatedField) ? fEmulatedTypeVersion : 0; }
159 std::uint32_t GetTypeChecksum() const final { return (fTraits & kTraitEmulatedField) ? fEmulatedTypeChecksum : 0; }
160};
161
162////////////////////////////////////////////////////////////////////////////////
163/// Template specializations for C++ std::pair
164////////////////////////////////////////////////////////////////////////////////
165
166/// The generic field for `std::pair<T1, T2>` types
167class RPairField : public RRecordField {
168protected:
169 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
170
171 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
172
173public:
174 RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields);
175 RPairField(RPairField &&other) = default;
176 RPairField &operator=(RPairField &&other) = default;
177 ~RPairField() override = default;
178};
179
180template <typename T1, typename T2>
181class RField<std::pair<T1, T2>> final : public RPairField {
182 using ContainerT = typename std::pair<T1, T2>;
183
184private:
185 static std::array<std::unique_ptr<RFieldBase>, 2> BuildItemFields()
186 {
187 return {std::make_unique<RField<T1>>("_0"), std::make_unique<RField<T2>>("_1")};
188 }
189
190public:
191 static std::string TypeName() { return "std::pair<" + RField<T1>::TypeName() + "," + RField<T2>::TypeName() + ">"; }
192 explicit RField(std::string_view name) : RPairField(name, BuildItemFields())
193 {
194 R__ASSERT(fMaxAlignment >= std::max(alignof(T1), alignof(T2)));
195 R__ASSERT(fSize >= sizeof(ContainerT));
196 }
197 RField(RField &&other) = default;
198 RField &operator=(RField &&other) = default;
199 ~RField() final = default;
200};
201
202////////////////////////////////////////////////////////////////////////////////
203/// Template specializations for C++ std::tuple
204////////////////////////////////////////////////////////////////////////////////
205
206/// The generic field for `std::tuple<Ts...>` types
207class RTupleField : public RRecordField {
208protected:
209 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
210
211 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
212
213public:
214 RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
215 RTupleField(RTupleField &&other) = default;
216 RTupleField &operator=(RTupleField &&other) = default;
217 ~RTupleField() override = default;
218};
219
220template <typename... ItemTs>
221class RField<std::tuple<ItemTs...>> final : public RTupleField {
222 using ContainerT = typename std::tuple<ItemTs...>;
223
224private:
225 template <typename HeadT, typename... TailTs>
226 static std::string BuildItemTypes()
227 {
228 std::string result = RField<HeadT>::TypeName();
229 if constexpr (sizeof...(TailTs) > 0)
230 result += "," + BuildItemTypes<TailTs...>();
231 return result;
232 }
233
234 template <typename HeadT, typename... TailTs>
235 static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
236 {
237 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
238 if constexpr (sizeof...(TailTs) > 0)
239 _BuildItemFields<TailTs...>(itemFields, index + 1);
240 }
241 static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
242 {
243 std::vector<std::unique_ptr<RFieldBase>> result;
244 _BuildItemFields<ItemTs...>(result);
245 return result;
246 }
247
248public:
249 static std::string TypeName() { return "std::tuple<" + BuildItemTypes<ItemTs...>() + ">"; }
250 explicit RField(std::string_view name) : RTupleField(name, BuildItemFields())
251 {
252 R__ASSERT(fMaxAlignment >= std::max({alignof(ItemTs)...}));
253 R__ASSERT(fSize >= sizeof(ContainerT));
254 }
255 RField(RField &&other) = default;
256 RField &operator=(RField &&other) = default;
257 ~RField() final = default;
258};
259
260} // namespace ROOT
261
262#endif
dim_t fSize
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:139
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:142
TCanvas * alignment()
Definition alignment.C:1
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.
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.
A field translates read and write calls from/to underlying columns to/from tree values.
@ kTraitEmulatedField
This field is a user defined type that was missing dictionaries and was reconstructed from the on-dis...
@ 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.
const std::string & GetTypeName() const
Metadata stored for every field of an RNTuple.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:342
~RField() final=default
RField & operator=(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:344
RField(std::string_view name)
Definition RField.hxx:345
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.
RRecordDeleter(std::vector< std::unique_ptr< RDeleter > > itemDeleters, const std::vector< std::size_t > &offsets, std::size_t alignment)
std::vector< std::size_t > fOffsets
std::vector< std::unique_ptr< RDeleter > > fItemDeleters
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:744
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:762
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:684
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
Definition RField.cxx:705
size_t GetAlignment() const final
What alignof(T) for this type returns.
RRecordField & operator=(RRecordField &&other)=default
size_t GetValueSize() const final
What sizeof(T) for this type returns.
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:774
void AttachItemFields(ContainerT &&itemFields)
std::uint32_t fEmulatedTypeVersion
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:752
RRecordField(RRecordField &&other)=default
bool IsPairOrTuple() const
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:674
void AddItem(std::unique_ptr< RFieldBase > item)
Adds an additional item field.
Definition RField.cxx:626
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:698
~RRecordField() override=default
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
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:737
std::vector< std::size_t > fOffsets
std::uint32_t fEmulatedTypeChecksum
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:689
std::uint32_t GetTypeChecksum() const final
Return the current TClass reported checksum of this class. Only valid if kTraitTypeChecksum is set.
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:712
Template specializations for C++ std::tuple.
~RTupleField() override=default
RTupleField(RTupleField &&other)=default
RTupleField & operator=(RTupleField &&other)=default
std::unique_ptr< RFieldBase > CreateEmulatedRecordField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields, const RFieldDescriptor &emulatedFrom)
Definition RField.cxx:590
void AddItemToRecord(RRecordField &record, std::unique_ptr< RFieldBase > newItem)
Definition RField.cxx:647
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.