Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleModel.cxx
Go to the documentation of this file.
1/// \file RNTupleModel.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-15
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#include <ROOT/RError.hxx>
17#include <ROOT/RField.hxx>
18#include <ROOT/RNTupleModel.hxx>
20#include <ROOT/StringUtils.hxx>
21
22#include <atomic>
23#include <cstdlib>
24#include <memory>
25#include <utility>
26
27namespace {
28std::uint64_t GetNewModelId()
29{
30 static std::atomic<std::uint64_t> gLastModelId = 0;
31 return ++gLastModelId;
32}
33} // anonymous namespace
34
37{
38 return *model.fFieldZero;
39}
40
43{
44 return *model.fProjectedFields;
45}
46
47//------------------------------------------------------------------------------
48
51{
52 auto source = fieldMap.at(target);
53 const bool hasCompatibleStructure =
54 (source->GetStructure() == target->GetStructure()) ||
55 ((source->GetStructure() == ENTupleStructure::kCollection) && dynamic_cast<const RCardinalityField *>(target));
56 if (!hasCompatibleStructure)
57 return R__FAIL("field mapping structural mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
58 if ((source->GetStructure() == ENTupleStructure::kLeaf) || (source->GetStructure() == ENTupleStructure::kStreamer)) {
59 if (target->GetTypeName() != source->GetTypeName())
60 return R__FAIL("field mapping type mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
61 }
62
63 auto fnHasArrayParent = [](const RFieldBase &f) -> bool {
64 auto parent = f.GetParent();
65 while (parent) {
66 if (parent->GetNRepetitions() > 0)
67 return true;
68 parent = parent->GetParent();
69 }
70 return false;
71 };
72 if (fnHasArrayParent(*source) || fnHasArrayParent(*target)) {
73 return R__FAIL("unsupported field mapping across fixed-size arrays");
74 }
75
76 // We support projections only across records and collections. In the following, we check that the projected
77 // field is on the same path of collection fields in the field tree than the source field.
78
79 // Finds the first non-record parent field of the input field
80 auto fnBreakPoint = [](const RFieldBase *f) -> const RFieldBase * {
81 auto parent = f->GetParent();
82 while (parent) {
83 if ((parent->GetStructure() != ENTupleStructure::kRecord) &&
84 (parent->GetStructure() != ENTupleStructure::kLeaf)) {
85 return parent;
86 }
87 parent = parent->GetParent();
88 }
89 // We reached the zero field
90 return nullptr;
91 };
92
93 // If source or target has a variant or reference as a parent, error out
94 auto *sourceBreakPoint = fnBreakPoint(source);
95 if (sourceBreakPoint && sourceBreakPoint->GetStructure() != ENTupleStructure::kCollection)
96 return R__FAIL("unsupported field mapping (source structure)");
97 auto *targetBreakPoint = fnBreakPoint(target);
98 if (targetBreakPoint && sourceBreakPoint->GetStructure() != ENTupleStructure::kCollection)
99 return R__FAIL("unsupported field mapping (target structure)");
100
101 if (!sourceBreakPoint && !targetBreakPoint) {
102 // Source and target have no collections as parent
103 return RResult<void>::Success();
104 }
105 if (sourceBreakPoint && targetBreakPoint) {
106 if (sourceBreakPoint == targetBreakPoint) {
107 // Source and target are children of the same collection
108 return RResult<void>::Success();
109 }
110 if (auto it = fieldMap.find(targetBreakPoint); it != fieldMap.end() && it->second == sourceBreakPoint) {
111 // The parent collection of parent is mapped to the parent collection of the source
112 return RResult<void>::Success();
113 }
114 // Source and target are children of different collections
115 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
116 }
117
118 // Either source or target have no collection as a parent, but the other one has; that doesn't fit
119 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
120}
121
123ROOT::Experimental::Internal::RProjectedFields::Add(std::unique_ptr<RFieldBase> field, const FieldMap_t &fieldMap)
124{
125 auto result = EnsureValidMapping(field.get(), fieldMap);
126 if (!result)
127 return R__FORWARD_ERROR(result);
128 for (const auto &f : *field) {
129 result = EnsureValidMapping(&f, fieldMap);
130 if (!result)
131 return R__FORWARD_ERROR(result);
132 }
133
134 fFieldMap.insert(fieldMap.begin(), fieldMap.end());
135 fFieldZero->Attach(std::move(field));
136 return RResult<void>::Success();
137}
138
141{
142 if (auto it = fFieldMap.find(target); it != fFieldMap.end())
143 return it->second;
144 return nullptr;
145}
146
147std::unique_ptr<ROOT::Experimental::Internal::RProjectedFields>
149{
150 auto cloneFieldZero = std::unique_ptr<RFieldZero>(static_cast<RFieldZero *>(fFieldZero->Clone("").release()));
151 auto clone = std::unique_ptr<RProjectedFields>(new RProjectedFields(std::move(cloneFieldZero)));
152 clone->fModel = &newModel;
153 // TODO(jblomer): improve quadratic search to re-wire the field mappings given the new model and the cloned
154 // projected fields. Not too critical as we generally expect a limited number of projected fields
155 for (const auto &[k, v] : fFieldMap) {
156 for (const auto &f : clone->GetFieldZero()) {
157 if (f.GetQualifiedFieldName() == k->GetQualifiedFieldName()) {
158 clone->fFieldMap[&f] = &newModel.GetConstField(v->GetQualifiedFieldName());
159 break;
160 }
161 }
162 }
163 return clone;
164}
165
167 : fWriter(writer), fOpenChangeset(fWriter.GetUpdatableModel())
168{
169}
170
172{
173 fOpenChangeset.fModel.Unfreeze();
174 // We set the model ID to zero until CommitUpdate(). That prevents calls to RNTupleWriter::Fill() in the middle
175 // of updates
176 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
177}
178
180{
181 fOpenChangeset.fModel.Freeze();
182 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
183 if (fOpenChangeset.IsEmpty())
184 return;
185 Internal::RNTupleModelChangeset toCommit{fOpenChangeset.fModel};
186 std::swap(fOpenChangeset.fAddedFields, toCommit.fAddedFields);
187 std::swap(fOpenChangeset.fAddedProjectedFields, toCommit.fAddedProjectedFields);
188 fWriter.GetSink().UpdateSchema(toCommit, fWriter.GetNEntries());
189}
190
191void ROOT::Experimental::RNTupleModel::RUpdater::AddField(std::unique_ptr<RFieldBase> field)
192{
193 auto fieldp = field.get();
194 fOpenChangeset.fModel.AddField(std::move(field));
195 fOpenChangeset.fAddedFields.emplace_back(fieldp);
196}
197
200 FieldMappingFunc_t mapping)
201{
202 auto fieldp = field.get();
203 auto result = fOpenChangeset.fModel.AddProjectedField(std::move(field), mapping);
204 if (result)
205 fOpenChangeset.fAddedProjectedFields.emplace_back(fieldp);
207}
208
210{
212 if (!nameValid) {
213 nameValid.Throw();
214 }
215 if (fieldName.empty()) {
216 throw RException(R__FAIL("name cannot be empty string \"\""));
217 }
218 auto fieldNameStr = std::string(fieldName);
219 if (fFieldNames.count(fieldNameStr) > 0)
220 throw RException(R__FAIL("field name '" + fieldNameStr + "' already exists in NTuple model"));
221}
222
224{
225 if (IsFrozen())
226 throw RException(R__FAIL("invalid attempt to modify frozen model"));
227}
228
230{
231 if (IsBare())
232 throw RException(R__FAIL("invalid attempt to use default entry of bare model"));
233}
234
235ROOT::Experimental::RNTupleModel::RNTupleModel(std::unique_ptr<RFieldZero> fieldZero)
236 : fFieldZero(std::move(fieldZero)), fModelId(GetNewModelId()), fSchemaId(fModelId)
237{}
238
239std::unique_ptr<ROOT::Experimental::RNTupleModel> ROOT::Experimental::RNTupleModel::CreateBare()
240{
241 return CreateBare(std::make_unique<RFieldZero>());
242}
243
244std::unique_ptr<ROOT::Experimental::RNTupleModel>
245ROOT::Experimental::RNTupleModel::CreateBare(std::unique_ptr<RFieldZero> fieldZero)
246{
247 auto model = std::unique_ptr<RNTupleModel>(new RNTupleModel(std::move(fieldZero)));
248 model->fProjectedFields = std::make_unique<Internal::RProjectedFields>(*model);
249 return model;
250}
251
252std::unique_ptr<ROOT::Experimental::RNTupleModel> ROOT::Experimental::RNTupleModel::Create()
253{
254 return Create(std::make_unique<RFieldZero>());
255}
256
257std::unique_ptr<ROOT::Experimental::RNTupleModel>
258ROOT::Experimental::RNTupleModel::Create(std::unique_ptr<RFieldZero> fieldZero)
259{
260 auto model = CreateBare(std::move(fieldZero));
261 model->fDefaultEntry = std::unique_ptr<REntry>(new REntry(model->fModelId, model->fSchemaId));
262 return model;
263}
264
265std::unique_ptr<ROOT::Experimental::RNTupleModel> ROOT::Experimental::RNTupleModel::Clone() const
266{
267 auto cloneModel = std::unique_ptr<RNTupleModel>(
268 new RNTupleModel(std::unique_ptr<RFieldZero>(static_cast<RFieldZero *>(fFieldZero->Clone("").release()))));
269 cloneModel->fModelId = GetNewModelId();
270 // For a frozen model, we can keep the schema id because adding new fields is forbidden. It is reset in Unfreeze()
271 // if called by the user.
272 if (fIsFrozen) {
273 cloneModel->fSchemaId = fSchemaId;
274 } else {
275 cloneModel->fSchemaId = cloneModel->fModelId;
276 }
277 cloneModel->fIsFrozen = fIsFrozen;
278 cloneModel->fFieldNames = fFieldNames;
279 cloneModel->fDescription = fDescription;
280 cloneModel->fProjectedFields = fProjectedFields->Clone(*cloneModel);
281 cloneModel->fRegisteredSubfields = fRegisteredSubfields;
282 if (fDefaultEntry) {
283 cloneModel->fDefaultEntry = std::unique_ptr<REntry>(new REntry(cloneModel->fModelId, cloneModel->fSchemaId));
284 for (const auto &f : cloneModel->fFieldZero->GetSubFields()) {
285 cloneModel->fDefaultEntry->AddValue(f->CreateValue());
286 }
287 for (const auto &f : cloneModel->fRegisteredSubfields) {
288 cloneModel->AddSubfield(f, *cloneModel->fDefaultEntry);
289 }
290 }
291 return cloneModel;
292}
293
295{
296 if (fieldName.empty())
297 return nullptr;
298
299 auto *field = static_cast<ROOT::Experimental::RFieldBase *>(fFieldZero.get());
300 for (auto subfieldName : ROOT::Split(fieldName, ".")) {
301 const auto subfields = field->GetSubFields();
302 auto it = std::find_if(subfields.begin(), subfields.end(),
303 [&](const auto *f) { return f->GetFieldName() == subfieldName; });
304 if (it != subfields.end()) {
305 field = *it;
306 } else {
307 field = nullptr;
308 break;
309 }
310 }
311
312 return field;
313}
314
315void ROOT::Experimental::RNTupleModel::AddField(std::unique_ptr<RFieldBase> field)
316{
317 EnsureNotFrozen();
318 if (!field)
319 throw RException(R__FAIL("null field"));
320 EnsureValidFieldName(field->GetFieldName());
321
322 if (fDefaultEntry)
323 fDefaultEntry->AddValue(field->CreateValue());
324 fFieldNames.insert(field->GetFieldName());
325 fFieldZero->Attach(std::move(field));
326}
327
328void ROOT::Experimental::RNTupleModel::AddSubfield(std::string_view qualifiedFieldName, REntry &entry,
329 bool initializeValue) const
330{
331 auto field = FindField(qualifiedFieldName);
332 if (initializeValue)
333 entry.AddValue(field->CreateValue());
334 else
335 entry.AddValue(field->BindValue(nullptr));
336}
337
338void ROOT::Experimental::RNTupleModel::RegisterSubfield(std::string_view qualifiedFieldName)
339{
340 if (qualifiedFieldName.empty())
341 throw RException(R__FAIL("no field name provided"));
342
343 if (fFieldNames.find(std::string(qualifiedFieldName)) != fFieldNames.end()) {
344 throw RException(
345 R__FAIL("cannot register top-level field \"" + std::string(qualifiedFieldName) + "\" as a subfield"));
346 }
347
348 if (fRegisteredSubfields.find(std::string(qualifiedFieldName)) != fRegisteredSubfields.end())
349 throw RException(R__FAIL("subfield \"" + std::string(qualifiedFieldName) + "\" already registered"));
350
351 EnsureNotFrozen();
352
353 auto *field = FindField(qualifiedFieldName);
354 if (!field) {
355 throw RException(R__FAIL("could not find subfield \"" + std::string(qualifiedFieldName) + "\" in model"));
356 }
357
358 auto parent = field->GetParent();
359 while (parent && !parent->GetFieldName().empty()) {
360 if (parent->GetStructure() == ENTupleStructure::kCollection || parent->GetNRepetitions() > 0 ||
361 parent->GetStructure() == ENTupleStructure::kVariant) {
362 throw RException(R__FAIL(
363 "registering a subfield as part of a collection, fixed-sized array or std::variant is not supported"));
364 }
365 parent = parent->GetParent();
366 }
367
368 if (fDefaultEntry)
369 AddSubfield(qualifiedFieldName, *fDefaultEntry);
370 fRegisteredSubfields.emplace(qualifiedFieldName);
371}
372
375{
376 EnsureNotFrozen();
377 if (!field)
378 return R__FAIL("null field");
379 auto fieldName = field->GetFieldName();
380
382 auto sourceField = FindField(mapping(fieldName));
383 if (!sourceField)
384 return R__FAIL("no such field: " + mapping(fieldName));
385 fieldMap[field.get()] = sourceField;
386 for (const auto &subField : *field) {
387 sourceField = FindField(mapping(subField.GetQualifiedFieldName()));
388 if (!sourceField)
389 return R__FAIL("no such field: " + mapping(fieldName));
390 fieldMap[&subField] = sourceField;
391 }
392
393 EnsureValidFieldName(fieldName);
394 auto result = fProjectedFields->Add(std::move(field), fieldMap);
395 if (!result) {
396 return R__FORWARD_ERROR(result);
397 }
398 fFieldNames.insert(fieldName);
399 return RResult<void>::Success();
400}
401
403{
404 if (IsFrozen())
405 throw RException(R__FAIL("invalid attempt to get mutable zero field of frozen model"));
406 return *fFieldZero;
407}
408
410{
411 if (IsFrozen())
412 throw RException(R__FAIL("invalid attempt to get mutable field of frozen model"));
413 auto f = FindField(fieldName);
414 if (!f)
415 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
416
417 return *f;
418}
419
421{
422 auto f = FindField(fieldName);
423 if (!f)
424 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
425
426 return *f;
427}
428
430{
431 EnsureNotBare();
432 return *fDefaultEntry;
433}
434
436{
437 if (!IsFrozen())
438 throw RException(R__FAIL("invalid attempt to get default entry of unfrozen model"));
439 EnsureNotBare();
440 return *fDefaultEntry;
441}
442
443std::unique_ptr<ROOT::Experimental::REntry> ROOT::Experimental::RNTupleModel::CreateEntry() const
444{
445 if (!IsFrozen())
446 throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
447
448 auto entry = std::unique_ptr<REntry>(new REntry(fModelId, fSchemaId));
449 for (const auto &f : fFieldZero->GetSubFields()) {
450 entry->AddValue(f->CreateValue());
451 }
452 for (const auto &f : fRegisteredSubfields) {
453 AddSubfield(f, *entry);
454 }
455 return entry;
456}
457
458std::unique_ptr<ROOT::Experimental::REntry> ROOT::Experimental::RNTupleModel::CreateBareEntry() const
459{
460 if (!IsFrozen())
461 throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
462
463 auto entry = std::unique_ptr<REntry>(new REntry(fModelId, fSchemaId));
464 for (const auto &f : fFieldZero->GetSubFields()) {
465 entry->AddValue(f->BindValue(nullptr));
466 }
467 for (const auto &f : fRegisteredSubfields) {
468 AddSubfield(f, *entry, false /* initializeValue */);
469 }
470 return entry;
471}
472
474{
475 const auto &topLevelFields = fFieldZero->GetSubFields();
476 auto it = std::find_if(topLevelFields.begin(), topLevelFields.end(),
477 [&fieldName](const RFieldBase *f) { return f->GetFieldName() == fieldName; });
478
479 if (it == topLevelFields.end()) {
480 throw RException(R__FAIL("invalid field name: " + std::string(fieldName)));
481 }
482 return REntry::RFieldToken(std::distance(topLevelFields.begin(), it), fSchemaId);
483}
484
486{
487 if (!IsFrozen())
488 throw RException(R__FAIL("invalid attempt to create bulk of unfrozen model"));
489
490 auto f = FindField(fieldName);
491 if (!f)
492 throw RException(R__FAIL("no such field: " + std::string(fieldName)));
493 return f->CreateBulk();
494}
495
497{
498 if (!IsFrozen())
499 return;
500
501 fModelId = GetNewModelId();
502 fSchemaId = fModelId;
503 if (fDefaultEntry) {
504 fDefaultEntry->fModelId = fModelId;
505 fDefaultEntry->fSchemaId = fSchemaId;
506 }
507 fIsFrozen = false;
508}
509
511{
512 fIsFrozen = true;
513}
514
515void ROOT::Experimental::RNTupleModel::SetDescription(std::string_view description)
516{
517 EnsureNotFrozen();
518 fDescription = std::string(description);
519}
520
522{
523 std::size_t bytes = 0;
524 std::size_t minPageBufferSize = 0;
525
526 // Start with the size of the page buffers used to fill a persistent sink
527 std::size_t nColumns = 0;
528 for (auto &&field : *fFieldZero) {
529 for (const auto &r : field.GetColumnRepresentatives()) {
530 nColumns += r.size();
531 for (auto columnType : r) {
532 minPageBufferSize +=
534 }
535 }
536 }
537 bytes = std::min(options.GetPageBufferBudget(), nColumns * options.GetMaxUnzippedPageSize());
538
539 // If using buffered writing with RPageSinkBuf, we create a clone of the model and keep at least
540 // the compressed pages in memory.
541 if (options.GetUseBufferedWrite()) {
542 bytes += minPageBufferSize;
543 // Use the target cluster size as an estimate for all compressed pages combined.
545 int compression = options.GetCompression();
546 if (compression != 0 && options.GetUseImplicitMT() == RNTupleWriteOptions::EImplicitMT::kDefault) {
547 // With IMT, compression happens asynchronously which means that the uncompressed pages also stay around. Use a
548 // compression factor of 2x as a very rough estimate.
549 bytes += 2 * options.GetApproxZippedClusterSize();
550 }
551 }
552
553 return bytes;
554}
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
Definition RError.hxx:294
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:292
#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:290
#define f(i)
Definition RSha256.hxx:104
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 Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
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 r
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 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 Atom_t Int_t ULong_t ULong_t bytes
static std::unique_ptr< RColumnElementBase > Generate(EColumnType type)
If CppT == void, use the default C++ type for the given column type.
The projected fields of a RNTupleModel
std::unique_ptr< RProjectedFields > Clone(const RNTupleModel &newModel) const
The new model needs to be a clone of fModel.
RResult< void > EnsureValidMapping(const RFieldBase *target, const FieldMap_t &fieldMap)
Asserts that the passed field is a valid target of the source field provided in the field map.
std::unordered_map< const RFieldBase *, const RFieldBase * > FieldMap_t
The map keys are the projected target fields, the map values are the backing source fields Note that ...
const RFieldBase * GetSourceField(const RFieldBase *target) const
RResult< void > Add(std::unique_ptr< RFieldBase > field, const FieldMap_t &fieldMap)
Adds a new projected field.
An artificial field that transforms an RNTuple column that contains the offset of collections into co...
Definition RField.hxx:268
The field token identifies a (sub)field in this entry.
Definition REntry.hxx:61
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
Definition REntry.hxx:51
void AddValue(RFieldBase::RValue &&value)
Definition REntry.hxx:88
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Similar to RValue but manages an array of consecutive values.
A field translates read and write calls from/to underlying columns to/from tree values.
const RFieldBase * GetParent() const
std::vector< RFieldBase * > GetSubFields()
Definition RField.cxx:995
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:58
void CommitUpdate()
Commit changes since the last call to BeginUpdate().
void BeginUpdate()
Begin a new set of alterations to the underlying model.
RResult< void > AddProjectedField(std::unique_ptr< RFieldBase > field, FieldMappingFunc_t mapping)
void AddField(std::unique_ptr< RFieldBase > field)
The RNTupleModel encapulates the schema of an ntuple.
std::unordered_set< std::string > fFieldNames
Keeps track of which field names are taken, including projected field names.
void EnsureValidFieldName(std::string_view fieldName)
Checks that user-provided field names are valid in the context of this RNTuple model.
std::uint64_t fModelId
Every model has a unique ID to distinguish it from other models.
std::function< std::string(const std::string &)> FieldMappingFunc_t
User provided function that describes the mapping of existing source fields to projected fields in te...
std::unique_ptr< Internal::RProjectedFields > fProjectedFields
The set of projected top-level fields.
const RFieldBase & GetConstField(std::string_view fieldName) const
std::uint64_t fSchemaId
Models have a separate schema ID to remember that the clone of a frozen model still has the same sche...
REntry::RFieldToken GetToken(std::string_view fieldName) const
Creates a token to be used in REntry methods to address a field present in the entry.
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.
RFieldZero & GetMutableFieldZero()
Mutable access to the root field is used to make adjustments to the fields.
std::size_t EstimateWriteMemoryUsage(const RNTupleWriteOptions &options=RNTupleWriteOptions()) const
Estimate the memory usage for this model during writing.
std::unique_ptr< REntry > CreateBareEntry() const
In a bare entry, all values point to nullptr.
std::unique_ptr< REntry > CreateEntry() const
RFieldBase::RBulk CreateBulk(std::string_view fieldName) const
Calls the given field's CreateBulk() method. Throws an exception if no field with the given name exis...
static std::unique_ptr< RNTupleModel > Create()
void AddSubfield(std::string_view fieldName, REntry &entry, bool initializeValue=true) const
Add a subfield to the provided entry.
RResult< void > AddProjectedField(std::unique_ptr< RFieldBase > field, FieldMappingFunc_t mapping)
Adds a top-level field based on existing fields.
void SetDescription(std::string_view description)
RFieldBase * FindField(std::string_view fieldName) const
The field name can be a top-level field or a nested field. Returns nullptr if the field is not in the...
RNTupleModel(std::unique_ptr< RFieldZero > fieldZero)
RFieldBase & GetMutableField(std::string_view fieldName)
static std::unique_ptr< RNTupleModel > CreateBare()
A bare model has no default entry.
void AddField(std::unique_ptr< RFieldBase > field)
Adds a field whose type is not known at compile time.
void RegisterSubfield(std::string_view qualifiedFieldName)
Register a subfield so it can be accessed directly from entries belonging to the model.
std::unique_ptr< RFieldZero > fFieldZero
Hierarchy of fields consisting of simple types and collections (sub trees)
Common user-tunable settings for storing ntuples.
An RNTuple that gets filled with entries (data) and writes them to storage.
void Throw()
Throws an RException with fError.
Definition RError.cxx:67
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:194
RProjectedFields & GetProjectedFieldsOfModel(RNTupleModel &model)
RResult< void > EnsureValidNameForRNTuple(std::string_view name, std::string_view where)
Check whether a given string is a valid name according to the RNTuple specification.
RFieldZero & GetFieldZeroOfModel(RNTupleModel &model)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
The incremental changes to a RNTupleModel