Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldRecord.hxx
Go to the documentation of this file.
1/// \file ROOT/RField/Fundamental.hxx
2/// \ingroup NTuple
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-09
5
6/*************************************************************************
7 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#ifndef ROOT_RField_Record
15#define ROOT_RField_Record
16
17#ifndef ROOT_RField
18#error "Please include RField.hxx!"
19#endif
20
21#include <ROOT/RFieldBase.hxx>
22#include <ROOT/RNTupleTypes.hxx>
23#include <ROOT/StringUtils.hxx>
24
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 {
41std::unique_ptr<RFieldBase> CreateEmulatedRecordField(std::string_view fieldName,
42 std::vector<std::unique_ptr<RFieldBase>> itemFields,
43 std::string_view emulatedFromType);
44// Used by to late-model-extend fields to untyped records
45void AddItemToRecord(RRecordField &record, std::unique_ptr<RFieldBase> newItem);
46} // namespace Internal
47
48/// The field for an untyped record. The subfields are stored consecutively in a memory block, i.e.
49/// the memory layout is identical to one that a C++ struct would have
50class RRecordField : public RFieldBase {
51 friend std::unique_ptr<RFieldBase>
52 Internal::CreateEmulatedRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
53 std::string_view emulatedFromType);
54 friend void Internal::AddItemToRecord(RRecordField &record, std::unique_ptr<RFieldBase> newItem);
55
56 class RRecordDeleter : public RDeleter {
57 private:
58 std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
59 std::vector<std::size_t> fOffsets;
60
61 public:
62 RRecordDeleter(std::vector<std::unique_ptr<RDeleter>> itemDeleters, const std::vector<std::size_t> &offsets)
63 : fItemDeleters(std::move(itemDeleters)), fOffsets(offsets)
64 {
65 }
66 void operator()(void *objPtr, bool dtorOnly) final;
67 };
68
69 std::unordered_set<std::string> fSubfieldNames; ///< Efficient detection of duplicate field names
70
71 RRecordField(std::string_view name, const RRecordField &source); // Used by CloneImpl()
72
73 /// If `emulatedFromType` is non-empty, this field was created as a replacement for a ClassField that we lack a
74 /// dictionary for and reconstructed from the on-disk information.
75 /// Used by the public constructor and by Internal::CreateEmulatedRecordField().
76 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
77 std::string_view emulatedFromType);
78
79 bool IsPairOrTuple() const
80 {
81 return StartsWith(GetTypeName(), "std::pair<") || StartsWith(GetTypeName(), "std::tuple<");
82 }
83
84 /// Adds an additional item field. Note that the derived RPairField and RTupleField have a sub field handling
85 /// that differs from a struct-like record: their sub field names must be numbered and these derived fields have
86 /// their own member offset calculation.
87 void AddItem(std::unique_ptr<RFieldBase> item);
88
89protected:
90 std::size_t fMaxAlignment = 1;
91 std::size_t fSize = 0;
92 std::vector<std::size_t> fOffsets;
93
94 std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const;
95
96 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
97
98 void ConstructValue(void *where) const final;
99 std::unique_ptr<RDeleter> GetDeleter() const final;
100
101 std::size_t AppendImpl(const void *from) final;
104
105 /// Used by RPairField and RTupleField descendants. These descendants have their own logic to attach the subfields
106 /// that ensure that the resulting memory layout matches std::pair or std::tuple, resp.
107 RRecordField(std::string_view fieldName, std::string_view typeName);
108
109 template <typename ContainerT>
110 void AttachItemFields(ContainerT &&itemFields)
111 {
112 static_assert(std::is_same_v<typename ContainerT::value_type, std::unique_ptr<ROOT::RFieldBase>>,
113 "ContainerT must hold std::unique_ptr<ROOT::RFieldBase>");
114
115 if (!IsPairOrTuple()) {
116 assert(fOffsets.empty());
117 fOffsets.reserve(itemFields.size());
118 }
119
121 for (auto &&item : itemFields) {
122 AddItem(std::move(item));
123 }
124 // Trailing padding: although this is implementation-dependent, most add enough padding to comply with the
125 // requirements of the type with strictest alignment
127 }
128
129 void ReconcileOnDiskField(const RNTupleDescriptor &desc) override;
130
131public:
132 /// Construct a RRecordField based on a vector of child fields. The ownership of the child fields is transferred
133 /// to the RRecordField instance.
134 /// The resulting field uses a memory layout for its values as if there was a struct consisting of the passed
135 /// item fields.
136 RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
139 ~RRecordField() override = default;
140
141 std::vector<RValue> SplitValue(const RValue &value) const final;
143 {
144 // The minimum size is 1 to support having vectors of empty records
145 return std::max<size_t>(1ul, fSize);
146 }
149
150 const std::vector<std::size_t> &GetOffsets() const { return fOffsets; }
151};
152
153////////////////////////////////////////////////////////////////////////////////
154/// Template specializations for C++ std::pair
155////////////////////////////////////////////////////////////////////////////////
156
157/// The generic field for `std::pair<T1, T2>` types
158class RPairField : public RRecordField {
159protected:
160 RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields,
161 const std::array<std::size_t, 2> &offsets);
162
163 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
164
165 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
166
167public:
168 RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields);
171 ~RPairField() override = default;
172};
173
174template <typename T1, typename T2>
175class RField<std::pair<T1, T2>> final : public RPairField {
176 using ContainerT = typename std::pair<T1, T2>;
177
178private:
179 static std::array<std::unique_ptr<RFieldBase>, 2> BuildItemFields()
180 {
181 return {std::make_unique<RField<T1>>("_0"), std::make_unique<RField<T2>>("_1")};
182 }
183
184 static std::array<std::size_t, 2> BuildItemOffsets()
185 {
186 auto pair = ContainerT();
187 auto offsetFirst = reinterpret_cast<std::uintptr_t>(&(pair.first)) - reinterpret_cast<std::uintptr_t>(&pair);
188 auto offsetSecond = reinterpret_cast<std::uintptr_t>(&(pair.second)) - reinterpret_cast<std::uintptr_t>(&pair);
189 return {offsetFirst, offsetSecond};
190 }
191
192public:
193 static std::string TypeName() { return "std::pair<" + RField<T1>::TypeName() + "," + RField<T2>::TypeName() + ">"; }
194 explicit RField(std::string_view name) : RPairField(name, BuildItemFields(), BuildItemOffsets())
195 {
196 R__ASSERT(fMaxAlignment >= std::max(alignof(T1), alignof(T2)));
197 R__ASSERT(fSize >= sizeof(ContainerT));
198 }
199 RField(RField &&other) = default;
200 RField &operator=(RField &&other) = default;
202};
203
204////////////////////////////////////////////////////////////////////////////////
205/// Template specializations for C++ std::tuple
206////////////////////////////////////////////////////////////////////////////////
207
208/// The generic field for `std::tuple<Ts...>` types
210protected:
211 RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
212 const std::vector<std::size_t> &offsets);
213
214 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
215
216 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
217
218public:
219 RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
222 ~RTupleField() override = default;
223};
224
225template <typename... ItemTs>
226class RField<std::tuple<ItemTs...>> final : public RTupleField {
227 using ContainerT = typename std::tuple<ItemTs...>;
228
229private:
230 template <typename HeadT, typename... TailTs>
231 static std::string BuildItemTypes()
232 {
233 std::string result = RField<HeadT>::TypeName();
234 if constexpr (sizeof...(TailTs) > 0)
235 result += "," + BuildItemTypes<TailTs...>();
236 return result;
237 }
238
239 template <typename HeadT, typename... TailTs>
240 static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
241 {
242 itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
243 if constexpr (sizeof...(TailTs) > 0)
244 _BuildItemFields<TailTs...>(itemFields, index + 1);
245 }
246 static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
247 {
248 std::vector<std::unique_ptr<RFieldBase>> result;
249 _BuildItemFields<ItemTs...>(result);
250 return result;
251 }
252
253 template <unsigned Index, typename HeadT, typename... TailTs>
254 static void _BuildItemOffsets(std::vector<std::size_t> &offsets, const ContainerT &tuple)
255 {
256 auto offset =
257 reinterpret_cast<std::uintptr_t>(&std::get<Index>(tuple)) - reinterpret_cast<std::uintptr_t>(&tuple);
258 offsets.emplace_back(offset);
259 if constexpr (sizeof...(TailTs) > 0)
260 _BuildItemOffsets<Index + 1, TailTs...>(offsets, tuple);
261 }
262 static std::vector<std::size_t> BuildItemOffsets()
263 {
264 std::vector<std::size_t> result;
265 _BuildItemOffsets<0, ItemTs...>(result, ContainerT());
266 return result;
267 }
268
269public:
270 static std::string TypeName() { return "std::tuple<" + BuildItemTypes<ItemTs...>() + ">"; }
271 explicit RField(std::string_view name) : RTupleField(name, BuildItemFields(), BuildItemOffsets())
272 {
273 R__ASSERT(fMaxAlignment >= std::max({alignof(ItemTs)...}));
274 R__ASSERT(fSize >= sizeof(ContainerT));
275 }
276 RField(RField &&other) = default;
277 RField &operator=(RField &&other) = default;
279};
280
281} // namespace ROOT
282
283#endif
dim_t fSize
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t 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:110
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:170
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.
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
const std::string & GetTypeName() const
@ kTraitTrivialType
Shorthand for types that are both trivially constructible and destructible.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:323
~RField() final=default
RField & operator=(RField &&other)=default
static std::string TypeName()
Definition RField.hxx:325
RField(std::string_view name)
Definition RField.hxx:326
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() override=default
RPairField(std::string_view fieldName, std::array< std::unique_ptr< RFieldBase >, 2 > itemFields, const std::array< std::size_t, 2 > &offsets)
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:714
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:732
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:654
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
Definition RField.cxx:675
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:568
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:744
void AttachItemFields(ContainerT &&itemFields)
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:722
RRecordField(RRecordField &&other)=default
bool IsPairOrTuple() const
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:644
void AddItem(std::unique_ptr< RFieldBase > item)
Adds an additional item field.
Definition RField.cxx:616
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:668
~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:707
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:659
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:682
Template specializations for C++ std::tuple.
~RTupleField() override=default
RTupleField(RTupleField &&other)=default
RTupleField & operator=(RTupleField &&other)=default
#define T2
Definition md5.inl:147
#define T1
Definition md5.inl:146
std::unique_ptr< RFieldBase > CreateEmulatedRecordField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields, std::string_view emulatedFromType)
Definition RField.cxx:586
void AddItemToRecord(RRecordField &record, std::unique_ptr< RFieldBase > newItem)
Definition RField.cxx:637
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.