Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RNTupleProcessorEntry.hxx
Go to the documentation of this file.
1/// \file ROOT/RNTupleProcessor.hxx
2/// \author Florine de Geus <florine.de.geus@cern.ch>
3/// \date 2025-06-25
4/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
5/// is welcome!
6
7/*************************************************************************
8 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
9 * All rights reserved. *
10 * *
11 * For the licensing terms see $ROOTSYS/LICENSE. *
12 * For the list of contributors see $ROOTSYS/README/CREDITS. *
13 *************************************************************************/
14
15#ifndef ROOT_RNTupleProcessorEntry
16#define ROOT_RNTupleProcessorEntry
17
18#include <ROOT/RNTupleModel.hxx>
19#include <ROOT/RFieldBase.hxx>
20
21#include <cassert>
22#include <string>
23#include <string_view>
24#include <unordered_map>
25#include <vector>
26
27namespace ROOT {
28namespace Experimental {
29namespace Internal {
30/**
31\class ROOT::Experimental::RNTupleProcessorProvenance
32\ingroup NTuple
33\brief Identifies how a processor is composed.
34
35The processor provenance is used in RNTupleProcessorEntry to identify how an (auxiliary) field in a composed processor
36can be accessed.
37*/
38// clang-format on
40private:
41 std::string fProvenance{};
42
43public:
45 RNTupleProcessorProvenance(const std::string &provenance) : fProvenance(provenance) {}
46
47 /////////////////////////////////////////////////////////////////////////////
48 /// \brief Get the full processor provenance, in the form of "x.y.z".
49 std::string Get() const { return fProvenance; }
50
51 /////////////////////////////////////////////////////////////////////////////
52 /// \brief Add a new processor to the provenance.
53 ///
54 /// \param[in] processorName Name of the processor to add.
55 ///
56 /// \return The updated provenance.
57 RNTupleProcessorProvenance Evolve(const std::string &processorName) const
58 {
59 if (fProvenance.empty())
60 return RNTupleProcessorProvenance(processorName);
61
62 return RNTupleProcessorProvenance(fProvenance + "." + processorName);
63 }
64
65 /////////////////////////////////////////////////////////////////////////////
66 /// \brief Check whether the provenance subsumes the provenance in `other`.
67 ///
68 /// \param[in] other The other provenance
69 bool Contains(const RNTupleProcessorProvenance &other) const
70 {
71 return fProvenance.rfind(other.fProvenance) != std::string::npos;
72 }
73
74 /////////////////////////////////////////////////////////////////////////////
75 /// \brief Check whether the provided field name contains this provenance.
76 ///
77 /// \param[in] fieldName Field name to check.
78 bool IsPresentInFieldName(std::string_view fieldName) const
79 {
80 return !fProvenance.empty() && fieldName.find(fProvenance + ".") == 0;
81 }
82};
83
84// clang-format off
85/**
86\class ROOT::Experimental::Internal::RNTupleProcessorEntry
87\ingroup NTuple
88\brief Collection of values in an RNTupleProcessor, analogous to REntry, with checks and support for missing values.
89*/
90// clang-format on
92public:
93 // We don't use RFieldTokens here, because it (semantically) does not make sense for the entry to be fixed to the
94 // schema ID of a particular model.
95 using FieldIndex_t = std::uint64_t;
96
97private:
108
109 std::vector<RProcessorValue> fProcessorValues;
110 std::unordered_map<std::string, FieldIndex_t> fFieldName2Index;
111
112public:
113 /////////////////////////////////////////////////////////////////////////////
114 /// \brief Set the validity of a field, i.e. whether it is possible to read its value in the current entry.
115 ///
116 /// \param[in] fieldIdx The index of the field in the entry.
117 /// \param[in] isValid The new validity of the field.
118 void SetFieldValidity(FieldIndex_t fieldIdx, bool isValid)
119 {
120 assert(fieldIdx < fProcessorValues.size());
121 fProcessorValues[fieldIdx].fIsValid = isValid;
122 }
123
124 /////////////////////////////////////////////////////////////////////////////
125 /// \brief Check whether a field is valid for reading.
126 ///
127 /// \param[in] fieldIdx The index of the field in the entry.
128 bool IsValidField(FieldIndex_t fieldIdx) const
129 {
130 assert(fieldIdx < fProcessorValues.size());
131 return fProcessorValues[fieldIdx].fIsValid;
132 }
133
134 /////////////////////////////////////////////////////////////////////////////
135 /// \brief Find the name of a field from its field index.
136 ///
137 /// \param[in] fieldIdx The index of the field in the entry.
138 ///
139 /// \warning This function has linear complexity, only use it for more helpful error messages!
140 const std::string &FindFieldName(FieldIndex_t fieldIdx) const
141 {
142 assert(fieldIdx < fProcessorValues.size());
143
144 for (const auto &[fieldName, index] : fFieldName2Index) {
145 if (index == fieldIdx) {
146 return fieldName;
147 }
148 }
149 // Should never happen, but avoid compiler warning about "returning reference to local temporary object".
150 R__ASSERT(false);
151 static const std::string empty = "";
152 return empty;
153 }
154
155 /////////////////////////////////////////////////////////////////////////////
156 /// \brief Find the field index of the provided field in the entry.
157 ///
158 /// \param[in] fieldName The name of the field in the entry.
159 ///
160 /// \return A `std::optional` containing the field index if it was found.
161 std::optional<FieldIndex_t> FindFieldIndex(std::string_view fieldName) const
162 {
163 auto it = fFieldName2Index.find(std::string(fieldName));
164 if (it == fFieldName2Index.end()) {
165 return std::nullopt;
166 }
167 return it->second;
168 }
169
170 /////////////////////////////////////////////////////////////////////////////
171 /// \brief Add a new field to the entry.
172 ///
173 /// \param[in] fieldName Name of the field to add.
174 /// \param[in] field Reference to the field to add, used to to create its corresponding RValue.
175 /// \param[in] valuePtr Pointer to an object corresponding to the field's type to bind to its value. If this is a
176 /// `nullptr`, a pointer will be created.
177 /// \param[in] provenance Processor provenance of the field.
178 ///
179 /// \return The field index of the newly added field.
180 FieldIndex_t AddField(std::string_view fieldName, ROOT::RFieldBase &field, void *valuePtr,
181 const RNTupleProcessorProvenance &provenance)
182 {
183 if (FindFieldIndex(fieldName))
184 throw ROOT::RException(
185 R__FAIL("field \"" + field.GetQualifiedFieldName() + "\" is already present in the entry"));
186
187 auto value = field.CreateValue();
188 if (valuePtr)
189 value.BindRawPtr(valuePtr);
190 auto fieldIdx = fProcessorValues.size();
191 fFieldName2Index[std::string(fieldName)] = fieldIdx;
192 fProcessorValues.emplace_back(RProcessorValue(std::move(value), true, provenance));
193
194 return fieldIdx;
195 }
196
197 /////////////////////////////////////////////////////////////////////////////
198 /// \brief Update a field in the entry, preserving the value pointer.
199 ///
200 /// \param[in] fieldIdx Index of the field to update.
201 /// \param[in] field The new field to use in the entry.
203 {
204 assert(fieldIdx < fProcessorValues.size());
205
206 auto currValuePtr = fProcessorValues[fieldIdx].fValue.GetPtr<void>();
207 auto value = field.CreateValue();
208 value.Bind(currValuePtr);
209 fProcessorValues[fieldIdx].fValue = value;
210 }
211
212 /////////////////////////////////////////////////////////////////////////////
213 /// \brief Bind a new value pointer to a field in the entry.
214 ///
215 /// \param[in] fieldIdx The index of the field in the entry.
216 /// \param[in] valuePtr Pointer to the value to bind to the field.
217 void BindRawPtr(FieldIndex_t fieldIdx, void *valuePtr)
218 {
219 assert(fieldIdx < fProcessorValues.size());
220 fProcessorValues[fieldIdx].fValue.BindRawPtr(valuePtr);
221 }
222
223 /////////////////////////////////////////////////////////////////////////////
224 /// \brief Read the field value corresponding to the given field index for the provided entry index.
225 ///
226 /// \param[in] fieldIdx The index of the field in the entry.
227 /// \param[in] entryIdx The entry number to read.
229 {
230 assert(fieldIdx < fProcessorValues.size());
231
232 if (fProcessorValues[fieldIdx].fIsValid) {
233 fProcessorValues[fieldIdx].fValue.Read(entryIdx);
234 }
235 }
236
237 /////////////////////////////////////////////////////////////////////////////
238 /// \brief Get a pointer to the value for the field represented by the provided field index.
239 ///
240 /// \tparam T The type of the pointer.
241 ///
242 /// \param[in] fieldIdx The index of the field in the entry.
243 ///
244 /// \return A shared pointer of type `T` with the field's value.
245 template <typename T>
246 std::shared_ptr<T> GetPtr(FieldIndex_t fieldIdx) const
247 {
248 assert(fieldIdx < fProcessorValues.size());
249
250 if (fProcessorValues[fieldIdx].fIsValid)
251 return fProcessorValues[fieldIdx].fValue.GetPtr<T>();
252
253 return nullptr;
254 }
255
256 /////////////////////////////////////////////////////////////////////////////
257 /// \brief Get a reference to a field in the entry.
258 ///
259 /// \param[in] fieldIdx The index of the field in the entry.
261 {
262 assert(fieldIdx < fProcessorValues.size());
263 return fProcessorValues[fieldIdx].fValue.GetField();
264 }
265
266 /////////////////////////////////////////////////////////////////////////////
267 /// \brief Get the processor provenance of a field in the entry.
268 ///
269 /// \param[in] fieldIdx The index of the field in the entry.
271 {
272 assert(fieldIdx < fProcessorValues.size());
273 return fProcessorValues[fieldIdx].fProcessorProvenance;
274 }
275
276 /////////////////////////////////////////////////////////////////////////////
277 /// \brief Get the name of a field in the entry, including processor name prefixes in the case of auxiliary fields.
278 ///
279 /// \param[in] fieldIdx The index of the field in the entry.
280 std::string GetFieldName(FieldIndex_t fieldIdx) const
281 {
282 assert(fieldIdx < fProcessorValues.size());
283 return fProcessorValues[fieldIdx].fProcessorProvenance.Get() + "." +
284 fProcessorValues[fieldIdx].fValue.GetField().GetQualifiedFieldName();
285 }
286
287 /////////////////////////////////////////////////////////////////////////////
288 /// \brief Get all field indices of this entry.
289 std::unordered_set<FieldIndex_t> GetFieldIndices() const
290 {
291 // Field indices are sequentially assigned, and the entry (currently) offers no way to remove fields, so we can
292 // just generate and return a set {0, ..., |fProcessorValues| - 1}.
293 std::unordered_set<FieldIndex_t> fieldIdxs(fProcessorValues.size());
294 std::generate_n(std::inserter(fieldIdxs, fieldIdxs.begin()), fProcessorValues.size(),
295 [i = 0]() mutable { return i++; });
296 return fieldIdxs;
297 }
298};
299} // namespace Internal
300} // namespace Experimental
301} // namespace ROOT
302
303#endif // ROOT_RNTupleProcessorEntry
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:299
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Collection of values in an RNTupleProcessor, analogous to REntry, with checks and support for missing...
FieldIndex_t AddField(std::string_view fieldName, ROOT::RFieldBase &field, void *valuePtr, const RNTupleProcessorProvenance &provenance)
Add a new field to the entry.
std::unordered_set< FieldIndex_t > GetFieldIndices() const
Get all field indices of this entry.
std::string GetFieldName(FieldIndex_t fieldIdx) const
Get the name of a field in the entry, including processor name prefixes in the case of auxiliary fiel...
void BindRawPtr(FieldIndex_t fieldIdx, void *valuePtr)
Bind a new value pointer to a field in the entry.
void UpdateField(FieldIndex_t fieldIdx, ROOT::RFieldBase &field)
Update a field in the entry, preserving the value pointer.
const ROOT::RFieldBase & GetField(FieldIndex_t fieldIdx) const
Get a reference to a field in the entry.
std::optional< FieldIndex_t > FindFieldIndex(std::string_view fieldName) const
Find the field index of the provided field in the entry.
bool IsValidField(FieldIndex_t fieldIdx) const
Check whether a field is valid for reading.
const std::string & FindFieldName(FieldIndex_t fieldIdx) const
Find the name of a field from its field index.
std::unordered_map< std::string, FieldIndex_t > fFieldName2Index
void ReadValue(FieldIndex_t fieldIdx, ROOT::NTupleSize_t entryIdx)
Read the field value corresponding to the given field index for the provided entry index.
void SetFieldValidity(FieldIndex_t fieldIdx, bool isValid)
Set the validity of a field, i.e.
const RNTupleProcessorProvenance & GetFieldProvenance(FieldIndex_t fieldIdx) const
Get the processor provenance of a field in the entry.
std::shared_ptr< T > GetPtr(FieldIndex_t fieldIdx) const
Get a pointer to the value for the field represented by the provided field index.
std::string Get() const
Get the full processor provenance, in the form of "x.y.z".
bool Contains(const RNTupleProcessorProvenance &other) const
Check whether the provenance subsumes the provenance in other.
bool IsPresentInFieldName(std::string_view fieldName) const
Check whether the provided field name contains this provenance.
RNTupleProcessorProvenance Evolve(const std::string &processorName) const
Add a new processor to the provenance.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
void BindRawPtr(void *rawPtr)
A field translates read and write calls from/to underlying columns to/from tree values.
RValue CreateValue()
Generates an object of the field's type, wraps it in a shared pointer and returns it as an RValue con...
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots (grandparent.parent....
Namespace for ROOT features in testing.
Definition TROOT.h:100
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
RProcessorValue(ROOT::RFieldBase::RValue &&value, bool isValid, RNTupleProcessorProvenance provenance)