Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleAttrWriting.hxx
Go to the documentation of this file.
1/// \file ROOT/RNTupleAttrWriting.hxx
2/// \author Giacomo Parolini <giacomo.parolini@cern.ch>
3/// \date 2026-01-27
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#ifndef ROOT7_RNTuple_Attr_Writing
8#define ROOT7_RNTuple_Attr_Writing
9
10#include <memory>
11#include <string_view>
12
13#include <ROOT/REntry.hxx>
15#include <ROOT/RNTupleUtils.hxx>
16
17namespace ROOT {
18
19class RNTupleModel;
20class RNTuple;
21class RNTupleWriter;
22
23class RNTupleAttrSetWriter;
24
25namespace Internal {
26
27// clang-format off
28/**
29\class ROOT::Internal::RNTupleAttrEntry
30\ingroup NTuple
31\brief A pair of scoped + meta entry used by the RNTupleAttrSetWriter.
32
33The meta entry is used to write the "meta fields" that are always present in an Attribute Set (start/len); the scoped
34entry is used to write the user-provided fields.
35*/
36// clang-format on
45
46} // namespace Internal
47
48// clang-format off
49/**
50\class ROOT::RNTupleAttrPendingRange
51\ingroup NTuple
52\brief A not-yet-finalized Attribute Range used for writing
53
54A range used for writing. It has a well-defined start but not a length/end yet.
55It is artificially made non-copyable in order to clarify the semantics of Begin/CommitRange.
56For the same reason, it can only be created by the AttrSetWriter.
57*/
58// clang-format on
61
63 std::uint64_t fModelId = 0;
64 bool fWasCommitted = false;
65
67 : fStart(start), fModelId(modelId)
68 {
69 }
70
71public:
75
76 RNTupleAttrPendingRange(RNTupleAttrPendingRange &&other) { *this = std::move(other); }
77
78 // NOTE: explicitly implemented to make sure that 'other' gets invalidated upon move.
80 {
81 if (&other != this) {
82 std::swap(fStart, other.fStart);
83 std::swap(fModelId, other.fModelId);
84 other.fWasCommitted = true;
85 fWasCommitted = false;
86 }
87 return *this;
88 }
89
91 {
93 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "A pending attribute range was not committed! If CommitRange() "
94 "is not explicitly called before closing the main "
95 "Writer, the attributes will not be saved to storage!";
96 }
97
99 {
100 if (!IsValid())
101 throw ROOT::RException(R__FAIL("Tried to get the start of an invalid AttrPendingRange."));
102 return fStart;
103 }
104
106
107 /// Returns true if this PendingRange is valid
108 operator bool() const { return IsValid(); }
109 bool IsValid() const { return fModelId != 0; }
110};
111
112// clang-format off
113/**
114\class ROOT::RNTupleAttrSetWriter
115\ingroup NTuple
116\brief Class used to write an RNTupleAttrSet in the context of an RNTupleWriter.
117
118An Attribute Set is written as a separate RNTuple linked to the "main" RNTuple that created it.
119A RNTupleAttrSetWriter only lives as long as the RNTupleWriter that created it (or until CloseAttributeSet() is called).
120Users should not use this class directly but rather via RNTupleAttrSetWriterHandle, which is the type returned by
121RNTupleWriter::CreateAttributeSet().
122
123~~~ {.cpp}
124// Writing attributes via RNTupleAttrSetWriter
125// -------------------------------------------
126
127// First define the schema of your Attribute Set:
128auto attrModel = ROOT::RNTupleModel::Create();
129auto pMyAttr = attrModel->MakeField<std::string>("myAttr");
130
131// Then, assuming `writer` is an RNTupleWriter, create it:
132auto attrSet = writer->CreateAttributeSet(std::move(attrModel), "MyAttrSet");
133
134// Attributes are assigned to entry ranges. A range is started via BeginRange():
135auto range = attrSet->BeginRange();
136
137// To assign actual attributes, you use the same interface as the main RNTuple:
138*pMyAttr = "This is my attribute for this range";
139
140// ... here you can fill your main RNTuple with data ...
141
142// Once you're done, close the range. This will commit the attribute data and bind it to all data written
143// between BeginRange() and CommitRange().
144attrSet->CommitRange(std::move(range));
145
146// You don't need to explicitly close the AttributeSet, but if you want to do so, use:
147// writer->CloseAttributeSet(std::move(attrSet));
148~~~
149*/
150// clang-format on
153
154 /// Our own fill context.
156 /// Fill context of the main RNTuple being written (i.e. the RNTuple whose attributes we are).
158 /// The model that the user provided on creation. Used to create user-visible entries.
159 std::unique_ptr<RNTupleModel> fUserModel;
160
161 // Cached values of the meta entry pointers.
162 std::shared_ptr<ROOT::NTupleSize_t> fRangeStartPtr;
163 std::shared_ptr<ROOT::NTupleSize_t> fRangeLenPtr;
164
165 /// Creates an RNTupleAttrSetWriter associated to the RNTupleWriter owning `mainFillContext` and writing
166 /// using `sink`. `userModel` is the schema of the AttributeSet.
167 static std::unique_ptr<RNTupleAttrSetWriter> Create(const RNTupleFillContext &mainFillContext,
168 std::unique_ptr<ROOT::Internal::RPageSink> sink,
169 std::unique_ptr<RNTupleModel> userModel);
170
171 RNTupleAttrSetWriter(const RNTupleFillContext &mainFillContext, std::unique_ptr<ROOT::Internal::RPageSink> sink,
172 std::unique_ptr<RNTupleModel> metaModel, std::unique_ptr<RNTupleModel> userModel,
173 std::shared_ptr<ROOT::NTupleSize_t> rangeStartPtr,
174 std::shared_ptr<ROOT::NTupleSize_t> rangeLenPtr);
175
176 /// Commits the attributes written so far to disk and disables writing any new ones.
178
179public:
180 /// Returns the descriptor of the underlying attribute RNTuple. This is **NOT** the same descriptor as the
181 /// main RNTuple being written!
182 const ROOT::RNTupleDescriptor &GetDescriptor() const { return fFillContext.fSink->GetDescriptor(); }
183 /// Returns the user-defined model used to create this attribute set.
184 const ROOT::RNTupleModel &GetModel() const { return *fUserModel; }
185
186 /// Begins an attribute range. All entries filled in the main RNTupleWriter between BeginRange and CommitRange
187 /// will be associated with the set of values of the fields of this attribute set at the moment of CommitRange.
188 /// Note that every attribute range must be explicitly committed for it to be stored on disk.
189 /// \return An object describing the pending range, which must be passed back to CommitRange to end the attribute
190 /// range
191 [[nodiscard]] RNTupleAttrPendingRange BeginRange();
192 /// Ends an attribute range and associates the current values of the fields of the attribute model's default entry
193 /// with all the main RNTuple entries filled since the BeginRange that created the given `range`.
194 /// This is only valid if the model used to create this attribute set is not bare.
196 /// Like CommitRange(RNTupleAttrPendingRange range) but uses the given entry rather than the default entry.
197 /// The given entry must have been created by CreateEntry().
198 void CommitRange(RNTupleAttrPendingRange range, REntry &entry);
199
200 /// Creates an REntry fit to pass to CommitRange(RNTupleAttrPendingRange range, REntry entry).
201 std::unique_ptr<REntry> CreateEntry() { return fUserModel->CreateEntry(); }
202};
203
204// clang-format off
205/**
206\class ROOT::RNTupleAttrSetWriterHandle
207\ingroup NTuple
208\brief Non-owning handle to an RNTupleAttrSetWriter
209
210RNTupleAttrSetWriter can only be used through an RNTupleAttrSetWriterHandle, a weak_ptr-like object that allows safe
211access to it. The lifetime of an attribute set writer is tied to its parent RNTupleWriter, so the handle handed out
212by RNTupleWriter::CreateAttributeSet is invalidated as soon as the parent writer is destructed.
213
214*/
215// clang-format on
218
219 std::weak_ptr<RNTupleAttrSetWriter> fWriter;
220
221 explicit RNTupleAttrSetWriterHandle(const std::shared_ptr<RNTupleAttrSetWriter> &range) : fWriter(range) {}
222
223public:
228
229 /// Retrieves the underlying pointer to the AttrSetWriter, throwing if it's invalid.
231 {
232 auto ptr = fWriter.lock();
233 if (R__unlikely(!ptr))
234 throw ROOT::RException(R__FAIL("Tried to access invalid RNTupleAttrSetWriterHandle"));
235 return ptr.get();
236 }
237};
238
239} // namespace ROOT
240
241#endif
#define R__unlikely(expr)
Definition RConfig.hxx:568
#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:322
#define R__LOG_WARNING(...)
Definition RLogger.hxx:357
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:55
std::uint64_t GetModelId() const
Definition REntry.hxx:256
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
A not-yet-finalized Attribute Range used for writing.
RNTupleAttrPendingRange & operator=(RNTupleAttrPendingRange &&other)
ROOT::DescriptorId_t GetModelId() const
RNTupleAttrPendingRange(ROOT::NTupleSize_t start, ROOT::DescriptorId_t modelId)
RNTupleAttrPendingRange(const RNTupleAttrPendingRange &)=delete
RNTupleAttrPendingRange & operator=(const RNTupleAttrPendingRange &)=delete
ROOT::NTupleSize_t GetStart() const
RNTupleAttrPendingRange(RNTupleAttrPendingRange &&other)
Non-owning handle to an RNTupleAttrSetWriter.
RNTupleAttrSetWriter * operator->()
Retrieves the underlying pointer to the AttrSetWriter, throwing if it's invalid.
RNTupleAttrSetWriterHandle(const RNTupleAttrSetWriterHandle &)=delete
RNTupleAttrSetWriterHandle(const std::shared_ptr< RNTupleAttrSetWriter > &range)
RNTupleAttrSetWriterHandle & operator=(RNTupleAttrSetWriterHandle &&other)=default
RNTupleAttrSetWriterHandle & operator=(const RNTupleAttrSetWriterHandle &)=delete
std::weak_ptr< RNTupleAttrSetWriter > fWriter
RNTupleAttrSetWriterHandle(RNTupleAttrSetWriterHandle &&)=default
Class used to write an RNTupleAttrSet in the context of an RNTupleWriter.
RNTupleAttrSetWriter(const RNTupleFillContext &mainFillContext, std::unique_ptr< ROOT::Internal::RPageSink > sink, std::unique_ptr< RNTupleModel > metaModel, std::unique_ptr< RNTupleModel > userModel, std::shared_ptr< ROOT::NTupleSize_t > rangeStartPtr, std::shared_ptr< ROOT::NTupleSize_t > rangeLenPtr)
void CommitRange(RNTupleAttrPendingRange range)
Ends an attribute range and associates the current values of the fields of the attribute model's defa...
static std::unique_ptr< RNTupleAttrSetWriter > Create(const RNTupleFillContext &mainFillContext, std::unique_ptr< ROOT::Internal::RPageSink > sink, std::unique_ptr< RNTupleModel > userModel)
Creates an RNTupleAttrSetWriter associated to the RNTupleWriter owning mainFillContext and writing us...
std::shared_ptr< ROOT::NTupleSize_t > fRangeLenPtr
std::unique_ptr< RNTupleModel > fUserModel
The model that the user provided on creation. Used to create user-visible entries.
std::unique_ptr< REntry > CreateEntry()
Creates an REntry fit to pass to CommitRange(RNTupleAttrPendingRange range, REntry entry).
RNTupleFillContext fFillContext
Our own fill context.
RNTupleAttrPendingRange BeginRange()
Begins an attribute range.
const ROOT::RNTupleModel & GetModel() const
Returns the user-defined model used to create this attribute set.
std::shared_ptr< ROOT::NTupleSize_t > fRangeStartPtr
const RNTupleFillContext * fMainFillContext
Fill context of the main RNTuple being written (i.e. the RNTuple whose attributes we are).
ROOT::Internal::RNTupleLink Commit()
Commits the attributes written so far to disk and disables writing any new ones.
const ROOT::RNTupleDescriptor & GetDescriptor() const
Returns the descriptor of the underlying attribute RNTuple.
The on-storage metadata of an RNTuple.
A context for filling entries (data) into clusters of an RNTuple.
std::unique_ptr< ROOT::Internal::RPageSink > fSink
The RNTupleModel encapulates the schema of an RNTuple.
An RNTuple that gets filled with entries (data) and writes them to storage.
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
A pair of scoped + meta entry used by the RNTupleAttrSetWriter.
ROOT::DescriptorId_t GetModelId() const