Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleModel.hxx
Go to the documentation of this file.
1/// \file ROOT/RNTupleModel.hxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-04
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#ifndef ROOT7_RNTupleModel
17#define ROOT7_RNTupleModel
18
19#include <ROOT/REntry.hxx>
20#include <ROOT/RField.hxx>
21#include <ROOT/RNTupleUtil.hxx>
22#include <ROOT/RFieldValue.hxx>
23#include <ROOT/RStringView.hxx>
24
25#include <cstdint>
26#include <memory>
27#include <unordered_set>
28#include <utility>
29
30namespace ROOT {
31namespace Experimental {
32
33class RCollectionNTupleWriter;
34
35// clang-format off
36/**
37\class ROOT::Experimental::RNTupleModel
38\ingroup NTuple
39\brief The RNTupleModel encapulates the schema of an ntuple.
40
41The ntuple model comprises a collection of hierarchically organized fields. From a model, "entries"
42can be extracted. For convenience, the model provides a default entry. Models have a unique model identifier
43that faciliates checking whether entries are compatible with it (i.e.: have been extracted from that model).
44*/
45// clang-format on
47 /// Hierarchy of fields consisting of simple types and collections (sub trees)
48 std::unique_ptr<RFieldZero> fFieldZero;
49 /// Contains field values corresponding to the created top-level fields
50 std::unique_ptr<REntry> fDefaultEntry;
51 /// Keeps track of which field names are taken.
52 std::unordered_set<std::string> fFieldNames;
53 /// Free text set by the user
54 std::string fDescription;
55 /// Upon freezing, every model has a unique ID to distingusish it from other models. Cloning preserves the ID.
56 /// Entries are linked to models via the ID.
57 std::uint64_t fModelId = 0;
58
59 /// Checks that user-provided field names are valid in the context
60 /// of this NTuple model. Throws an RException for invalid names.
61 void EnsureValidFieldName(std::string_view fieldName);
62
63 /// Throws an RException if fFrozen is true
64 void EnsureNotFrozen() const;
65
66 /// Throws an RException if fDefaultEntry is nullptr
67 void EnsureNotBare() const;
68
70
71public:
72 RNTupleModel(const RNTupleModel&) = delete;
74 ~RNTupleModel() = default;
75
76 std::unique_ptr<RNTupleModel> Clone() const;
77 static std::unique_ptr<RNTupleModel> Create();
78 /// A bare model has no default entry
79 static std::unique_ptr<RNTupleModel> CreateBare() { return std::unique_ptr<RNTupleModel>(new RNTupleModel()); }
80
83 NameWithDescription_t(std::string_view name): fName(name) {}
84 NameWithDescription_t(std::string_view name, std::string_view descr):
85 fName(name), fDescription(descr) {}
86
87 std::string_view fName;
88 std::string_view fDescription = "";
89 };
90
91 /// Creates a new field given a `name` or `{name, description}` pair and a
92 /// corresponding tree value that is managed by a shared pointer.
93 ///
94 /// **Example: create some fields and fill an %RNTuple**
95 /// ~~~ {.cpp}
96 /// #include <ROOT/RNTuple.hxx>
97 /// using ROOT::Experimental::RNTupleModel;
98 /// using ROOT::Experimental::RNTupleWriter;
99 ///
100 /// #include <vector>
101 ///
102 /// auto model = RNTupleModel::Create();
103 /// auto pt = model->MakeField<float>("pt");
104 /// auto vec = model->MakeField<std::vector<int>>("vec");
105 ///
106 /// // The RNTuple is written to disk when the RNTupleWriter goes out of scope
107 /// {
108 /// auto ntuple = RNTupleWriter::Recreate(std::move(model), "myNTuple", "myFile.root");
109 /// for (int i = 0; i < 100; i++) {
110 /// *pt = static_cast<float>(i);
111 /// *vec = {i, i+1, i+2};
112 /// ntuple->Fill();
113 /// }
114 /// }
115 /// ~~~
116 ///
117 /// **Example: create a field with an initial value**
118 /// ~~~ {.cpp}
119 /// #include <ROOT/RNTuple.hxx>
120 /// using ROOT::Experimental::RNTupleModel;
121 ///
122 /// auto model = RNTupleModel::Create();
123 /// // pt's initial value is 42.0
124 /// auto pt = model->MakeField<float>("pt", 42.0);
125 /// ~~~
126 /// **Example: create a field with a description**
127 /// ~~~ {.cpp}
128 /// #include <ROOT/RNTuple.hxx>
129 /// using ROOT::Experimental::RNTupleModel;
130 ///
131 /// auto model = RNTupleModel::Create();
132 /// auto hadronFlavour = model->MakeField<float>({
133 /// "hadronFlavour", "flavour from hadron ghost clustering"
134 /// });
135 /// ~~~
136 template <typename T, typename... ArgsT>
137 std::shared_ptr<T> MakeField(const NameWithDescription_t &fieldNameDesc,
138 ArgsT&&... args)
139 {
141 EnsureValidFieldName(fieldNameDesc.fName);
142 auto field = std::make_unique<RField<T>>(fieldNameDesc.fName);
143 field->SetDescription(fieldNameDesc.fDescription);
144 std::shared_ptr<T> ptr;
145 if (fDefaultEntry)
146 ptr = fDefaultEntry->AddValue<T>(field.get(), std::forward<ArgsT>(args)...);
147 fFieldZero->Attach(std::move(field));
148 return ptr;
149 }
150
151 /// Adds a field whose type is not known at compile time. Thus there is no shared pointer returned.
152 ///
153 /// Throws an exception if the field is null.
154 void AddField(std::unique_ptr<Detail::RFieldBase> field);
155
156 /// Throws an exception if fromWhere is null.
157 template <typename T>
158 void AddField(const NameWithDescription_t &fieldNameDesc, T* fromWhere) {
161 if (!fromWhere)
162 throw RException(R__FAIL("null field fromWhere"));
163 EnsureValidFieldName(fieldNameDesc.fName);
164
165 auto field = std::make_unique<RField<T>>(fieldNameDesc.fName);
166 field->SetDescription(fieldNameDesc.fDescription);
167 fDefaultEntry->CaptureValue(field->CaptureValue(fromWhere));
168 fFieldZero->Attach(std::move(field));
169 }
170
171 template <typename T>
172 T *Get(std::string_view fieldName) const
173 {
175 return fDefaultEntry->Get<T>(fieldName);
176 }
177
178 void Freeze();
179 bool IsFrozen() const { return fModelId != 0; }
180 std::uint64_t GetModelId() const { return fModelId; }
181
182 /// Ingests a model for a sub collection and attaches it to the current model
183 ///
184 /// Throws an exception if collectionModel is null.
185 std::shared_ptr<RCollectionNTupleWriter> MakeCollection(
186 std::string_view fieldName,
187 std::unique_ptr<RNTupleModel> collectionModel);
188
189 std::unique_ptr<REntry> CreateEntry() const;
190 /// In a bare entry, all values point to nullptr. The resulting entry shall use CaptureValueUnsafe() in order
191 /// set memory addresses to be serialized / deserialized
192 std::unique_ptr<REntry> CreateBareEntry() const;
193 REntry *GetDefaultEntry() const;
194
195 RFieldZero *GetFieldZero() const { return fFieldZero.get(); }
196 const Detail::RFieldBase *GetField(std::string_view fieldName) const;
197
198 std::string GetDescription() const { return fDescription; }
199 void SetDescription(std::string_view description);
200};
201
202} // namespace Experimental
203} // namespace ROOT
204
205#endif
#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:303
char name[80]
Definition TGX11.cxx:110
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
Definition REntry.hxx:43
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:321
The RNTupleModel encapulates the schema of an ntuple.
std::unordered_set< std::string > fFieldNames
Keeps track of which field names are taken.
void AddField(const NameWithDescription_t &fieldNameDesc, T *fromWhere)
Throws an exception if fromWhere is null.
std::string fDescription
Free text set by the user.
void EnsureValidFieldName(std::string_view fieldName)
Checks that user-provided field names are valid in the context of this NTuple model.
std::uint64_t fModelId
Upon freezing, every model has a unique ID to distingusish it from other models.
std::uint64_t GetModelId() const
RNTupleModel(const RNTupleModel &)=delete
std::shared_ptr< T > MakeField(const NameWithDescription_t &fieldNameDesc, ArgsT &&... args)
Creates a new field given a name or {name, description} pair and a corresponding tree value that is m...
void EnsureNotBare() const
Throws an RException if fDefaultEntry is nullptr.
std::unique_ptr< RNTupleModel > Clone() const
void EnsureNotFrozen() const
Throws an RException if fFrozen is true.
std::unique_ptr< REntry > CreateBareEntry() const
In a bare entry, all values point to nullptr.
std::unique_ptr< REntry > CreateEntry() const
static std::unique_ptr< RNTupleModel > Create()
static std::unique_ptr< RNTupleModel > CreateBare()
A bare model has no default entry.
void SetDescription(std::string_view description)
std::unique_ptr< REntry > fDefaultEntry
Contains field values corresponding to the created top-level fields.
std::shared_ptr< RCollectionNTupleWriter > MakeCollection(std::string_view fieldName, std::unique_ptr< RNTupleModel > collectionModel)
Ingests a model for a sub collection and attaches it to the current model.
const Detail::RFieldBase * GetField(std::string_view fieldName) const
RFieldZero * GetFieldZero() const
T * Get(std::string_view fieldName) const
RNTupleModel & operator=(const RNTupleModel &)=delete
void AddField(std::unique_ptr< Detail::RFieldBase > field)
Adds a field whose type is not known at compile time.
std::unique_ptr< RFieldZero > fFieldZero
Hierarchy of fields consisting of simple types and collections (sub trees)
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
NameWithDescription_t(std::string_view name, std::string_view descr)